完成目录和分享

main
落雨楓 2 years ago
parent 7ac20f877a
commit 1aab54a6d8

@ -39,7 +39,7 @@ class _IsekaiWikiAppWrapperState extends State<IsekaiWikiAppWrapper> {
statusBarBrightness: Brightness.dark,
statusBarIconBrightness: Brightness.light,
systemStatusBarContrastEnforced: false,
systemNavigationBarColor: Colors.transparent.withAlpha(1),
systemNavigationBarColor: Colors.black.withAlpha(1),
systemNavigationBarContrastEnforced: false,
systemNavigationBarIconBrightness: Brightness.dark,
),

@ -52,8 +52,7 @@ class _HeroTag {
// Let the Hero tag be described in tree dumps.
@override
String toString() =>
'Default Hero tag for Cupertino navigation bars with navigator $navigator';
String toString() => 'Default Hero tag for Cupertino navigation bars with navigator $navigator';
@override
bool operator ==(Object other) {
@ -130,9 +129,8 @@ Widget _wrapWithBackground({
Widget result = child;
if (updateSystemUiOverlay) {
final bool isDark = backgroundColor.computeLuminance() < 0.179;
final Brightness newBrightness =
brightness ?? (isDark ? Brightness.dark : Brightness.light);
final SystemUiOverlayStyle overlayStyle;
final Brightness newBrightness = brightness ?? (isDark ? Brightness.dark : Brightness.light);
SystemUiOverlayStyle overlayStyle;
switch (newBrightness) {
case Brightness.dark:
overlayStyle = SystemUiOverlayStyle.light;
@ -141,6 +139,12 @@ Widget _wrapWithBackground({
overlayStyle = SystemUiOverlayStyle.dark;
break;
}
overlayStyle = overlayStyle.copyWith(
systemStatusBarContrastEnforced: false,
systemNavigationBarColor: CupertinoColors.black.withAlpha(1),
systemNavigationBarContrastEnforced: false,
systemNavigationBarIconBrightness: Brightness.dark,
);
result = AnnotatedRegion<SystemUiOverlayStyle>(
value: overlayStyle,
child: result,
@ -233,8 +237,7 @@ bool _isTransitionable(BuildContext context) {
/// * [IsekaiSliverNavigationBar] for a navigation bar to be placed in a
/// scrolling list and that supports iOS-11-style large titles.
/// * <https://developer.apple.com/design/human-interface-guidelines/ios/bars/navigation-bars/>
class IsekaiNavigationBar extends StatefulWidget
implements ObstructingPreferredSizeWidget {
class IsekaiNavigationBar extends StatefulWidget implements ObstructingPreferredSizeWidget {
/// Creates a navigation bar in the iOS style.
const IsekaiNavigationBar({
super.key,
@ -447,8 +450,7 @@ class _IsekaiNavigationBarState extends State<IsekaiNavigationBar> {
CupertinoDynamicColor.maybeResolve(widget.backgroundColor, context) ??
CupertinoTheme.of(context).barBackgroundColor;
final _NavigationBarStaticComponents components =
_NavigationBarStaticComponents(
final _NavigationBarStaticComponents components = _NavigationBarStaticComponents(
keys: keys,
route: ModalRoute.of(context),
userLeading: widget.leading,
@ -484,9 +486,7 @@ class _IsekaiNavigationBarState extends State<IsekaiNavigationBar> {
// Get the context that might have a possibly changed CupertinoTheme.
builder: (BuildContext context) {
return Hero(
tag: widget.heroTag == _defaultHeroTag
? _HeroTag(Navigator.of(context))
: widget.heroTag,
tag: widget.heroTag == _defaultHeroTag ? _HeroTag(Navigator.of(context)) : widget.heroTag,
createRectTween: _linearTranslateWithLargestRectSizeTween,
placeholderBuilder: _navBarHeroLaunchPadBuilder,
flightShuttleBuilder: _navBarHeroFlightShuttleBuilder,
@ -494,10 +494,8 @@ class _IsekaiNavigationBarState extends State<IsekaiNavigationBar> {
child: _TransitionableNavigationBar(
componentsKeys: keys,
backgroundColor: backgroundColor,
backButtonTextStyle:
CupertinoTheme.of(context).textTheme.navActionTextStyle,
titleTextStyle:
CupertinoTheme.of(context).textTheme.navTitleTextStyle,
backButtonTextStyle: CupertinoTheme.of(context).textTheme.navActionTextStyle,
titleTextStyle: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
largeTitleTextStyle: null,
border: widget.border,
hasUserMiddle: widget.middle != null,
@ -696,8 +694,7 @@ class IsekaiSliverNavigationBar extends StatefulWidget {
final bool stretch;
@override
State<IsekaiSliverNavigationBar> createState() =>
_IsekaiSliverNavigationBarState();
State<IsekaiSliverNavigationBar> createState() => _IsekaiSliverNavigationBarState();
}
// A state class exists for the nav bar so that the keys of its sub-components
@ -714,8 +711,7 @@ class _IsekaiSliverNavigationBarState extends State<IsekaiSliverNavigationBar> {
@override
Widget build(BuildContext context) {
final _NavigationBarStaticComponents components =
_NavigationBarStaticComponents(
final _NavigationBarStaticComponents components = _NavigationBarStaticComponents(
keys: keys,
route: ModalRoute.of(context),
userLeading: widget.leading,
@ -736,8 +732,7 @@ class _IsekaiSliverNavigationBarState extends State<IsekaiSliverNavigationBar> {
keys: keys,
components: components,
userMiddle: widget.middle,
backgroundColor: CupertinoDynamicColor.maybeResolve(
widget.backgroundColor, context) ??
backgroundColor: CupertinoDynamicColor.maybeResolve(widget.backgroundColor, context) ??
CupertinoTheme.of(context).barBackgroundColor,
brightness: widget.brightness,
border: widget.border,
@ -745,18 +740,17 @@ class _IsekaiSliverNavigationBarState extends State<IsekaiSliverNavigationBar> {
actionsForegroundColor: CupertinoTheme.of(context).primaryColor,
transitionBetweenRoutes: widget.transitionBetweenRoutes,
heroTag: widget.heroTag,
persistentHeight: (_kNavBarPersistentHeight * scaleFactor) +
MediaQuery.of(context).padding.top,
persistentHeight:
(_kNavBarPersistentHeight * scaleFactor) + MediaQuery.of(context).padding.top,
alwaysShowMiddle: widget.middle != null,
stretchConfiguration:
widget.stretch ? OverScrollHeaderStretchConfiguration() : null,
stretchConfiguration: widget.stretch ? OverScrollHeaderStretchConfiguration() : null,
),
);
}
}
class _LargeTitleNavigationBarSliverDelegate
extends SliverPersistentHeaderDelegate with DiagnosticableTreeMixin {
class _LargeTitleNavigationBarSliverDelegate extends SliverPersistentHeaderDelegate
with DiagnosticableTreeMixin {
_LargeTitleNavigationBarSliverDelegate({
required this.keys,
required this.components,
@ -794,20 +788,17 @@ class _LargeTitleNavigationBarSliverDelegate
@override
double get maxExtent =>
persistentHeight +
(_kNavBarLargeTitleHeightExtension *
MediaQuery.of(Get.context!).textScaleFactor);
(_kNavBarLargeTitleHeightExtension * MediaQuery.of(Get.context!).textScaleFactor);
@override
OverScrollHeaderStretchConfiguration? stretchConfiguration;
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
final bool showLargeTitle =
shrinkOffset < maxExtent - minExtent - _kNavBarShowLargeTitleThreshold;
final _PersistentNavigationBar persistentNavigationBar =
_PersistentNavigationBar(
final _PersistentNavigationBar persistentNavigationBar = _PersistentNavigationBar(
components: components,
padding: padding,
// If a user specified middle exists, always show it. Otherwise, show
@ -851,9 +842,7 @@ class _LargeTitleNavigationBarSliverDelegate
child: Semantics(
header: true,
child: DefaultTextStyle(
style: CupertinoTheme.of(context)
.textTheme
.navLargeTitleTextStyle,
style: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle,
maxLines: 1,
overflow: TextOverflow.ellipsis,
child: components.largeTitle!,
@ -881,9 +870,7 @@ class _LargeTitleNavigationBarSliverDelegate
}
return Hero(
tag: heroTag == _defaultHeroTag
? _HeroTag(Navigator.of(context))
: heroTag,
tag: heroTag == _defaultHeroTag ? _HeroTag(Navigator.of(context)) : heroTag,
createRectTween: _linearTranslateWithLargestRectSizeTween,
flightShuttleBuilder: _navBarHeroFlightShuttleBuilder,
placeholderBuilder: _navBarHeroLaunchPadBuilder,
@ -893,13 +880,10 @@ class _LargeTitleNavigationBarSliverDelegate
// needs to wrap the top level RenderBox rather than a RenderSliver.
child: _TransitionableNavigationBar(
componentsKeys: keys,
backgroundColor:
CupertinoDynamicColor.resolve(backgroundColor, context),
backButtonTextStyle:
CupertinoTheme.of(context).textTheme.navActionTextStyle,
backgroundColor: CupertinoDynamicColor.resolve(backgroundColor, context),
backButtonTextStyle: CupertinoTheme.of(context).textTheme.navActionTextStyle,
titleTextStyle: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
largeTitleTextStyle:
CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle,
largeTitleTextStyle: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle,
border: border,
hasUserMiddle: userMiddle != null,
largeExpanded: showLargeTitle,
@ -994,8 +978,7 @@ class _PersistentNavigationBar extends StatelessWidget {
double scaleFactor = MediaQuery.of(context).textScaleFactor;
return SizedBox(
height: (_kNavBarPersistentHeight * scaleFactor) +
MediaQuery.of(context).padding.top,
height: (_kNavBarPersistentHeight * scaleFactor) + MediaQuery.of(context).padding.top,
child: SafeArea(
bottom: false,
child: paddedToolbar,
@ -1354,11 +1337,10 @@ class IsekaiNavigationBarBackButton extends StatelessWidget {
);
}
TextStyle actionTextStyle =
CupertinoTheme.of(context).textTheme.navActionTextStyle;
TextStyle actionTextStyle = CupertinoTheme.of(context).textTheme.navActionTextStyle;
if (color != null) {
actionTextStyle = actionTextStyle.copyWith(
color: CupertinoDynamicColor.maybeResolve(color, context));
actionTextStyle =
actionTextStyle.copyWith(color: CupertinoDynamicColor.maybeResolve(color, context));
}
return CupertinoButton(
@ -1371,8 +1353,7 @@ class IsekaiNavigationBarBackButton extends StatelessWidget {
child: DefaultTextStyle(
style: actionTextStyle,
child: ConstrainedBox(
constraints:
const BoxConstraints(minWidth: _kNavBarBackButtonTapWidth),
constraints: const BoxConstraints(minWidth: _kNavBarBackButtonTapWidth),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
@ -1457,8 +1438,7 @@ class _BackLabel extends StatelessWidget {
// `child` is never passed in into ValueListenableBuilder so it's always
// null here and unused.
Widget _buildPreviousTitleWidget(
BuildContext context, String? previousTitle, Widget? child) {
Widget _buildPreviousTitleWidget(BuildContext context, String? previousTitle, Widget? child) {
previousTitle ??= "返回";
Text textWidget = Text(
@ -1482,8 +1462,7 @@ class _BackLabel extends StatelessWidget {
Widget build(BuildContext context) {
if (specifiedPreviousTitle != null) {
return _buildPreviousTitleWidget(context, specifiedPreviousTitle, null);
} else if (route is CupertinoRouteTransitionMixin<dynamic> &&
!route!.isFirst) {
} else if (route is CupertinoRouteTransitionMixin<dynamic> && !route!.isFirst) {
final CupertinoRouteTransitionMixin<dynamic> cupertinoRoute =
route! as CupertinoRouteTransitionMixin<dynamic>;
// There is no timing issue because the previousTitle Listenable changes
@ -1534,8 +1513,8 @@ class _TransitionableNavigationBar extends StatelessWidget {
final Widget child;
RenderBox get renderBox {
final RenderBox box = componentsKeys.navBarBoxKey.currentContext!
.findRenderObject()! as RenderBox;
final RenderBox box =
componentsKeys.navBarBoxKey.currentContext!.findRenderObject()! as RenderBox;
assert(
box.attached,
'_TransitionableNavigationBar.renderBox should be called when building '
@ -1645,31 +1624,19 @@ class _NavigationBarTransition extends StatelessWidget {
},
),
// Draw all the components on top of the empty bar box.
if (componentsTransition.bottomBackChevron != null)
componentsTransition.bottomBackChevron!,
if (componentsTransition.bottomBackLabel != null)
componentsTransition.bottomBackLabel!,
if (componentsTransition.bottomLeading != null)
componentsTransition.bottomLeading!,
if (componentsTransition.bottomMiddle != null)
componentsTransition.bottomMiddle!,
if (componentsTransition.bottomLargeTitle != null)
componentsTransition.bottomLargeTitle!,
if (componentsTransition.bottomTrailing != null)
componentsTransition.bottomTrailing!,
if (componentsTransition.bottomBackChevron != null) componentsTransition.bottomBackChevron!,
if (componentsTransition.bottomBackLabel != null) componentsTransition.bottomBackLabel!,
if (componentsTransition.bottomLeading != null) componentsTransition.bottomLeading!,
if (componentsTransition.bottomMiddle != null) componentsTransition.bottomMiddle!,
if (componentsTransition.bottomLargeTitle != null) componentsTransition.bottomLargeTitle!,
if (componentsTransition.bottomTrailing != null) componentsTransition.bottomTrailing!,
// Draw top components on top of the bottom components.
if (componentsTransition.topLeading != null)
componentsTransition.topLeading!,
if (componentsTransition.topBackChevron != null)
componentsTransition.topBackChevron!,
if (componentsTransition.topBackLabel != null)
componentsTransition.topBackLabel!,
if (componentsTransition.topMiddle != null)
componentsTransition.topMiddle!,
if (componentsTransition.topLargeTitle != null)
componentsTransition.topLargeTitle!,
if (componentsTransition.topTrailing != null)
componentsTransition.topTrailing!,
if (componentsTransition.topLeading != null) componentsTransition.topLeading!,
if (componentsTransition.topBackChevron != null) componentsTransition.topBackChevron!,
if (componentsTransition.topBackLabel != null) componentsTransition.topBackLabel!,
if (componentsTransition.topMiddle != null) componentsTransition.topMiddle!,
if (componentsTransition.topLargeTitle != null) componentsTransition.topLargeTitle!,
if (componentsTransition.topTrailing != null) componentsTransition.topTrailing!,
];
// The actual outer box is big enough to contain both the bottom and top
@ -1677,8 +1644,7 @@ class _NavigationBarTransition extends StatelessWidget {
// can actually be outside the linearly lerp'ed Rect in the middle of
// the animation, such as the topLargeTitle.
return SizedBox(
height: math.max(heightTween.begin!, heightTween.end!) +
MediaQuery.of(context).padding.top,
height: math.max(heightTween.begin!, heightTween.end!) + MediaQuery.of(context).padding.top,
width: double.infinity,
child: Stack(
children: children,
@ -1731,8 +1697,7 @@ class _NavigationBarComponentsTransition {
topLargeExpanded = topNavBar.largeExpanded,
transitionBox =
// paintBounds are based on offset zero so it's ok to expand the Rects.
bottomNavBar.renderBox.paintBounds
.expandToInclude(topNavBar.renderBox.paintBounds),
bottomNavBar.renderBox.paintBounds.expandToInclude(topNavBar.renderBox.paintBounds),
forwardDirection = directionality == TextDirection.ltr ? 1.0 : -1.0;
static final Animatable<double> fadeOut = Tween<double>(
@ -1779,13 +1744,11 @@ class _NavigationBarComponentsTransition {
GlobalKey key, {
required RenderBox from,
}) {
final RenderBox componentBox =
key.currentContext!.findRenderObject()! as RenderBox;
final RenderBox componentBox = key.currentContext!.findRenderObject()! as RenderBox;
assert(componentBox.attached);
return RelativeRect.fromRect(
componentBox.localToGlobal(Offset.zero, ancestor: from) &
componentBox.size,
componentBox.localToGlobal(Offset.zero, ancestor: from) & componentBox.size,
transitionBox,
);
}
@ -1810,10 +1773,8 @@ class _NavigationBarComponentsTransition {
required RenderBox toNavBarBox,
required Widget child,
}) {
final RenderBox fromBox =
fromKey.currentContext!.findRenderObject()! as RenderBox;
final RenderBox toBox =
toKey.currentContext!.findRenderObject()! as RenderBox;
final RenderBox fromBox = fromKey.currentContext!.findRenderObject()! as RenderBox;
final RenderBox toBox = toKey.currentContext!.findRenderObject()! as RenderBox;
final bool isLTR = forwardDirection > 0;
@ -1829,8 +1790,7 @@ class _NavigationBarComponentsTransition {
);
final Offset fromAnchorInFromBox =
fromBox.localToGlobal(fromAnchorLocal, ancestor: fromNavBarBox);
final Offset toAnchorInToBox =
toBox.localToGlobal(toAnchorLocal, ancestor: toNavBarBox);
final Offset toAnchorInToBox = toBox.localToGlobal(toAnchorLocal, ancestor: toNavBarBox);
// We can't get ahold of the render box of the stack (i.e., `transitionBox`)
// we place components on yet, but we know the stack needs to be top-leading
@ -1842,13 +1802,10 @@ class _NavigationBarComponentsTransition {
// coordinates.
final Offset translation = isLTR
? toAnchorInToBox - fromAnchorInFromBox
: Offset(toNavBarBox.size.width - toAnchorInToBox.dx,
toAnchorInToBox.dy) -
Offset(fromNavBarBox.size.width - fromAnchorInFromBox.dx,
fromAnchorInFromBox.dy);
: Offset(toNavBarBox.size.width - toAnchorInToBox.dx, toAnchorInToBox.dy) -
Offset(fromNavBarBox.size.width - fromAnchorInFromBox.dx, fromAnchorInFromBox.dy);
final RelativeRect fromBoxMargin =
positionInTransitionBox(fromKey, from: fromNavBarBox);
final RelativeRect fromBoxMargin = positionInTransitionBox(fromKey, from: fromNavBarBox);
final Offset fromOriginInTransitionBox = Offset(
isLTR ? fromBoxMargin.left : fromBoxMargin.right,
fromBoxMargin.top,
@ -1880,16 +1837,14 @@ class _NavigationBarComponentsTransition {
}
Widget? get bottomLeading {
final KeyedSubtree? bottomLeading =
bottomComponents.leadingKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? bottomLeading = bottomComponents.leadingKey.currentWidget as KeyedSubtree?;
if (bottomLeading == null) {
return null;
}
return Positioned.fromRelativeRect(
rect: positionInTransitionBox(bottomComponents.leadingKey,
from: bottomNavBarBox),
rect: positionInTransitionBox(bottomComponents.leadingKey, from: bottomNavBarBox),
child: FadeTransition(
opacity: fadeOutBy(0.4),
child: bottomLeading.child,
@ -1906,8 +1861,7 @@ class _NavigationBarComponentsTransition {
}
return Positioned.fromRelativeRect(
rect: positionInTransitionBox(bottomComponents.backChevronKey,
from: bottomNavBarBox),
rect: positionInTransitionBox(bottomComponents.backChevronKey, from: bottomNavBarBox),
child: FadeTransition(
opacity: fadeOutBy(0.6),
child: DefaultTextStyle(
@ -1926,9 +1880,8 @@ class _NavigationBarComponentsTransition {
return null;
}
final RelativeRect from = positionInTransitionBox(
bottomComponents.backLabelKey,
from: bottomNavBarBox);
final RelativeRect from =
positionInTransitionBox(bottomComponents.backLabelKey, from: bottomNavBarBox);
// Transition away by sliding horizontally to the leading edge off of the screen.
final RelativeRectTween positionTween = RelativeRectTween(
@ -1954,12 +1907,9 @@ class _NavigationBarComponentsTransition {
}
Widget? get bottomMiddle {
final KeyedSubtree? bottomMiddle =
bottomComponents.middleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topBackLabel =
topComponents.backLabelKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topLeading =
topComponents.leadingKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? bottomMiddle = bottomComponents.middleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topBackLabel = topComponents.backLabelKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topLeading = topComponents.leadingKey.currentWidget as KeyedSubtree?;
// The middle component is non-null when the nav bar is a large title
// nav bar but would be invisible when expanded, therefore don't show it here.
@ -1998,8 +1948,7 @@ class _NavigationBarComponentsTransition {
// fade.
if (bottomMiddle != null && topLeading != null) {
return Positioned.fromRelativeRect(
rect: positionInTransitionBox(bottomComponents.middleKey,
from: bottomNavBarBox),
rect: positionInTransitionBox(bottomComponents.middleKey, from: bottomNavBarBox),
child: FadeTransition(
opacity: fadeOutBy(bottomHasUserMiddle ? 0.4 : 0.7),
// Keep the font when transitioning into a non-back label leading.
@ -2017,10 +1966,8 @@ class _NavigationBarComponentsTransition {
Widget? get bottomLargeTitle {
final KeyedSubtree? bottomLargeTitle =
bottomComponents.largeTitleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topBackLabel =
topComponents.backLabelKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topLeading =
topComponents.leadingKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topBackLabel = topComponents.backLabelKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topLeading = topComponents.leadingKey.currentWidget as KeyedSubtree?;
if (bottomLargeTitle == null || !bottomLargeExpanded) {
return null;
@ -2056,9 +2003,8 @@ class _NavigationBarComponentsTransition {
if (bottomLargeTitle != null && topLeading != null) {
// Unlike bottom middle, the bottom large title moves when it can't
// transition to the top back label position.
final RelativeRect from = positionInTransitionBox(
bottomComponents.largeTitleKey,
from: bottomNavBarBox);
final RelativeRect from =
positionInTransitionBox(bottomComponents.largeTitleKey, from: bottomNavBarBox);
final RelativeRectTween positionTween = RelativeRectTween(
begin: from,
@ -2097,8 +2043,7 @@ class _NavigationBarComponentsTransition {
}
return Positioned.fromRelativeRect(
rect: positionInTransitionBox(bottomComponents.trailingKey,
from: bottomNavBarBox),
rect: positionInTransitionBox(bottomComponents.trailingKey, from: bottomNavBarBox),
child: FadeTransition(
opacity: fadeOutBy(0.6),
child: bottomTrailing.child,
@ -2107,16 +2052,14 @@ class _NavigationBarComponentsTransition {
}
Widget? get topLeading {
final KeyedSubtree? topLeading =
topComponents.leadingKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topLeading = topComponents.leadingKey.currentWidget as KeyedSubtree?;
if (topLeading == null) {
return null;
}
return Positioned.fromRelativeRect(
rect:
positionInTransitionBox(topComponents.leadingKey, from: topNavBarBox),
rect: positionInTransitionBox(topComponents.leadingKey, from: topNavBarBox),
child: FadeTransition(
opacity: fadeInFrom(0.6),
child: topLeading.child,
@ -2134,17 +2077,15 @@ class _NavigationBarComponentsTransition {
return null;
}
final RelativeRect to = positionInTransitionBox(
topComponents.backChevronKey,
from: topNavBarBox);
final RelativeRect to =
positionInTransitionBox(topComponents.backChevronKey, from: topNavBarBox);
RelativeRect from = to;
// If it's the first page with a back chevron, shift in slightly from the
// right.
if (bottomBackChevron == null) {
final RenderBox topBackChevronBox =
topComponents.backChevronKey.currentContext!.findRenderObject()!
as RenderBox;
topComponents.backChevronKey.currentContext!.findRenderObject()! as RenderBox;
from = to.shift(
Offset(
forwardDirection * topBackChevronBox.size.width * 2.0,
@ -2171,24 +2112,20 @@ class _NavigationBarComponentsTransition {
}
Widget? get topBackLabel {
final KeyedSubtree? bottomMiddle =
bottomComponents.middleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? bottomMiddle = bottomComponents.middleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? bottomLargeTitle =
bottomComponents.largeTitleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topBackLabel =
topComponents.backLabelKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topBackLabel = topComponents.backLabelKey.currentWidget as KeyedSubtree?;
if (topBackLabel == null) {
return null;
}
final RenderAnimatedOpacity? topBackLabelOpacity = topComponents
.backLabelKey.currentContext
final RenderAnimatedOpacity? topBackLabelOpacity = topComponents.backLabelKey.currentContext
?.findAncestorRenderObjectOfType<RenderAnimatedOpacity>();
Animation<double>? midClickOpacity;
if (topBackLabelOpacity != null &&
topBackLabelOpacity.opacity.value < 1.0) {
if (topBackLabelOpacity != null && topBackLabelOpacity.opacity.value < 1.0) {
midClickOpacity = animation.drive(Tween<double>(
begin: 0.0,
end: topBackLabelOpacity.opacity.value,
@ -2200,9 +2137,7 @@ class _NavigationBarComponentsTransition {
// content text might be different. For instance, if the bottomLargeTitle
// text is too long, the topBackLabel will say 'Back' instead of the original
// text.
if (bottomLargeTitle != null &&
topBackLabel != null &&
bottomLargeExpanded) {
if (bottomLargeTitle != null && topBackLabel != null && bottomLargeExpanded) {
return slideFromLeadingEdge(
fromKey: bottomComponents.largeTitleKey,
fromNavBarBox: bottomNavBarBox,
@ -2248,8 +2183,7 @@ class _NavigationBarComponentsTransition {
}
Widget? get topMiddle {
final KeyedSubtree? topMiddle =
topComponents.middleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topMiddle = topComponents.middleKey.currentWidget as KeyedSubtree?;
if (topMiddle == null) {
return null;
@ -2261,10 +2195,9 @@ class _NavigationBarComponentsTransition {
return null;
}
final RelativeRect to =
positionInTransitionBox(topComponents.middleKey, from: topNavBarBox);
final RenderBox toBox = topComponents.middleKey.currentContext!
.findRenderObject()! as RenderBox;
final RelativeRect to = positionInTransitionBox(topComponents.middleKey, from: topNavBarBox);
final RenderBox toBox =
topComponents.middleKey.currentContext!.findRenderObject()! as RenderBox;
final bool isLTR = forwardDirection > 0;
@ -2301,16 +2234,14 @@ class _NavigationBarComponentsTransition {
}
Widget? get topTrailing {
final KeyedSubtree? topTrailing =
topComponents.trailingKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topTrailing = topComponents.trailingKey.currentWidget as KeyedSubtree?;
if (topTrailing == null) {
return null;
}
return Positioned.fromRelativeRect(
rect: positionInTransitionBox(topComponents.trailingKey,
from: topNavBarBox),
rect: positionInTransitionBox(topComponents.trailingKey, from: topNavBarBox),
child: FadeTransition(
opacity: fadeInFrom(0.4),
child: topTrailing.child,
@ -2319,15 +2250,14 @@ class _NavigationBarComponentsTransition {
}
Widget? get topLargeTitle {
final KeyedSubtree? topLargeTitle =
topComponents.largeTitleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topLargeTitle = topComponents.largeTitleKey.currentWidget as KeyedSubtree?;
if (topLargeTitle == null || !topLargeExpanded) {
return null;
}
final RelativeRect to = positionInTransitionBox(topComponents.largeTitleKey,
from: topNavBarBox);
final RelativeRect to =
positionInTransitionBox(topComponents.largeTitleKey, from: topNavBarBox);
// Shift in from the trailing edge of the screen.
final RelativeRectTween positionTween = RelativeRectTween(
@ -2417,8 +2347,7 @@ Widget _navBarHeroFlightShuttleBuilder(
final _TransitionableNavigationBar fromNavBar =
fromHeroWidget.child as _TransitionableNavigationBar;
final _TransitionableNavigationBar toNavBar =
toHeroWidget.child as _TransitionableNavigationBar;
final _TransitionableNavigationBar toNavBar = toHeroWidget.child as _TransitionableNavigationBar;
assert(fromNavBar.componentsKeys != null);
assert(toNavBar.componentsKeys != null);

@ -1,10 +1,14 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:isekai_wiki/api/response/parse.dart';
import 'package:isekai_wiki/components/gesture_detector.dart';
import 'package:isekai_wiki/components/safearea_builder.dart';
import 'package:isekai_wiki/styles.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
class TOCStyles {
static const double listPadding = 2;
static const activeColor = Color.fromRGBO(51, 102, 204, 1);
}
class TOCList extends StatefulWidget {
final String activedItem;
@ -27,13 +31,16 @@ class TOCList extends StatefulWidget {
class _TOCListState extends State<TOCList> {
String _activedItem = "";
String _lastSelectedItem = "";
final ItemScrollController _itemScrollController = ItemScrollController();
double _listPaddingTop = 0;
double _listPaddingBottom = 0;
final ScrollController _scrollController = ScrollController();
@override
void didUpdateWidget(covariant TOCList oldWidget) {
super.didUpdateWidget(oldWidget);
if (_activedItem != widget.activedItem && _activedItem != _lastSelectedItem) {
if (_activedItem != widget.activedItem) {
_activedItem = widget.activedItem;
// Scroll to current item
int activedIndex;
@ -48,7 +55,29 @@ class _TOCListState extends State<TOCList> {
activedIndex = 0;
}
}
_itemScrollController.jumpTo(index: activedIndex);
scrollToTOCItem(activedIndex);
}
}
void scrollToTOCItem(int index) {
var listLength = widget.sections.length + (widget.hasFirstSection ? 1 : 0);
var scrollInnerOffsetHeight =
_scrollController.position.maxScrollExtent + _scrollController.position.viewportDimension;
var scrollInnerHeight = scrollInnerOffsetHeight - _listPaddingTop - _listPaddingBottom;
var itemHeight = scrollInnerHeight / listLength;
var target = itemHeight * index;
var scrollTop = _scrollController.position.pixels;
var scrollOffsetBottom = scrollTop +
_scrollController.position.viewportDimension -
_listPaddingTop -
_listPaddingBottom -
itemHeight;
if (target < scrollTop || target > scrollOffsetBottom) {
_scrollController.jumpTo(clampDouble(target, _scrollController.position.minScrollExtent,
_scrollController.position.maxScrollExtent));
}
}
@ -61,36 +90,27 @@ class _TOCListState extends State<TOCList> {
Widget build(BuildContext context) {
final itemCount = widget.hasFirstSection ? widget.sections.length + 1 : widget.sections.length;
return DefaultTextStyle(
style: CupertinoTheme.of(context).textTheme.textStyle,
child: Container(
color: Styles.themePageBackgroundColor,
child: SafeAreaBuilder(
builder: (context, padding) => ScrollablePositionedList.builder(
itemScrollController: _itemScrollController,
padding: EdgeInsets.only(
top: padding.top + 2,
bottom: padding.bottom + 2,
right: padding.right,
),
itemCount: itemCount,
itemBuilder: (context, index) {
if (widget.hasFirstSection && index == 0) {
List<Widget> tocItemList = [];
if (widget.hasFirstSection) {
//
return TOCItem(
tocItemList.add(
TOCItem(
text: "简介",
anchor: "_firstSection",
active: widget.activedItem == "_firstSection",
onPressed: handleTOCItemPressed,
),
);
}
var section =
widget.hasFirstSection ? widget.sections[index - 1] : widget.sections[index];
return Container(
for (var index = 0; index < widget.sections.length; index++) {
var section = widget.sections[index];
var isTopItem = !widget.hasFirstSection && index == 0;
tocItemList.add(
Container(
decoration: BoxDecoration(
border: Border(
top: index == 0
top: isTopItem
? BorderSide.none
: const BorderSide(color: Color.fromRGBO(234, 236, 240, 1))),
),
@ -101,10 +121,27 @@ class _TOCListState extends State<TOCList> {
active: widget.activedItem == section.anchor,
onPressed: handleTOCItemPressed,
),
);
},
),
);
}
return DefaultTextStyle(
style: CupertinoTheme.of(context).textTheme.textStyle,
child: Container(
color: Styles.themePageBackgroundColor,
child: SafeAreaBuilder(builder: (context, padding) {
_listPaddingTop = padding.top + TOCStyles.listPadding;
_listPaddingBottom = padding.bottom + TOCStyles.listPadding;
return ListView(
controller: _scrollController,
padding: EdgeInsets.only(
top: _listPaddingTop,
bottom: _listPaddingBottom,
right: padding.right,
),
children: tocItemList,
);
}),
),
);
}
@ -169,7 +206,7 @@ class TOCItem extends StatelessWidget {
bottom: 0,
width: 4,
child: Container(
color: const Color.fromRGBO(51, 102, 204, 1),
color: TOCStyles.activeColor,
),
),
],

@ -1,4 +1,3 @@
import 'package:cupertino_lists/cupertino_lists.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

@ -1,5 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_share/flutter_share.dart';
import 'package:flutter_slider_drawer/flutter_slider_drawer.dart';
import 'package:get/get.dart';
import 'package:isekai_wiki/api/mw/list.dart';
@ -12,10 +13,13 @@ import 'package:isekai_wiki/components/nav_bar_button.dart';
import 'package:isekai_wiki/components/safearea_builder.dart';
import 'package:isekai_wiki/components/toc.dart';
import 'package:isekai_wiki/components/wikipage_parser.dart';
import 'package:isekai_wiki/global.dart';
import 'package:isekai_wiki/models/favorite_list.dart';
import 'package:isekai_wiki/reactive/reactive.dart';
import 'package:isekai_wiki/utils/dialog.dart';
import 'package:isekai_wiki/utils/error.dart';
import 'package:isekai_wiki/utils/utils.dart';
import 'package:share_plus/share_plus.dart';
import '../components/isekai_nav_bar.dart';
import '../components/isekai_page_scaffold.dart';
@ -103,7 +107,20 @@ class ArticlePageController extends GetxController {
alert(Get.overlayContext!, "评论功能暂未完成");
}
void handleMenuButtonClick() {
void handleShareButtonClick() {
if (pageInfo.value != null) {
var pageUrl = pageInfo.value!.fullurl ?? getPageUrl(pageInfo.value!.title);
var shareTitle = "${pageInfo.value!.title} - ${Global.siteTitle}";
var shareText = "$shareTitle\n$pageUrl";
FlutterShare.share(
title: shareTitle, text: shareTitle, linkUrl: pageUrl, chooserTitle: "分享到");
} else {
alert(Get.overlayContext!, "页面还未加载完成");
}
}
void handleTOCButtonClick() {
menuSlider.currentState?.openSlider();
}
@ -215,7 +232,7 @@ class _ArticlePageState extends ReactiveState<ArticlePage> {
}),
NavBarButton(
icon: CupertinoIcons.share,
onPressed: c.handleFlowButtonClick,
onPressed: c.handleShareButtonClick,
semanticLabel: "分享",
),
NavBarButton(
@ -225,7 +242,7 @@ class _ArticlePageState extends ReactiveState<ArticlePage> {
),
NavBarButton(
icon: CupertinoIcons.list_bullet,
onPressed: c.handleMenuButtonClick,
onPressed: c.handleTOCButtonClick,
semanticLabel: "目录",
),
],

@ -1,5 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cupertino_lists/cupertino_lists.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';

@ -1,4 +1,3 @@
import 'package:cupertino_lists/cupertino_lists.dart';
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:isekai_wiki/components/dummy_icon.dart';

@ -1 +1,6 @@
import 'package:isekai_wiki/global.dart';
String getPageUrl(String title) {
var titleEncoded = Uri.encodeFull(title.replaceAll(RegExp(r" "), "_"));
return Global.siteConfig.pageUrlTemplate.replaceAll(RegExp(r"\$1"), titleEncoded);
}

@ -7,6 +7,7 @@ import Foundation
import package_info_plus
import path_provider_foundation
import share_plus
import sqflite
import url_launcher_macos
import wakelock_macos
@ -14,6 +15,7 @@ import wakelock_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin"))

@ -1 +1 @@
Subproject commit 1faaf0e222b5155f6533abdf8df7b9273a6e06c4
Subproject commit 339d58aac7b404f21964bcb44c22bf5f39ba2e77

File diff suppressed because it is too large Load Diff

@ -47,7 +47,8 @@ dependencies:
like_button: ^2.0.4
skeletons: ^0.0.3
scroll_bottom_navigation_bar: ^4.0.0
scrollable_positioned_list: ^0.3.5
share_plus: ^6.3.0
flutter_share: ^2.0.0
modal_bottom_sheet: ^2.1.2
fluttertoast: ^8.1.2
animated_snack_bar: ^0.3.0

@ -6,9 +6,12 @@
#include "generated_plugin_registrant.h"
#include <share_plus/share_plus_windows_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
SharePlusWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
share_plus
url_launcher_windows
)

Loading…
Cancel
Save