diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index cb1ef88..97a4e20 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -14,5 +14,7 @@
This Theme is only used starting with V2 of Flutter's Android embedding. -->
diff --git a/lib/components/appbar.dart b/lib/components/appbar.dart
index adfc96d..13487ba 100644
--- a/lib/components/appbar.dart
+++ b/lib/components/appbar.dart
@@ -296,7 +296,7 @@ class _FilledTabBarState extends State {
padding: tabPadding,
radius: tabRadius,
);
- if (old != null) {
+ if (old != null && old.offsets != null && old.itemHeight != null) {
painter!.update(old.offsets!, old.itemHeight!);
}
}
diff --git a/lib/components/message.dart b/lib/components/message.dart
index 7b5a562..d886f72 100644
--- a/lib/components/message.dart
+++ b/lib/components/message.dart
@@ -262,6 +262,8 @@ class ContentDialog extends StatelessWidget {
insetPadding: context.width < 400
? const EdgeInsets.symmetric(horizontal: 4)
: const EdgeInsets.symmetric(horizontal: 16),
+ elevation: 2,
+ shadowColor: context.colorScheme.shadow,
child: IntrinsicWidth(
child: ConstrainedBox(
constraints: BoxConstraints(
diff --git a/lib/components/navigation_bar.dart b/lib/components/navigation_bar.dart
index 2b9d84e..9eec4ab 100644
--- a/lib/components/navigation_bar.dart
+++ b/lib/components/navigation_bar.dart
@@ -127,15 +127,15 @@ class _NaviPaneState extends State
}
if (target == 1) {
StateController.find()
- .setWithPadding(true, true);
+ .setWithPadding(true, true, true);
controller.value = target;
} else if (controller.value == 1 && target == 0) {
StateController.findOrNull()
- ?.setWithPadding(false, false);
+ ?.setWithPadding(false, false, false);
controller.value = target;
} else {
StateController.findOrNull()
- ?.setWithPadding(true, false);
+ ?.setWithPadding(true, false, false);
controller.animateTo(target);
}
animationTarget = target;
@@ -660,9 +660,13 @@ class NaviPaddingWidgetController extends StateController {
bool _withTopBarPadding = false;
- void setWithPadding(bool withPadding, bool withAppbarPadding) {
+ bool _withBottomBarPadding = false;
+
+ void setWithPadding(
+ bool withPadding, bool withAppbarPadding, bool withBottomBarPadding) {
_withPadding = withPadding;
_withTopBarPadding = withAppbarPadding;
+ _withBottomBarPadding = withBottomBarPadding;
update();
}
}
@@ -683,8 +687,10 @@ class NaviPaddingWidget extends StatelessWidget {
(controller._withTopBarPadding
? _NaviPaneState._kTopBarHeight
: 0),
- bottom:
- _NaviPaneState._kBottomBarHeight + context.padding.bottom,
+ bottom: context.padding.bottom +
+ (controller._withBottomBarPadding
+ ? _NaviPaneState._kBottomBarHeight
+ : 0),
)
: EdgeInsets.zero,
child: child,
diff --git a/lib/components/scroll.dart b/lib/components/scroll.dart
index f5aa95d..0e39345 100644
--- a/lib/components/scroll.dart
+++ b/lib/components/scroll.dart
@@ -55,7 +55,7 @@ class _SmoothScrollProviderState extends State {
return widget.builder(
context,
_controller,
- const ClampingScrollPhysics(),
+ const BouncingScrollPhysics(),
);
}
return Listener(
@@ -93,7 +93,7 @@ class _SmoothScrollProviderState extends State {
_controller,
_isMouseScroll
? const NeverScrollableScrollPhysics()
- : const ClampingScrollPhysics(),
+ : const BouncingScrollPhysics(),
),
);
}
diff --git a/lib/foundation/appdata.dart b/lib/foundation/appdata.dart
index 0ae83a1..6be3432 100644
--- a/lib/foundation/appdata.dart
+++ b/lib/foundation/appdata.dart
@@ -51,9 +51,9 @@ class _Appdata {
return;
}
var json = jsonDecode(await file.readAsString());
- for(var key in json['settings'].keys) {
- if(json[key] != null) {
- settings[key] = json[key];
+ for(var key in (json['settings'] as Map).keys) {
+ if(json['settings'][key] != null) {
+ settings[key] = json['settings'][key];
}
}
searchHistory = List.from(json['searchHistory']);
diff --git a/lib/main.dart b/lib/main.dart
index d9e6e33..ae34ad4 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -56,6 +56,7 @@ class _MyAppState extends State {
@override
void initState() {
App.registerForceRebuild(forceRebuild);
+ SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
super.initState();
}
diff --git a/lib/pages/comic_page.dart b/lib/pages/comic_page.dart
index 2af3c64..f82b11b 100644
--- a/lib/pages/comic_page.dart
+++ b/lib/pages/comic_page.dart
@@ -74,6 +74,7 @@ class _ComicPageState extends LoadingState
buildChapters(),
buildThumbnails(),
buildRecommend(),
+ SliverPadding(padding: EdgeInsets.only(bottom: context.padding.bottom)),
],
);
}
@@ -109,6 +110,8 @@ class _ComicPageState extends LoadingState
],
);
+ yield const SliverPadding(padding: EdgeInsets.only(top: 8));
+
yield Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
diff --git a/lib/pages/comic_source_page.dart b/lib/pages/comic_source_page.dart
index cc1da40..a4f965d 100644
--- a/lib/pages/comic_source_page.dart
+++ b/lib/pages/comic_source_page.dart
@@ -243,7 +243,7 @@ class _BodyState extends State<_Body> {
.paddingBottom(32),
Row(
children: [
- TextButton(onPressed: chooseFile, child: Text("Choose file".tl))
+ TextButton(onPressed: selectFile, child: Text("Select file".tl))
.paddingLeft(8),
const Spacer(),
TextButton(
@@ -265,7 +265,7 @@ class _BodyState extends State<_Body> {
);
}
- void chooseFile() async {
+ void selectFile() async {
final result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['js'],
diff --git a/lib/pages/reader/comic_image.dart b/lib/pages/reader/comic_image.dart
index 841058c..e5c1068 100644
--- a/lib/pages/reader/comic_image.dart
+++ b/lib/pages/reader/comic_image.dart
@@ -260,7 +260,8 @@ class _ComicImageState extends State with WidgetsBindingObserver {
if (_lastException != null) {
// display error and retry button on screen
return SizedBox(
- height: 300,
+ height: widget.height == null ? 300 : null,
+ width: widget.width == null ? 300 : null,
child: Center(
child: SizedBox(
height: 300,
@@ -295,87 +296,92 @@ class _ComicImageState extends State with WidgetsBindingObserver {
);
}
- var width = widget.width??MediaQuery.of(context).size.width;
- double? height;
+ return LayoutBuilder(builder: (context, constrains) {
+ var width = widget.width;
+ var height = widget.height;
- Size? cacheSize = _cache[widget.image.hashCode];
- if(cacheSize != null){
- height = cacheSize.height * (width / cacheSize.width);
- height = height.ceilToDouble();
- }
-
- var brightness = Theme.of(context).brightness;
-
- if(_imageInfo != null){
- // Record the height and the width of the image
- _cache[widget.image.hashCode] = Size(
- _imageInfo!.image.width.toDouble(),
- _imageInfo!.image.height.toDouble()
- );
- // build image
- Widget result = RawImage(
- // Do not clone the image, because RawImage is a stateless wrapper.
- // The image will be disposed by this state object when it is not needed
- // anymore, such as when it is unmounted or when the image stream pushes
- // a new image.
- image: _imageInfo?.image,
- debugImageLabel: _imageInfo?.debugLabel,
- width: width,
- height: height,
- scale: _imageInfo?.scale ?? 1.0,
- color: widget.color,
- opacity: widget.opacity,
- colorBlendMode: widget.colorBlendMode,
- fit: widget.fit,
- alignment: widget.alignment,
- repeat: widget.repeat,
- centerSlice: widget.centerSlice,
- matchTextDirection: widget.matchTextDirection,
- invertColors: _invertColors,
- isAntiAlias: widget.isAntiAlias,
- filterQuality: widget.filterQuality,
- );
-
- if (!widget.excludeFromSemantics) {
- result = Semantics(
- container: widget.semanticLabel != null,
- image: true,
- label: widget.semanticLabel ?? '',
- child: result,
+ if(_imageInfo != null) {
+ // Record the height and the width of the image
+ _cache[widget.image.hashCode] = Size(
+ _imageInfo!.image.width.toDouble(),
+ _imageInfo!.image.height.toDouble()
);
}
- result = SizedBox(
- width: width,
- height: height,
- child: Center(
- child: result,
- ),
- );
- return result;
- } else {
- // build progress
- return SizedBox(
- width: width,
- height: height??300,
- child: Center(
- child: SizedBox(
- width: 24,
- height: 24,
- child: CircularProgressIndicator(
- backgroundColor: brightness == Brightness.dark
- ? Colors.white24
- : Colors.black12,
- strokeWidth: 3,
- value: (_loadingProgress != null &&
- _loadingProgress!.expectedTotalBytes!=null &&
- _loadingProgress!.expectedTotalBytes! != 0)
- ?_loadingProgress!.cumulativeBytesLoaded / _loadingProgress!.expectedTotalBytes!
- :0,
+
+ Size? cacheSize = _cache[widget.image.hashCode];
+ if(cacheSize != null){
+ if(width == double.infinity) {
+ width = constrains.maxWidth;
+ height = width * cacheSize.height / cacheSize.width;
+ } else if(height == double.infinity) {
+ height = constrains.maxHeight;
+ width = height * cacheSize.width / cacheSize.height;
+ }
+ }
+
+ if(_imageInfo != null){
+ // build image
+ Widget result = RawImage(
+ // Do not clone the image, because RawImage is a stateless wrapper.
+ // The image will be disposed by this state object when it is not needed
+ // anymore, such as when it is unmounted or when the image stream pushes
+ // a new image.
+ image: _imageInfo?.image,
+ debugImageLabel: _imageInfo?.debugLabel,
+ width: width,
+ height: height,
+ scale: _imageInfo?.scale ?? 1.0,
+ color: widget.color,
+ opacity: widget.opacity,
+ colorBlendMode: widget.colorBlendMode,
+ fit: widget.fit,
+ alignment: widget.alignment,
+ repeat: widget.repeat,
+ centerSlice: widget.centerSlice,
+ matchTextDirection: widget.matchTextDirection,
+ invertColors: _invertColors,
+ isAntiAlias: widget.isAntiAlias,
+ filterQuality: widget.filterQuality,
+ );
+
+ if (!widget.excludeFromSemantics) {
+ result = Semantics(
+ container: widget.semanticLabel != null,
+ image: true,
+ label: widget.semanticLabel ?? '',
+ child: result,
+ );
+ }
+ result = SizedBox(
+ width: width,
+ height: height,
+ child: Center(
+ child: result,
+ ),
+ );
+ return result;
+ } else {
+ // build progress
+ return SizedBox(
+ width: width,
+ height: height,
+ child: Center(
+ child: SizedBox(
+ width: 24,
+ height: 24,
+ child: CircularProgressIndicator(
+ strokeWidth: 3,
+ value: (_loadingProgress != null &&
+ _loadingProgress!.expectedTotalBytes!=null &&
+ _loadingProgress!.expectedTotalBytes! != 0)
+ ?_loadingProgress!.cumulativeBytesLoaded / _loadingProgress!.expectedTotalBytes!
+ :0,
+ ),
),
),
- ),
- );
- }
+ );
+ }
+ });
}
@override
diff --git a/lib/pages/reader/images.dart b/lib/pages/reader/images.dart
index 17ee9b9..d25c966 100644
--- a/lib/pages/reader/images.dart
+++ b/lib/pages/reader/images.dart
@@ -258,7 +258,7 @@ class _GalleryModeState extends State<_GalleryMode>
event.logicalKey == LogicalKeyboardKey.arrowRight) {
forward = false;
}
- if(event is KeyDownEvent || event is KeyRepeatEvent) {
+ if (event is KeyDownEvent || event is KeyRepeatEvent) {
if (forward == true) {
controller.nextPage(
duration: const Duration(milliseconds: 200),
@@ -371,13 +371,12 @@ class _ContinuousModeState extends State<_ContinuousMode>
if (index == 0 || index == reader.maxPage + 1) {
return const SizedBox();
}
- double width = MediaQuery.of(context).size.width;
- double height = MediaQuery.of(context).size.height;
-
- double imageWidth = width;
-
- if (height / width < 1.2) {
- imageWidth = height / 1.2;
+ double? width, height;
+ if (reader.mode == ReaderMode.continuousLeftToRight ||
+ reader.mode == ReaderMode.continuousRightToLeft) {
+ height = double.infinity;
+ } else {
+ width = double.infinity;
}
_precacheImage(index, context);
@@ -387,9 +386,9 @@ class _ContinuousModeState extends State<_ContinuousMode>
return ComicImage(
filterQuality: FilterQuality.medium,
image: image,
- width: imageWidth,
- height: imageWidth * 1.2,
- fit: BoxFit.cover,
+ width: width,
+ height: height,
+ fit: BoxFit.contain,
);
},
scrollBehavior: const MaterialScrollBehavior()
@@ -420,10 +419,10 @@ class _ContinuousModeState extends State<_ContinuousMode>
return;
}
if (scrollController.offset !=
- scrollController.position.maxScrollExtent &&
+ scrollController.position.maxScrollExtent &&
scrollController.offset !=
scrollController.position.minScrollExtent) {
- if(reader.mode == ReaderMode.continuousTopToBottom) {
+ if (reader.mode == ReaderMode.continuousTopToBottom) {
value = Offset(value.dx, 0);
} else {
value = Offset(0, value.dy);
diff --git a/lib/pages/reader/reader.dart b/lib/pages/reader/reader.dart
index 55bf4d0..7ee05a9 100644
--- a/lib/pages/reader/reader.dart
+++ b/lib/pages/reader/reader.dart
@@ -102,7 +102,9 @@ class _ReaderState extends State with _ReaderLocation, _ReaderWindow {
chapter = widget.initialChapter ?? 1;
mode = ReaderMode.fromKey(appdata.settings['readerMode']);
history = widget.history;
- updateHistory();
+ Future.microtask(() {
+ updateHistory();
+ });
super.initState();
}