Fix settings button and dialog tab buttons

- Change 'Settings' button to 'Manage' with proper icon visibility
- Only show Manage button when in an organization (selectedOrg != null)
- Replace TabBar with custom animated tab buttons that match app styling
- Add smooth animations and visual feedback to tab buttons
- Maintain consistent splash effects across the dialog
This commit is contained in:
Leon Bösche
2026-01-24 00:00:04 +01:00
parent e10e499b6c
commit 48c9c19a64
2 changed files with 103 additions and 52 deletions

View File

@@ -493,28 +493,35 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
if (!isLoggedIn) { if (!isLoggedIn) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return Row( return BlocBuilder<OrganizationBloc, OrganizationState>(
mainAxisSize: MainAxisSize.min, builder: (context, orgState) {
children: [ final hasSelectedOrg = orgState is OrganizationLoaded && orgState.selectedOrg != null;
_buildNavButton('Drive', Icons.cloud), return Row(
const SizedBox(width: 16), mainAxisSize: MainAxisSize.min,
_buildNavButton('Mail', Icons.mail), children: [
const SizedBox(width: 16), _buildNavButton('Drive', Icons.cloud),
_buildNavButton('Add', Icons.add), const SizedBox(width: 16),
const SizedBox(width: 16), _buildNavButton('Mail', Icons.mail),
_buildNavButton( const SizedBox(width: 16),
'Settings', _buildNavButton('Add', Icons.add),
Icons.settings, const SizedBox(width: 16),
onTap: () => if (hasSelectedOrg)
_showOrganizationSettings(context), _buildNavButton(
), 'Manage',
const SizedBox(width: 16), Icons.settings,
_buildNavButton( onTap: () =>
'Profile', _showOrganizationSettings(context),
Icons.person, ),
isAvatar: true, if (hasSelectedOrg)
), const SizedBox(width: 16),
], _buildNavButton(
'Profile',
Icons.person,
isAvatar: true,
),
],
);
},
); );
}, },
), ),

View File

@@ -25,9 +25,8 @@ class OrganizationSettingsDialog extends StatefulWidget {
_OrganizationSettingsDialogState(); _OrganizationSettingsDialogState();
} }
class _OrganizationSettingsDialogState extends State<OrganizationSettingsDialog> class _OrganizationSettingsDialogState extends State<OrganizationSettingsDialog> {
with TickerProviderStateMixin { int _selectedTabIndex = 0;
late TabController _tabController;
List<Member> _members = []; List<Member> _members = [];
List<Invitation> _invitations = []; List<Invitation> _invitations = [];
List<JoinRequest> _joinRequests = []; List<JoinRequest> _joinRequests = [];
@@ -39,16 +38,9 @@ class _OrganizationSettingsDialogState extends State<OrganizationSettingsDialog>
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_tabController = TabController(length: 4, vsync: this);
_loadData(); _loadData();
} }
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
Future<void> _loadData() async { Future<void> _loadData() async {
if (!mounted) return; if (!mounted) return;
setState(() => _isLoading = true); setState(() => _isLoading = true);
@@ -226,18 +218,14 @@ class _OrganizationSettingsDialogState extends State<OrganizationSettingsDialog>
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
// Tabs // Custom Tabs
TabBar( Row(
controller: _tabController, children: [
tabs: const [ _buildTabButton('Members', 0),
Tab(text: 'Members'), _buildTabButton('Invite', 1),
Tab(text: 'Invite'), _buildTabButton('Requests', 2),
Tab(text: 'Requests'), _buildTabButton('Link', 3),
Tab(text: 'Link'),
], ],
labelColor: AppTheme.accentColor,
unselectedLabelColor: AppTheme.secondaryText,
indicatorColor: AppTheme.accentColor,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
@@ -262,15 +250,7 @@ class _OrganizationSettingsDialogState extends State<OrganizationSettingsDialog>
], ],
), ),
) )
: TabBarView( : _buildTabContent(),
controller: _tabController,
children: [
_buildMembersTab(),
_buildInviteTab(),
_buildRequestsTab(),
_buildLinkTab(),
],
),
), ),
], ],
), ),
@@ -278,6 +258,70 @@ class _OrganizationSettingsDialogState extends State<OrganizationSettingsDialog>
); );
} }
Widget _buildTabButton(String text, int index) {
final isSelected = _selectedTabIndex == index;
return Expanded(
child: GestureDetector(
onTap: () => setState(() => _selectedTabIndex = index),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
margin: const EdgeInsets.symmetric(horizontal: 2),
decoration: BoxDecoration(
color: isSelected
? AppTheme.accentColor.withValues(alpha: 0.15)
: Colors.transparent,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isSelected
? AppTheme.accentColor
: AppTheme.secondaryText.withValues(alpha: 0.3),
width: 1.5,
),
boxShadow: isSelected
? [
BoxShadow(
color: AppTheme.accentColor.withValues(alpha: 0.3),
blurRadius: 8,
spreadRadius: 1,
),
]
: null,
),
child: AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 200),
style: TextStyle(
color: isSelected
? AppTheme.accentColor
: AppTheme.secondaryText,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
fontSize: 14,
),
child: Text(
text,
textAlign: TextAlign.center,
),
),
),
),
);
}
Widget _buildTabContent() {
switch (_selectedTabIndex) {
case 0:
return _buildMembersTab();
case 1:
return _buildInviteTab();
case 2:
return _buildRequestsTab();
case 3:
return _buildLinkTab();
default:
return _buildMembersTab();
}
}
Widget _buildMembersTab() { Widget _buildMembersTab() {
return ListView.builder( return ListView.builder(
itemCount: _members.length, itemCount: _members.length,