Better side navigation

🐛 Bug fixes and optimizations
This commit is contained in:
LittleSheep 2024-09-13 20:22:10 +08:00
parent dd01f964d4
commit b449735bf5
33 changed files with 212 additions and 182 deletions

View File

@ -391,5 +391,6 @@
"userLevel10": "Grandmaster",
"userLevel11": "Legend",
"userLevel12": "Mythic",
"userLevel13": "Immortal"
"userLevel13": "Immortal",
"postBrowsingIn": "Browsing in @region"
}

View File

@ -392,5 +392,6 @@
"userLevel10": "出神入化",
"userLevel11": "名垂千古",
"userLevel12": "独占鳌头",
"userLevel13": "万古流芳"
"userLevel13": "万古流芳",
"postBrowsingIn": "浏览 @region 内的帖子中"
}

View File

@ -155,13 +155,14 @@ class PostEditorController extends GetxController {
);
}
void localRead() {
SharedPreferences.getInstance().then((inst) {
if (inst.containsKey('post_editor_local_save')) {
isRestoreFromLocal.value = true;
payload = jsonDecode(inst.getString('post_editor_local_save')!);
}
});
Future<bool> localRead() async {
final inst = await SharedPreferences.getInstance();
if (inst.containsKey('post_editor_local_save')) {
isRestoreFromLocal.value = true;
payload = jsonDecode(inst.getString('post_editor_local_save')!);
return true;
}
return false;
}
void localClear() {

View File

@ -80,8 +80,8 @@ Future<void> _initializePlatformComponents() async {
}
final themeSwitcher = ThemeSwitcher(
lightThemeData: SolianTheme.build(Brightness.light),
darkThemeData: SolianTheme.build(Brightness.dark),
lightThemeData: AppTheme.build(Brightness.light),
darkThemeData: AppTheme.build(Brightness.dark),
);
class SolianApp extends StatelessWidget {

View File

@ -16,8 +16,8 @@ class ThemeSwitcher extends ChangeNotifier {
if (prefs.containsKey('global_theme_color')) {
final value = prefs.getInt('global_theme_color')!;
final color = Color(value);
lightThemeData = SolianTheme.build(Brightness.light, seedColor: color);
darkThemeData = SolianTheme.build(Brightness.dark, seedColor: color);
lightThemeData = AppTheme.build(Brightness.light, seedColor: color);
darkThemeData = AppTheme.build(Brightness.dark, seedColor: color);
notifyListeners();
}
}

View File

@ -154,6 +154,7 @@ abstract class AppRouter {
name: 'channelChat',
builder: (context, state) {
return ChannelChatScreen(
key: UniqueKey(),
alias: state.pathParameters['alias']!,
realm: state.uri.queryParameters['realm'] ?? 'global',
);

View File

@ -133,7 +133,7 @@ class _FriendScreenState extends State<FriendScreen>
).paddingAll(14),
),
SizedBox(
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
width: AppTheme.isLargeScreen(context) ? 8 : 16,
),
],
bottom: TabBar(

View File

@ -152,7 +152,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
SliverAppBar(
centerTitle: false,
floating: true,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
leadingWidth: 24,
automaticallyImplyLeading: false,
flexibleSpace: Row(
@ -207,7 +207,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
onPressed: null,
),
SizedBox(
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
width: AppTheme.isLargeScreen(context) ? 8 : 16,
),
],
),

View File

@ -205,7 +205,7 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
: AppBar(
leading: AppBarLeadingButton.adaptive(context),
centerTitle: true,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
title: Obx(
() => RichText(
textAlign: TextAlign.center,

View File

@ -217,8 +217,8 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
leading: AppBarLeadingButton.adaptive(context),
title: AppBarTitle(title),
centerTitle: false,
titleSpacing: SolianTheme.titleSpacing(context),
toolbarHeight: SolianTheme.toolbarHeight(context),
titleSpacing: AppTheme.titleSpacing(context),
toolbarHeight: AppTheme.toolbarHeight(context),
actions: [
const BackgroundStateWidget(),
Builder(builder: (context) {
@ -255,7 +255,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
},
),
SizedBox(
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
width: AppTheme.isLargeScreen(context) ? 8 : 16,
),
],
),
@ -276,7 +276,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
channel: _channel!,
ongoingCall: _ongoingCall!,
onJoin: () {
if (!SolianTheme.isLargeScreen(context)) {
if (!AppTheme.isLargeScreen(context)) {
final ChatCallProvider call = Get.find();
call.gotoScreen(context);
}
@ -337,7 +337,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
),
Obx(() {
final ChatCallProvider call = Get.find();
if (call.isMounted.value && SolianTheme.isLargeScreen(context)) {
if (call.isMounted.value && AppTheme.isLargeScreen(context)) {
return const Expanded(
child: Row(children: [
VerticalDivider(width: 0.3, thickness: 0.3),

View File

@ -110,7 +110,7 @@ class _ChannelOrganizeScreenState extends State<ChannelOrganizeScreen> {
appBar: AppBar(
title: AppBarTitle('channelOrganizing'.tr),
centerTitle: false,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
actions: [
TextButton(
onPressed: _isBusy ? null : () => applyChannel(),

View File

@ -47,7 +47,7 @@ class _ChatScreenState extends State<ChatScreen> {
leading: AppBarLeadingButton.adaptive(context),
title: AppBarTitle('chat'.tr),
centerTitle: true,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
actions: [
const BackgroundStateWidget(),
const NotificationButton(),
@ -95,7 +95,7 @@ class _ChatScreenState extends State<ChatScreen> {
],
),
SizedBox(
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
width: AppTheme.isLargeScreen(context) ? 8 : 16,
),
],
),

View File

@ -504,7 +504,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
/// Footer
Column(
mainAxisAlignment: SolianTheme.isLargeScreen(context)
mainAxisAlignment: AppTheme.isLargeScreen(context)
? MainAxisAlignment.start
: MainAxisAlignment.center,
children: [

View File

@ -85,13 +85,13 @@ class _FeedScreenState extends State<FeedScreen>
title: AppBarTitle('feed'.tr),
centerTitle: false,
floating: true,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
leading: AppBarLeadingButton.adaptive(context),
actions: [
const BackgroundStateWidget(),
const NotificationButton(),
SizedBox(
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
width: AppTheme.isLargeScreen(context) ? 8 : 16,
),
],
bottom: TabBar(
@ -118,7 +118,9 @@ class _FeedScreenState extends State<FeedScreen>
MaterialBanner(
leading: const Icon(Icons.layers),
content: Text(
'Browsing in realm #${navState.focusedRealm.value!.alias}',
'postBrowsingIn'.trParams({
'region': '#${navState.focusedRealm.value!.alias}',
}),
),
actions: const [SizedBox.shrink()],
),

View File

@ -61,10 +61,10 @@ class _DraftBoxScreenState extends State<DraftBoxScreen> {
leading: AppBarLeadingButton.adaptive(context),
title: AppBarTitle('draftBox'.tr),
centerTitle: false,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
actions: [
SizedBox(
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
width: AppTheme.isLargeScreen(context) ? 8 : 16,
),
],
),

View File

@ -11,6 +11,7 @@ import 'package:solian/models/post.dart';
import 'package:solian/models/realm.dart';
import 'package:solian/providers/attachment_uploader.dart';
import 'package:solian/providers/auth.dart';
import 'package:solian/providers/navigation.dart';
import 'package:solian/router.dart';
import 'package:solian/theme.dart';
import 'package:solian/widgets/app_bar_leading.dart';
@ -124,7 +125,12 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
void initState() {
super.initState();
if (widget.edit == null && widget.reply == null && widget.repost == null) {
_editorController.localRead();
_editorController.localRead().then((res) {
if (!res) {
final navState = Get.find<NavigationStateProvider>();
_editorController.realmZone.value = navState.focusedRealm.value;
}
});
}
if (widget.reply != null) {
_editorController.replyTo.value = widget.reply;
@ -158,7 +164,7 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
),
),
centerTitle: false,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
actions: [
TextButton(
onPressed: _isBusy ? null : () => _applyPost(),
@ -177,23 +183,19 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
children: [
ListTile(
tileColor: Theme.of(context).colorScheme.surfaceContainerLow,
title: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
Text(
_editorController.title ?? 'title'.tr,
maxLines: 1,
overflow: TextOverflow.ellipsis,
title: Row(
children: [
Text(
_editorController.title ?? 'title'.tr,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const Gap(6),
if (_editorController.aliasController.text.isNotEmpty)
Badge(
label: Text('#${_editorController.aliasController.text}'),
),
const Gap(6),
if (_editorController.aliasController.text.isNotEmpty)
Badge(
label:
Text('#${_editorController.aliasController.text}'),
),
],
),
],
),
subtitle: Text(
_editorController.description ?? 'description'.tr,
@ -365,12 +367,12 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
],
),
),
if (SolianTheme.isLargeScreen(context))
if (AppTheme.isLargeScreen(context))
const VerticalDivider(width: 0.3, thickness: 0.3)
.paddingSymmetric(
horizontal: 16,
),
if (SolianTheme.isLargeScreen(context))
if (AppTheme.isLargeScreen(context))
Expanded(
child: SingleChildScrollView(
child: MarkdownTextContent(

View File

@ -62,7 +62,7 @@ class _RealmListScreenState extends State<RealmListScreen> {
leading: AppBarLeadingButton.adaptive(context),
title: AppBarTitle('realm'.tr),
centerTitle: true,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
actions: [
const BackgroundStateWidget(),
const NotificationButton(),
@ -77,7 +77,7 @@ class _RealmListScreenState extends State<RealmListScreen> {
},
),
SizedBox(
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
width: AppTheme.isLargeScreen(context) ? 8 : 16,
),
],
),

View File

@ -102,7 +102,7 @@ class _RealmOrganizeScreenState extends State<RealmOrganizeScreen> {
leading: AppBarLeadingButton.adaptive(context),
title: AppBarTitle('realmOrganizing'.tr),
centerTitle: false,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
actions: [
TextButton(
onPressed: _isBusy ? null : () => applyRealm(),

View File

@ -114,7 +114,7 @@ class _RealmViewScreenState extends State<RealmViewScreen> {
},
),
SizedBox(
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
width: AppTheme.isLargeScreen(context) ? 8 : 16,
),
],
bottom: const TabBar(

View File

@ -33,11 +33,11 @@ class _SettingScreenState extends State<SettingScreen> {
tooltip: label,
onPressed: () {
context.read<ThemeSwitcher>().setTheme(
SolianTheme.build(
AppTheme.build(
Brightness.light,
seedColor: color,
),
SolianTheme.build(
AppTheme.build(
Brightness.dark,
seedColor: color,
),

View File

@ -25,7 +25,7 @@ class CenteredShell extends StatelessWidget {
leading: AppBarLeadingButton.adaptive(context),
title: AppBarTitle(state.topRoute?.name?.tr ?? 'page'.tr),
centerTitle: false,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
)
: null,
body: Center(

View File

@ -41,10 +41,10 @@ class RootShell extends StatelessWidget {
return Scaffold(
key: rootScaffoldKey,
drawer: SolianTheme.isLargeScreen(context)
drawer: AppTheme.isLargeScreen(context)
? null
: AppNavigationDrawer(routeName: routeName),
body: SolianTheme.isLargeScreen(context)
body: AppTheme.isLargeScreen(context)
? Row(
children: [
if (showNavigation) AppNavigationDrawer(routeName: routeName),

View File

@ -29,9 +29,9 @@ class SidebarShell extends StatelessWidget {
flex: 2,
child: child,
),
if (SolianTheme.isExtraLargeScreen(context))
if (AppTheme.isExtraLargeScreen(context))
const VerticalDivider(thickness: 0.3, width: 1),
if (SolianTheme.isExtraLargeScreen(context))
if (AppTheme.isExtraLargeScreen(context))
Flexible(
flex: 1,
child: sidebar ?? const SidebarPlaceholder(),
@ -47,10 +47,10 @@ class SidebarShell extends StatelessWidget {
leading: AppBarLeadingButton.adaptive(context),
title: AppBarTitle(state.topRoute?.name?.tr ?? 'page'.tr),
centerTitle: false,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
)
: null,
body: SolianTheme.isLargeScreen(context)
body: AppTheme.isLargeScreen(context)
? Row(
children: sidebarFirst
? buildContent(context).reversed.toList()

View File

@ -32,11 +32,11 @@ class TitleShell extends StatelessWidget {
title ?? (state!.topRoute?.name?.tr ?? 'page'.tr),
),
centerTitle: isCenteredTitle,
toolbarHeight: SolianTheme.toolbarHeight(context),
toolbarHeight: AppTheme.toolbarHeight(context),
actions: [
const BackgroundStateWidget(),
SizedBox(
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
width: AppTheme.isLargeScreen(context) ? 8 : 16,
),
],
)

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:solian/platform.dart';
abstract class SolianTheme {
abstract class AppTheme {
static bool isLargeScreen(BuildContext context) =>
MediaQuery.of(context).size.width > 640;
@ -9,13 +9,13 @@ abstract class SolianTheme {
MediaQuery.of(context).size.width > 720;
static bool isSpecializedMacOS(BuildContext context) =>
PlatformInfo.isMacOS && !SolianTheme.isLargeScreen(context);
PlatformInfo.isMacOS && !AppTheme.isLargeScreen(context);
static double? titleSpacing(BuildContext context) {
if (SolianTheme.isSpecializedMacOS(context)) {
if (AppTheme.isSpecializedMacOS(context)) {
return 24;
} else {
return SolianTheme.isLargeScreen(context) ? null : 24;
return AppTheme.isLargeScreen(context) ? null : 24;
}
}

View File

@ -8,7 +8,7 @@ class AppBarTitle extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (SolianTheme.isSpecializedMacOS(context)) {
if (AppTheme.isSpecializedMacOS(context)) {
return Text(title);
} else {
return Text(title);

View File

@ -98,12 +98,12 @@ class ChannelCallIndicator extends StatelessWidget {
child: Text('callJoin'.tr),
);
} else if (call.channel.value?.id == channel.id &&
!SolianTheme.isLargeScreen(context)) {
!AppTheme.isLargeScreen(context)) {
return TextButton(
onPressed: () => onJoin(),
child: Text('callResume'.tr),
);
} else if (!SolianTheme.isLargeScreen(context)) {
} else if (!AppTheme.isLargeScreen(context)) {
return TextButton(
onPressed: null,
child: Text('callJoin'.tr),

View File

@ -11,6 +11,7 @@ class ChannelListWidget extends StatefulWidget {
final List<Channel> channels;
final int selfId;
final bool isDense;
final bool isCollapsed;
final bool noCategory;
final bool useReplace;
final Function(Channel)? onSelected;
@ -20,6 +21,7 @@ class ChannelListWidget extends StatefulWidget {
required this.channels,
required this.selfId,
this.isDense = false,
this.isCollapsed = false,
this.noCategory = false,
this.useReplace = false,
this.onSelected,
@ -130,13 +132,25 @@ class _ChannelListWidgetState extends State<ChannelListWidget> {
final otherside =
item.members!.where((e) => e.account.id != widget.selfId).first;
final avatar = AccountAvatar(
content: otherside.account.avatar,
radius: widget.isDense ? 12 : 20,
bgColor: Theme.of(context).colorScheme.primary,
feColor: Theme.of(context).colorScheme.onPrimary,
);
if (widget.isCollapsed) {
return Tooltip(
message: otherside.account.nick,
child: InkWell(
child: avatar.paddingSymmetric(vertical: 12),
onTap: () => _gotoChannel(item),
),
);
}
return ListTile(
leading: AccountAvatar(
content: otherside.account.avatar,
radius: widget.isDense ? 12 : 20,
bgColor: Theme.of(context).colorScheme.primary,
feColor: Theme.of(context).colorScheme.onPrimary,
),
leading: avatar,
contentPadding: padding,
title: Text(otherside.account.nick),
subtitle: !widget.isDense
@ -145,21 +159,33 @@ class _ChannelListWidgetState extends State<ChannelListWidget> {
onTap: () => _gotoChannel(item),
);
} else {
final avatar = CircleAvatar(
backgroundColor: item.realmId == null
? Theme.of(context).colorScheme.primary
: Colors.transparent,
radius: widget.isDense ? 12 : 20,
child: FaIcon(
FontAwesomeIcons.hashtag,
color: item.realmId == null
? Theme.of(context).colorScheme.onPrimary
: Theme.of(context).colorScheme.primary,
size: widget.isDense ? 12 : 16,
),
);
if (widget.isCollapsed) {
return Tooltip(
message: item.name,
child: InkWell(
child: avatar.paddingSymmetric(vertical: 12),
onTap: () => _gotoChannel(item),
),
);
}
return ListTile(
minTileHeight: widget.isDense ? 48 : null,
leading: CircleAvatar(
backgroundColor: item.realmId == null
? Theme.of(context).colorScheme.primary
: Colors.transparent,
radius: widget.isDense ? 12 : 20,
child: FaIcon(
FontAwesomeIcons.hashtag,
color: item.realmId == null
? Theme.of(context).colorScheme.onPrimary
: Theme.of(context).colorScheme.primary,
size: widget.isDense ? 12 : 16,
),
),
leading: avatar,
contentPadding: padding,
title: Text(item.name),
subtitle: !widget.isDense

View File

@ -75,9 +75,6 @@ class ChatEvent extends StatelessWidget {
key: Key('m${item.uuid}attachments-box'),
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.only(top: isMerged ? 0 : 4, bottom: 4),
constraints: const BoxConstraints(
maxHeight: 720,
),
child: AttachmentList(
key: Key('m${item.uuid}attachments'),
parentId: item.uuid,
@ -301,7 +298,10 @@ class ChatEvent extends StatelessWidget {
],
).paddingSymmetric(horizontal: 12),
_buildLinkExpansion().paddingOnly(left: 52, right: 8),
_buildAttachment(context).paddingOnly(left: 56, right: 8),
_buildAttachment(
context,
isMinimal: ['messages.edit'].contains(item.type),
).paddingOnly(left: 56, right: 8),
],
);
}

View File

@ -245,7 +245,8 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
_editTo = widget.edit!;
_textController.text = body.text;
_attachments.addAll(
widget.edit!.body['attachments']?.cast<int>() ?? List.empty());
widget.edit!.body['attachments']?.cast<String>() ?? List.empty(),
);
}
if (widget.reply != null) {
_replyTo = widget.reply!;

View File

@ -192,9 +192,9 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer>
}
void _autoResize() {
if (SolianTheme.isExtraLargeScreen(context)) {
if (AppTheme.isExtraLargeScreen(context)) {
_expandDrawer();
} else if (SolianTheme.isLargeScreen(context)) {
} else if (AppTheme.isLargeScreen(context)) {
_collapseDrawer();
} else {
_drawerAnimationController.value = 1;
@ -229,7 +229,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer>
return Drawer(
width: _drawerAnimation.value,
backgroundColor:
SolianTheme.isLargeScreen(context) ? Colors.transparent : null,
AppTheme.isLargeScreen(context) ? Colors.transparent : null,
child: child,
);
},
@ -247,20 +247,20 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer>
alignment: WrapAlignment.spaceAround,
children: AppNavigation.destinations
.map(
(e) => Card(
elevation: 0,
margin: EdgeInsets.zero,
child: Tooltip(
message: e.label,
child: InkWell(
borderRadius:
const BorderRadius.all(Radius.circular(8)),
child: Icon(e.icon, size: 20).paddingAll(20),
onTap: () {
AppRouter.instance.goNamed(e.page);
_closeDrawer();
},
),
(e) => Tooltip(
message: e.label,
child: InkWell(
borderRadius:
const BorderRadius.all(Radius.circular(8)),
child: Icon(
e.icon,
size: 22,
color: Theme.of(context).colorScheme.onSurface,
).paddingAll(16),
onTap: () {
AppRouter.instance.goNamed(e.page);
_closeDrawer();
},
),
),
)

View File

@ -20,62 +20,42 @@ class AppNavigationRegion extends StatefulWidget {
State<AppNavigationRegion> createState() => _AppNavigationRegionState();
}
class _AppNavigationRegionState extends State<AppNavigationRegion>
with SingleTickerProviderStateMixin {
class _AppNavigationRegionState extends State<AppNavigationRegion> {
bool _isTryingExit = false;
late final AnimationController _animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 250),
);
late final Animation<Offset> _animationTween = Tween<Offset>(
begin: Offset.zero,
end: const Offset(1.0, 0.0),
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.fastOutSlowIn,
));
void _focusRealm(Realm item) {
_animationController.animateTo(1).then((_) {
setState(
() => Get.find<NavigationStateProvider>().focusedRealm.value = item,
);
_animationController.animateTo(0);
});
setState(
() => Get.find<NavigationStateProvider>().focusedRealm.value = item,
);
}
void _unFocusRealm() {
_animationController.animateTo(1).then((_) {
setState(
() => Get.find<NavigationStateProvider>().focusedRealm.value = null,
);
_animationController.animateTo(0);
});
setState(
() => Get.find<NavigationStateProvider>().focusedRealm.value = null,
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
Widget _buildRealmFocusAvatar() {
final focusedRealm = Get.find<NavigationStateProvider>().focusedRealm.value;
return MouseRegion(
child: AnimatedSwitcher(
switchInCurve: Curves.fastOutSlowIn,
switchOutCurve: Curves.fastOutSlowIn,
duration: const Duration(milliseconds: 300),
transitionBuilder: (child, animation) {
return ScaleTransition(
scale: animation,
child: child,
);
},
child: _isTryingExit
? GestureDetector(
child: CircleAvatar(
return GestureDetector(
child: MouseRegion(
child: AnimatedSwitcher(
switchInCurve: Curves.fastOutSlowIn,
switchOutCurve: Curves.fastOutSlowIn,
duration: const Duration(milliseconds: 300),
transitionBuilder: (child, animation) {
return ScaleTransition(
scale: animation,
child: child,
);
},
child: _isTryingExit
? CircleAvatar(
backgroundColor: Theme.of(context).colorScheme.primary,
child: const Icon(
Icons.arrow_back,
@ -84,13 +64,13 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
),
).paddingSymmetric(
vertical: 8,
),
onTap: () => _unFocusRealm(),
)
: _buildEntryAvatar(focusedRealm!),
)
: _buildEntryAvatar(focusedRealm!),
),
onEnter: (_) => setState(() => _isTryingExit = true),
onExit: (_) => setState(() => _isTryingExit = false),
),
onEnter: (_) => setState(() => _isTryingExit = true),
onExit: (_) => setState(() => _isTryingExit = false),
onTap: () => _unFocusRealm(),
);
}
@ -113,11 +93,11 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
}
Widget _buildEntry(BuildContext context, Realm item) {
const padding = EdgeInsets.symmetric(horizontal: 20);
const padding = EdgeInsets.symmetric(horizontal: 20, vertical: 8);
if (widget.isCollapsed) {
return InkWell(
child: _buildEntryAvatar(item),
child: _buildEntryAvatar(item).paddingSymmetric(vertical: 8),
onTap: () => _focusRealm(item),
);
}
@ -144,19 +124,27 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
final NavigationStateProvider navState = Get.find();
return Obx(
() => AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
() => AnimatedSwitcher(
switchInCurve: Curves.fastOutSlowIn,
switchOutCurve: Curves.fastOutSlowIn,
duration: const Duration(milliseconds: 300),
transitionBuilder: (child, animation) {
return SlideTransition(
position: _animationTween,
child: child,
position: Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: Material(
color: Theme.of(context).colorScheme.surface,
child: child,
),
);
},
child: navState.focusedRealm.value == null
? widget.isCollapsed
? CustomScrollView(
slivers: [
const SliverPadding(padding: EdgeInsets.only(top: 8)),
const SliverPadding(padding: EdgeInsets.only(top: 16)),
SliverList.builder(
itemCount: realms.availableRealms.length,
itemBuilder: (context, index) {
@ -171,7 +159,6 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
)
: CustomScrollView(
slivers: [
const SliverPadding(padding: EdgeInsets.only(top: 8)),
SliverList.builder(
itemCount: realms.availableRealms.length,
itemBuilder: (context, index) {
@ -179,7 +166,6 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
return _buildEntry(context, element);
},
),
const SliverPadding(padding: EdgeInsets.only(bottom: 8)),
],
)
: Column(
@ -187,8 +173,9 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
if (widget.isCollapsed)
Tooltip(
message: navState.focusedRealm.value!.name,
child: _buildRealmFocusAvatar().paddingSymmetric(
vertical: 8,
child: _buildRealmFocusAvatar().paddingOnly(
top: 24,
bottom: 8,
),
)
else
@ -209,13 +196,12 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
Expanded(
child: Obx(
() => ChannelListWidget(
useReplace: true,
channels: channels.availableChannels
.where(
(x) =>
x.realm?.id ==
navState.focusedRealm.value?.id,
)
.where((x) =>
x.realm?.id == navState.focusedRealm.value?.id)
.toList(),
isCollapsed: widget.isCollapsed,
selfId: auth.userProfile.value!['id'],
noCategory: true,
),

View File

@ -8,6 +8,7 @@ import 'package:intl/intl.dart';
import 'package:solian/models/post.dart';
import 'package:solian/screens/posts/post_detail.dart';
import 'package:solian/shells/title_shell.dart';
import 'package:solian/theme.dart';
import 'package:solian/widgets/account/account_avatar.dart';
import 'package:solian/widgets/account/account_profile_popup.dart';
import 'package:solian/widgets/attachments/attachment_list.dart';
@ -302,7 +303,7 @@ class _PostItemState extends State<PostItem> {
autoload: false,
isGrid: true,
).paddingOnly(left: 36, top: 4, bottom: 4);
} else if (attachments.length > 1) {
} else if (attachments.length > 1 || AppTheme.isLargeScreen(context)) {
return AttachmentList(
parentId: widget.item.id.toString(),
attachmentsId: attachments,
@ -497,7 +498,10 @@ class _PostItemState extends State<PostItem> {
],
).paddingOnly(
top: 10,
bottom: attachments.length == 1 ? 10 : 0,
bottom:
(attachments.length == 1 && !AppTheme.isLargeScreen(context))
? 10
: 0,
right: 16,
left: 16,
),
@ -514,8 +518,13 @@ class _PostItemState extends State<PostItem> {
});
},
).paddingOnly(
top: attachments.length == 1 ? 10 : 6,
left: attachments.length == 1 ? 24 : 60,
top: (attachments.length == 1 && !AppTheme.isLargeScreen(context))
? 10
: 6,
left:
(attachments.length == 1 && !AppTheme.isLargeScreen(context))
? 24
: 60,
right: 16,
bottom: 10,
)