mirror of
https://github.com/wgh136/pixes.git
synced 2025-09-27 04:57:23 +00:00
improve mobile ui
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:pixes/components/md.dart';
|
||||||
|
|
||||||
void showToast(BuildContext context, {required String message, IconData? icon}) {
|
void showToast(BuildContext context, {required String message, IconData? icon}) {
|
||||||
var newEntry = OverlayEntry(
|
var newEntry = OverlayEntry(
|
||||||
@@ -27,7 +28,7 @@ class ToastOverlay extends StatelessWidget {
|
|||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: PhysicalModel(
|
child: PhysicalModel(
|
||||||
color: Colors.white,
|
color: ColorScheme.of(context).surface,
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
child: Container(
|
child: Container(
|
||||||
@@ -42,8 +43,11 @@ class ToastOverlay extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
message,
|
message,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16, fontWeight: FontWeight.w500),
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: ColorScheme.of(context).onSurface
|
||||||
|
),
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@@ -307,7 +307,7 @@ class SideBarRoute<T> extends PopupRoute<T> {
|
|||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Color? get barrierColor => const Color.fromARGB(64, 205, 205, 205);
|
Color? get barrierColor => Colors.transparent;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get barrierDismissible => true;
|
bool get barrierDismissible => true;
|
||||||
@@ -331,7 +331,8 @@ class SideBarRoute<T> extends PopupRoute<T> {
|
|||||||
color: FluentTheme.of(context).micaBackgroundColor.withOpacity(0.98),
|
color: FluentTheme.of(context).micaBackgroundColor.withOpacity(0.98),
|
||||||
borderRadius: const BorderRadius.only(topLeft: Radius.circular(4), bottomLeft: Radius.circular(4))
|
borderRadius: const BorderRadius.only(topLeft: Radius.circular(4), bottomLeft: Radius.circular(4))
|
||||||
),
|
),
|
||||||
constraints: const BoxConstraints(maxWidth: _kSideBarWidth),
|
constraints: BoxConstraints(maxWidth: min(_kSideBarWidth,
|
||||||
|
MediaQuery.of(context).size.width)),
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
|
@@ -31,20 +31,26 @@ class _BookMarkedArtworkPageState extends State<BookMarkedArtworkPage>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildTab() {
|
Widget buildTab() {
|
||||||
return SegmentedButton(
|
return Row(
|
||||||
options: [
|
children: [
|
||||||
SegmentedButtonOption("public", "Public".tl),
|
Text("Following".tl, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20)),
|
||||||
SegmentedButtonOption("private", "Private".tl),
|
const Spacer(),
|
||||||
|
SegmentedButton(
|
||||||
|
options: [
|
||||||
|
SegmentedButtonOption("public", "Public".tl),
|
||||||
|
SegmentedButtonOption("private", "Private".tl),
|
||||||
|
],
|
||||||
|
onPressed: (key) {
|
||||||
|
if(key != restrict) {
|
||||||
|
setState(() {
|
||||||
|
restrict = key;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: restrict,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
onPressed: (key) {
|
).paddingHorizontal(16).paddingVertical(4);
|
||||||
if(key != restrict) {
|
|
||||||
setState(() {
|
|
||||||
restrict = key;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
value: restrict,
|
|
||||||
).padding(const EdgeInsets.symmetric(vertical: 8, horizontal: 8));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +68,7 @@ class _OneBookmarkedPageState extends MultiPageLoadingState<_OneBookmarkedPage,
|
|||||||
Widget buildContent(BuildContext context, final List<Illust> data) {
|
Widget buildContent(BuildContext context, final List<Illust> data) {
|
||||||
return LayoutBuilder(builder: (context, constrains){
|
return LayoutBuilder(builder: (context, constrains){
|
||||||
return MasonryGridView.builder(
|
return MasonryGridView.builder(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
|
gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
|
||||||
maxCrossAxisExtent: 240,
|
maxCrossAxisExtent: 240,
|
||||||
),
|
),
|
||||||
|
@@ -31,21 +31,28 @@ class _FollowingArtworksPageState extends State<FollowingArtworksPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildTab() {
|
Widget buildTab() {
|
||||||
return SegmentedButton(
|
return Row(
|
||||||
options: [
|
children: [
|
||||||
SegmentedButtonOption("all", "All".tl),
|
Text("Following".tl,
|
||||||
SegmentedButtonOption("public", "Public".tl),
|
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),),
|
||||||
SegmentedButtonOption("private", "Private".tl),
|
const Spacer(),
|
||||||
|
SegmentedButton(
|
||||||
|
options: [
|
||||||
|
SegmentedButtonOption("all", "All".tl),
|
||||||
|
SegmentedButtonOption("public", "Public".tl),
|
||||||
|
SegmentedButtonOption("private", "Private".tl),
|
||||||
|
],
|
||||||
|
onPressed: (key) {
|
||||||
|
if(key != restrict) {
|
||||||
|
setState(() {
|
||||||
|
restrict = key;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: restrict,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
onPressed: (key) {
|
).paddingHorizontal(16).paddingBottom(4);
|
||||||
if(key != restrict) {
|
|
||||||
setState(() {
|
|
||||||
restrict = key;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
value: restrict,
|
|
||||||
).padding(const EdgeInsets.symmetric(vertical: 8, horizontal: 8));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +70,7 @@ class _OneFollowingPageState extends MultiPageLoadingState<_OneFollowingPage, Il
|
|||||||
Widget buildContent(BuildContext context, final List<Illust> data) {
|
Widget buildContent(BuildContext context, final List<Illust> data) {
|
||||||
return LayoutBuilder(builder: (context, constrains){
|
return LayoutBuilder(builder: (context, constrains){
|
||||||
return MasonryGridView.builder(
|
return MasonryGridView.builder(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
|
gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
|
||||||
maxCrossAxisExtent: 240,
|
maxCrossAxisExtent: 240,
|
||||||
),
|
),
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart' show Icons;
|
import 'package:flutter/material.dart' show Icons;
|
||||||
import 'package:pixes/components/animated_image.dart';
|
import 'package:pixes/components/animated_image.dart';
|
||||||
import 'package:pixes/components/loading.dart';
|
import 'package:pixes/components/loading.dart';
|
||||||
@@ -11,6 +12,7 @@ import 'package:pixes/foundation/image_provider.dart';
|
|||||||
import 'package:pixes/network/download.dart';
|
import 'package:pixes/network/download.dart';
|
||||||
import 'package:pixes/network/network.dart';
|
import 'package:pixes/network/network.dart';
|
||||||
import 'package:pixes/pages/image_page.dart';
|
import 'package:pixes/pages/image_page.dart';
|
||||||
|
import 'package:pixes/pages/search_page.dart';
|
||||||
import 'package:pixes/pages/user_info_page.dart';
|
import 'package:pixes/pages/user_info_page.dart';
|
||||||
import 'package:pixes/utils/translation.dart';
|
import 'package:pixes/utils/translation.dart';
|
||||||
|
|
||||||
@@ -65,6 +67,7 @@ class _IllustPageState extends State<IllustPage> {
|
|||||||
Widget buildBody(double width, double height) {
|
Widget buildBody(double width, double height) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: widget.illust.images.length + 2,
|
itemCount: widget.illust.images.length + 2,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return buildImage(width, height, index);
|
return buildImage(width, height, index);
|
||||||
});
|
});
|
||||||
@@ -155,9 +158,7 @@ class _BottomBar extends StatefulWidget {
|
|||||||
State<_BottomBar> createState() => _BottomBarState();
|
State<_BottomBar> createState() => _BottomBarState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BottomBarState extends State<_BottomBar> {
|
class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
|
||||||
double? top;
|
|
||||||
|
|
||||||
double pageHeight = 0;
|
double pageHeight = 0;
|
||||||
|
|
||||||
double widgetHeight = 48;
|
double widgetHeight = 48;
|
||||||
@@ -166,36 +167,77 @@ class _BottomBarState extends State<_BottomBar> {
|
|||||||
|
|
||||||
double _width = 0;
|
double _width = 0;
|
||||||
|
|
||||||
|
late VerticalDragGestureRecognizer _recognizer;
|
||||||
|
|
||||||
|
late final AnimationController animationController;
|
||||||
|
|
||||||
|
double get minValue => pageHeight - widgetHeight;
|
||||||
|
double get maxValue => pageHeight - _kBottomBarHeight;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_width = widget.width;
|
_width = widget.width;
|
||||||
pageHeight = widget.height;
|
pageHeight = widget.height;
|
||||||
top = pageHeight - _kBottomBarHeight;
|
|
||||||
Future.delayed(const Duration(milliseconds: 200), () {
|
Future.delayed(const Duration(milliseconds: 200), () {
|
||||||
final box = key.currentContext?.findRenderObject() as RenderBox?;
|
final box = key.currentContext?.findRenderObject() as RenderBox?;
|
||||||
widgetHeight = (box?.size.height) ?? 0;
|
widgetHeight = (box?.size.height) ?? 0;
|
||||||
});
|
});
|
||||||
|
_recognizer = VerticalDragGestureRecognizer()
|
||||||
|
..onStart = _handlePointerDown
|
||||||
|
..onUpdate = _handlePointerMove
|
||||||
|
..onEnd = _handlePointerUp
|
||||||
|
..onCancel = _handlePointerCancel;
|
||||||
|
animationController = AnimationController(
|
||||||
|
vsync: this, duration: const Duration(milliseconds: 180),
|
||||||
|
value: 1
|
||||||
|
);
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handlePointerDown(DragStartDetails details) {}
|
||||||
|
void _handlePointerMove(DragUpdateDetails details) {
|
||||||
|
var offset = details.primaryDelta ?? 0;
|
||||||
|
final minValue = pageHeight - widgetHeight;
|
||||||
|
final maxValue = pageHeight - _kBottomBarHeight;
|
||||||
|
var top = animationController.value * (maxValue - minValue) + minValue;
|
||||||
|
top = (top + offset).clamp(minValue, maxValue);
|
||||||
|
animationController.value = (top - minValue) / (maxValue - minValue);
|
||||||
|
}
|
||||||
|
void _handlePointerUp(DragEndDetails details) {
|
||||||
|
var speed = details.primaryVelocity ?? 0;
|
||||||
|
const minShouldTransitionSpeed = 1000;
|
||||||
|
if(speed > minShouldTransitionSpeed) {
|
||||||
|
animationController.forward();
|
||||||
|
} else if(speed < minShouldTransitionSpeed) {
|
||||||
|
animationController.reverse();
|
||||||
|
} else {
|
||||||
|
_handlePointerCancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void _handlePointerCancel() {
|
||||||
|
if(animationController.value >= 0.5 ) {
|
||||||
|
animationController.forward();
|
||||||
|
} else {
|
||||||
|
animationController.reverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant _BottomBar oldWidget) {
|
void didUpdateWidget(covariant _BottomBar oldWidget) {
|
||||||
if (widget.height != pageHeight) {
|
if (widget.height != pageHeight) {
|
||||||
setState(() {
|
setState(() {
|
||||||
pageHeight = widget.height;
|
pageHeight = widget.height;
|
||||||
top = pageHeight - _kBottomBarHeight;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
_recognizer.dispose();
|
||||||
if(_width != widget.width) {
|
if(_width != widget.width) {
|
||||||
_width = widget.width;
|
_width = widget.width;
|
||||||
Future.microtask(() {
|
Future.microtask(() {
|
||||||
final box = key.currentContext?.findRenderObject() as RenderBox?;
|
final box = key.currentContext?.findRenderObject() as RenderBox?;
|
||||||
var oldHeight = widgetHeight;
|
var oldHeight = widgetHeight;
|
||||||
widgetHeight = (box?.size.height) ?? 0;
|
widgetHeight = (box?.size.height) ?? 0;
|
||||||
if(oldHeight != widgetHeight && top != pageHeight - _kBottomBarHeight) {
|
if(oldHeight != widgetHeight) {
|
||||||
setState(() {
|
setState(() {});
|
||||||
top = pageHeight - widgetHeight;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -204,32 +246,44 @@ class _BottomBarState extends State<_BottomBar> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedPositioned(
|
return AnimatedBuilder(
|
||||||
top: top,
|
animation: CurvedAnimation(
|
||||||
left: 0,
|
parent: animationController,
|
||||||
right: 0,
|
curve: Curves.ease,
|
||||||
duration: const Duration(milliseconds: 180),
|
reverseCurve: Curves.ease,
|
||||||
curve: Curves.ease,
|
|
||||||
child: Card(
|
|
||||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(8)),
|
|
||||||
backgroundColor:
|
|
||||||
FluentTheme.of(context).micaBackgroundColor.withOpacity(0.96),
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
child: SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
key: key,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
buildTop(),
|
|
||||||
buildStats(),
|
|
||||||
buildTags(),
|
|
||||||
SelectableText("${"Artwork ID".tl}: ${widget.illust.id}\n${"Artist ID".tl}: ${widget.illust.author.id}", style: TextStyle(color: ColorScheme.of(context).outline),).paddingLeft(4),
|
|
||||||
const SizedBox(height: 8,)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
builder: (context, child) {
|
||||||
|
return Positioned(
|
||||||
|
top: minValue + (maxValue - minValue) * animationController.value,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Listener(
|
||||||
|
onPointerDown: (event) {
|
||||||
|
_recognizer.addPointer(event);
|
||||||
|
},
|
||||||
|
child: Card(
|
||||||
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(8)),
|
||||||
|
backgroundColor:
|
||||||
|
FluentTheme.of(context).micaBackgroundColor.withOpacity(0.96),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
key: key,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
buildTop(),
|
||||||
|
buildStats(),
|
||||||
|
buildTags(),
|
||||||
|
SelectableText("${"Artwork ID".tl}: ${widget.illust.id}\n${"Artist ID".tl}: ${widget.illust.author.id}", style: TextStyle(color: ColorScheme.of(context).outline),).paddingLeft(4),
|
||||||
|
const SizedBox(height: 8,)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,21 +297,17 @@ class _BottomBarState extends State<_BottomBar> {
|
|||||||
buildAuthor(),
|
buildAuthor(),
|
||||||
...buildActions(constrains.maxWidth),
|
...buildActions(constrains.maxWidth),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
if (top == pageHeight - _kBottomBarHeight)
|
if (animationController.value == 1)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(FluentIcons.up),
|
icon: const Icon(FluentIcons.up),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
animationController.reverse();
|
||||||
top = pageHeight - widgetHeight;
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
else
|
else
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(FluentIcons.down),
|
icon: const Icon(FluentIcons.down),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
animationController.forward();
|
||||||
top = pageHeight - _kBottomBarHeight;
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -287,14 +337,15 @@ class _BottomBarState extends State<_BottomBar> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final bool showUserName = MediaQuery.of(context).size.width > 640;
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
margin: const EdgeInsets.symmetric(vertical: 8),
|
margin: const EdgeInsets.symmetric(vertical: 8),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
backgroundColor: FluentTheme.of(context).cardColor.withOpacity(0.72),
|
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
width: 246,
|
width: showUserName ? 246 : 128,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@@ -325,12 +376,13 @@ class _BottomBarState extends State<_BottomBar> {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 8,
|
width: 8,
|
||||||
),
|
),
|
||||||
Expanded(
|
if(showUserName)
|
||||||
child: Text(
|
Expanded(
|
||||||
widget.illust.author.name,
|
child: Text(
|
||||||
maxLines: 2,
|
widget.illust.author.name,
|
||||||
|
maxLines: 2,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
if(isFollowing)
|
if(isFollowing)
|
||||||
Button(onPressed: follow, child: const SizedBox(
|
Button(onPressed: follow, child: const SizedBox(
|
||||||
width: 42,
|
width: 42,
|
||||||
@@ -343,11 +395,14 @@ class _BottomBarState extends State<_BottomBar> {
|
|||||||
),
|
),
|
||||||
))
|
))
|
||||||
else if (!widget.illust.author.isFollowed)
|
else if (!widget.illust.author.isFollowed)
|
||||||
Button(onPressed: follow, child: Text("Follow".tl))
|
Button(onPressed: follow, child: Text("Follow".tl).fixWidth(56))
|
||||||
else
|
else
|
||||||
Button(
|
Button(
|
||||||
onPressed: follow,
|
onPressed: follow,
|
||||||
child: Text("Unfollow".tl, style: TextStyle(color: ColorScheme.of(context).error),),
|
child: Text(
|
||||||
|
"Unfollow".tl,
|
||||||
|
style: TextStyle(color: ColorScheme.of(context).error),
|
||||||
|
).fixWidth(56),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -558,9 +613,17 @@ class _BottomBarState extends State<_BottomBar> {
|
|||||||
if(e.translatedName != null && e.name != e.translatedName) {
|
if(e.translatedName != null && e.name != e.translatedName) {
|
||||||
text += "/${e.translatedName}";
|
text += "/${e.translatedName}";
|
||||||
}
|
}
|
||||||
return Card(
|
return MouseRegion(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
|
cursor: SystemMouseCursors.click,
|
||||||
child: Text(text, style: const TextStyle(fontSize: 13),),
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
context.to(() => SearchResultPage(e.name));
|
||||||
|
},
|
||||||
|
child: Card(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
|
||||||
|
child: Text(text, style: const TextStyle(fontSize: 13),),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
@@ -601,10 +664,11 @@ class _CommentsPageState extends MultiPageLoadingState<_CommentsPage, Comment> {
|
|||||||
|
|
||||||
Widget buildBody(BuildContext context, List<Comment> data) {
|
Widget buildBody(BuildContext context, List<Comment> data) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
itemCount: data.length + 2,
|
itemCount: data.length + 2,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if(index == 0) {
|
if(index == 0) {
|
||||||
return Text("Comments".tl, style: const TextStyle(fontSize: 20)).paddingVertical(8).paddingHorizontal(12);
|
return Text("Comments".tl, style: const TextStyle(fontSize: 20)).paddingVertical(16).paddingHorizontal(12);
|
||||||
} else if(index == data.length + 1) {
|
} else if(index == data.length + 1) {
|
||||||
return const SizedBox(height: 64,);
|
return const SizedBox(height: 64,);
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ import "package:window_manager/window_manager.dart";
|
|||||||
import "../components/page_route.dart";
|
import "../components/page_route.dart";
|
||||||
import "downloading_page.dart";
|
import "downloading_page.dart";
|
||||||
|
|
||||||
const _kAppBarHeight = 36.0;
|
double get _appBarHeight => App.isDesktop ? 36.0 : 48.0;
|
||||||
|
|
||||||
class MainPage extends StatefulWidget {
|
class MainPage extends StatefulWidget {
|
||||||
const MainPage({super.key});
|
const MainPage({super.key});
|
||||||
@@ -143,11 +143,14 @@ class _MainPageState extends State<MainPage> with WindowListener {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
paneBodyBuilder: (pane, child) => Navigator(
|
paneBodyBuilder: (pane, child) => NavigatorPopHandler(
|
||||||
key: navigatorKey,
|
key: const Key("navigator"),
|
||||||
onGenerateRoute: (settings) => AppPageRoute(
|
onPop: () => navigatorKey.currentState?.pop(),
|
||||||
builder: (context) => const RecommendationPage()),
|
child: Navigator(
|
||||||
)),
|
key: navigatorKey,
|
||||||
|
onGenerateRoute: (settings) => AppPageRoute(
|
||||||
|
builder: (context) => const RecommendationPage()),
|
||||||
|
))),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +179,7 @@ class _MainPageState extends State<MainPage> with WindowListener {
|
|||||||
BuildContext context, GlobalKey<NavigatorState> navigatorKey) {
|
BuildContext context, GlobalKey<NavigatorState> navigatorKey) {
|
||||||
return NavigationAppBar(
|
return NavigationAppBar(
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
height: _kAppBarHeight,
|
height: _appBarHeight,
|
||||||
title: () {
|
title: () {
|
||||||
if (!App.isDesktop) {
|
if (!App.isDesktop) {
|
||||||
return const Align(
|
return const Align(
|
||||||
@@ -198,9 +201,9 @@ class _MainPageState extends State<MainPage> with WindowListener {
|
|||||||
);
|
);
|
||||||
}(),
|
}(),
|
||||||
leading: _BackButton(navigatorKey),
|
leading: _BackButton(navigatorKey),
|
||||||
actions: WindowButtons(
|
actions: App.isDesktop ? WindowButtons(
|
||||||
key: ValueKey(windowButtonKey),
|
key: ValueKey(windowButtonKey),
|
||||||
),
|
) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,7 +301,7 @@ class WindowButtons extends StatelessWidget {
|
|||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 138,
|
width: 138,
|
||||||
height: _kAppBarHeight,
|
height: _appBarHeight,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
WindowButton(
|
WindowButton(
|
||||||
|
@@ -67,7 +67,7 @@ class _RankingPageState extends State<RankingPage> {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
).padding(const EdgeInsets.symmetric(vertical: 8, horizontal: 12));
|
).padding(const EdgeInsets.symmetric(vertical: 8, horizontal: 16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +85,7 @@ class _OneRankingPageState extends MultiPageLoadingState<_OneRankingPage, Illust
|
|||||||
Widget buildContent(BuildContext context, final List<Illust> data) {
|
Widget buildContent(BuildContext context, final List<Illust> data) {
|
||||||
return LayoutBuilder(builder: (context, constrains){
|
return LayoutBuilder(builder: (context, constrains){
|
||||||
return MasonryGridView.builder(
|
return MasonryGridView.builder(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
|
gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
|
||||||
maxCrossAxisExtent: 240,
|
maxCrossAxisExtent: 240,
|
||||||
),
|
),
|
||||||
|
@@ -35,20 +35,29 @@ class _RecommendationPageState extends State<RecommendationPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildTab() {
|
Widget buildTab() {
|
||||||
return SegmentedButton<int>(
|
return SizedBox(
|
||||||
options: [
|
child: Row(
|
||||||
SegmentedButtonOption(0, "Artworks".tl),
|
children: [
|
||||||
SegmentedButtonOption(1, "Users".tl),
|
Text("Explore".tl,
|
||||||
],
|
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),),
|
||||||
onPressed: (key) {
|
const Spacer(),
|
||||||
if(key != type) {
|
SegmentedButton<int>(
|
||||||
setState(() {
|
options: [
|
||||||
type = key;
|
SegmentedButtonOption(0, "Artworks".tl),
|
||||||
});
|
SegmentedButtonOption(1, "Users".tl),
|
||||||
}
|
],
|
||||||
},
|
onPressed: (key) {
|
||||||
value: type,
|
if(key != type) {
|
||||||
).padding(const EdgeInsets.symmetric(vertical: 8, horizontal: 8));
|
setState(() {
|
||||||
|
type = key;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: type,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
).paddingHorizontal(16).paddingBottom(4),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +74,7 @@ class _RecommendationArtworksPageState extends MultiPageLoadingState<_Recommenda
|
|||||||
Widget buildContent(BuildContext context, final List<Illust> data) {
|
Widget buildContent(BuildContext context, final List<Illust> data) {
|
||||||
return LayoutBuilder(builder: (context, constrains){
|
return LayoutBuilder(builder: (context, constrains){
|
||||||
return MasonryGridView.builder(
|
return MasonryGridView.builder(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
|
gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
|
||||||
maxCrossAxisExtent: 240,
|
maxCrossAxisExtent: 240,
|
||||||
),
|
),
|
||||||
|
@@ -58,6 +58,7 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ScaffoldPage(
|
return ScaffoldPage(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
content: Column(
|
content: Column(
|
||||||
children: [
|
children: [
|
||||||
buildSearchBar(),
|
buildSearchBar(),
|
||||||
@@ -171,6 +172,7 @@ class _TrendingTagsViewState extends LoadingState<_TrendingTagsView, List<Trendi
|
|||||||
@override
|
@override
|
||||||
Widget buildContent(BuildContext context, List<TrendingTag> data) {
|
Widget buildContent(BuildContext context, List<TrendingTag> data) {
|
||||||
return MasonryGridView.builder(
|
return MasonryGridView.builder(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
|
gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
|
||||||
maxCrossAxisExtent: 240,
|
maxCrossAxisExtent: 240,
|
||||||
),
|
),
|
||||||
|
@@ -77,6 +77,7 @@ class _UserInfoPageState extends LoadingState<UserInfoPage, UserDetails> {
|
|||||||
image: CachedImageProvider(data!.avatar),
|
image: CachedImageProvider(data!.avatar),
|
||||||
width: 64,
|
width: 64,
|
||||||
height: 64,
|
height: 64,
|
||||||
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),),
|
),),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
Reference in New Issue
Block a user