This commit is contained in:
kodjomoustapha 2024-05-20 16:28:16 +01:00
parent eeddf0d929
commit 2353b48e59
11 changed files with 700 additions and 674 deletions

4
Cargo.lock generated
View file

@ -1117,9 +1117,9 @@ dependencies = [
[[package]]
name = "rinf"
version = "6.7.0"
version = "6.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cac0dc63e157673747bd0286a8565762fd34d0890ff7eedb90eba035dfa4c43"
checksum = "b0aa1d51ab106785c8d06df0b3aaa2fd4ca4134afc2757aac95688e60a952a65"
dependencies = [
"allo-isolate",
"backtrace",

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:grouped_list/grouped_list.dart';
import 'package:grouped_list/sliver_grouped_list.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
@ -39,80 +39,85 @@ class SourcesFilterScreen extends ConsumerWidget {
: element.isNsfw == false)
.toList();
return GroupedListView<Source, String>(
elements: entries,
groupBy: (element) => element.lang!,
groupSeparatorBuilder: (String groupByValue) =>
SwitchListTile(
value: entries
.where((element) =>
element.lang!.toLowerCase() == groupByValue &&
element.isActive! &&
element.isManga == isManga)
.isNotEmpty,
onChanged: (val) {
isar.writeTxnSync(() {
for (var source in entries) {
if (source.lang!.toLowerCase() == groupByValue) {
isar.sources
.putSync(source..isActive = val == true);
}
}
});
},
title: Text(
completeLanguageName(groupByValue),
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
),
),
itemBuilder: (context, Source element) {
if (entries
.where((s) =>
s.lang!.toLowerCase() == element.lang &&
s.isActive! &&
s.isManga == isManga)
.isEmpty) {
return Container();
}
return CheckboxListTile(
secondary: Container(
height: 37,
width: 37,
decoration: BoxDecoration(
color: Theme.of(context)
.secondaryHeaderColor
.withOpacity(0.5),
borderRadius: BorderRadius.circular(5)),
child: element.iconUrl!.isEmpty
? const Icon(Icons.source_outlined)
: cachedNetworkImage(
imageUrl: element.iconUrl!,
fit: BoxFit.contain,
width: 37,
height: 37,
errorWidget: const SizedBox(
width: 37,
height: 37,
child: Center(
child: Icon(Icons.source_outlined),
),
),
),
return CustomScrollView(
slivers: [
SliverGroupedListView<Source, String>(
elements: entries,
groupBy: (element) => element.lang!,
groupSeparatorBuilder: (String groupByValue) =>
SwitchListTile(
value: entries
.where((element) =>
element.lang!.toLowerCase() == groupByValue &&
element.isActive! &&
element.isManga == isManga)
.isNotEmpty,
onChanged: (val) {
isar.writeTxnSync(() {
for (var source in entries) {
if (source.lang!.toLowerCase() == groupByValue) {
isar.sources
.putSync(source..isActive = val == true);
}
}
});
},
title: Text(
completeLanguageName(groupByValue),
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
),
),
onChanged: (bool? value) {
isar.writeTxnSync(() {
isar.sources.putSync(element..isAdded = value);
});
itemBuilder: (context, Source element) {
if (entries
.where((s) =>
s.lang!.toLowerCase() == element.lang &&
s.isActive! &&
s.isManga == isManga)
.isEmpty) {
return Container();
}
return CheckboxListTile(
secondary: Container(
height: 37,
width: 37,
decoration: BoxDecoration(
color: Theme.of(context)
.secondaryHeaderColor
.withOpacity(0.5),
borderRadius: BorderRadius.circular(5)),
child: element.iconUrl!.isEmpty
? const Icon(Icons.source_outlined)
: cachedNetworkImage(
imageUrl: element.iconUrl!,
fit: BoxFit.contain,
width: 37,
height: 37,
errorWidget: const SizedBox(
width: 37,
height: 37,
child: Center(
child: Icon(Icons.source_outlined),
),
),
),
),
onChanged: (bool? value) {
isar.writeTxnSync(() {
isar.sources.putSync(element..isAdded = value);
});
},
value: element.isAdded!,
title: Text(element.name!),
);
},
value: element.isAdded!,
title: Text(element.name!),
);
},
groupComparator: (group1, group2) => group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC,
groupComparator: (group1, group2) =>
group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC,
),
],
);
}
return Container();

View file

@ -2,7 +2,8 @@ import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:grouped_list/grouped_list.dart';
import 'package:grouped_list/sliver_grouped_list.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
@ -198,198 +199,209 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
.toList();
if (entries.isNotEmpty) {
return GroupedListView<History, String>(
elements: entries,
groupBy: (element) => dateFormat(element.date!,
context: context,
ref: ref,
forHistoryValue: true,
useRelativeTimesTamps: false),
groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(bottom: 8, left: 12),
child: Row(
children: [
Text(dateFormat(
null,
return CustomScrollView(
slivers: [
SliverGroupedListView<History, String>(
elements: entries,
groupBy: (element) => dateFormat(element.date!,
context: context,
stringDate: groupByValue,
ref: ref,
)),
],
),
),
itemBuilder: (context, History element) {
final manga = element.chapter.value!.manga.value!;
final chapter = element.chapter.value!;
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0)),
elevation: 0,
shadowColor: Colors.transparent),
onPressed: () {
pushMangaReaderView(context: context, chapter: chapter);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: SizedBox(
height: 105,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 60,
height: 90,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7)),
forHistoryValue: true,
useRelativeTimesTamps: false),
groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(bottom: 8, left: 12),
child: Row(
children: [
Text(dateFormat(
null,
context: context,
stringDate: groupByValue,
ref: ref,
)),
],
),
),
itemBuilder: (context, History element) {
final manga = element.chapter.value!.manga.value!;
final chapter = element.chapter.value!;
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0)),
elevation: 0,
shadowColor: Colors.transparent),
onPressed: () {
pushMangaReaderView(context: context, chapter: chapter);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: SizedBox(
height: 105,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 60,
height: 90,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7)),
),
onPressed: () {
context.push('/manga-reader/detail',
extra: manga.id);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(7),
child: manga.customCoverImage != null
? Image.memory(
manga.customCoverImage as Uint8List)
: cachedNetworkImage(
headers: ref.watch(headersProvider(
source: manga.source!,
lang: manga.lang!)),
imageUrl: toImgUrl(
manga.customCoverFromTracker ??
manga.imageUrl!),
width: 60,
height: 90,
fit: BoxFit.cover),
),
),
),
onPressed: () {
context.push('/manga-reader/detail',
extra: manga.id);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(7),
child: manga.customCoverImage != null
? Image.memory(
manga.customCoverImage as Uint8List)
: cachedNetworkImage(
headers: ref.watch(headersProvider(
source: manga.source!,
lang: manga.lang!)),
imageUrl: toImgUrl(
manga.customCoverFromTracker ??
manga.imageUrl!),
width: 60,
height: 90,
fit: BoxFit.cover),
),
),
),
Flexible(
child: Row(
children: [
Expanded(
child: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
manga.name!,
style: TextStyle(
fontSize: 14,
color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
fontWeight: FontWeight.bold),
textAlign: TextAlign.start,
),
Wrap(
Flexible(
child: Row(
children: [
Expanded(
child: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
WrapCrossAlignment.end,
CrossAxisAlignment.start,
children: [
Text(
chapter.name!,
manga.name!,
style: TextStyle(
fontSize: 11,
color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
),
),
Text(
" - ${dateFormatHour(element.date!, context)}",
style: TextStyle(
fontSize: 11,
fontSize: 14,
color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
fontWeight: FontWeight.w400),
fontWeight: FontWeight.bold),
textAlign: TextAlign.start,
),
Wrap(
crossAxisAlignment:
WrapCrossAlignment.end,
children: [
Text(
chapter.name!,
style: TextStyle(
fontSize: 11,
color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
),
),
Text(
" - ${dateFormatHour(element.date!, context)}",
style: TextStyle(
fontSize: 11,
color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
fontWeight:
FontWeight.w400),
),
],
),
],
),
],
),
),
),
),
),
IconButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(
l10n.remove,
),
content:
Text(l10n.remove_history_msg),
actions: [
Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed: () async {
await isar
.writeTxn(() async {
await isar.historys
.delete(
element.id!);
});
if (context.mounted) {
Navigator.pop(
context);
}
},
child: Text(l10n.remove)),
IconButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(
l10n.remove,
),
content: Text(
l10n.remove_history_msg),
actions: [
Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(
context);
},
child: Text(
l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed: () async {
await isar.writeTxn(
() async {
await isar
.historys
.delete(
element
.id!);
});
if (context
.mounted) {
Navigator.pop(
context);
}
},
child: Text(
l10n.remove)),
],
)
],
)
],
);
});
},
icon: Icon(
Icons.delete_outline,
size: 25,
color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
)),
],
),
)
],
);
});
},
icon: Icon(
Icons.delete_outline,
size: 25,
color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
)),
],
),
)
],
),
),
),
),
),
);
},
itemComparator: (item1, item2) =>
item1.date!.compareTo(item2.date!),
order: GroupedListOrder.DESC,
);
},
itemComparator: (item1, item2) =>
item1.date!.compareTo(item2.date!),
order: GroupedListOrder.DESC,
),
],
);
}
return Center(

View file

@ -14,13 +14,11 @@ import 'package:photo_view/photo_view_gallery.dart';
class DoubleColummView extends StatefulWidget {
final List<UChapDataPreload?> datas;
final Function(UChapDataPreload datas) onLongPressData;
final Function(double) scale;
final BackgroundColor backgroundColor;
final Function(bool) isFailedToLoadImage;
const DoubleColummView(
{super.key,
required this.datas,
required this.scale,
required this.onLongPressData,
required this.backgroundColor,
required this.isFailedToLoadImage});
@ -70,7 +68,6 @@ class _DoubleColummViewState extends State<DoubleColummView>
CurvedAnimation(curve: Curves.ease, parent: _scaleAnimationController));
_animation.addListener(() {
_photoViewController.scale = _animation.value;
widget.scale(_animation.value);
});
super.initState();

View file

@ -24,12 +24,12 @@ Future<Uint8List?> cropBorders(CropBordersRef ref,
nextId++;
final completer = Completer<Uint8List>();
CropBordersInput(
interactionId: currentId,
).sendSignalToRust(imageBytes);
image: imageBytes,
).sendSignalToRust();
final stream = CropBordersOutput.rustSignalStream;
final subscription = stream.listen((rustSignal) {
if (rustSignal.message.interactionId == currentId) {
completer.complete(rustSignal.blob!);
completer.complete(rustSignal.message.image as Uint8List);
}
});
final image = await completer.future;

View file

@ -473,374 +473,385 @@ class _MangaChapterPageGalleryState
return true;
},
child: SafeArea(
top: !fullScreenReader,
child: ValueListenableBuilder(
valueListenable: _failedToLoadImage,
builder: (context, failedToLoadImage, child) {
return Stack(
children: [
_isVerticalOrHorizontalContinous()
? PhotoViewGallery.builder(
itemCount: 1,
builder: (_, __) =>
PhotoViewGalleryPageOptions.customChild(
controller: _photoViewController,
scaleStateController:
_photoViewScaleStateController,
basePosition: _scalePosition,
onScaleEnd: _onScaleEnd,
child: ScrollablePositionedList.separated(
scrollDirection: isHorizontalContinuaous
? Axis.horizontal
: Axis.vertical,
minCacheExtent:
pagePreloadAmount * context.height(1),
initialScrollIndex:
_readerController.getPageIndex(),
itemCount:
(_pageMode == PageMode.doublePage &&
!isHorizontalContinuaous)
? (_uChapDataPreload.length / 2)
.ceil() +
1
: _uChapDataPreload.length,
child: Material(
child: SafeArea(
top: !fullScreenReader,
child: ValueListenableBuilder(
valueListenable: _failedToLoadImage,
builder: (context, failedToLoadImage, child) {
return Stack(
children: [
_isVerticalOrHorizontalContinous()
? PhotoViewGallery.builder(
itemCount: 1,
builder: (_, __) =>
PhotoViewGalleryPageOptions.customChild(
controller: _photoViewController,
scaleStateController:
_photoViewScaleStateController,
basePosition: _scalePosition,
onScaleEnd: _onScaleEnd,
child: ScrollablePositionedList.separated(
scrollDirection: isHorizontalContinuaous
? Axis.horizontal
: Axis.vertical,
minCacheExtent: pagePreloadAmount *
context.height(1),
initialScrollIndex:
_readerController.getPageIndex(),
itemCount:
(_pageMode == PageMode.doublePage &&
!isHorizontalContinuaous)
? (_uChapDataPreload.length / 2)
.ceil() +
1
: _uChapDataPreload.length,
physics: const ClampingScrollPhysics(),
itemScrollController:
_itemScrollController,
scrollOffsetController:
_pageOffsetController,
itemPositionsListener:
_itemPositionsListener,
itemBuilder: (context, index) {
int index1 = index * 2 - 1;
int index2 = index1 + 1;
return GestureDetector(
behavior:
HitTestBehavior.translucent,
onDoubleTapDown: (details) {
_toggleScale(
details.globalPosition);
},
onDoubleTap: () {},
child: (_pageMode ==
PageMode.doublePage &&
!isHorizontalContinuaous)
? DoubleColummVerticalView(
datas: index == 0
? [
_uChapDataPreload[
0],
null
]
: [
index1 <
_uChapDataPreload
.length
? _uChapDataPreload[
index1]
: null,
index2 <
_uChapDataPreload
.length
? _uChapDataPreload[
index2]
: null,
],
scale: (a) {},
backgroundColor:
backgroundColor,
isFailedToLoadImage:
(val) {},
onLongPressData: (datas) {
_onLongPressImageDialog(
datas, context);
},
)
: ImageViewVertical(
data: _uChapDataPreload[
index],
failedToLoadImage: (value) {
// _failedToLoadImage.value = value;
},
onLongPressData: (datas) {
_onLongPressImageDialog(
datas, context);
},
isHorizontal: ref.watch(
_currentReaderMode) ==
ReaderMode
.horizontalContinuous,
),
);
},
separatorBuilder: (_, __) => ref.watch(
_currentReaderMode) ==
ReaderMode.webtoon
? const SizedBox.shrink()
: ref.watch(_currentReaderMode) ==
ReaderMode
.horizontalContinuous
? VerticalDivider(
color: getBackgroundColor(
backgroundColor),
width: 6)
: Divider(
color: getBackgroundColor(
backgroundColor),
height: 6),
)),
)
: Material(
color: getBackgroundColor(backgroundColor),
shadowColor: getBackgroundColor(backgroundColor),
child: (_pageMode == PageMode.doublePage &&
!isHorizontalContinuaous)
? ExtendedImageGesturePageView.builder(
controller: _extendedController,
scrollDirection: _scrollDirection,
reverse: _isReverseHorizontal,
physics: const ClampingScrollPhysics(),
itemScrollController:
_itemScrollController,
scrollOffsetController:
_pageOffsetController,
itemPositionsListener:
_itemPositionsListener,
canScrollPage: (_) {
return _horizontalScaleValue == 1.0;
},
itemBuilder: (context, index) {
int index1 = index * 2 - 1;
int index2 = index1 + 1;
return GestureDetector(
behavior: HitTestBehavior.translucent,
onDoubleTapDown:
(TapDownDetails details) {
_toggleScale(
details.globalPosition);
final pageList = (index == 0
? [_uChapDataPreload[0], null]
: [
index1 <
_uChapDataPreload.length
? _uChapDataPreload[index1]
: null,
index2 <
_uChapDataPreload.length
? _uChapDataPreload[index2]
: null,
]);
return DoubleColummView(
datas: _isReverseHorizontal
? pageList.reversed.toList()
: pageList,
backgroundColor: backgroundColor,
isFailedToLoadImage: (val) {
if (_failedToLoadImage.value !=
val &&
mounted) {
_failedToLoadImage.value = val;
}
},
onLongPressData: (datas) {
_onLongPressImageDialog(
datas, context);
},
onDoubleTap: () {},
child: (_pageMode ==
PageMode.doublePage &&
!isHorizontalContinuaous)
? DoubleColummVerticalView(
datas: index == 0
? [
_uChapDataPreload[0],
null
]
: [
index1 <
_uChapDataPreload
.length
? _uChapDataPreload[
index1]
: null,
index2 <
_uChapDataPreload
.length
? _uChapDataPreload[
index2]
: null,
],
scale: (a) {},
backgroundColor:
backgroundColor,
isFailedToLoadImage: (val) {},
onLongPressData: (datas) {
_onLongPressImageDialog(
datas, context);
},
)
: ImageViewVertical(
data:
_uChapDataPreload[index],
failedToLoadImage: (value) {
// _failedToLoadImage.value = value;
},
onLongPressData: (datas) {
_onLongPressImageDialog(
datas, context);
},
isHorizontal: ref.watch(
_currentReaderMode) ==
ReaderMode
.horizontalContinuous,
),
);
},
separatorBuilder: (_, __) =>
ref.watch(_currentReaderMode) ==
ReaderMode.webtoon
? const SizedBox.shrink()
: ref.watch(_currentReaderMode) ==
ReaderMode
.horizontalContinuous
? VerticalDivider(
color: getBackgroundColor(
backgroundColor),
width: 6)
: Divider(
color: getBackgroundColor(
backgroundColor),
height: 6),
)),
)
: Material(
color: getBackgroundColor(backgroundColor),
shadowColor: getBackgroundColor(backgroundColor),
child: (_pageMode == PageMode.doublePage &&
!isHorizontalContinuaous)
? ExtendedImageGesturePageView.builder(
controller: _extendedController,
scrollDirection: _scrollDirection,
reverse: _isReverseHorizontal,
physics: const ClampingScrollPhysics(),
canScrollPage: (_) {
return _horizontalScaleValue == 1.0;
},
itemBuilder: (context, index) {
int index1 = index * 2 - 1;
int index2 = index1 + 1;
final pageList = (index == 0
? [_uChapDataPreload[0], null]
: [
index1 < _uChapDataPreload.length
? _uChapDataPreload[index1]
: null,
index2 < _uChapDataPreload.length
? _uChapDataPreload[index2]
: null,
]);
return DoubleColummView(
datas: _isReverseHorizontal
? pageList.reversed.toList()
: pageList,
scale: (a) {},
backgroundColor: backgroundColor,
isFailedToLoadImage: (val) {
if (_failedToLoadImage.value != val &&
mounted) {
_failedToLoadImage.value = val;
}
},
onLongPressData: (datas) {
_onLongPressImageDialog(
datas, context);
},
);
},
itemCount:
(_uChapDataPreload.length / 2).ceil() +
1,
onPageChanged: _onPageChanged)
: ExtendedImageGesturePageView.builder(
controller: _extendedController,
scrollDirection: _scrollDirection,
reverse: _isReverseHorizontal,
physics: const ClampingScrollPhysics(),
canScrollPage: (gestureDetails) {
return gestureDetails != null
? !(gestureDetails.totalScale! > 1.0)
: true;
},
itemBuilder:
(BuildContext context, int index) {
return ImageViewCenter(
data: _uChapDataPreload[index],
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: context.height(0.8),
child:
CircularProgressIndicatorAnimateRotate(
progress: progress),
);
}
if (state.extendedImageLoadState ==
LoadState.completed) {
if (_failedToLoadImage.value ==
true) {
_failedToLoadImage.value = false;
}
return StreamBuilder(
builder: (context, data) {
return ExtendedImageGesture(
state,
canScaleImage: (_) =>
_imageDetailY == 0,
imageBuilder: (image) {
return Stack(
children: [
Positioned.fill(
top: _imageDetailY,
bottom:
-_imageDetailY,
child: image,
),
],
);
},
);
},
initialData: _imageDetailY,
stream: _rebuildDetail.stream,
);
}
if (state.extendedImageLoadState ==
LoadState.failed) {
if (_failedToLoadImage.value ==
false) {
_failedToLoadImage.value = true;
}
return Container(
itemCount: (_uChapDataPreload.length / 2)
.ceil() +
1,
onPageChanged: _onPageChanged)
: ExtendedImageGesturePageView.builder(
controller: _extendedController,
scrollDirection: _scrollDirection,
reverse: _isReverseHorizontal,
physics: const ClampingScrollPhysics(),
canScrollPage: (gestureDetails) {
return gestureDetails != null
? !(gestureDetails.totalScale! >
1.0)
: true;
},
itemBuilder:
(BuildContext context, int index) {
return ImageViewCenter(
data: _uChapDataPreload[index],
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: context.height(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();
_failedToLoadImage
.value = false;
},
onTap: () {
state.reLoadImage();
_failedToLoadImage
.value = false;
},
child: Container(
decoration: BoxDecoration(
color: context
.primaryColor,
borderRadius:
BorderRadius
.circular(
30)),
child: Padding(
padding:
const EdgeInsets
.symmetric(
vertical:
8,
horizontal:
16),
child: Text(
l10n.retry,
child:
CircularProgressIndicatorAnimateRotate(
progress: progress),
);
}
if (state.extendedImageLoadState ==
LoadState.completed) {
if (_failedToLoadImage.value ==
true) {
_failedToLoadImage.value =
false;
}
return StreamBuilder(
builder: (context, data) {
return ExtendedImageGesture(
state,
canScaleImage: (_) =>
_imageDetailY == 0,
imageBuilder: (image) {
return Stack(
children: [
Positioned.fill(
top: _imageDetailY,
bottom:
-_imageDetailY,
child: image,
),
],
);
},
);
},
initialData: _imageDetailY,
stream: _rebuildDetail.stream,
);
}
if (state.extendedImageLoadState ==
LoadState.failed) {
if (_failedToLoadImage.value ==
false) {
_failedToLoadImage.value = true;
}
return Container(
color: getBackgroundColor(
backgroundColor),
height: context.height(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();
_failedToLoadImage
.value =
false;
},
onTap: () {
state
.reLoadImage();
_failedToLoadImage
.value =
false;
},
child: Container(
decoration: BoxDecoration(
color: context
.primaryColor,
borderRadius:
BorderRadius
.circular(
30)),
child: Padding(
padding: const EdgeInsets
.symmetric(
vertical: 8,
horizontal:
16),
child: Text(
l10n.retry,
),
),
),
)),
),
],
));
}
return const SizedBox.shrink();
},
initGestureConfigHandler: (state) {
return GestureConfig(
inertialSpeed: 200,
inPageView: true,
maxScale: 8,
animationMaxScale: 8,
cacheGesture: true,
hitTestBehavior:
HitTestBehavior.translucent,
);
},
onDoubleTap: (state) {
final Offset? pointerDownPosition =
state.pointerDownPosition;
final double? begin =
state.gestureDetails!.totalScale;
double end;
)),
),
],
));
}
return const SizedBox.shrink();
},
initGestureConfigHandler: (state) {
return GestureConfig(
inertialSpeed: 200,
inPageView: true,
maxScale: 8,
animationMaxScale: 8,
cacheGesture: true,
hitTestBehavior:
HitTestBehavior.translucent,
);
},
onDoubleTap: (state) {
final Offset? pointerDownPosition =
state.pointerDownPosition;
final double? begin = state
.gestureDetails!.totalScale;
double end;
//remove old
_doubleClickAnimation?.removeListener(
_doubleClickAnimationListener);
//remove old
_doubleClickAnimation?.removeListener(
_doubleClickAnimationListener);
//stop pre
_doubleClickAnimationController
.stop();
//stop pre
_doubleClickAnimationController
.stop();
//reset to use
_doubleClickAnimationController
.reset();
//reset to use
_doubleClickAnimationController
.reset();
if (begin == doubleTapScales[0]) {
end = doubleTapScales[1];
} else {
end = doubleTapScales[0];
}
if (begin == doubleTapScales[0]) {
end = doubleTapScales[1];
} else {
end = doubleTapScales[0];
}
_doubleClickAnimationListener = () {
state.handleDoubleTap(
scale: _doubleClickAnimation!
.value,
doubleTapPosition:
pointerDownPosition);
};
_doubleClickAnimationListener = () {
state.handleDoubleTap(
scale: _doubleClickAnimation!
.value,
doubleTapPosition:
pointerDownPosition);
};
_doubleClickAnimation = Tween(
begin: begin, end: end)
.animate(CurvedAnimation(
curve: Curves.ease,
parent:
_doubleClickAnimationController));
_doubleClickAnimation = Tween(
begin: begin, end: end)
.animate(CurvedAnimation(
curve: Curves.ease,
parent:
_doubleClickAnimationController));
_doubleClickAnimation!.addListener(
_doubleClickAnimationListener);
_doubleClickAnimation!.addListener(
_doubleClickAnimationListener);
_doubleClickAnimationController
.forward();
},
onLongPressData: (datas) {
_onLongPressImageDialog(
datas, context);
},
);
},
itemCount: _uChapDataPreload.length,
onPageChanged: _onPageChanged)),
_gestureRightLeft(failedToLoadImage, usePageTapZones),
_gestureTopBottom(failedToLoadImage, usePageTapZones),
_appBar(),
_bottomBar(),
_showPage(),
_autoScrollPlayPauseBtn()
],
);
}),
_doubleClickAnimationController
.forward();
},
onLongPressData: (datas) {
_onLongPressImageDialog(
datas, context);
},
);
},
itemCount: _uChapDataPreload.length,
onPageChanged: _onPageChanged)),
_gestureRightLeft(failedToLoadImage, usePageTapZones),
_gestureTopBottom(failedToLoadImage, usePageTapZones),
_appBar(),
_bottomBar(),
_showPage(),
_autoScrollPlayPauseBtn()
],
);
}),
),
),
),
);
@ -1853,12 +1864,12 @@ class _MangaChapterPageGalleryState
}
},
onDoubleTapDown: _isVerticalOrHorizontalContinous()
? (TapDownDetails details) {
? (details) {
_toggleScale(details.globalPosition);
}
: null,
onSecondaryTapDown: _isVerticalOrHorizontalContinous()
? (TapDownDetails details) {
? (details) {
_toggleScale(details.globalPosition);
}
: null,
@ -1882,12 +1893,12 @@ class _MangaChapterPageGalleryState
_isViewFunction();
},
onDoubleTapDown: _isVerticalOrHorizontalContinous()
? (TapDownDetails details) {
? (details) {
_toggleScale(details.globalPosition);
}
: null,
onSecondaryTapDown: _isVerticalOrHorizontalContinous()
? (TapDownDetails details) {
? (details) {
_toggleScale(details.globalPosition);
}
: null,
@ -1915,12 +1926,12 @@ class _MangaChapterPageGalleryState
}
},
onDoubleTapDown: _isVerticalOrHorizontalContinous()
? (TapDownDetails details) {
? (details) {
_toggleScale(details.globalPosition);
}
: null,
onSecondaryTapDown: _isVerticalOrHorizontalContinous()
? (TapDownDetails details) {
? (details) {
_toggleScale(details.globalPosition);
}
: null,
@ -1953,12 +1964,12 @@ class _MangaChapterPageGalleryState
: _isViewFunction();
},
onDoubleTapDown: _isVerticalOrHorizontalContinous()
? (TapDownDetails details) {
? (details) {
_toggleScale(details.globalPosition);
}
: null,
onSecondaryTapDown: _isVerticalOrHorizontalContinous()
? (TapDownDetails details) {
? (details) {
_toggleScale(details.globalPosition);
}
: null,
@ -1984,12 +1995,12 @@ class _MangaChapterPageGalleryState
: _isViewFunction();
},
onDoubleTapDown: _isVerticalOrHorizontalContinous()
? (TapDownDetails details) {
? (details) {
_toggleScale(details.globalPosition);
}
: null,
onSecondaryTapDown: _isVerticalOrHorizontalContinous()
? (TapDownDetails details) {
? (details) {
_toggleScale(details.globalPosition);
}
: null,

View file

@ -2,7 +2,7 @@ syntax = "proto3";
package crop_borders;
// [RINF:DART-SIGNAL]
message CropBordersInput { int32 interaction_id = 1; }
message CropBordersInput { int32 interaction_id = 1; bytes image = 2; }
// [RINF:RUST-SIGNAL]
message CropBordersOutput { int32 interaction_id = 1; }
message CropBordersOutput { int32 interaction_id = 1; bytes image = 2; }

View file

@ -12,7 +12,7 @@ edition = "2021"
crate-type = ["lib", "cdylib", "staticlib"]
[dependencies]
rinf = "6.7.0"
rinf = "6.9.2"
allo-isolate = "0.1.24"
wasm-bindgen = "0.2.90"
prost = "0.12.3"

View file

@ -142,14 +142,15 @@ pub async fn start_croping() {
let mut receiver = CropBordersInput::get_dart_signal_receiver();
while let Some(dart_signal) = receiver.recv().await {
let image = dart_signal.blob.unwrap();
let image = dart_signal.message.image;
let res = crop_image(image);
let mut image_data: Vec<u8> = Vec::new();
res.write_to(&mut Cursor::new(&mut image_data), image::ImageFormat::Png)
.unwrap();
CropBordersOutput {
interaction_id: dart_signal.message.interaction_id,
image: image_data,
}
.send_signal_to_dart(Some(image_data));
.send_signal_to_dart();
}
}

View file

@ -221,10 +221,10 @@ packages:
dependency: transitive
description:
name: cross_file
sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32"
url: "https://pub.dev"
source: hosted
version: "0.3.3+8"
version: "0.3.4+1"
crypto:
dependency: "direct main"
description:
@ -404,10 +404,10 @@ packages:
dependency: "direct main"
description:
name: ffigen
sha256: dead012f29db2be71ea152458f5eab600de98fbc244e01088ae6bf2616bceca7
sha256: "3e12e80ccb6539bb3917217bb6f32709220efb737de0d0fa8736da0b7cb507da"
url: "https://pub.dev"
source: hosted
version: "11.0.0"
version: "12.0.0"
file:
dependency: transitive
description:
@ -420,10 +420,10 @@ packages:
dependency: "direct main"
description:
name: file_picker
sha256: "1bbf65dd997458a08b531042ec3794112a6c39c07c37ff22113d2e7e4f81d4e4"
sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a"
url: "https://pub.dev"
source: hosted
version: "6.2.1"
version: "8.0.3"
fixnum:
dependency: transitive
description:
@ -444,10 +444,10 @@ packages:
dependency: "direct overridden"
description:
name: flex_seed_scheme
sha256: "116dc56093aa4e64d2f03135957b5ef61b1134a4a4990c66f76bc635903d0d8c"
sha256: fb66cdb8ca89084e79efcad2bc2d9deb144666875116f08cdd8d9f8238c8b3ab
url: "https://pub.dev"
source: hosted
version: "2.0.0-dev.1"
version: "2.0.0"
flutter:
dependency: "direct main"
description: flutter
@ -489,10 +489,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_lints
sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "4.0.0"
flutter_localizations:
dependency: "direct main"
description: flutter
@ -594,10 +594,10 @@ packages:
dependency: "direct main"
description:
name: go_router
sha256: c5fa45fa502ee880839e3b2152d987c44abae26d064a2376d4aad434cf0f7b15
sha256: aa073287b8f43553678e6fa9e8bb9c83212ff76e09542129a8099bbc8db4df65
url: "https://pub.dev"
source: hosted
version: "12.1.3"
version: "14.1.2"
google_api_availability:
dependency: "direct main"
description:
@ -674,10 +674,10 @@ packages:
dependency: "direct main"
description:
name: http
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.2.1"
http_client_helper:
dependency: transitive
description:
@ -866,10 +866,10 @@ packages:
dependency: transitive
description:
name: lints
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
version: "4.0.0"
logging:
dependency: transitive
description:
@ -1019,18 +1019,18 @@ packages:
dependency: "direct main"
description:
name: package_info_plus
sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79"
sha256: b93d8b4d624b4ea19b0a5a208b2d6eff06004bc3ce74c06040b120eeadd00ce0
url: "https://pub.dev"
source: hosted
version: "5.0.1"
version: "8.0.0"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
sha256: f49918f3433a3146047372f9d4f1f847511f2acd5cd030e1f44fe5a50036b70e
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "3.0.0"
path:
dependency: transitive
description:
@ -1147,10 +1147,10 @@ packages:
dependency: "direct main"
description:
name: photo_view
sha256: "8036802a00bae2a78fc197af8a158e3e2f7b500561ed23b4c458107685e645bb"
sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e"
url: "https://pub.dev"
source: hosted
version: "0.14.0"
version: "0.15.0"
platform:
dependency: transitive
description:
@ -1235,10 +1235,10 @@ packages:
dependency: "direct main"
description:
name: rinf
sha256: a8a61585a5c8e57bb374d6491821dd4656096a44761d300e435490495af73e77
sha256: "2b4cb68c83634c3e7012c67443dab3f03d232ea326362ab1ca89585192468ffb"
url: "https://pub.dev"
source: hosted
version: "6.7.0"
version: "6.9.2"
riverpod:
dependency: transitive
description:
@ -1355,18 +1355,18 @@ packages:
dependency: "direct main"
description:
name: share_plus
sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900"
sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544
url: "https://pub.dev"
source: hosted
version: "7.2.2"
version: "9.0.0"
share_plus_platform_interface:
dependency: transitive
description:
name: share_plus_platform_interface
sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496"
sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4"
url: "https://pub.dev"
source: hosted
version: "3.4.0"
version: "4.0.0"
shelf:
dependency: transitive
description:
@ -1576,10 +1576,10 @@ packages:
dependency: transitive
description:
name: url_launcher_web
sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a"
url: "https://pub.dev"
source: hosted
version: "2.2.3"
version: "2.3.1"
url_launcher_windows:
dependency: transitive
description:
@ -1624,18 +1624,18 @@ packages:
dependency: transitive
description:
name: wakelock_plus
sha256: f268ca2116db22e57577fb99d52515a24bdc1d570f12ac18bb762361d43b043d
sha256: "14758533319a462ffb5aa3b7ddb198e59b29ac3b02da14173a1715d65d4e6e68"
url: "https://pub.dev"
source: hosted
version: "1.1.4"
version: "1.2.5"
wakelock_plus_platform_interface:
dependency: transitive
description:
name: wakelock_plus_platform_interface
sha256: "40fabed5da06caff0796dc638e1f07ee395fb18801fbff3255a2372db2d80385"
sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.2.1"
watcher:
dependency: transitive
description:
@ -1648,26 +1648,26 @@ packages:
dependency: transitive
description:
name: web
sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05"
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
url: "https://pub.dev"
source: hosted
version: "0.4.2"
version: "0.5.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23"
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42"
url: "https://pub.dev"
source: hosted
version: "2.4.3"
version: "2.4.5"
win32:
dependency: transitive
description:
name: win32
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
url: "https://pub.dev"
source: hosted
version: "5.3.0"
version: "5.5.1"
window_manager:
dependency: "direct main"
description:

View file

@ -11,7 +11,7 @@ dependencies:
sdk: flutter
flutter_localizations:
sdk: flutter
go_router: ^12.1.3
go_router: ^14.1.2
flutter_riverpod: ^2.4.10
riverpod_annotation: ^2.3.3
html: ^0.15.4
@ -19,26 +19,26 @@ dependencies:
expandable_text: ^2.3.0
flex_color_scheme: ^7.3.1
extended_image: ^8.2.0
photo_view: ^0.14.0
photo_view: ^0.15.0
draggable_scrollbar: ^0.1.0
grouped_list: ^5.1.2
intl: ^0.19.0
google_fonts: ^6.1.0
url_launcher: ^6.2.4
package_info_plus: ^5.0.1
package_info_plus: ^8.0.0
permission_handler: ^11.2.0
flutter_inappwebview: ^5.8.0
draggable_menu: ^4.4.1
isar: 3.1.0+1
isar_flutter_libs: 3.1.0+1
share_plus: ^7.2.2
share_plus: ^9.0.0
xpath_selector_html_parser: ^3.0.1
desktop_webview_window:
path: ./packages/desktop_webview_window
archive: ^3.4.10
file_picker: ^6.1.1
file_picker: ^8.0.3
path_provider: ^2.1.2
scrollable_positioned_list: ^0.3.5
scrollable_positioned_list: ^0.3.8
dart_eval: ^0.7.9
json_path: ^0.7.0
bot_toast: ^4.1.3
@ -56,8 +56,8 @@ dependencies:
protobuf: ^3.1.0
cupertino_icons: ^1.0.6
window_manager: ^0.3.8
ffi: ^2.1.0
ffigen: ^11.0.0
ffi: ^2.1.1
ffigen: ^12.0.0
http_interceptor: ^2.0.0-beta.8
js_packer: ^0.0.5
flutter_windows_webview:
@ -70,19 +70,19 @@ dependencies:
ref: main
cronet_http: ^1.2.0
cupertino_http: ^1.3.0
http: ^1.2.0
http: ^1.2.1
google_api_availability: ^5.0.0
flutter_code_editor: ^0.3.1
flutter_highlight: ^0.7.0
highlight: ^0.7.0
json_view: ^0.4.2
rinf: ^6.7.0
rinf: ^6.9.2
dependency_overrides:
analyzer: ">=5.2.0 <7.0.0"
http: ^1.2.0
ffi: ^2.1.0
flex_seed_scheme: ^2.0.0-dev.1
http: ^1.2.1
ffi: ^2.1.2
flex_seed_scheme: ^2.0.0
dev_dependencies:
flutter_test:
@ -91,7 +91,7 @@ dev_dependencies:
riverpod_generator: ^2.3.2
flutter_launcher_icons: ^0.13.1
isar_generator: ^3.1.0+1
flutter_lints: ^3.0.1
flutter_lints: ^4.0.0
flutter:
uses-material-design: true