Added double columm page view

This commit is contained in:
kodjomoustapha 2023-10-26 19:21:18 +01:00
parent cad4d1bcc2
commit 864d00417a
16 changed files with 1682 additions and 576 deletions

View file

@ -129,6 +129,8 @@ class Settings {
@enumerated
BackgroundColor backgroundColor;
List<PersonalPageMode>? personalPageModeList;
Settings(
{this.id = 227,
this.displayType = DisplayType.compactGrid,
@ -183,7 +185,8 @@ class Settings {
this.pagePreloadAmount = 6,
this.scaleType = ScaleType.fitScreen,
this.checkForExtensionUpdates = true,
this.backgroundColor = BackgroundColor.black});
this.backgroundColor = BackgroundColor.black,
this.personalPageModeList});
}
enum DisplayType {
@ -266,8 +269,18 @@ class PersonalReaderMode {
ReaderMode readerMode = ReaderMode.vertical;
}
@embedded
class PersonalPageMode {
int? mangaId;
@enumerated
PageMode pageMode = PageMode.onePage;
}
enum ReaderMode { vertical, ltr, rtl, verticalContinuous, webtoon }
enum PageMode { onePage, doubleColumm }
@embedded
class FilterScanlator {
int? mangaId;

View file

@ -254,68 +254,74 @@ const SettingsSchema = CollectionSchema(
name: r'pagePreloadAmount',
type: IsarType.long,
),
r'personalReaderModeList': PropertySchema(
r'personalPageModeList': PropertySchema(
id: 45,
name: r'personalPageModeList',
type: IsarType.objectList,
target: r'PersonalPageMode',
),
r'personalReaderModeList': PropertySchema(
id: 46,
name: r'personalReaderModeList',
type: IsarType.objectList,
target: r'PersonalReaderMode',
),
r'pureBlackDarkMode': PropertySchema(
id: 46,
id: 47,
name: r'pureBlackDarkMode',
type: IsarType.bool,
),
r'relativeTimesTamps': PropertySchema(
id: 47,
id: 48,
name: r'relativeTimesTamps',
type: IsarType.long,
),
r'saveAsCBZArchive': PropertySchema(
id: 48,
id: 49,
name: r'saveAsCBZArchive',
type: IsarType.bool,
),
r'scaleType': PropertySchema(
id: 49,
id: 50,
name: r'scaleType',
type: IsarType.byte,
enumMap: _SettingsscaleTypeEnumValueMap,
),
r'showNSFW': PropertySchema(
id: 50,
id: 51,
name: r'showNSFW',
type: IsarType.bool,
),
r'showPagesNumber': PropertySchema(
id: 51,
id: 52,
name: r'showPagesNumber',
type: IsarType.bool,
),
r'sortChapterList': PropertySchema(
id: 52,
id: 53,
name: r'sortChapterList',
type: IsarType.objectList,
target: r'SortChapter',
),
r'sortLibraryAnime': PropertySchema(
id: 53,
id: 54,
name: r'sortLibraryAnime',
type: IsarType.object,
target: r'SortLibraryManga',
),
r'sortLibraryManga': PropertySchema(
id: 54,
id: 55,
name: r'sortLibraryManga',
type: IsarType.object,
target: r'SortLibraryManga',
),
r'themeIsDark': PropertySchema(
id: 55,
id: 56,
name: r'themeIsDark',
type: IsarType.bool,
),
r'userAgent': PropertySchema(
id: 56,
id: 57,
name: r'userAgent',
type: IsarType.string,
)
@ -345,7 +351,8 @@ const SettingsSchema = CollectionSchema(
r'Cookie': CookieSchema,
r'PersonalReaderMode': PersonalReaderModeSchema,
r'FilterScanlator': FilterScanlatorSchema,
r'L10nLocale': L10nLocaleSchema
r'L10nLocale': L10nLocaleSchema,
r'PersonalPageMode': PersonalPageModeSchema
},
getId: _settingsGetId,
getLinks: _settingsGetLinks,
@ -476,6 +483,20 @@ int _settingsEstimateSize(
value, allOffsets[L10nLocale]!, allOffsets);
}
}
{
final list = object.personalPageModeList;
if (list != null) {
bytesCount += 3 + list.length * 3;
{
final offsets = allOffsets[PersonalPageMode]!;
for (var i = 0; i < list.length; i++) {
final value = list[i];
bytesCount +=
PersonalPageModeSchema.estimateSize(value, offsets, allOffsets);
}
}
}
}
{
final list = object.personalReaderModeList;
if (list != null) {
@ -620,38 +641,44 @@ void _settingsSerialize(
);
writer.writeBool(offsets[43], object.onlyIncludePinnedSources);
writer.writeLong(offsets[44], object.pagePreloadAmount);
writer.writeObjectList<PersonalReaderMode>(
writer.writeObjectList<PersonalPageMode>(
offsets[45],
allOffsets,
PersonalPageModeSchema.serialize,
object.personalPageModeList,
);
writer.writeObjectList<PersonalReaderMode>(
offsets[46],
allOffsets,
PersonalReaderModeSchema.serialize,
object.personalReaderModeList,
);
writer.writeBool(offsets[46], object.pureBlackDarkMode);
writer.writeLong(offsets[47], object.relativeTimesTamps);
writer.writeBool(offsets[48], object.saveAsCBZArchive);
writer.writeByte(offsets[49], object.scaleType.index);
writer.writeBool(offsets[50], object.showNSFW);
writer.writeBool(offsets[51], object.showPagesNumber);
writer.writeBool(offsets[47], object.pureBlackDarkMode);
writer.writeLong(offsets[48], object.relativeTimesTamps);
writer.writeBool(offsets[49], object.saveAsCBZArchive);
writer.writeByte(offsets[50], object.scaleType.index);
writer.writeBool(offsets[51], object.showNSFW);
writer.writeBool(offsets[52], object.showPagesNumber);
writer.writeObjectList<SortChapter>(
offsets[52],
offsets[53],
allOffsets,
SortChapterSchema.serialize,
object.sortChapterList,
);
writer.writeObject<SortLibraryManga>(
offsets[53],
offsets[54],
allOffsets,
SortLibraryMangaSchema.serialize,
object.sortLibraryAnime,
);
writer.writeObject<SortLibraryManga>(
offsets[54],
offsets[55],
allOffsets,
SortLibraryMangaSchema.serialize,
object.sortLibraryManga,
);
writer.writeBool(offsets[55], object.themeIsDark);
writer.writeString(offsets[56], object.userAgent);
writer.writeBool(offsets[56], object.themeIsDark);
writer.writeString(offsets[57], object.userAgent);
}
Settings _settingsDeserialize(
@ -731,38 +758,44 @@ Settings _settingsDeserialize(
libraryShowNumbersOfItems: reader.readBoolOrNull(offsets[41]),
onlyIncludePinnedSources: reader.readBoolOrNull(offsets[43]),
pagePreloadAmount: reader.readLongOrNull(offsets[44]),
personalReaderModeList: reader.readObjectList<PersonalReaderMode>(
personalPageModeList: reader.readObjectList<PersonalPageMode>(
offsets[45],
PersonalPageModeSchema.deserialize,
allOffsets,
PersonalPageMode(),
),
personalReaderModeList: reader.readObjectList<PersonalReaderMode>(
offsets[46],
PersonalReaderModeSchema.deserialize,
allOffsets,
PersonalReaderMode(),
),
pureBlackDarkMode: reader.readBoolOrNull(offsets[46]),
relativeTimesTamps: reader.readLongOrNull(offsets[47]),
saveAsCBZArchive: reader.readBoolOrNull(offsets[48]),
pureBlackDarkMode: reader.readBoolOrNull(offsets[47]),
relativeTimesTamps: reader.readLongOrNull(offsets[48]),
saveAsCBZArchive: reader.readBoolOrNull(offsets[49]),
scaleType:
_SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offsets[49])] ??
_SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offsets[50])] ??
ScaleType.fitScreen,
showNSFW: reader.readBoolOrNull(offsets[50]),
showPagesNumber: reader.readBoolOrNull(offsets[51]),
showNSFW: reader.readBoolOrNull(offsets[51]),
showPagesNumber: reader.readBoolOrNull(offsets[52]),
sortChapterList: reader.readObjectList<SortChapter>(
offsets[52],
offsets[53],
SortChapterSchema.deserialize,
allOffsets,
SortChapter(),
),
sortLibraryAnime: reader.readObjectOrNull<SortLibraryManga>(
offsets[53],
SortLibraryMangaSchema.deserialize,
allOffsets,
),
sortLibraryManga: reader.readObjectOrNull<SortLibraryManga>(
offsets[54],
SortLibraryMangaSchema.deserialize,
allOffsets,
),
themeIsDark: reader.readBoolOrNull(offsets[55]),
userAgent: reader.readStringOrNull(offsets[56]),
sortLibraryManga: reader.readObjectOrNull<SortLibraryManga>(
offsets[55],
SortLibraryMangaSchema.deserialize,
allOffsets,
),
themeIsDark: reader.readBoolOrNull(offsets[56]),
userAgent: reader.readStringOrNull(offsets[57]),
);
object.chapterFilterBookmarkedList =
reader.readObjectList<ChapterFilterBookmarked>(
@ -935,38 +968,39 @@ P _settingsDeserializeProp<P>(
case 44:
return (reader.readLongOrNull(offset)) as P;
case 45:
return (reader.readObjectList<PersonalPageMode>(
offset,
PersonalPageModeSchema.deserialize,
allOffsets,
PersonalPageMode(),
)) as P;
case 46:
return (reader.readObjectList<PersonalReaderMode>(
offset,
PersonalReaderModeSchema.deserialize,
allOffsets,
PersonalReaderMode(),
)) as P;
case 46:
return (reader.readBoolOrNull(offset)) as P;
case 47:
return (reader.readLongOrNull(offset)) as P;
case 48:
return (reader.readBoolOrNull(offset)) as P;
case 48:
return (reader.readLongOrNull(offset)) as P;
case 49:
return (reader.readBoolOrNull(offset)) as P;
case 50:
return (_SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offset)] ??
ScaleType.fitScreen) as P;
case 50:
return (reader.readBoolOrNull(offset)) as P;
case 51:
return (reader.readBoolOrNull(offset)) as P;
case 52:
return (reader.readBoolOrNull(offset)) as P;
case 53:
return (reader.readObjectList<SortChapter>(
offset,
SortChapterSchema.deserialize,
allOffsets,
SortChapter(),
)) as P;
case 53:
return (reader.readObjectOrNull<SortLibraryManga>(
offset,
SortLibraryMangaSchema.deserialize,
allOffsets,
)) as P;
case 54:
return (reader.readObjectOrNull<SortLibraryManga>(
offset,
@ -974,8 +1008,14 @@ P _settingsDeserializeProp<P>(
allOffsets,
)) as P;
case 55:
return (reader.readBoolOrNull(offset)) as P;
return (reader.readObjectOrNull<SortLibraryManga>(
offset,
SortLibraryMangaSchema.deserialize,
allOffsets,
)) as P;
case 56:
return (reader.readBoolOrNull(offset)) as P;
case 57:
return (reader.readStringOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@ -3923,6 +3963,113 @@ extension SettingsQueryFilter
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalPageModeListIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'personalPageModeList',
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalPageModeListIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'personalPageModeList',
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalPageModeListLengthEqualTo(int length) {
return QueryBuilder.apply(this, (query) {
return query.listLength(
r'personalPageModeList',
length,
true,
length,
true,
);
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalPageModeListIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.listLength(
r'personalPageModeList',
0,
true,
0,
true,
);
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalPageModeListIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.listLength(
r'personalPageModeList',
0,
false,
999999,
true,
);
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalPageModeListLengthLessThan(
int length, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.listLength(
r'personalPageModeList',
0,
true,
length,
include,
);
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalPageModeListLengthGreaterThan(
int length, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.listLength(
r'personalPageModeList',
length,
include,
999999,
true,
);
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalPageModeListLengthBetween(
int lower,
int upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.listLength(
r'personalPageModeList',
lower,
includeLower,
upper,
includeUpper,
);
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalReaderModeListIsNull() {
return QueryBuilder.apply(this, (query) {
@ -4645,6 +4792,13 @@ extension SettingsQueryObject
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalPageModeListElement(FilterQuery<PersonalPageMode> q) {
return QueryBuilder.apply(this, (query) {
return query.object(q, r'personalPageModeList');
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalReaderModeListElement(FilterQuery<PersonalReaderMode> q) {
return QueryBuilder.apply(this, (query) {
@ -6554,6 +6708,13 @@ extension SettingsQueryProperty
});
}
QueryBuilder<Settings, List<PersonalPageMode>?, QQueryOperations>
personalPageModeListProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'personalPageModeList');
});
}
QueryBuilder<Settings, List<PersonalReaderMode>?, QQueryOperations>
personalReaderModeListProperty() {
return QueryBuilder.apply(this, (query) {
@ -8991,6 +9152,227 @@ extension PersonalReaderModeQueryObject
// coverage:ignore-file
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
const PersonalPageModeSchema = Schema(
name: r'PersonalPageMode',
id: -7061860019786197792,
properties: {
r'mangaId': PropertySchema(
id: 0,
name: r'mangaId',
type: IsarType.long,
),
r'pageMode': PropertySchema(
id: 1,
name: r'pageMode',
type: IsarType.byte,
enumMap: _PersonalPageModepageModeEnumValueMap,
)
},
estimateSize: _personalPageModeEstimateSize,
serialize: _personalPageModeSerialize,
deserialize: _personalPageModeDeserialize,
deserializeProp: _personalPageModeDeserializeProp,
);
int _personalPageModeEstimateSize(
PersonalPageMode object,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
var bytesCount = offsets.last;
return bytesCount;
}
void _personalPageModeSerialize(
PersonalPageMode object,
IsarWriter writer,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
writer.writeLong(offsets[0], object.mangaId);
writer.writeByte(offsets[1], object.pageMode.index);
}
PersonalPageMode _personalPageModeDeserialize(
Id id,
IsarReader reader,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
final object = PersonalPageMode();
object.mangaId = reader.readLongOrNull(offsets[0]);
object.pageMode = _PersonalPageModepageModeValueEnumMap[
reader.readByteOrNull(offsets[1])] ??
PageMode.onePage;
return object;
}
P _personalPageModeDeserializeProp<P>(
IsarReader reader,
int propertyId,
int offset,
Map<Type, List<int>> allOffsets,
) {
switch (propertyId) {
case 0:
return (reader.readLongOrNull(offset)) as P;
case 1:
return (_PersonalPageModepageModeValueEnumMap[
reader.readByteOrNull(offset)] ??
PageMode.onePage) as P;
default:
throw IsarError('Unknown property with id $propertyId');
}
}
const _PersonalPageModepageModeEnumValueMap = {
'onePage': 0,
'doubleColumm': 1,
};
const _PersonalPageModepageModeValueEnumMap = {
0: PageMode.onePage,
1: PageMode.doubleColumm,
};
extension PersonalPageModeQueryFilter
on QueryBuilder<PersonalPageMode, PersonalPageMode, QFilterCondition> {
QueryBuilder<PersonalPageMode, PersonalPageMode, QAfterFilterCondition>
mangaIdIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'mangaId',
));
});
}
QueryBuilder<PersonalPageMode, PersonalPageMode, QAfterFilterCondition>
mangaIdIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'mangaId',
));
});
}
QueryBuilder<PersonalPageMode, PersonalPageMode, QAfterFilterCondition>
mangaIdEqualTo(int? value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'mangaId',
value: value,
));
});
}
QueryBuilder<PersonalPageMode, PersonalPageMode, QAfterFilterCondition>
mangaIdGreaterThan(
int? value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'mangaId',
value: value,
));
});
}
QueryBuilder<PersonalPageMode, PersonalPageMode, QAfterFilterCondition>
mangaIdLessThan(
int? value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'mangaId',
value: value,
));
});
}
QueryBuilder<PersonalPageMode, PersonalPageMode, QAfterFilterCondition>
mangaIdBetween(
int? lower,
int? upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'mangaId',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
QueryBuilder<PersonalPageMode, PersonalPageMode, QAfterFilterCondition>
pageModeEqualTo(PageMode value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'pageMode',
value: value,
));
});
}
QueryBuilder<PersonalPageMode, PersonalPageMode, QAfterFilterCondition>
pageModeGreaterThan(
PageMode value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'pageMode',
value: value,
));
});
}
QueryBuilder<PersonalPageMode, PersonalPageMode, QAfterFilterCondition>
pageModeLessThan(
PageMode value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'pageMode',
value: value,
));
});
}
QueryBuilder<PersonalPageMode, PersonalPageMode, QAfterFilterCondition>
pageModeBetween(
PageMode lower,
PageMode upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'pageMode',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
}
extension PersonalPageModeQueryObject
on QueryBuilder<PersonalPageMode, PersonalPageMode, QFilterCondition> {}
// coverage:ignore-file
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
const FilterScanlatorSchema = Schema(
name: r'FilterScanlator',
id: 3007689993900015493,

View file

@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart';
// RiverpodGenerator
// **************************************************************************
String _$updateMangaDetailHash() => r'f35fb2908d83d5a8bea456e71de805503065d670';
String _$updateMangaDetailHash() => r'3433a9fed78f2e288244dc46485bbeeda644ae93';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -0,0 +1,304 @@
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/modules/manga/reader/image_view_center.dart';
import 'package:mangayomi/modules/manga/reader/reader_view.dart';
import 'package:mangayomi/modules/manga/reader/widgets/circular_progress_indicator_animate_rotate.dart';
import 'package:mangayomi/modules/more/settings/reader/reader_screen.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/media_query.dart';
import 'package:photo_view/photo_view.dart';
import 'package:photo_view/photo_view_gallery.dart';
class DoubleColummView extends StatefulWidget {
final bool cropBorders;
final List<UChapDataPreload?> datas;
final Function(double) scale;
final BackgroundColor backgroundColor;
final Function(bool) isFailedToLoadImage;
const DoubleColummView(
{super.key,
required this.datas,
required this.scale,
required this.backgroundColor,
required this.isFailedToLoadImage,
required this.cropBorders});
@override
State<DoubleColummView> createState() => _DoubleColummViewState();
}
class _DoubleColummViewState extends State<DoubleColummView>
with TickerProviderStateMixin {
late AnimationController _scaleAnimationController;
late Animation<double> _animation;
Alignment _scalePosition = Alignment.center;
final PhotoViewController _photoViewController = PhotoViewController();
final PhotoViewScaleStateController _photoViewScaleStateController =
PhotoViewScaleStateController();
Duration? _doubleTapAnimationDuration() {
int doubleTapAnimationValue =
isar.settings.getSync(227)!.doubleTapAnimationSpeed!;
if (doubleTapAnimationValue == 0) {
return const Duration(milliseconds: 10);
} else if (doubleTapAnimationValue == 1) {
return const Duration(milliseconds: 800);
}
return const Duration(milliseconds: 200);
}
void _onScaleEnd(BuildContext context, ScaleEndDetails details,
PhotoViewControllerValue controllerValue) {
if (controllerValue.scale! < 1) {
_photoViewScaleStateController.reset();
}
}
double get pixelRatio => View.of(context).devicePixelRatio;
Size get size => View.of(context).physicalSize / pixelRatio;
Alignment _computeAlignmentByTapOffset(Offset offset) {
return Alignment((offset.dx - size.width / 2) / (size.width / 2),
(offset.dy - size.height / 2) / (size.height / 2));
}
@override
void initState() {
_scaleAnimationController = AnimationController(
duration: _doubleTapAnimationDuration(), vsync: this);
_animation = Tween(begin: 1.0, end: 2.0).animate(
CurvedAnimation(curve: Curves.ease, parent: _scaleAnimationController));
_animation.addListener(() {
_photoViewController.scale = _animation.value;
widget.scale(_animation.value);
});
super.initState();
}
void _toggleScale(Offset tapPosition) {
if (mounted) {
setState(() {
if (_scaleAnimationController.isAnimating) {
return;
}
if (_photoViewController.scale == 1.0) {
_scalePosition = _computeAlignmentByTapOffset(tapPosition);
if (_scaleAnimationController.isCompleted) {
_scaleAnimationController.reset();
}
_scaleAnimationController.forward();
return;
}
if (_photoViewController.scale == 2.0) {
_scaleAnimationController.reverse();
return;
}
_photoViewScaleStateController.reset();
});
}
}
@override
Widget build(BuildContext context) {
return PhotoViewGallery.builder(
backgroundDecoration: const BoxDecoration(color: Colors.transparent),
itemCount: 1,
builder: (context, _) {
final l10n = l10nLocalizations(context)!;
return PhotoViewGalleryPageOptions.customChild(
controller: _photoViewController,
scaleStateController: _photoViewScaleStateController,
basePosition: _scalePosition,
onScaleEnd: _onScaleEnd,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onDoubleTapDown: (TapDownDetails details) {
_toggleScale(details.globalPosition);
},
onDoubleTap: () {},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (widget.datas[0] != null)
Flexible(
child: ImageViewCenter(
datas: widget.datas[0]!,
loadStateChanged: (state) {
if (state.extendedImageLoadState ==
LoadState.loading) {
final ImageChunkEvent? loadingProgress =
state.loadingProgress;
final double progress =
loadingProgress?.expectedTotalBytes != null
? loadingProgress!
.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: 0;
return Container(
color: getBackgroundColor(
widget.backgroundColor),
height: mediaHeight(context, 0.8),
child: CircularProgressIndicatorAnimateRotate(
progress: progress),
);
}
if (state.extendedImageLoadState ==
LoadState.completed) {
widget.isFailedToLoadImage(false);
return Image(image: state.imageProvider);
}
if (state.extendedImageLoadState ==
LoadState.failed) {
widget.isFailedToLoadImage(true);
return Container(
color: getBackgroundColor(
widget.backgroundColor),
height: mediaHeight(context, 0.8),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
l10n.image_loading_error,
style: TextStyle(
color: Colors.white
.withOpacity(0.7)),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onLongPress: () {
state.reLoadImage();
widget
.isFailedToLoadImage(false);
},
onTap: () {
state.reLoadImage();
widget
.isFailedToLoadImage(false);
},
child: Container(
decoration: BoxDecoration(
color:
primaryColor(context),
borderRadius:
BorderRadius.circular(
30)),
child: Padding(
padding: const EdgeInsets
.symmetric(
vertical: 8,
horizontal: 16),
child: Text(
l10n.retry,
),
),
)),
),
],
));
}
return null;
},
cropBorders: widget.cropBorders,
),
),
// if (widget.datas[1] != null) const SizedBox(width: 10),
if (widget.datas[1] != null)
Flexible(
child: ImageViewCenter(
datas: widget.datas[1]!,
loadStateChanged: (state) {
if (state.extendedImageLoadState ==
LoadState.loading) {
final ImageChunkEvent? loadingProgress =
state.loadingProgress;
final double progress =
loadingProgress?.expectedTotalBytes != null
? loadingProgress!
.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: 0;
return Container(
color: getBackgroundColor(
widget.backgroundColor),
height: mediaHeight(context, 0.8),
child: CircularProgressIndicatorAnimateRotate(
progress: progress),
);
}
if (state.extendedImageLoadState ==
LoadState.completed) {
widget.isFailedToLoadImage(false);
return Image(image: state.imageProvider);
}
if (state.extendedImageLoadState ==
LoadState.failed) {
widget.isFailedToLoadImage(true);
return Container(
color: getBackgroundColor(
widget.backgroundColor),
height: mediaHeight(context, 0.8),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
l10n.image_loading_error,
style: TextStyle(
color: Colors.white
.withOpacity(0.7)),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onLongPress: () {
state.reLoadImage();
widget
.isFailedToLoadImage(false);
},
onTap: () {
state.reLoadImage();
widget
.isFailedToLoadImage(false);
},
child: Container(
decoration: BoxDecoration(
color:
primaryColor(context),
borderRadius:
BorderRadius.circular(
30)),
child: Padding(
padding: const EdgeInsets
.symmetric(
vertical: 8,
horizontal: 16),
child: Text(
l10n.retry,
),
),
)),
),
],
));
}
return null;
},
cropBorders: widget.cropBorders,
),
),
],
),
));
},
);
}
}

