Refactor dependencies and remove unused packages; update Flutter HTML package; add novel reader settings UI

This commit is contained in:
Moustapha Kodjo Amadou 2025-11-08 01:38:29 +01:00
parent 430e062a06
commit af20e084b0
21 changed files with 2927 additions and 946 deletions

View file

@ -244,6 +244,22 @@ class Settings {
@enumerated
late NovelTextAlign novelTextAlign;
String? novelReaderTheme;
String? novelReaderTextColor;
int? novelReaderPadding;
double? novelReaderLineHeight;
bool? novelShowScrollPercentage;
bool? novelAutoScroll;
bool? novelRemoveExtraParagraphSpacing;
bool? novelTapToScroll;
List<String>? navigationOrder;
List<String>? hideItems;
@ -392,6 +408,14 @@ class Settings {
this.novelDisplayType = DisplayType.comfortableGrid,
this.novelFontSize = 14,
this.novelTextAlign = NovelTextAlign.left,
this.novelReaderTheme = '#292832',
this.novelReaderTextColor = '#CCCCCC',
this.novelReaderPadding = 16,
this.novelReaderLineHeight = 1.5,
this.novelShowScrollPercentage = true,
this.novelAutoScroll = false,
this.novelRemoveExtraParagraphSpacing = false,
this.novelTapToScroll = false,
this.navigationOrder,
this.hideItems,
this.clearChapterCacheOnAppLaunch = false,
@ -605,6 +629,22 @@ class Settings {
}
novelTextAlign = NovelTextAlign
.values[json['novelTextAlign'] ?? NovelTextAlign.left.index];
if (json['novelReaderTheme'] != null) {
novelReaderTheme = json['novelReaderTheme'];
}
if (json['novelReaderTextColor'] != null) {
novelReaderTextColor = json['novelReaderTextColor'];
}
if (json['novelReaderPadding'] != null) {
novelReaderPadding = json['novelReaderPadding'];
}
if (json['novelReaderLineHeight'] != null) {
novelReaderLineHeight = json['novelReaderLineHeight'];
}
novelShowScrollPercentage = json['novelShowScrollPercentage'];
novelAutoScroll = json['novelAutoScroll'];
novelRemoveExtraParagraphSpacing = json['novelRemoveExtraParagraphSpacing'];
novelTapToScroll = json['novelTapToScroll'];
if (json['navigationOrder'] != null) {
navigationOrder = (json['navigationOrder'] as List).cast<String>();
}
@ -783,6 +823,14 @@ class Settings {
'novelDisplayType': novelDisplayType.index,
'novelFontSize': novelFontSize,
'novelTextAlign': novelTextAlign.index,
'novelReaderTheme': novelReaderTheme,
'novelReaderTextColor': novelReaderTextColor,
'novelReaderPadding': novelReaderPadding,
'novelReaderLineHeight': novelReaderLineHeight,
'novelShowScrollPercentage': novelShowScrollPercentage,
'novelAutoScroll': novelAutoScroll,
'novelRemoveExtraParagraphSpacing': novelRemoveExtraParagraphSpacing,
'novelTapToScroll': novelTapToScroll,
'navigationOrder': navigationOrder,
'hideItems': hideItems,
'clearChapterCacheOnAppLaunch': clearChapterCacheOnAppLaunch,

File diff suppressed because it is too large Load diff

View file

@ -40,4 +40,4 @@ final class MigrationProvider
}
}
String _$migrationHash() => r'2a82120544e693a3162da887a3ca1b3066f3799f';
String _$migrationHash() => r'43d62ddf79798d616ac7d11ce50a47551ef42c98';

View file

@ -68,7 +68,7 @@ final class CropBordersProvider
}
}
String _$cropBordersHash() => r'04b24357737d6cc75caa38feca77bb5d41f00aa6';
String _$cropBordersHash() => r'f60987c3f38afd5e10263f3d6935e6007ff942f0';
final class CropBordersFamily extends $Family
with

View file

