chore: some UI/UX to bottom nav bar navigation (#2190)

This commit is contained in:
ggurdin 2025-03-21 12:10:41 -04:00 committed by GitHub
parent 185595370e
commit bf102a33ef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 145 additions and 220 deletions

View file

@ -692,11 +692,14 @@ abstract class AppRoutes {
GoRouterState state,
Widget child,
) =>
FluffyThemes.isColumnMode(context)
? noTransitionPageBuilder(context, state, child)
: MaterialPage(
key: state.pageKey,
restorationId: state.pageKey.value,
child: child,
);
// #Pangea
noTransitionPageBuilder(context, state, child);
// FluffyThemes.isColumnMode(context)
// ? noTransitionPageBuilder(context, state, child)
// : MaterialPage(
// key: state.pageKey,
// restorationId: state.pageKey.value,
// child: child,
// );
// Pangea#
}

View file

@ -3,8 +3,6 @@
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
import 'package:fluffychat/pangea/activity_planner/activity_plan_request.dart';
@ -44,37 +42,6 @@ class ActivitySuggestionsAreaState extends State<ActivitySuggestionsArea> {
double get cardPadding => _isColumnMode ? 8.0 : 0.0;
double get cardWidth => _isColumnMode ? 225.0 : 150.0;
void _scrollToItem(int index) {
final viewportDimension = _scrollController.position.viewportDimension;
final double scrollOffset = _isColumnMode
? index * cardWidth - (viewportDimension / 2) + (cardWidth / 2)
: (index + 1) * (cardHeight + 8.0);
final maxScrollExtent = _scrollController.position.maxScrollExtent;
final safeOffset = scrollOffset.clamp(0.0, maxScrollExtent);
if (safeOffset == _scrollController.offset) {
return;
}
_scrollController.animateTo(
safeOffset,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
);
}
// void _scrollToNextItem(AxisDirection direction) {
// final currentOffset = _scrollController.offset;
// final scrollAmount = _isColumnMode ? cardWidth : cardHeight;
// _scrollController.animateTo(
// (direction == AxisDirection.left
// ? currentOffset - scrollAmount
// : currentOffset + scrollAmount)
// .clamp(0.0, _scrollController.position.maxScrollExtent),
// duration: FluffyThemes.animationDuration,
// curve: FluffyThemes.animationCurve,
// );
// }
Future<void> _setActivityItems() async {
final ActivityPlanRequest request = ActivityPlanRequest(
topic: "",
@ -91,17 +58,16 @@ class ActivitySuggestionsAreaState extends State<ActivitySuggestionsArea> {
);
final resp = await ActivitySearchRepo.get(request);
_activityItems.addAll(resp.activityPlans);
setState(() {});
if (mounted) setState(() {});
}
@override
Widget build(BuildContext context) {
final List<Widget> cards = _activityItems
.mapIndexed((i, activity) {
.map((activity) {
return ActivitySuggestionCard(
activity: activity,
onPressed: () {
_scrollToItem(i);
showDialog(
context: context,
builder: (context) {
@ -142,14 +108,13 @@ class ActivitySuggestionsAreaState extends State<ActivitySuggestionsArea> {
),
),
)
: SizedBox.expand(
child: SingleChildScrollView(
controller: _scrollController,
child: Wrap(
alignment: WrapAlignment.spaceEvenly,
runSpacing: 16.0,
children: cards,
),
: SizedBox(
width: MediaQuery.of(context).size.width,
child: Wrap(
alignment: WrapAlignment.spaceEvenly,
runSpacing: 16.0,
spacing: 4.0,
children: cards,
),
);
}

View file

@ -15,67 +15,72 @@ class SuggestionsPage extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
final isColumnMode = FluffyThemes.isColumnMode(context);
return Padding(
padding: EdgeInsets.symmetric(
horizontal: isColumnMode ? 36.0 : 8.0,
vertical: isColumnMode ? 24.0 : 8.0,
),
child: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (!isColumnMode) const LearningProgressIndicators(),
Padding(
padding: EdgeInsets.only(
left: isColumnMode ? 12.0 : 4.0,
right: isColumnMode ? 12.0 : 4.0,
top: 16.0,
bottom: 16.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
L10n.of(context).learnByTexting,
style: isColumnMode
? theme.textTheme.titleLarge
?.copyWith(fontWeight: FontWeight.bold)
: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
return SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: isColumnMode ? 36.0 : 4.0,
vertical: 16.0,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (!isColumnMode)
Padding(
padding:
EdgeInsets.symmetric(horizontal: isColumnMode ? 0 : 12.0),
child: const LearningProgressIndicators(),
),
Padding(
padding: EdgeInsets.only(
left: isColumnMode ? 12.0 : 4.0,
right: isColumnMode ? 12.0 : 4.0,
top: 16.0,
bottom: 16.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
L10n.of(context).learnByTexting,
style: isColumnMode
? theme.textTheme.titleLarge
?.copyWith(fontWeight: FontWeight.bold)
: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
Container(
decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(36.0),
),
padding: const EdgeInsets.symmetric(
vertical: 6.0,
horizontal: 10.0,
),
child: Row(
spacing: 8.0,
children: [
PangeaLogoSvg(
width: 16.0,
forceColor: theme.colorScheme.primary,
),
),
Container(
decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(36.0),
),
padding: const EdgeInsets.symmetric(
vertical: 6.0,
horizontal: 10.0,
),
child: Row(
spacing: 8.0,
children: [
PangeaLogoSvg(
width: 16.0,
forceColor: theme.colorScheme.primary,
),
Text(
AppConfig.applicationName,
style: theme.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.bold,
Text(
AppConfig.applicationName,
style: theme.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.bold,
),
),
),
],
],
),
),
),
],
],
),
),
),
const Flexible(
child: ActivitySuggestionsArea(),
),
],
const ActivitySuggestionsArea(),
],
),
),
),
);

View file

@ -113,44 +113,51 @@ class LearningProgressIndicatorsState
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () => context.go("/rooms/settings"),
child: Stack(
children: [
FutureBuilder<Profile>(
future: client.fetchOwnProfile(),
builder: (context, snapshot) => Stack(
alignment: Alignment.center,
children: [
Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(99),
child: Avatar(
mxContent: snapshot.data?.avatarUrl,
name: snapshot.data?.displayName ??
client.userID!.localpart,
size: 60,
child: Padding(
padding: const EdgeInsets.only(
bottom: 8.0,
right: 8.0,
),
child: Stack(
clipBehavior: Clip.none, // Allow overflow
children: [
FutureBuilder<Profile>(
future: client.fetchOwnProfile(),
builder: (context, snapshot) => Stack(
alignment: Alignment.center,
children: [
Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(99),
child: Avatar(
mxContent: snapshot.data?.avatarUrl,
name: snapshot.data?.displayName ??
client.userID!.localpart,
size: 60,
),
),
],
),
),
Positioned(
bottom: -3,
right: -3,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Theme.of(context).colorScheme.surfaceBright,
),
padding: const EdgeInsets.all(4.0),
child: Icon(
size: 14,
Icons.settings_outlined,
color: Theme.of(context).colorScheme.primary,
weight: 1000,
),
],
),
),
Positioned(
bottom: -3,
right: -3,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Theme.of(context).colorScheme.surfaceBright,
),
padding: const EdgeInsets.all(4.0),
child: Icon(
size: 14,
Icons.settings_outlined,
color: Theme.of(context).colorScheme.primary,
weight: 1000,
),
),
),
],
],
),
),
),
),