View file

@ -0,0 +1,185 @@
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/modules/manga/reader/image_view_center.dart';
import 'package:mangayomi/modules/manga/reader/reader_view.dart';
import 'package:mangayomi/modules/manga/reader/widgets/circular_progress_indicator_animate_rotate.dart';
import 'package:mangayomi/modules/more/settings/reader/reader_screen.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/media_query.dart';
class DoubleColummVerticalView extends StatelessWidget {
final bool cropBorders;
final List<UChapDataPreload?> datas;
final Function(double) scale;
final BackgroundColor backgroundColor;
final Function(bool) isFailedToLoadImage;
const DoubleColummVerticalView(
{super.key,
required this.datas,
required this.scale,
required this.backgroundColor,
required this.isFailedToLoadImage,
required this.cropBorders});
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (datas[0] != null && datas[0]!.index == 0)
SizedBox(
height: MediaQuery.of(context).padding.top,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (datas[0] != null)
Flexible(
child: ImageViewCenter(
datas: datas[0]!,
loadStateChanged: (state) {
if (state.extendedImageLoadState == LoadState.loading) {
final ImageChunkEvent? loadingProgress =
state.loadingProgress;
final double progress =
loadingProgress?.expectedTotalBytes != null
? loadingProgress!.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: 0;
return Container(
color: getBackgroundColor(backgroundColor),
height: mediaHeight(context, 0.8),
child: CircularProgressIndicatorAnimateRotate(
progress: progress),
);
}
if (state.extendedImageLoadState == LoadState.completed) {
isFailedToLoadImage(false);
return Image(image: state.imageProvider);
}
if (state.extendedImageLoadState == LoadState.failed) {
isFailedToLoadImage(true);
return Container(
color: getBackgroundColor(backgroundColor),
height: mediaHeight(context, 0.8),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
l10n.image_loading_error,
style: TextStyle(
color: Colors.white.withOpacity(0.7)),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onLongPress: () {
state.reLoadImage();
isFailedToLoadImage(false);
},
onTap: () {
state.reLoadImage();
isFailedToLoadImage(false);
},
child: Container(
decoration: BoxDecoration(
color: primaryColor(context),
borderRadius:
BorderRadius.circular(30)),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8, horizontal: 16),
child: Text(
l10n.retry,
),
),
)),
),
],
));
}
return null;
},
cropBorders: cropBorders,
),
),
// if (datas[1] != null) const SizedBox(width: 10),
if (datas[1] != null)
Flexible(
child: ImageViewCenter(
datas: datas[1]!,
loadStateChanged: (state) {
if (state.extendedImageLoadState == LoadState.loading) {
final ImageChunkEvent? loadingProgress =
state.loadingProgress;
final double progress =
loadingProgress?.expectedTotalBytes != null
? loadingProgress!.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: 0;
return Container(
color: getBackgroundColor(backgroundColor),
height: mediaHeight(context, 0.8),
child: CircularProgressIndicatorAnimateRotate(
progress: progress),
);
}
if (state.extendedImageLoadState == LoadState.completed) {
isFailedToLoadImage(false);
return Image(image: state.imageProvider);
}
if (state.extendedImageLoadState == LoadState.failed) {
isFailedToLoadImage(true);
return Container(
color: getBackgroundColor(backgroundColor),
height: mediaHeight(context, 0.8),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
l10n.image_loading_error,
style: TextStyle(
color: Colors.white.withOpacity(0.7)),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onLongPress: () {
state.reLoadImage();
isFailedToLoadImage(false);
},
onTap: () {
state.reLoadImage();
isFailedToLoadImage(false);
},
child: Container(
decoration: BoxDecoration(
color: primaryColor(context),
borderRadius:
BorderRadius.circular(30)),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8, horizontal: 16),
child: Text(
l10n.retry,
),
),
)),
),
],
));
}
return null;
},
cropBorders: cropBorders,
),
),
],
),
],
);
}
}