@ -302,3 +302,165 @@ class NovelTextAlignState extends _$NovelTextAlignState {
);
}
}
@riverpod
class NovelReaderThemeState extends _$NovelReaderThemeState {
@override
String build() {
return isar.settings.getSync(227)!.novelReaderTheme ?? '#292832';
}
void set(String value) {
final settings = isar.settings.getSync(227);
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(
settings!
..novelReaderTheme = value
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
}
@riverpod
class NovelReaderTextColorState extends _$NovelReaderTextColorState {
@override
String build() {
return isar.settings.getSync(227)!.novelReaderTextColor ?? '#CCCCCC';
}
void set(String value) {
final settings = isar.settings.getSync(227);
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(
settings!
..novelReaderTextColor = value
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
}
@riverpod
class NovelReaderPaddingState extends _$NovelReaderPaddingState {
@override
int build() {
return isar.settings.getSync(227)!.novelReaderPadding ?? 16;
}
void set(int value) {
final settings = isar.settings.getSync(227);
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(
settings!
..novelReaderPadding = value
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
}
@riverpod
class NovelReaderLineHeightState extends _$NovelReaderLineHeightState {
@override
double build() {
return isar.settings.getSync(227)!.novelReaderLineHeight ?? 1.5;
}
void set(double value) {
final settings = isar.settings.getSync(227);
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(
settings!
..novelReaderLineHeight = value
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
}
@riverpod
class NovelShowScrollPercentageState extends _$NovelShowScrollPercentageState {
@override
bool build() {
return isar.settings.getSync(227)!.novelShowScrollPercentage ?? true;
}
void set(bool value) {
final settings = isar.settings.getSync(227);
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(
settings!
..novelShowScrollPercentage = value
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
}
@riverpod
class NovelAutoScrollState extends _$NovelAutoScrollState {
@override
bool build() {
return isar.settings.getSync(227)!.novelAutoScroll ?? false;
}
void set(bool value) {
final settings = isar.settings.getSync(227);
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(
settings!
..novelAutoScroll = value
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
}
@riverpod
class NovelRemoveExtraParagraphSpacingState
extends _$NovelRemoveExtraParagraphSpacingState {
@override
bool build() {
return isar.settings.getSync(227)!.novelRemoveExtraParagraphSpacing ??
false;
}
void set(bool value) {
final settings = isar.settings.getSync(227);
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(
settings!
..novelRemoveExtraParagraphSpacing = value
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
}
@riverpod
class NovelTapToScrollState extends _$NovelTapToScrollState {
@override
bool build() {
return isar.settings.getSync(227)!.novelTapToScroll ?? false;
}
void set(bool value) {
final settings = isar.settings.getSync(227);
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(
settings!
..novelTapToScroll = value
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
}

View file

@ -764,3 +764,440 @@ abstract class _$NovelTextAlignState extends $Notifier<NovelTextAlign> {
element.handleValue(ref, created);
}
}
@ProviderFor(NovelReaderThemeState)
const novelReaderThemeStateProvider = NovelReaderThemeStateProvider._();
final class NovelReaderThemeStateProvider
extends $NotifierProvider<NovelReaderThemeState, String> {
const NovelReaderThemeStateProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'novelReaderThemeStateProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$novelReaderThemeStateHash();
@$internal
@override
NovelReaderThemeState create() => NovelReaderThemeState();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(String value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<String>(value),
);
}
}
String _$novelReaderThemeStateHash() =>
r'3149f8ea16353f770b57cce9f27f3e63d062ee7b';
abstract class _$NovelReaderThemeState extends $Notifier<String> {
String build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<String, String>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<String, String>,
String,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}
@ProviderFor(NovelReaderTextColorState)
const novelReaderTextColorStateProvider = NovelReaderTextColorStateProvider._();
final class NovelReaderTextColorStateProvider
extends $NotifierProvider<NovelReaderTextColorState, String> {
const NovelReaderTextColorStateProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'novelReaderTextColorStateProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$novelReaderTextColorStateHash();
@$internal
@override
NovelReaderTextColorState create() => NovelReaderTextColorState();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(String value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<String>(value),
);
}
}
String _$novelReaderTextColorStateHash() =>
r'28a1987b49a9b0a209c4848dfa4c8c730432c75d';
abstract class _$NovelReaderTextColorState extends $Notifier<String> {
String build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<String, String>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<String, String>,
String,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}
@ProviderFor(NovelReaderPaddingState)
const novelReaderPaddingStateProvider = NovelReaderPaddingStateProvider._();
final class NovelReaderPaddingStateProvider
extends $NotifierProvider<NovelReaderPaddingState, int> {
const NovelReaderPaddingStateProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'novelReaderPaddingStateProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$novelReaderPaddingStateHash();
@$internal
@override
NovelReaderPaddingState create() => NovelReaderPaddingState();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(int value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<int>(value),
);
}
}
String _$novelReaderPaddingStateHash() =>
r'572f1a7134c499a9a5107d29552beca9a5fd55ea';
abstract class _$NovelReaderPaddingState extends $Notifier<int> {
int build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<int, int>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<int, int>,
int,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}
@ProviderFor(NovelReaderLineHeightState)
const novelReaderLineHeightStateProvider =
NovelReaderLineHeightStateProvider._();
final class NovelReaderLineHeightStateProvider
extends $NotifierProvider<NovelReaderLineHeightState, double> {
const NovelReaderLineHeightStateProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'novelReaderLineHeightStateProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$novelReaderLineHeightStateHash();
@$internal
@override
NovelReaderLineHeightState create() => NovelReaderLineHeightState();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(double value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<double>(value),
);
}
}
String _$novelReaderLineHeightStateHash() =>
r'cc21fb550eecf8d7869c076ab47647afd2873996';
abstract class _$NovelReaderLineHeightState extends $Notifier<double> {
double build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<double, double>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<double, double>,
double,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}
@ProviderFor(NovelShowScrollPercentageState)
const novelShowScrollPercentageStateProvider =
NovelShowScrollPercentageStateProvider._();
final class NovelShowScrollPercentageStateProvider
extends $NotifierProvider<NovelShowScrollPercentageState, bool> {
const NovelShowScrollPercentageStateProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'novelShowScrollPercentageStateProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$novelShowScrollPercentageStateHash();
@$internal
@override
NovelShowScrollPercentageState create() => NovelShowScrollPercentageState();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(bool value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<bool>(value),
);
}
}
String _$novelShowScrollPercentageStateHash() =>
r'adc9cb5def293fa4ed8b367929e7538f6f056b76';
abstract class _$NovelShowScrollPercentageState extends $Notifier<bool> {
bool build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<bool, bool>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<bool, bool>,
bool,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}
@ProviderFor(NovelAutoScrollState)
const novelAutoScrollStateProvider = NovelAutoScrollStateProvider._();
final class NovelAutoScrollStateProvider
extends $NotifierProvider<NovelAutoScrollState, bool> {
const NovelAutoScrollStateProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'novelAutoScrollStateProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$novelAutoScrollStateHash();
@$internal
@override
NovelAutoScrollState create() => NovelAutoScrollState();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(bool value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<bool>(value),
);
}
}
String _$novelAutoScrollStateHash() =>
r'80f717515844fa97396dffc6f45ee0b7b9e6f96d';
abstract class _$NovelAutoScrollState extends $Notifier<bool> {
bool build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<bool, bool>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<bool, bool>,
bool,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}
@ProviderFor(NovelRemoveExtraParagraphSpacingState)
const novelRemoveExtraParagraphSpacingStateProvider =
NovelRemoveExtraParagraphSpacingStateProvider._();
final class NovelRemoveExtraParagraphSpacingStateProvider
extends $NotifierProvider<NovelRemoveExtraParagraphSpacingState, bool> {
const NovelRemoveExtraParagraphSpacingStateProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'novelRemoveExtraParagraphSpacingStateProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() =>
_$novelRemoveExtraParagraphSpacingStateHash();
@$internal
@override
NovelRemoveExtraParagraphSpacingState create() =>
NovelRemoveExtraParagraphSpacingState();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(bool value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<bool>(value),
);
}
}
String _$novelRemoveExtraParagraphSpacingStateHash() =>
r'5c784a57ce5ee57524317dd00d4b40020e5e0582';
abstract class _$NovelRemoveExtraParagraphSpacingState extends $Notifier<bool> {
bool build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<bool, bool>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<bool, bool>,
bool,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}
@ProviderFor(NovelTapToScrollState)
const novelTapToScrollStateProvider = NovelTapToScrollStateProvider._();
final class NovelTapToScrollStateProvider
extends $NotifierProvider<NovelTapToScrollState, bool> {
const NovelTapToScrollStateProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'novelTapToScrollStateProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$novelTapToScrollStateHash();
@$internal
@override
NovelTapToScrollState create() => NovelTapToScrollState();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(bool value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<bool>(value),
);
}
}
String _$novelTapToScrollStateHash() =>
r'4ad09be8c324b019bd1d94cd8d77ef6077bd2100';
abstract class _$NovelTapToScrollState extends $Notifier<bool> {
bool build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<bool, bool>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<bool, bool>,
bool,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}

View file

@ -1,10 +1,10 @@
import 'package:isar_community/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/download.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'novel_reader_controller_provider.g.dart';
@ -188,115 +188,3 @@ class NovelReaderController extends _$NovelReaderController {
return chapter.name!;
}
}
extension MangaExtensions on Manga {
List<Chapter> getFilteredChapterList() {
final data = this.chapters.toList().toList();
final filterUnread =
(isar.settings
.getSync(227)!
.chapterFilterUnreadList!
.where((element) => element.mangaId == id)
.toList()
.firstOrNull ??
ChapterFilterUnread(mangaId: id, type: 0))
.type!;
final filterBookmarked =
(isar.settings
.getSync(227)!
.chapterFilterBookmarkedList!
.where((element) => element.mangaId == id)
.toList()
.firstOrNull ??
ChapterFilterBookmarked(mangaId: id, type: 0))
.type!;
final filterDownloaded =
(isar.settings
.getSync(227)!
.chapterFilterDownloadedList!
.where((element) => element.mangaId == id)
.toList()
.firstOrNull ??
ChapterFilterDownloaded(mangaId: id, type: 0))
.type!;
final sortChapter =
(isar.settings
.getSync(227)!
.sortChapterList!
.where((element) => element.mangaId == id)
.toList()
.firstOrNull ??
SortChapter(mangaId: id, index: 1, reverse: false))
.index;
final filterScanlator = _getFilterScanlator(this) ?? [];
List<Chapter>? chapterList;
chapterList = data
.where(
(element) => filterUnread == 1
? element.isRead == false
: filterUnread == 2
? element.isRead == true
: true,
)
.where(
(element) => filterBookmarked == 1
? element.isBookmarked == true
: filterBookmarked == 2
? element.isBookmarked == false
: true,
)
.where((element) {
final modelChapDownload = isar.downloads
.filter()
.idIsNotNull()
.idEqualTo(element.id)
.findAllSync();
return filterDownloaded == 1
? modelChapDownload.isNotEmpty &&
modelChapDownload.first.isDownload == true
: filterDownloaded == 2
? !(modelChapDownload.isNotEmpty &&
modelChapDownload.first.isDownload == true)
: true;
})
.where((element) => !filterScanlator.contains(element.scanlator))
.toList();
List<Chapter> chapters = sortChapter == 1
? chapterList.reversed.toList()
: chapterList;
if (sortChapter == 0) {
chapters.sort((a, b) {
return (a.scanlator == null ||
b.scanlator == null ||
a.dateUpload == null ||
b.dateUpload == null)
? 0
: a.scanlator!.compareTo(b.scanlator!) |
a.dateUpload!.compareTo(b.dateUpload!);
});
} else if (sortChapter == 2) {
chapters.sort((a, b) {
return (a.dateUpload == null || b.dateUpload == null)
? 0
: int.parse(a.dateUpload!).compareTo(int.parse(b.dateUpload!));
});
} else if (sortChapter == 3) {
chapters.sort((a, b) {
return (a.name == null || b.name == null)
? 0
: a.name!.compareTo(b.name!);
});
}
return chapterList;
}
}
List<String>? _getFilterScanlator(Manga manga) {
final scanlators = isar.settings.getSync(227)!.filterScanlatorList ?? [];
final filter = scanlators
.where((element) => element.mangaId == manga.id)
.toList();
return filter.firstOrNull?.scanlators;
}

View file

@ -16,6 +16,8 @@ import 'package:mangayomi/modules/anime/widgets/desktop.dart';
import 'package:mangayomi/modules/manga/reader/widgets/btn_chapter_list_dialog.dart';
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
import 'package:mangayomi/modules/novel/novel_reader_controller_provider.dart';
import 'package:mangayomi/modules/novel/widgets/novel_reader_settings_sheet.dart';
import 'package:mangayomi/modules/widgets/custom_draggable_tabbar.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/services/get_html_content.dart';
import 'package:mangayomi/utils/extensions/dom_extensions.dart';
@ -24,7 +26,7 @@ import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:window_manager/window_manager.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:html/dom.dart' as dom;
import 'package:flutter/widgets.dart' as widgets;
@ -73,6 +75,7 @@ class _NovelWebViewState extends ConsumerState<NovelWebView>
if (_scrollController.hasClients) {
offset = _scrollController.offset;
maxOffset = _scrollController.position.maxScrollExtent;
_rebuildDetail.add(offset);
}
}
@ -203,119 +206,254 @@ class _NovelWebViewState extends ConsumerState<NovelWebView>
bottom: false,
child: Stack(
children: [
widget.result.when(
data: (data) {
epubBook = data.$2;
Future.delayed(const Duration(milliseconds: 1000), () {
if (!scrolled && _scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent *
(double.tryParse(chapter.lastPageRead!) ?? 0),
duration: Duration(seconds: 2),
curve: Curves.fastOutSlowIn,
);
scrolled = true;
}
});
return Scrollbar(
controller: _scrollController,
interactive: true,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
_isViewFunction();
},
child: CustomScrollView(
controller: _scrollController,
physics: const BouncingScrollPhysics(),
slivers: [
HtmlWidget(
data.$1,
customWidgetBuilder: (element) =>
_buildCustomWidgets(element),
customStylesBuilder: (element) {
switch (backgroundColor) {
case BackgroundColor.black:
return {'background-color': 'black'};
default:
return {'background-color': '#F0F0F0'};
}
},
onTapUrl: (url) {
context.push(
"/mangawebview",
extra: {'url': url, 'title': url},
);
return true;
},
renderMode: RenderMode.sliverList,
textStyle: TextStyle(
color: backgroundColor == BackgroundColor.white
? Colors.black
: Colors.white,
fontSize: fontSize.toDouble(),
),
),
SliverToBoxAdapter(
child: Center(
heightFactor: 2,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 5,
children: [
IconButton(
padding: const EdgeInsets.all(5),
onPressed: () =>
pushReplacementMangaReaderView(
context: context,
chapter: _readerController
.getPrevChapter(),
),
icon: Icon(
size: 32,
Icons.arrow_back,
color:
backgroundColor ==
BackgroundColor.white
? Colors.black
: Colors.white,
Column(
children: [
Flexible(
child: widget.result.when(
data: (data) {
epubBook = data.$2;
final padding = ref.watch(
novelReaderPaddingStateProvider,
);
final lineHeight = ref.watch(
novelReaderLineHeightStateProvider,
);
final textAlign = ref.watch(
novelTextAlignStateProvider,
);
final removeExtraSpacing = ref.watch(
novelRemoveExtraParagraphSpacingStateProvider,
);
final customBackgroundColor = ref.watch(
novelReaderThemeStateProvider,
);
final customTextColor = ref.watch(
novelReaderTextColorStateProvider,
);
Color parseColor(String hex) {
final hexColor = hex.replaceAll('#', '');
return Color(int.parse('FF$hexColor', radix: 16));
}
TextAlign getTextAlign() {
switch (textAlign) {
case NovelTextAlign.left:
return TextAlign.left;
case NovelTextAlign.center:
return TextAlign.center;
case NovelTextAlign.right:
return TextAlign.right;
case NovelTextAlign.block:
return TextAlign.justify;
}
}
Future.delayed(const Duration(milliseconds: 10), () {
if (!scrolled && _scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent *
(double.tryParse(chapter.lastPageRead!) ??
0),
duration: Duration(seconds: 2),
curve: Curves.fastOutSlowIn,
);
scrolled = true;
}
});
return Consumer(
builder: (context, ref, _) {
final fontSize = ref.read(
novelFontSizeStateProvider,
);
return Scrollbar(
controller: _scrollController,
interactive: true,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
_isViewFunction();
},
child: CustomScrollView(
controller: _scrollController,
physics: const BouncingScrollPhysics(),
slivers: [
SliverToBoxAdapter(
child: Html(
data: data.$1,
style: {
"body": Style(
fontSize: FontSize(
fontSize.toDouble(),
),
color: parseColor(
customTextColor,
),
backgroundColor: parseColor(
customBackgroundColor,
),
margin: Margins.zero,
padding: HtmlPaddings.all(
padding.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"p": Style(
margin: removeExtraSpacing
? Margins.only(bottom: 4)
: Margins.only(bottom: 8),
fontSize: FontSize(
fontSize.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"div": Style(
fontSize: FontSize(
fontSize.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"span": Style(
fontSize: FontSize(
fontSize.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
),
"h1, h2, h3, h4, h5, h6": Style(
color: parseColor(
customTextColor,
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"a": Style(
color: Colors.blue,
textDecoration:
TextDecoration.underline,
),
"img": Style(
width: Width(100, Unit.percent),
height: Height.auto(),
),
},
extensions: [
TagExtension(
tagsToExtend: {"img"},
builder: (extensionContext) {
final element =
extensionContext.node
as dom.Element;
final customWidget =
_buildCustomWidgets(
element,
);
if (customWidget != null) {
return customWidget;
}
return const SizedBox.shrink();
},
),
],
onLinkTap:
(url, attributes, element) {
if (url != null) {
context.push(
"/mangawebview",
extra: {
'url': url,
'title': url,
},
);
}
},
),
),
),
IconButton(
padding: const EdgeInsets.all(5),
onPressed: () =>
pushReplacementMangaReaderView(
context: context,
chapter: _readerController
.getNextChapter(),
),
icon: Icon(
size: 32,
Icons.arrow_forward,
color:
backgroundColor ==
BackgroundColor.white
? Colors.black
: Colors.white,
),
),
],
],
),
),
),
),
],
);
},
);
},
loading: () => scaffoldWith(
context,
Center(child: CircularProgressIndicator()),
),
error: (err, stack) => scaffoldWith(
context,
Center(child: Text(err.toString())),
),
),
);
},
loading: () => scaffoldWith(
context,
Center(child: CircularProgressIndicator()),
),
error: (err, stack) => scaffoldWith(
context,
Center(child: Text(err.toString())),
),
),
if (ref.watch(novelShowScrollPercentageStateProvider))
StreamBuilder(
stream: _rebuildDetail.stream,
builder: (context, asyncSnapshot) {
return Consumer(
builder: (context, ref, child) {
final customBackgroundColor = ref.watch(
novelReaderThemeStateProvider,
);
final customTextColor = ref.watch(
novelReaderTextColorStateProvider,
);
final scrollPercentage = maxOffset > 0
? ((offset / maxOffset) * 100)
.clamp(0, 100)
.toInt()
: 0;
return Row(
children: [
Expanded(
child: Container(
color: Color(
int.parse(
'FF${customBackgroundColor.replaceAll('#', '')}',
radix: 16,
),
),
child: Center(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
'$scrollPercentage %',
style: TextStyle(
color: Color(
int.parse(
'FF${customTextColor.replaceAll('#', '')}',
radix: 16,
),
),
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
],
);
},
);
},
),
],
),
_appBar(),
_bottomBar(backgroundColor),
@ -485,70 +623,186 @@ class _NovelWebViewState extends ConsumerState<NovelWebView>
_readerController.getChapterIndex().$2,
);
bool hasNextChapter = _readerController.getChapterIndex().$1 != 0;
final novelTextAlign = ref.watch(novelTextAlignStateProvider);
final bodyLargeColor = Theme.of(context).textTheme.bodyLarge!.color;
return Positioned(
bottom: 0,
child: AnimatedContainer(
curve: Curves.ease,
duration: const Duration(milliseconds: 300),
width: context.width(1),
height: (_isView ? 130 : 0),
height: (_isView ? 140 : 0),
child: Column(
children: [
Flexible(
child: Transform.scale(
scaleX: 1,
child: Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: CircleAvatar(
radius: 23,
backgroundColor: _backgroundColor(context),
child: IconButton(
onPressed: hasPrevChapter
? () {
pushReplacementMangaReaderView(
context: context,
chapter: _readerController.getPrevChapter(),
);
}
: null,
icon: Transform.scale(
scaleX: 1,
child: Icon(
Icons.skip_previous_rounded,
color: hasPrevChapter
? Theme.of(context).textTheme.bodyLarge!.color
: Theme.of(context)
.textTheme
.bodyLarge!
.color!
.withValues(alpha: 0.4),
),
if (_isView)
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: CircleAvatar(
radius: 21,
backgroundColor: _backgroundColor(context),
child: IconButton(
onPressed: hasPrevChapter
? () {
pushReplacementMangaReaderView(
context: context,
chapter: _readerController.getPrevChapter(),
);
}
: null,
icon: Icon(
Icons.skip_previous_rounded,
color: hasPrevChapter
? bodyLargeColor
: bodyLargeColor!.withValues(alpha: 0.4),
),
),
),
),
Flexible(
child: Container(
height: 40,
decoration: BoxDecoration(
color: _backgroundColor(context),
borderRadius: BorderRadius.circular(50),
),
child: StreamBuilder(
stream: _rebuildDetail.stream,
builder: (context, asyncSnapshot) {
return Consumer(
builder: (context, ref, child) {
final scrollPercentage = maxOffset > 0
? ((offset / maxOffset) * 100)
.clamp(0, 100)
.toInt()
: 0;
return Row(
children: [
SizedBox(width: 10),
Padding(
padding: const EdgeInsets.all(4),
child: Text(
scrollPercentage.toInt().toString(),
style: TextStyle(
color: bodyLargeColor,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
),
if (_isView)
Expanded(
flex: 14,
child: SliderTheme(
data: SliderTheme.of(context).copyWith(
trackHeight: 2.0,
thumbShape:
const RoundSliderThumbShape(
enabledThumbRadius: 6.0,
),
overlayShape:
const RoundSliderOverlayShape(
overlayRadius: 12.0,
),
),
child: Slider(
onChanged: (value) {
_scrollController.jumpTo(
_scrollController
.position
.maxScrollExtent *
value,
);
},
value: scrollPercentage / 100,
min: 0,
max: 1,
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
'100',
style: TextStyle(
color: bodyLargeColor,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(width: 10),
],
);
},
);
},
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: CircleAvatar(
radius: 21,
backgroundColor: _backgroundColor(context),
child: IconButton(
onPressed: hasNextChapter
? () {
pushReplacementMangaReaderView(
context: context,
chapter: _readerController.getNextChapter(),
);
}
: null,
icon: Transform.scale(
scaleX: 1,
child: Icon(
Icons.skip_next_rounded,
color: hasNextChapter
? bodyLargeColor
: bodyLargeColor!.withValues(alpha: 0.4),
),
),
),
),
Flexible(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Container(
height: 70,
decoration: BoxDecoration(
color: _backgroundColor(context),
borderRadius: BorderRadius.circular(25),
),
),
],
),
if (_isView)
Expanded(
child: Container(
color: _backgroundColor(context),
child: Row(
children: [
Flexible(
child: SizedBox(
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Transform.scale(
scaleX: 1,
child: SizedBox(
width: 55,
child: Center(
child: IconButton(
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
border: Border.all(
color: bodyLargeColor!,
width: 0.2,
),
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Text Size :',
style: TextStyle(
fontWeight: FontWeight.bold,
color: bodyLargeColor,
),
),
IconButton(
onPressed: () {
final newFontSize = max(
4,
@ -564,58 +818,52 @@ class _NovelWebViewState extends ConsumerState<NovelWebView>
fontSize = newFontSize;
});
},
icon: const Icon(Icons.text_decrease),
icon: Icon(Icons.text_decrease),
iconSize: 20,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(
minWidth: 40,
minHeight: 40,
),
),
),
),
),
if (_isView)
Flexible(
flex: 14,
child: Consumer(
builder: (context, ref, child) {
final currentFontSize = ref.watch(
novelFontSizeStateProvider,
);
return SliderTheme(
data: SliderTheme.of(context).copyWith(
overlayShape:
const RoundSliderOverlayShape(
overlayRadius: 5.0,
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 5,
),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primaryContainer
.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(
8,
),
),
child: Consumer(
builder: (context, ref, child) {
final currentFontSize = ref.watch(
novelFontSizeStateProvider,
);
return Text(
"$currentFontSize px",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Theme.of(context)
.colorScheme
.onPrimaryContainer,
),
),
child: Slider(
onChanged: (value) {
ref
.read(
novelFontSizeStateProvider
.notifier,
)
.set(value.toInt());
);
},
onChangeEnd: (newValue) {
try {
setState(() {
fontSize = newValue.toInt();
});
} catch (_) {}
},
divisions: 36,
value: currentFontSize.toDouble(),
label: "$currentFontSize",
min: 4,
max: 40,
),
);
},
),
),
Transform.scale(
scaleX: 1,
child: SizedBox(
width: 55,
child: Center(
child: IconButton(
),
),
IconButton(
onPressed: () {
final newFontSize = min(
40,
@ -632,106 +880,42 @@ class _NovelWebViewState extends ConsumerState<NovelWebView>
});
},
icon: const Icon(Icons.text_increase),
iconSize: 20,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(
minWidth: 40,
minHeight: 40,
),
),
),
],
),
),
IconButton(
onPressed: () {
customDraggableTabBar(
tabs: [
Tab(text: context.l10n.reader),
Tab(text: context.l10n.general),
],
children: [
ReaderSettingsTab(),
GeneralSettingsTab(),
],
context: context,
vsync: this,
);
},
icon: const Icon(Icons.settings),
),
],
),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: CircleAvatar(
radius: 23,
backgroundColor: _backgroundColor(context),
child: IconButton(
onPressed: hasNextChapter
? () {
pushReplacementMangaReaderView(
context: context,
chapter: _readerController.getNextChapter(),
);
}
: null,
icon: Transform.scale(
scaleX: 1,
child: Icon(
Icons.skip_next_rounded,
color: hasNextChapter
? Theme.of(context).textTheme.bodyLarge!.color
: Theme.of(context)
.textTheme
.bodyLarge!
.color!
.withValues(alpha: 0.4),
// size: 17,
),
),
),
),
),
],
],
),
),
),
),
/*Flexible(
child: Container(
height: 65,
color: _backgroundColor(context),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
PopupMenuButton(
popUpAnimationStyle: popupAnimationStyle,
color: Colors.black,
child: const Icon(
Icons.format_align_center_outlined,
),
onSelected: (value) {
ref
.read(novelTextAlignStateProvider.notifier)
.set(value);
},
itemBuilder: (context) => [
for (var mode in NovelTextAlign.values)
PopupMenuItem(
value: mode,
child: Row(
children: [
Icon(
Icons.check,
color: novelTextAlign == mode
? Colors.white
: Colors.transparent,
),
const SizedBox(
width: 7,
),
Text(
mode.name,
style: const TextStyle(
color: Colors.white,
fontSize: 12,
),
),
],
)),
],
),
IconButton(
onPressed: () {
// _showModalSettings();
},
icon: const Icon(
Icons.settings_rounded,
),
),
],
),
),
),*/
],
),
),

View file

@ -0,0 +1,591 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
class ReaderSettingsTab extends ConsumerWidget {
const ReaderSettingsTab({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final padding = ref.watch(novelReaderPaddingStateProvider);
final lineHeight = ref.watch(novelReaderLineHeightStateProvider);
final textAlign = ref.watch(novelTextAlignStateProvider);
final backgroundColor = ref.watch(novelReaderThemeStateProvider);
final textColor = ref.watch(novelReaderTextColorStateProvider);
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_SettingSection(
title: 'Theme',
child: Column(
children: [
Wrap(
spacing: 8,
runSpacing: 8,
children: [
_ThemeButton(
backgroundColor: '#292832',
textColor: '#CCCCCC',
label: 'Dark',
isSelected: backgroundColor == '#292832',
onTap: () {
ref
.read(novelReaderThemeStateProvider.notifier)
.set('#292832');
ref
.read(novelReaderTextColorStateProvider.notifier)
.set('#CCCCCC');
},
),
_ThemeButton(
backgroundColor: '#FFFFFF',
textColor: '#000000',
label: 'Light',
isSelected: backgroundColor == '#FFFFFF',
onTap: () {
ref
.read(novelReaderThemeStateProvider.notifier)
.set('#FFFFFF');
ref
.read(novelReaderTextColorStateProvider.notifier)
.set('#000000');
},
),
_ThemeButton(
backgroundColor: '#000000',
textColor: '#FFFFFF',
label: 'Black',
isSelected: backgroundColor == '#000000',
onTap: () {
ref
.read(novelReaderThemeStateProvider.notifier)
.set('#000000');
ref
.read(novelReaderTextColorStateProvider.notifier)
.set('#FFFFFF');
},
),
_ThemeButton(
backgroundColor: '#F5E6D3',
textColor: '#5F4B32',
label: 'Sepia',
isSelected: backgroundColor == '#F5E6D3',
onTap: () {
ref
.read(novelReaderThemeStateProvider.notifier)
.set('#F5E6D3');
ref
.read(novelReaderTextColorStateProvider.notifier)
.set('#5F4B32');
},
),
],
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: _ColorPicker(
label: 'Background',
color: backgroundColor,
onColorChanged: (color) {
ref
.read(novelReaderThemeStateProvider.notifier)
.set(color);
},
),
),
const SizedBox(width: 12),
Expanded(
child: _ColorPicker(
label: 'Text',
color: textColor,
onColorChanged: (color) {
ref
.read(novelReaderTextColorStateProvider.notifier)
.set(color);
},
),
),
],
),
],
),
),
const SizedBox(height: 16),
_SettingSection(
title: 'Text Align',
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_AlignButton(
icon: Icons.format_align_left,
isSelected: textAlign == NovelTextAlign.left,
onTap: () {
ref
.read(novelTextAlignStateProvider.notifier)
.set(NovelTextAlign.left);
},
),
_AlignButton(
icon: Icons.format_align_center,
isSelected: textAlign == NovelTextAlign.center,
onTap: () {
ref
.read(novelTextAlignStateProvider.notifier)
.set(NovelTextAlign.center);
},
),
_AlignButton(
icon: Icons.format_align_right,
isSelected: textAlign == NovelTextAlign.right,
onTap: () {
ref
.read(novelTextAlignStateProvider.notifier)
.set(NovelTextAlign.right);
},
),
_AlignButton(
icon: Icons.format_align_justify,
isSelected: textAlign == NovelTextAlign.block,
onTap: () {
ref
.read(novelTextAlignStateProvider.notifier)
.set(NovelTextAlign.block);
},
),
],
),
),
const SizedBox(height: 16),
_SettingSection(
title: 'Padding',
child: Column(
children: [
Row(
children: [
const Icon(Icons.space_bar, size: 20),
Expanded(
child: Slider(
value: padding.toDouble(),
min: 0,
max: 50,
divisions: 50,
label: '$padding px',
onChanged: (value) {
ref
.read(novelReaderPaddingStateProvider.notifier)
.set(value.toInt());
},
),
),
Text('${padding}px'),
],
),
],
),
),
const SizedBox(height: 16),
_SettingSection(
title: 'Line Height',
child: Column(
children: [
Row(
children: [
const Icon(Icons.height, size: 20),
Expanded(
child: Slider(
value: lineHeight,
min: 1.0,
max: 3.0,
divisions: 20,
label: lineHeight.toStringAsFixed(1),
onChanged: (value) {
ref
.read(novelReaderLineHeightStateProvider.notifier)
.set(value);
},
),
),
Text(lineHeight.toStringAsFixed(1)),
],
),
],
),
),
],
),
);
}
}
class GeneralSettingsTab extends ConsumerWidget {
const GeneralSettingsTab({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_SwitchListTileSetting(
title: 'Show Scroll Percentage',
subtitle: 'Display reading progress percentage',
value: ref.watch(novelShowScrollPercentageStateProvider),
onChanged: (value) {
ref
.read(novelShowScrollPercentageStateProvider.notifier)
.set(value);
},
),
// _SwitchListTileSetting(
// title: 'Auto Scroll',
// subtitle: 'Automatically scroll through pages',
// value: ref.watch(novelAutoScrollStateProvider),
// onChanged: (value) {
// ref.read(novelAutoScrollStateProvider.notifier).set(value);
// },
// ),
_SwitchListTileSetting(
title: 'Remove Extra Paragraph Spacing',
subtitle: 'Reduce spacing between paragraphs',
value: ref.watch(novelRemoveExtraParagraphSpacingStateProvider),
onChanged: (value) {
ref
.read(novelRemoveExtraParagraphSpacingStateProvider.notifier)
.set(value);
},
),
// _SwitchListTileSetting(
// title: 'Tap to Scroll',
// subtitle: 'Tap screen to scroll up/down',
// value: ref.watch(novelTapToScrollStateProvider),
// onChanged: (value) {
// ref.read(novelTapToScrollStateProvider.notifier).set(value);
// },
// ),
],
),
);
}
}
class _SettingSection extends StatelessWidget {
final String title;
final Widget child;
const _SettingSection({required this.title, required this.child});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Theme.of(context).textTheme.titleLarge?.color,
),
),
Card(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
child: child,
),
),
],
);
}
}
class _SwitchListTileSetting extends StatelessWidget {
final String title;
final String subtitle;
final bool value;
final ValueChanged<bool> onChanged;
const _SwitchListTileSetting({
required this.title,
required this.subtitle,
required this.value,
required this.onChanged,
});
@override
Widget build(BuildContext context) {
return SwitchListTile(
title: Text(title),
subtitle: Text(subtitle, style: Theme.of(context).textTheme.bodySmall),
value: value,
onChanged: onChanged,
);
}
}
class _ThemeButton extends StatelessWidget {
final String backgroundColor;
final String textColor;
final String label;
final bool isSelected;
final VoidCallback onTap;
const _ThemeButton({
required this.backgroundColor,
required this.textColor,
required this.label,
required this.isSelected,
required this.onTap,
});
Color _parseColor(String hex) {
final hexColor = hex.replaceAll('#', '');
return Color(int.parse('FF$hexColor', radix: 16));
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
width: 70,
height: 60,
decoration: BoxDecoration(
color: _parseColor(backgroundColor),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isSelected
? Theme.of(context).primaryColor
: Colors.grey.withValues(alpha: 0.3),
width: isSelected ? 3 : 1,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Aa',
style: TextStyle(
color: _parseColor(textColor),
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
label,
style: TextStyle(color: _parseColor(textColor), fontSize: 10),
),
],
),
),
);
}
}
class _ColorPicker extends StatelessWidget {
final String label;
final String color;
final ValueChanged<String> onColorChanged;
const _ColorPicker({
required this.label,
required this.color,
required this.onColorChanged,
});
Color _parseColor(String hex) {
final hexColor = hex.replaceAll('#', '');
return Color(int.parse('FF$hexColor', radix: 16));
}
String _colorToHex(Color color) {
return '#${color.toARGB32().toRadixString(16).substring(2).toUpperCase()}';
}
void _showColorPickerDialog(BuildContext context) {
Color selectedColor = _parseColor(color);
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Select $label Color'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Wrap(
spacing: 8,
runSpacing: 8,
children: [
_colorOption(context, Colors.white, selectedColor),
_colorOption(context, Colors.black, selectedColor),
_colorOption(
context,
const Color(0xFF292832),
selectedColor,
),
_colorOption(
context,
const Color(0xFFF5E6D3),
selectedColor,
),
_colorOption(
context,
const Color(0xFF5F4B32),
selectedColor,
),
_colorOption(
context,
const Color(0xFFCCCCCC),
selectedColor,
),
_colorOption(context, Colors.grey[800]!, selectedColor),
_colorOption(context, Colors.grey[300]!, selectedColor),
_colorOption(context, Colors.brown[100]!, selectedColor),
_colorOption(context, Colors.blue[100]!, selectedColor),
_colorOption(context, Colors.green[100]!, selectedColor),
_colorOption(context, Colors.amber[100]!, selectedColor),
],
),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Cancel'),
),
],
);
},
);
}
Widget _colorOption(
BuildContext context,
Color optionColor,
Color selectedColor,
) {
final isSelected = optionColor.toARGB32() == selectedColor.toARGB32();
return GestureDetector(
onTap: () {
onColorChanged(_colorToHex(optionColor));
Navigator.of(context).pop();
},
child: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: optionColor,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isSelected ? Theme.of(context).primaryColor : Colors.grey,
width: isSelected ? 3 : 1,
),
),
child: isSelected
? Icon(
Icons.check,
color: optionColor.computeLuminance() > 0.5
? Colors.black
: Colors.white,
)
: null,
),
);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _showColorPickerDialog(context),
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.withValues(alpha: 0.3)),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: _parseColor(color),
borderRadius: BorderRadius.circular(6),
border: Border.all(color: Colors.grey),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: const TextStyle(fontSize: 12)),
Text(
color,
style: TextStyle(fontSize: 10, color: Colors.grey[600]),
),
],
),
),
const Icon(Icons.arrow_drop_down),
],
),
),
);
}
}
class _AlignButton extends StatelessWidget {
final IconData icon;
final bool isSelected;
final VoidCallback onTap;
const _AlignButton({
required this.icon,
required this.isSelected,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: isSelected
? Theme.of(context).primaryColor.withValues(alpha: 0.2)
: Colors.transparent,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isSelected
? Theme.of(context).primaryColor
: Colors.grey.withValues(alpha: 0.3),
width: isSelected ? 2 : 1,
),
),
child: Icon(
icon,
color: isSelected
? Theme.of(context).primaryColor
: Theme.of(context).iconTheme.color,
),
),
);
}
}

