更改卡片样式

main
落雨楓 2 years ago
parent 5ad50bbc58
commit 484810d390

@ -31,9 +31,7 @@ class IsekaiWikiApp extends StatelessWidget {
return Material(
child: GetCupertinoApp(
title: '异世界百科',
theme: const CupertinoThemeData(
textTheme: Styles.defaultTextTheme,
scaffoldBackgroundColor: Styles.themePageBackgroundColor),
theme: Styles.cupertinoLightTheme,
localizationsDelegates: const <LocalizationsDelegate<dynamic>>[
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
@ -51,7 +49,16 @@ class IsekaiWikiApp extends StatelessWidget {
} else {
Styles.textScaleFactor = MediaQuery.of(context).textScaleFactor;
Styles.isXs = MediaQuery.of(context).size.width <= 340;
return child;
return CupertinoTheme(
data: MediaQuery.of(context).platformBrightness != Brightness.dark
? Styles.cupertinoLightTheme
: Styles.cupertinoDarkTheme,
child: Theme(
data: MediaQuery.of(context).platformBrightness != Brightness.dark
? Styles.materialLightTheme
: Styles.materialDarkTheme,
child: child),
);
}
},
debugShowCheckedModeBanner: false,

@ -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,8 +129,7 @@ Widget _wrapWithBackground({
Widget result = child;
if (updateSystemUiOverlay) {
final bool isDark = backgroundColor.computeLuminance() < 0.179;
final Brightness newBrightness =
brightness ?? (isDark ? Brightness.dark : Brightness.light);
final Brightness newBrightness = brightness ?? (isDark ? Brightness.dark : Brightness.light);
final SystemUiOverlayStyle overlayStyle;
switch (newBrightness) {
case Brightness.dark:
@ -233,8 +231,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 +444,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 +480,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 +488,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 +688,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 +705,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 +726,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 +734,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 +782,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 +836,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 +864,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 +874,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 +972,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 +1331,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 +1347,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 +1432,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 +1456,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 +1507,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 +1618,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 +1638,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 +1691,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 +1738,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 +1767,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 +1784,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 +1796,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 +1831,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 +1855,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 +1874,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 +1901,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 +1942,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 +1960,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 +1997,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 +2037,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 +2046,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 +2071,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 +2106,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 +2131,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 +2177,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 +2189,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 +2228,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 +2244,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 +2341,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,3 +1,5 @@
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@ -9,15 +11,44 @@ import 'package:like_button/like_button.dart';
import 'package:pull_down_button/pull_down_button.dart';
import 'package:skeletons/skeletons.dart';
import '../styles.dart';
typedef AddFavoriteCallback = Future<bool> Function(PageInfo pageInfo, bool localIsFavorite);
typedef PageInfoCallback = Future<void> Function(PageInfo pageInfo);
class PageCardStyles {
static const double cardInnerHeight = 150;
static const cardInnerPadding = EdgeInsets.only(top: 16, left: 20, right: 20, bottom: 12);
static const cardContainerHeight = 100.0;
static const cardContentHeight = 100.0;
static const cardHeaderPadding = EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 16);
static const cardHeaderCompactPadding = EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 10);
static const cardContentPadding = EdgeInsets.only(top: 0, left: 20, right: 20, bottom: 14);
static const cardFooterPadding = EdgeInsets.only(top: 0, left: 20, right: 20, bottom: 14);
static const titleFontSize = 24.0;
static const subTitleFontSize = 12.0;
static const contentFontSize = 14.0;
static const TextStyle titleTextStyle = TextStyle(
color: CupertinoDynamicColor.withBrightness(color: Colors.black, darkColor: Colors.white),
fontSize: titleFontSize,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w700,
height: 1.2,
);
static const TextStyle subTitleTextStyle = TextStyle(
color: Color.fromRGBO(102, 102, 102, 1),
fontSize: subTitleFontSize,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w700,
height: 1.2,
);
static const TextStyle contentTextStyle = TextStyle(
color: Color.fromRGBO(102, 102, 102, 1),
fontSize: contentFontSize,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.normal,
height: 1.4);
static const double footerButtonSize = 30;
static const double footerButtonInnerSize = 26;
}
@ -106,24 +137,42 @@ class PageCard extends StatelessWidget {
var textScale = MediaQuery.of(context).textScaleFactor;
return Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Skeleton(
isLoading: isLoading,
skeleton: SkeletonLine(
style: SkeletonLineStyle(
height: (Styles.pageCardTitle.fontSize! + 4) * textScale, randomLength: true),
),
child: Text(pageInfo?.mainTitle ?? "页面信息丢失", style: Styles.pageCardTitle),
padding: pageInfo?.subtitle == null
? PageCardStyles.cardHeaderPadding
: PageCardStyles.cardHeaderCompactPadding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (pageInfo?.subtitle != null)
Text(
pageInfo!.subtitle!,
style: PageCardStyles.subTitleTextStyle,
textScaleFactor: max(1, MediaQuery.of(context).textScaleFactor),
),
if (pageInfo?.subtitle != null) const SizedBox(height: 6),
Skeleton(
isLoading: isLoading,
skeleton: SkeletonLine(
style: SkeletonLineStyle(
height: (PageCardStyles.titleFontSize * 1.1) * textScale, randomLength: true),
),
child: Text(
pageInfo?.mainTitle ?? "页面信息丢失",
style: PageCardStyles.titleTextStyle,
textScaleFactor: 1,
),
),
],
),
);
}
Widget _buildCardBody(BuildContext context) {
var textScale = MediaQuery.of(context).textScaleFactor;
double textScale = max(1, MediaQuery.of(context).textScaleFactor);
return Expanded(
child: Padding(
padding: const EdgeInsets.only(bottom: 8),
padding: PageCardStyles.cardContentPadding,
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
@ -132,18 +181,26 @@ class PageCard extends StatelessWidget {
flex: 1,
child: isLoading
? ClipRect(
clipBehavior: Clip.antiAlias,
child: SkeletonParagraph(
style: SkeletonParagraphStyle(
lines: 3,
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 0),
padding: EdgeInsets.symmetric(
vertical: PageCardStyles.contentFontSize * textScale * 0.2,
horizontal: 0,
),
lineStyle: SkeletonLineStyle(
randomLength: true,
height: Styles.pageCardDescription.fontSize! * textScale),
height: PageCardStyles.contentFontSize * textScale),
),
),
)
: Text(pageInfo?.description ?? "没有简介",
overflow: TextOverflow.fade, style: Styles.pageCardDescription),
: Text(
pageInfo?.description ?? "没有简介",
overflow: TextOverflow.fade,
style: PageCardStyles.contentTextStyle,
textScaleFactor: textScale,
),
),
const SizedBox(width: 10),
Skeleton(
@ -162,77 +219,83 @@ class PageCard extends StatelessWidget {
Widget _buildCardFooter(BuildContext context) {
return ScaleTapIgnore(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//
pageInfo?.mainCategory != null
? Chip(
backgroundColor: const Color.fromARGB(1, 238, 238, 238),
label:
Text(pageInfo!.mainCategory!, style: const TextStyle(color: Colors.black54)),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap)
: const SizedBox(),
pageInfo?.mainCategory != null ? const SizedBox(width: 10) : const SizedBox(),
//
Skeleton(
isLoading: isLoading,
skeleton: const SkeletonLine(
style: SkeletonLineStyle(width: 100),
),
child: Text(
child: Padding(
padding: PageCardStyles.cardFooterPadding,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//
pageInfo?.mainCategory != null
? Chip(
backgroundColor: const Color.fromARGB(1, 238, 238, 238),
label: Text(pageInfo!.mainCategory!,
style: const TextStyle(color: Colors.black54)),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap)
: const SizedBox(),
pageInfo?.mainCategory != null ? const SizedBox(width: 10) : const SizedBox(),
//
Skeleton(
isLoading: isLoading,
skeleton: const SkeletonLine(
style: SkeletonLineStyle(width: 100),
),
child: Text(
pageInfo?.updatedTime != null ? Utils.getFriendDate(pageInfo!.updatedTime!) : "",
style: Styles.pageCardDescription),
),
const Spacer(),
//
_actionButtonSkeleton(
isLoading,
LikeButton(
size: PageCardStyles.footerButtonInnerSize,
isLiked: isFavorite,
onTap: handleFavoriteClick,
likeBuilder: (bool isLiked) {
return Icon(
isLiked ? Icons.favorite : Icons.favorite_border,
color: isLiked ? Colors.red : Colors.grey,
size: PageCardStyles.footerButtonInnerSize,
);
},
overflow: TextOverflow.fade,
style: PageCardStyles.contentTextStyle,
textScaleFactor: max(1, MediaQuery.of(context).textScaleFactor),
),
),
),
const SizedBox(width: 18),
//
_actionButtonSkeleton(
isLoading,
SizedBox(
height: PageCardStyles.footerButtonSize,
width: PageCardStyles.footerButtonSize,
child: PullDownButton(
routeTheme: PullDownMenuRouteTheme(
endShadow: BoxShadow(
color: Colors.grey.withOpacity(0.6),
spreadRadius: 1,
blurRadius: 20,
offset: const Offset(0, 2),
const Spacer(),
//
_actionButtonSkeleton(
isLoading,
LikeButton(
size: PageCardStyles.footerButtonInnerSize,
isLiked: isFavorite,
onTap: handleFavoriteClick,
likeBuilder: (bool isLiked) {
return Icon(
isLiked ? Icons.favorite : Icons.favorite_border,
color: isLiked ? Colors.red : Colors.grey,
size: PageCardStyles.footerButtonInnerSize,
);
},
),
),
const SizedBox(width: 18),
//
_actionButtonSkeleton(
isLoading,
SizedBox(
height: PageCardStyles.footerButtonSize,
width: PageCardStyles.footerButtonSize,
child: PullDownButton(
routeTheme: PullDownMenuRouteTheme(
endShadow: BoxShadow(
color: Colors.grey.withOpacity(0.6),
spreadRadius: 1,
blurRadius: 20,
offset: const Offset(0, 2),
),
),
),
itemBuilder: _buildMenuItem,
position: PullDownMenuPosition.under,
buttonBuilder: (context, showMenu) => IconButton(
onPressed: showMenu,
padding: const EdgeInsets.all(0.0),
splashRadius: PageCardStyles.footerButtonInnerSize - 4,
iconSize: PageCardStyles.footerButtonInnerSize,
icon: const Icon(
Icons.more_horiz,
color: Colors.grey,
itemBuilder: _buildMenuItem,
position: PullDownMenuPosition.under,
buttonBuilder: (context, showMenu) => IconButton(
onPressed: showMenu,
padding: const EdgeInsets.all(0.0),
splashRadius: PageCardStyles.footerButtonInnerSize - 4,
iconSize: PageCardStyles.footerButtonInnerSize,
icon: const Icon(
Icons.more_horiz,
color: Colors.grey,
),
),
),
),
),
),
],
],
),
),
);
}
@ -276,30 +339,33 @@ class PageCard extends StatelessWidget {
Widget _buildCard(BuildContext context) {
var textScale = MediaQuery.of(context).textScaleFactor;
return Card(
elevation: 4.0,
//
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(Styles.isXs ? 0 : 14.0)),
return Container(
margin: Theme.of(context).cardTheme.margin,
clipBehavior: Theme.of(context).cardTheme.clipBehavior ?? Clip.antiAlias,
decoration: BoxDecoration(
color: Theme.of(context).cardTheme.color,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Theme.of(context).cardTheme.shadowColor ?? Colors.transparent,
blurRadius: 16,
offset: const Offset(0, 2),
blurStyle: BlurStyle.outer),
],
),
// 齿
clipBehavior: Clip.antiAlias,
semanticContainer: false,
child: Padding(
padding: PageCardStyles.cardInnerPadding,
child: SizedBox(
height: PageCardStyles.cardInnerHeight * textScale,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//
_buildCardHeader(context),
//
_buildCardBody(context),
// Footer
_buildCardFooter(context),
],
),
child: SizedBox(
height: PageCardStyles.cardContainerHeight +
(PageCardStyles.cardContentHeight * max(1, MediaQuery.of(context).textScaleFactor)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//
_buildCardHeader(context),
//
_buildCardBody(context),
// Footer
_buildCardFooter(context),
],
),
),
);

@ -11,7 +11,7 @@ import 'package:pull_down_button/pull_down_button.dart';
import 'package:skeletons/skeletons.dart';
import '../styles.dart';
/*
typedef AddFavoriteCallback = Future<bool> Function(
PageInfo pageInfo, bool localIsFavorite, bool showToast);
@ -144,9 +144,9 @@ class _PageCardState extends ReactiveState<PageCard> {
isLoading: c.isLoading.value,
skeleton: SkeletonLine(
style: SkeletonLineStyle(
height: (Styles.pageCardTitle.fontSize! + 4) * textScale, randomLength: true),
height: (Styles.titleTextStyle.fontSize! + 4) * textScale, randomLength: true),
),
child: Text(c.pageInfo.value?.mainTitle ?? "页面信息丢失", style: Styles.pageCardTitle),
child: Text(c.pageInfo.value?.mainTitle ?? "页面信息丢失", style: Styles.titleTextStyle),
),
);
}
@ -169,12 +169,12 @@ class _PageCardState extends ReactiveState<PageCard> {
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 0),
lineStyle: SkeletonLineStyle(
randomLength: true,
height: Styles.pageCardDescription.fontSize! * textScale),
height: Styles.contentTextStyle.fontSize! * textScale),
),
),
)
: Text(c.pageInfo.value?.description ?? "没有简介",
overflow: TextOverflow.fade, style: Styles.pageCardDescription),
overflow: TextOverflow.fade, style: Styles.contentTextStyle),
),
const SizedBox(width: 10),
Skeleton(
@ -215,7 +215,7 @@ class _PageCardState extends ReactiveState<PageCard> {
c.pageInfo.value?.updatedTime != null
? Utils.getFriendDate(c.pageInfo.value!.updatedTime!)
: "",
style: Styles.pageCardDescription),
style: Styles.contentTextStyle),
),
const Spacer(),
//
@ -353,3 +353,4 @@ class _PageCardState extends ReactiveState<PageCard> {
);
}
}
*/

@ -134,6 +134,7 @@ class RecentPageList extends StatelessWidget {
Widget _buildPageCard(
int index, PageInfo pageInfo, RecentPageListController c, FavoriteListController flc) {
return PageCard(
key: ValueKey("rpl-card-$index"),
pageInfo: c.pageList[index],
isFavorite: flc.isFavorite(c.pageList[index]),
onSetFavorite: flc.setFavoriteImmediate,

@ -23,6 +23,8 @@ class SiteConfig {
String restfulApiUrl;
String pageUrlTemplate;
bool enableFollowing;
SiteConfig({
this.moduleStyles = const [],
this.moduleScripts = const [],
@ -33,6 +35,7 @@ class SiteConfig {
this.resourceLoaderUrl = "",
this.restfulApiUrl = "",
this.pageUrlTemplate = "",
this.enableFollowing = false,
});
factory SiteConfig.fromJson(Map<String, dynamic> json) => _$SiteConfigFromJson(json);

@ -142,8 +142,8 @@ class HomeTab extends StatelessWidget {
backgroundColor: Styles.themeMainColor,
brightness: Brightness.dark,
largeTitle: const Text('首页', style: TextStyle(color: Styles.themeNavTitleColor)),
border: Border.all(style: BorderStyle.none),
trailing: _buildNotificationIconButton(),
border: Border.all(style: BorderStyle.none),
),
SliverPersistentHeader(
delegate: _SliverAppBarDelegate(
@ -184,39 +184,40 @@ class HomeTab extends StatelessWidget {
),
),
),
SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
minHeight: 40.0,
maxHeight: 40.0,
child: Container(
decoration: BoxDecoration(color: Colors.white, boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 4,
offset: const Offset(0, 2),
)
]),
child: Row(
children: [
SizedBox(
child: TabBar(
isScrollable: true,
controller: c.tabController,
indicatorColor: Styles.themeMainColor,
labelColor: Styles.themeMainColor,
unselectedLabelColor: Colors.black45,
tabs: const [CollapsedTabText('最新'), CollapsedTabText('关注')],
onTap: (int selected) {},
if (Global.siteConfig.enableFollowing) //
SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
minHeight: 40.0,
maxHeight: 40.0,
child: Container(
decoration: BoxDecoration(color: Colors.white, boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 4,
offset: const Offset(0, 2),
)
]),
child: Row(
children: [
SizedBox(
child: TabBar(
isScrollable: true,
controller: c.tabController,
indicatorColor: Styles.themeMainColor,
labelColor: Styles.themeMainColor,
unselectedLabelColor: Colors.black45,
tabs: const [CollapsedTabText('最新'), CollapsedTabText('关注')],
onTap: (int selected) {},
),
),
),
const Expanded(child: Text('')),
],
const Expanded(child: Text('')),
],
),
),
),
),
),
CupertinoSliverRefreshControl(
onRefresh: c.handleRefresh,
),

@ -23,6 +23,30 @@ abstract class Styles {
),
);
static CupertinoThemeData cupertinoLightTheme = const CupertinoThemeData(
textTheme: Styles.defaultTextTheme,
scaffoldBackgroundColor: Styles.themePageBackgroundColor,
);
static CupertinoThemeData cupertinoDarkTheme = const CupertinoThemeData(
brightness: Brightness.dark,
textTheme: Styles.defaultTextTheme,
scaffoldBackgroundColor: Styles.themePageBackgroundColor,
);
static ThemeData materialLightTheme = ThemeData.light().copyWith(
cardTheme: cardTheme,
);
static ThemeData materialDarkTheme = ThemeData.light().copyWith(
cardTheme: cardTheme.copyWith(color: const Color.fromRGBO(28, 28, 28, 1)),
);
static CardTheme cardTheme = CardTheme(
shadowColor: CupertinoColors.black.withOpacity(0.2),
margin: const EdgeInsets.symmetric(horizontal: 6, vertical: 8),
);
static const TextStyle navLargeTitleTextStyle = TextStyle(
fontWeight: FontWeight.normal, fontSize: 32, color: CupertinoColors.label, inherit: false);
@ -40,25 +64,12 @@ abstract class Styles {
fontWeight: FontWeight.bold,
);
static const TextStyle pageCardTitle = TextStyle(
fontSize: 20,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
);
static const TextStyle articleTitle = TextStyle(
fontSize: 28,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
);
static const TextStyle pageCardDescription = TextStyle(
color: Colors.black54,
fontSize: 14,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.normal,
);
static const TextStyle listTileLargeTitle = TextStyle(fontSize: 18);
static const TextStyle listTileSubTitle = TextStyle(fontSize: 16);
@ -70,6 +81,7 @@ abstract class Styles {
static const Color themeNavTitleColor = Color.fromRGBO(255, 255, 255, 1);
static const Color themeBottomColor = Color.fromRGBO(255, 255, 255, 1);
static const Color themePageBackgroundColor = Color.fromRGBO(240, 240, 240, 1);
static const Color darkThemePageBackgroundColor = Color.fromRGBO(0, 0, 0, 1);
static const Color themeNavSegmentTextColor = Color.fromRGBO(12, 12, 12, 1);
static const Color panelBackgroundColor = Color.fromRGBO(255, 255, 255, 1);
static const Color linkColor = CupertinoColors.link;

Loading…
Cancel
Save