View file

@ -14,17 +14,11 @@ class ImageViewCenter extends ConsumerWidget {
final UChapDataPreload datas;
final bool cropBorders;
final Widget? Function(ExtendedImageState state) loadStateChanged;
final Function(ExtendedImageGestureState state) onDoubleTap;
final GestureConfig Function(ExtendedImageState state)
initGestureConfigHandler;
const ImageViewCenter({
super.key,
required this.datas,
required this.cropBorders,
required this.loadStateChanged,
required this.onDoubleTap,
required this.initGestureConfigHandler,
});
const ImageViewCenter(
{super.key,
required this.datas,
required this.cropBorders,
required this.loadStateChanged});
@override
Widget build(BuildContext context, WidgetRef ref) {
@ -53,9 +47,6 @@ class ImageViewCenter extends ConsumerWidget {
fit: getBoxFit(scaleType),
clearMemoryCacheWhenDispose: true,
enableMemoryCache: false,
mode: ExtendedImageMode.gesture,
initGestureConfigHandler: initGestureConfigHandler,
onDoubleTap: onDoubleTap,
loadStateChanged: loadStateChanged,
)
: ExtendedImage.file(
@ -63,9 +54,6 @@ class ImageViewCenter extends ConsumerWidget {
fit: getBoxFit(scaleType),
clearMemoryCacheWhenDispose: true,
enableMemoryCache: false,
mode: ExtendedImageMode.gesture,
initGestureConfigHandler: initGestureConfigHandler,
onDoubleTap: onDoubleTap,
loadStateChanged: loadStateChanged,
)
: ExtendedImage.network(
@ -77,8 +65,6 @@ class ImageViewCenter extends ConsumerWidget {
enableMemoryCache: true,
mode: ExtendedImageMode.gesture,
cacheMaxAge: const Duration(days: 7),
initGestureConfigHandler: initGestureConfigHandler,
onDoubleTap: onDoubleTap,
handleLoadingProgress: true,
loadStateChanged: loadStateChanged,
);

View file

@ -37,7 +37,6 @@ Future<Uint8List?> cropBorders(CropBordersRef ref,
operation: RustOperation.Read,
message: requestMessage.writeToBuffer());
final rustResponse = await requestToRust(rustRequest);
return rustResponse.blob;
}
return null;

View file

@ -6,7 +6,7 @@ part of 'crop_borders_provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$cropBordersHash() => r'01a2567a5461a9ef1fa1c9d7ee547220b16d8861';
String _$cropBordersHash() => r'70030b178c121d536676f66ba1f90d9a15b801ba';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -62,6 +62,16 @@ class ReaderController {
return isar.settings.getSync(227)!.defaultReaderMode;
}
PageMode getPageMode() {
final personalPageModeList = getIsarSetting().personalPageModeList ?? [];
final personalPageMode = personalPageModeList
.where((element) => element.mangaId == getManga().id);
if (personalPageMode.isNotEmpty) {
return personalPageMode.first.pageMode;
}
return PageMode.onePage;
}
void setReaderMode(ReaderMode newReaderMode) {
List<PersonalReaderMode>? personalReaderModeLists = [];
for (var personalReaderMode
@ -77,6 +87,20 @@ class ReaderController {
getIsarSetting()..personalReaderModeList = personalReaderModeLists));
}
void setPageMode(PageMode newPageMode) {
List<PersonalPageMode>? personalPageModeLists = [];
for (var personalPageMode in getIsarSetting().personalPageModeList ?? []) {
if (personalPageMode.mangaId != getManga().id) {
personalPageModeLists.add(personalPageMode);
}
}
personalPageModeLists.add(PersonalPageMode()
..mangaId = getManga().id
..pageMode = newPageMode);
isar.writeTxnSync(() => isar.settings.putSync(
getIsarSetting()..personalPageModeList = personalPageModeLists));
}
void setShowPageNumber(bool value) {
if (!incognitoMode) {
isar.writeTxnSync(() =>

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,7 @@ part of 'get_anime_servers.dart';
// RiverpodGenerator
// **************************************************************************
String _$getAnimeServersHash() => r'908cdc967253129e94e25f58a8d7df18044ccd3a';
String _$getAnimeServersHash() => r'9bac62e3b98438831ac0331a7725fee7127b5f60';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'get_chapter_url.dart';
// RiverpodGenerator
// **************************************************************************
String _$getChapterUrlHash() => r'd3836616473c773e79c4b09258fbb7c127a60202';
String _$getChapterUrlHash() => r'40dd54d0a1d2dfd216041fea4e16bba8b8714f45';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -7,7 +7,7 @@ part of 'get_latest_updates_manga.dart';
// **************************************************************************
String _$getLatestUpdatesMangaHash() =>
r'a5d39851af8f86e57147591b2c261298ecaa6a1d';
r'1d73d374c00305d86e3a62ea762367391a01b093';
/// Copied from Dart SDK
class _SystemHash {
@ -35,8 +35,7 @@ class _SystemHash {
const getLatestUpdatesMangaProvider = GetLatestUpdatesMangaFamily();
/// See also [getLatestUpdatesManga].
class GetLatestUpdatesMangaFamily
extends Family<AsyncValue<List<MManga?>>> {
class GetLatestUpdatesMangaFamily extends Family<AsyncValue<List<MManga?>>> {
/// See also [getLatestUpdatesManga].
const GetLatestUpdatesMangaFamily();
@ -118,8 +117,7 @@ class GetLatestUpdatesMangaProvider
@override
Override overrideWith(
FutureOr<List<MManga?>> Function(GetLatestUpdatesMangaRef provider)
create,
FutureOr<List<MManga?>> Function(GetLatestUpdatesMangaRef provider) create,
) {
return ProviderOverride(
origin: this,
@ -158,8 +156,7 @@ class GetLatestUpdatesMangaProvider
}
}
mixin GetLatestUpdatesMangaRef
on AutoDisposeFutureProviderRef<List<MManga?>> {
mixin GetLatestUpdatesMangaRef on AutoDisposeFutureProviderRef<List<MManga?>> {
/// The parameter `source` of this provider.
Source get source;

View file

@ -6,7 +6,7 @@ part of 'get_manga_detail.dart';
// RiverpodGenerator
// **************************************************************************
String _$getMangaDetailHash() => r'0977fe9466dcf9262e37beb644b7f66be2214d1a';
String _$getMangaDetailHash() => r'33da4cfb298929d814fdda8ebece1a0f3474c5d2';
/// Copied from Dart SDK
class _SystemHash {
@ -163,8 +163,7 @@ mixin GetMangaDetailRef on AutoDisposeFutureProviderRef<MManga> {
}
class _GetMangaDetailProviderElement
extends AutoDisposeFutureProviderElement<MManga>
with GetMangaDetailRef {
extends AutoDisposeFutureProviderElement<MManga> with GetMangaDetailRef {
_GetMangaDetailProviderElement(super.provider);
@override

View file

@ -6,7 +6,7 @@ part of 'get_popular_manga.dart';
// RiverpodGenerator
// **************************************************************************
String _$getPopularMangaHash() => r'94fbfc0ba4aca487c3f510263bde2566d7b2bf5a';
String _$getPopularMangaHash() => r'68fcd40dfff14b97e19592e611098b1634e5e17c';
/// Copied from Dart SDK
class _SystemHash {
@ -75,8 +75,7 @@ class GetPopularMangaFamily extends Family<AsyncValue<List<MManga?>>> {
}
/// See also [getPopularManga].
class GetPopularMangaProvider
extends AutoDisposeFutureProvider<List<MManga?>> {
class GetPopularMangaProvider extends AutoDisposeFutureProvider<List<MManga?>> {
/// See also [getPopularManga].
GetPopularMangaProvider({
required Source source,

View file

@ -6,7 +6,7 @@ part of 'search_manga.dart';
// RiverpodGenerator
// **************************************************************************
String _$searchMangaHash() => r'd0bfdc659fa6bd6d3664ec80e7c426509f39002c';
String _$searchMangaHash() => r'0b909c6f3e6d9f0ff7eb01432019b58fece0fbeb';
/// Copied from Dart SDK
class _SystemHash {