View file

@ -65,7 +65,7 @@ final class FetchItemSourcesListProvider
}
String _$fetchItemSourcesListHash() =>
r'16238be20517fddacf52a2694fbd50cafbfa7496';
r'219aed67d2329f03101f2270e2f344bf70eff128';
final class FetchItemSourcesListFamily extends $Family
with

View file

@ -58,7 +58,7 @@ final class GetDetailProvider
}
}
String _$getDetailHash() => r'6b758b79281cb00a7df2fe1903d4a67068052bca';
String _$getDetailHash() => r'7eab7d00e6ad61a9bafaee855eae1f49b127af9f';
final class GetDetailFamily extends $Family
with

View file

@ -66,7 +66,7 @@ final class GetHtmlContentProvider
}
}
String _$getHtmlContentHash() => r'f1f734a95f8dfcd7197712eee61609589d76de1f';
String _$getHtmlContentHash() => r'a5763e11960bfe0dbd38ce2b2a3f4b51fefc976e';
final class GetHtmlContentFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<(String, EpubBook?)>, Chapter> {

View file

@ -58,7 +58,7 @@ final class GetLatestUpdatesProvider
}
}
String _$getLatestUpdatesHash() => r'7a3c06c469c77ec933cf2f4dd7d39780d993f0ea';
String _$getLatestUpdatesHash() => r'6f99dfe1d4aa950b6852110ec23f92b5c73c413c';
final class GetLatestUpdatesFamily extends $Family
with