View file

@ -40,12 +40,6 @@ class BottomNavBarState extends State<BottomNavBar> {
return 1;
}
@override
void didUpdateWidget(covariant BottomNavBar oldWidget) {
super.didUpdateWidget(oldWidget);
debugPrint("didUpdateWidget");
}
void onItemTapped(int index) {
switch (index) {
case 0:
@ -65,87 +59,38 @@ class BottomNavBarState extends State<BottomNavBar> {
@override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(
color: Colors.white,
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Theme.of(context).colorScheme.primary.withAlpha(50),
),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
BottomNavItem(
controller: this,
icon: Icons.home,
child: BottomNavigationBar(
iconSize: 16.0,
onTap: onItemTapped,
selectedItemColor: Theme.of(context).colorScheme.primary,
selectedFontSize: 14.0,
unselectedFontSize: 14.0,
currentIndex: selectedIndex,
items: [
BottomNavigationBarItem(
icon: const Icon(Icons.home_outlined),
activeIcon: const Icon(Icons.home),
label: L10n.of(context).home,
index: 0,
),
BottomNavItem(
controller: this,
icon: Icons.chat_bubble_outline,
BottomNavigationBarItem(
icon: const Icon(Icons.chat_bubble_outline),
activeIcon: const Icon(Icons.chat_bubble),
label: L10n.of(context).chats,
index: 1,
),
BottomNavItem(
controller: this,
icon: Icons.settings,
BottomNavigationBarItem(
icon: const Icon(Icons.settings_outlined),
activeIcon: const Icon(Icons.settings),
label: L10n.of(context).settings,
index: 2,
),
],
),
);
}
}
class BottomNavItem extends StatelessWidget {
final BottomNavBarState controller;
final int index;
final IconData icon;
final String label;
const BottomNavItem({
required this.controller,
required this.index,
required this.icon,
required this.label,
super.key,
});
@override
Widget build(BuildContext context) {
final isSelected = controller.selectedIndex == index;
final theme = Theme.of(context);
return Expanded(
child: GestureDetector(
onTap: () => controller.onItemTapped(index),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 6.0,
),
decoration: BoxDecoration(
color: isSelected
? theme.colorScheme.primary
: theme.colorScheme.secondaryContainer,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon,
color: isSelected
? theme.colorScheme.onPrimary
: theme.colorScheme.onSecondaryContainer,
),
Text(
label,
style: TextStyle(
color: isSelected
? theme.colorScheme.onPrimary
: theme.colorScheme.onSecondaryContainer,
),
),
],
),
),
),
);
}
}