View file

@ -58,7 +58,7 @@ final class GetPopularProvider
}
}
String _$getPopularHash() => r'f169b6a9ba76d9dd9237ba9c21805151a1419843';
String _$getPopularHash() => r'7e1139bc0f6a3a495fa0dc59d450bc7fd70f36a8';
final class GetPopularFamily extends $Family
with

View file

@ -65,7 +65,7 @@ final class GetVideoListProvider
}
}
String _$getVideoListHash() => r'c99fd33a99b3fb2e2cc66353f1b8b560f3c8e184';
String _$getVideoListHash() => r'd374dccf3edc478c883cb79b9f1be724342b9ac7';
final class GetVideoListFamily extends $Family
with

View file

@ -72,7 +72,7 @@ final class SearchProvider
}
}
String _$searchHash() => r'b6bac0a3af58547bb93356f3c00a04135cd5a891';
String _$searchHash() => r'03bfee6172b386c53aee05fe2429a10ce5915b18';
final class SearchFamily extends $Family
with

View file

@ -72,7 +72,7 @@ final class SearchProvider
}
}
String _$searchHash() => r'e23c6dd56549ffdfc89b5fcfa43719d90ca1760e';
String _$searchHash() => r'0fa9d882436b1b58b3420dae5a757e7622273eb5';
final class SearchFamily extends $Family
with

View file

@ -6,7 +6,6 @@ import FlutterMacOS
import Foundation
import app_links
import audio_session
import connectivity_plus
import device_info_plus
import file_picker
@ -14,7 +13,6 @@ import flutter_inappwebview_macos
import flutter_qjs
import flutter_web_auth_2
import isar_community_flutter_libs
import just_audio
import media_kit_libs_macos_video
import media_kit_video
import package_info_plus
@ -22,18 +20,14 @@ import path_provider_foundation
import screen_brightness_macos
import screen_retriever_macos
import share_plus
import sqflite_darwin
import url_launcher_macos
import video_player_avfoundation
import volume_controller
import wakelock_plus
import webview_flutter_wkwebview
import window_manager
import window_to_front
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
@ -41,7 +35,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterQjsPlugin.register(with: registry.registrar(forPlugin: "FlutterQjsPlugin"))
FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin"))
IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin"))
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin"))
MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
@ -49,12 +42,9 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin"))
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
VolumeControllerPlugin.register(with: registry.registrar(forPlugin: "VolumeControllerPlugin"))
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin"))
}

View file

@ -1,8 +1,6 @@
PODS:
- app_links (6.4.1):
- FlutterMacOS
- audio_session (0.0.1):
- FlutterMacOS
- connectivity_plus (0.0.1):
- FlutterMacOS
- device_info_plus (0.0.1):
@ -21,9 +19,6 @@ PODS:
- FlutterMacOS (1.0.0)
- isar_community_flutter_libs (1.0.0):
- FlutterMacOS
- just_audio (0.0.1):
- Flutter
- FlutterMacOS
- media_kit_libs_macos_video (1.0.4):
- FlutterMacOS
- media_kit_video (0.0.1):
@ -42,21 +37,12 @@ PODS:
- FlutterMacOS
- share_plus (0.0.1):
- FlutterMacOS
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
- url_launcher_macos (0.0.1):
- FlutterMacOS
- video_player_avfoundation (0.0.1):
- Flutter
- FlutterMacOS
- volume_controller (0.0.1):
- FlutterMacOS
- wakelock_plus (0.0.1):
- FlutterMacOS
- webview_flutter_wkwebview (0.0.1):
- Flutter
- FlutterMacOS
- window_manager (0.5.0):
- FlutterMacOS
- window_to_front (0.0.1):
@ -64,7 +50,6 @@ PODS:
DEPENDENCIES:
- app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`)
- audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`)
- connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`)
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
- file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`)
@ -74,7 +59,6 @@ DEPENDENCIES:
- flutter_web_auth_2 (from `Flutter/ephemeral/.symlinks/plugins/flutter_web_auth_2/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- isar_community_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/isar_community_flutter_libs/macos`)
- just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/darwin`)
- media_kit_libs_macos_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos`)
- media_kit_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos`)
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
@ -83,12 +67,9 @@ DEPENDENCIES:
- screen_brightness_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos`)
- screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`)
- volume_controller (from `Flutter/ephemeral/.symlinks/plugins/volume_controller/macos`)
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
- webview_flutter_wkwebview (from `Flutter/ephemeral/.symlinks/plugins/webview_flutter_wkwebview/darwin`)
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
- window_to_front (from `Flutter/ephemeral/.symlinks/plugins/window_to_front/macos`)
@ -99,8 +80,6 @@ SPEC REPOS:
EXTERNAL SOURCES:
app_links:
:path: Flutter/ephemeral/.symlinks/plugins/app_links/macos
audio_session:
:path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos
connectivity_plus:
:path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos
device_info_plus:
@ -119,8 +98,6 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral
isar_community_flutter_libs:
:path: Flutter/ephemeral/.symlinks/plugins/isar_community_flutter_libs/macos
just_audio:
:path: Flutter/ephemeral/.symlinks/plugins/just_audio/darwin
media_kit_libs_macos_video:
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos
media_kit_video:
@ -137,18 +114,12 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos
share_plus:
:path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos
sqflite_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
video_player_avfoundation:
:path: Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin
volume_controller:
:path: Flutter/ephemeral/.symlinks/plugins/volume_controller/macos
wakelock_plus:
:path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos
webview_flutter_wkwebview:
:path: Flutter/ephemeral/.symlinks/plugins/webview_flutter_wkwebview/darwin
window_manager:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
window_to_front:
@ -156,7 +127,6 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
app_links: 05a6ec2341985eb05e9f97dc63f5837c39895c3f
audio_session: eaca2512cf2b39212d724f35d11f46180ad3a33e
connectivity_plus: 4adf20a405e25b42b9c9f87feff8f4b6fde18a4e
device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76
file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a
@ -166,7 +136,6 @@ SPEC CHECKSUMS:
flutter_web_auth_2: 62b08da29f15a20fa63f144234622a1488d45b65
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
isar_community_flutter_libs: a631ceb5622413b56bcd0a8bf49cb55bf3d8bb2b
just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed
media_kit_libs_macos_video: 85a23e549b5f480e72cae3e5634b5514bc692f65
media_kit_video: fa6564e3799a0a28bff39442334817088b7ca758
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
@ -176,12 +145,9 @@ SPEC CHECKSUMS:
screen_brightness_macos: 2a3ee243f8051c340381e8e51bcedced8360f421
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
volume_controller: 5c068e6d085c80dadd33fc2c918d2114b775b3dd
wakelock_plus: 917609be14d812ddd9e9528876538b2263aaa03b
webview_flutter_wkwebview: 8ebf4fded22593026f7dbff1fbff31ea98573c8d
window_manager: b729e31d38fb04905235df9ea896128991cad99e
window_to_front: 9e76fd432e36700a197dac86a0011e49c89abe0a

View file

@ -105,14 +105,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.13.0"
audio_session:
dependency: transitive
description:
name: audio_session
sha256: "8f96a7fecbb718cb093070f868b4cdcb8a9b1053dce342ff8ab2fde10eb9afb7"
url: "https://pub.dev"
source: hosted
version: "0.2.2"
boolean_selector:
dependency: transitive
description:
@ -201,30 +193,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.12.0"
cached_network_image:
dependency: transitive
description:
name: cached_network_image
sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916"
url: "https://pub.dev"
source: hosted
version: "3.4.1"
cached_network_image_platform_interface:
dependency: transitive
description:
name: cached_network_image_platform_interface
sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829"
url: "https://pub.dev"
source: hosted
version: "4.1.1"
cached_network_image_web:
dependency: transitive
description:
name: cached_network_image_web
sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
characters:
dependency: transitive
description:
@ -241,14 +209,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.4"
chewie:
dependency: transitive
description:
name: chewie
sha256: "44bcfc5f0dfd1de290c87c9d86a61308b3282a70b63435d5557cfd60f54a69ca"
url: "https://pub.dev"
source: hosted
version: "1.13.0"
cli_config:
dependency: transitive
description:
@ -552,14 +512,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_cache_manager:
dependency: transitive
description:
name: flutter_cache_manager
sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
url: "https://pub.dev"
source: hosted
version: "3.4.1"
flutter_discord_rpc_fork:
dependency: "direct main"
description:
@ -569,6 +521,14 @@ packages:
url: "https://github.com/Schnitzel5/flutter-discord-rpc.git"
source: git
version: "1.0.5"
flutter_html:
dependency: "direct main"
description:
name: flutter_html
sha256: "38a2fd702ffdf3243fb7441ab58aa1bc7e6922d95a50db76534de8260638558d"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
flutter_inappwebview:
dependency: "direct main"
description:
@ -687,14 +647,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.11.1"
flutter_svg:
dependency: transitive
description:
name: flutter_svg
sha256: b9c2ad5872518a27507ab432d1fb97e8813b05f0fc693f9d40fad06d073e0678
url: "https://pub.dev"
source: hosted
version: "2.2.1"
flutter_test:
dependency: "direct dev"
description: flutter
@ -722,22 +674,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_widget_from_html:
dependency: "direct main"
description:
name: flutter_widget_from_html
sha256: "7f1daefcd3009c43c7e7fb37501e6bb752d79aa7bfad0085fb0444da14e89bd0"
url: "https://pub.dev"
source: hosted
version: "0.17.1"
flutter_widget_from_html_core:
dependency: transitive
description:
name: flutter_widget_from_html_core
sha256: "1120ee6ed3509ceff2d55aa6c6cbc7b6b1291434422de2411b5a59364dd6ff03"
url: "https://pub.dev"
source: hosted
version: "0.17.0"
font_awesome_flutter:
dependency: "direct main"
description:
@ -770,54 +706,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.0"
fwfh_cached_network_image:
dependency: transitive
description:
name: fwfh_cached_network_image
sha256: "484cb5f8047f02cfac0654fca5832bfa91bb715fd7fc651c04eb7454187c4af8"
url: "https://pub.dev"
source: hosted
version: "0.16.1"
fwfh_chewie:
dependency: transitive
description:
name: fwfh_chewie
sha256: ae74fc26798b0e74f3983f7b851e74c63b9eeb2d3015ecd4b829096b2c3f8818
url: "https://pub.dev"
source: hosted
version: "0.16.1"
fwfh_just_audio:
dependency: transitive
description:
name: fwfh_just_audio
sha256: dfd622a0dfe049ac647423a2a8afa7f057d9b2b93d92710b624e3d370b1ac69a
url: "https://pub.dev"
source: hosted
version: "0.17.0"
fwfh_svg:
dependency: transitive
description:
name: fwfh_svg
sha256: "2e6bb241179eeeb1a7941e05c8c923b05d332d36a9085233e7bf110ea7deb915"
url: "https://pub.dev"
source: hosted
version: "0.16.1"
fwfh_url_launcher:
dependency: transitive
description:
name: fwfh_url_launcher
sha256: c38aa8fb373fda3a89b951fa260b539f623f6edb45eee7874cb8b492471af881
url: "https://pub.dev"
source: hosted
version: "0.16.1"
fwfh_webview:
dependency: transitive
description:
name: fwfh_webview
sha256: f71b0aa16e15d82f3c017f33560201ff5ae04e91e970cab5d12d3bcf970b870c
url: "https://pub.dev"
source: hosted
version: "0.15.6"
glob:
dependency: transitive
description:
@ -1042,30 +930,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.4.2"
just_audio:
dependency: transitive
description:
name: just_audio
sha256: "9694e4734f515f2a052493d1d7e0d6de219ee0427c7c29492e246ff32a219908"
url: "https://pub.dev"
source: hosted
version: "0.10.5"
just_audio_platform_interface:
dependency: transitive
description:
name: just_audio_platform_interface
sha256: "2532c8d6702528824445921c5ff10548b518b13f808c2e34c2fd54793b999a6a"
url: "https://pub.dev"
source: hosted
version: "4.6.0"
just_audio_web:
dependency: transitive
description:
name: just_audio_web
sha256: "6ba8a2a7e87d57d32f0f7b42856ade3d6a9fbe0f1a11fabae0a4f00bb73f0663"
url: "https://pub.dev"
source: hosted
version: "0.4.16"
leak_tracker:
dependency: transitive
description:
@ -1098,6 +962,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.0"
list_counter:
dependency: transitive
description:
name: list_counter
sha256: c447ae3dfcd1c55f0152867090e67e219d42fe6d4f2807db4bbe8b8d69912237
url: "https://pub.dev"
source: hosted
version: "1.0.2"
logging:
dependency: transitive
description:
@ -1226,14 +1098,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.5.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
nm:
dependency: transitive
description:
@ -1258,14 +1122,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.2"
octo_image:
dependency: transitive
description:
name: octo_image
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
package_config:
dependency: transitive
description:
@ -1298,14 +1154,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.1"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
path_provider:
dependency: "direct main"
description:
@ -1474,14 +1322,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "23.0.0"
provider:
dependency: transitive
description:
name: provider
sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
url: "https://pub.dev"
source: hosted
version: "6.1.5+1"
pseudom:
dependency: "direct main"
description:
@ -1790,46 +1630,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.0"
sqflite:
dependency: transitive
description:
name: sqflite
sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03
url: "https://pub.dev"
source: hosted
version: "2.4.2"
sqflite_android:
dependency: transitive
description:
name: sqflite_android
sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88
url: "https://pub.dev"
source: hosted
version: "2.4.2+2"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6"
url: "https://pub.dev"
source: hosted
version: "2.5.6"
sqflite_darwin:
dependency: transitive
description:
name: sqflite_darwin
sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3"
url: "https://pub.dev"
source: hosted
version: "2.4.2"
sqflite_platform_interface:
dependency: transitive
description:
name: sqflite_platform_interface
sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
stack_trace:
dependency: transitive
description:
@ -2038,30 +1838,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.5.1"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6
url: "https://pub.dev"
source: hosted
version: "1.1.19"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
url: "https://pub.dev"
source: hosted
version: "1.1.13"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc
url: "https://pub.dev"
source: hosted
version: "1.1.19"
vector_math:
dependency: transitive
description:
@ -2070,46 +1846,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.0"
video_player:
dependency: transitive
description:
name: video_player
sha256: "0d55b1f1a31e5ad4c4967bfaa8ade0240b07d20ee4af1dfef5f531056512961a"
url: "https://pub.dev"
source: hosted
version: "2.10.0"
video_player_android:
dependency: transitive
description:
name: video_player_android
sha256: a8dc4324f67705de057678372bedb66cd08572fe7c495605ac68c5f503324a39
url: "https://pub.dev"
source: hosted
version: "2.8.15"
video_player_avfoundation:
dependency: transitive
description:
name: video_player_avfoundation
sha256: f9a780aac57802b2892f93787e5ea53b5f43cc57dc107bee9436458365be71cd
url: "https://pub.dev"
source: hosted
version: "2.8.4"
video_player_platform_interface:
dependency: transitive
description:
name: video_player_platform_interface
sha256: "9e372520573311055cb353b9a0da1c9d72b094b7ba01b8ecc66f28473553793b"
url: "https://pub.dev"
source: hosted
version: "6.5.0"
video_player_web:
dependency: transitive
description:
name: video_player_web
sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
vm_service:
dependency: transitive
description:
@ -2182,38 +1918,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.1"
webview_flutter:
dependency: transitive
description:
name: webview_flutter
sha256: c3e4fe614b1c814950ad07186007eff2f2e5dd2935eba7b9a9a1af8e5885f1ba
url: "https://pub.dev"
source: hosted
version: "4.13.0"
webview_flutter_android:
dependency: transitive
description:
name: webview_flutter_android
sha256: e5201c620eb2637dca88a756961fae4a7191bb30b4f2271e08b746405ffdf3fd
url: "https://pub.dev"
source: hosted
version: "4.10.5"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: "63d26ee3aca7256a83ccb576a50272edd7cfc80573a4305caa98985feb493ee0"
url: "https://pub.dev"
source: hosted
version: "2.14.0"
webview_flutter_wkwebview:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: fea63576b3b7e02b2df8b78ba92b48ed66caec2bb041e9a0b1cbd586d5d80bfd
url: "https://pub.dev"
source: hosted
version: "3.23.1"
win32:
dependency: "direct main"
description:

View file

@ -79,7 +79,7 @@ dependencies:
path: packages/desktop_webview_window
ref: main
screen_brightness: ^2.1.1
flutter_widget_from_html: ^0.17.1
flutter_html: ^3.0.0
convert: ^3.1.2
connectivity_plus: ^7.0.0
app_links: ^6.4.0