redesign for settings page
This commit is contained in:
64
frontend/pweb/lib/pages/settings/profile/actions/body.dart
Normal file
64
frontend/pweb/lib/pages/settings/profile/actions/body.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pweb/controllers/settings/profile_actions.dart';
|
||||
import 'package:pweb/pages/settings/profile/actions/buttons.dart';
|
||||
import 'package:pweb/pages/settings/profile/actions/constants.dart';
|
||||
import 'package:pweb/pages/settings/profile/actions/content.dart';
|
||||
|
||||
|
||||
class ProfileActionsSectionBody extends StatelessWidget {
|
||||
const ProfileActionsSectionBody({
|
||||
super.key,
|
||||
required this.nameLabel,
|
||||
required this.languageLabel,
|
||||
required this.passwordLabel,
|
||||
required this.passwordSuccessText,
|
||||
required this.passwordErrorText,
|
||||
required this.oldPasswordLabel,
|
||||
required this.newPasswordLabel,
|
||||
required this.confirmPasswordLabel,
|
||||
required this.savePasswordLabel,
|
||||
});
|
||||
|
||||
final String nameLabel;
|
||||
final String languageLabel;
|
||||
final String passwordLabel;
|
||||
final String passwordSuccessText;
|
||||
final String passwordErrorText;
|
||||
final String oldPasswordLabel;
|
||||
final String newPasswordLabel;
|
||||
final String confirmPasswordLabel;
|
||||
final String savePasswordLabel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = context.watch<ProfileActionsController>();
|
||||
final expandedSection = controller.expandedSection;
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
ProfileActionButtons(
|
||||
nameLabel: nameLabel,
|
||||
languageLabel: languageLabel,
|
||||
passwordLabel: passwordLabel,
|
||||
),
|
||||
if (expandedSection != null) ...[
|
||||
const SizedBox(height: ProfileActionsLayoutConstants.contentGap),
|
||||
ProfileActionsContent(
|
||||
section: expandedSection,
|
||||
passwordSuccessText: passwordSuccessText,
|
||||
passwordErrorText: passwordErrorText,
|
||||
oldPasswordLabel: oldPasswordLabel,
|
||||
newPasswordLabel: newPasswordLabel,
|
||||
confirmPasswordLabel: confirmPasswordLabel,
|
||||
savePasswordLabel: savePasswordLabel,
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
63
frontend/pweb/lib/pages/settings/profile/actions/button.dart
Normal file
63
frontend/pweb/lib/pages/settings/profile/actions/button.dart
Normal file
@@ -0,0 +1,63 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
class ProfileActionButton extends StatelessWidget {
|
||||
const ProfileActionButton({
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.label,
|
||||
required this.isSelected,
|
||||
required this.onPressed,
|
||||
});
|
||||
|
||||
final IconData icon;
|
||||
final String label;
|
||||
final bool isSelected;
|
||||
final VoidCallback onPressed;
|
||||
|
||||
static const _buttonPadding = EdgeInsets.symmetric(
|
||||
horizontal: 28,
|
||||
vertical: 24,
|
||||
);
|
||||
static const _iconSize = 28.0;
|
||||
static const _contentGap = 12.0;
|
||||
static const _borderRadius = 16.0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final colorScheme = theme.colorScheme;
|
||||
final backgroundColor = colorScheme.onSecondary;
|
||||
final borderColor = isSelected
|
||||
? colorScheme.primary
|
||||
: colorScheme.onPrimary;
|
||||
final textColor = colorScheme.primary;
|
||||
|
||||
return TextButton(
|
||||
onPressed: onPressed,
|
||||
style: TextButton.styleFrom(
|
||||
padding: _buttonPadding,
|
||||
backgroundColor: backgroundColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(_borderRadius),
|
||||
side: BorderSide(color: borderColor),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(icon, color: textColor, size: _iconSize),
|
||||
const SizedBox(height: _contentGap),
|
||||
Text(
|
||||
label,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: textColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pweb/pages/settings/profile/actions/buttons_layout.dart';
|
||||
import 'package:pweb/pages/settings/profile/actions/language_button.dart';
|
||||
import 'package:pweb/pages/settings/profile/actions/name_button.dart';
|
||||
import 'package:pweb/pages/settings/profile/actions/password_button.dart';
|
||||
|
||||
|
||||
class ProfileActionButtons extends StatelessWidget {
|
||||
const ProfileActionButtons({
|
||||
super.key,
|
||||
required this.nameLabel,
|
||||
required this.languageLabel,
|
||||
required this.passwordLabel,
|
||||
});
|
||||
|
||||
final String nameLabel;
|
||||
final String languageLabel;
|
||||
final String passwordLabel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ProfileActionButtonsLayout(
|
||||
children: [
|
||||
ProfileNameActionButton(label: nameLabel),
|
||||
ProfileLanguageActionButton(label: languageLabel),
|
||||
ProfilePasswordActionButton(label: passwordLabel),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pweb/pages/settings/profile/actions/constants.dart';
|
||||
|
||||
|
||||
class ProfileActionButtonsLayout extends StatelessWidget {
|
||||
const ProfileActionButtonsLayout({super.key, required this.children});
|
||||
|
||||
final List<Widget> children;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final isCompact =
|
||||
constraints.maxWidth <
|
||||
ProfileActionsLayoutConstants.compactBreakpoint;
|
||||
|
||||
if (isCompact) {
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: ProfileActionsLayoutConstants.buttonWidth,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: _buildChildren(isCompact: true),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: _buildChildren(isCompact: false),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildChildren({required bool isCompact}) {
|
||||
return [
|
||||
for (var index = 0; index < children.length; index++) ...[
|
||||
SizedBox(
|
||||
width: isCompact
|
||||
? double.infinity
|
||||
: ProfileActionsLayoutConstants.buttonWidth,
|
||||
child: children[index],
|
||||
),
|
||||
if (index != children.length - 1)
|
||||
SizedBox(
|
||||
width: isCompact ? 0 : ProfileActionsLayoutConstants.buttonGap,
|
||||
height: isCompact ? ProfileActionsLayoutConstants.buttonGap : 0,
|
||||
),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class ProfileActionsLayoutConstants {
|
||||
static const buttonGap = 12.0;
|
||||
static const contentGap = 16.0;
|
||||
static const buttonWidth = 180.0;
|
||||
static const compactBreakpoint = buttonWidth * 3 + buttonGap * 2;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pweb/models/settings/profile_action_section.dart';
|
||||
import 'package:pweb/pages/settings/profile/account/locale.dart';
|
||||
import 'package:pweb/pages/settings/profile/account/password/password.dart';
|
||||
|
||||
|
||||
class ProfileActionsContent extends StatelessWidget {
|
||||
const ProfileActionsContent({
|
||||
super.key,
|
||||
required this.section,
|
||||
required this.passwordSuccessText,
|
||||
required this.passwordErrorText,
|
||||
required this.oldPasswordLabel,
|
||||
required this.newPasswordLabel,
|
||||
required this.confirmPasswordLabel,
|
||||
required this.savePasswordLabel,
|
||||
});
|
||||
|
||||
final ProfileActionSection section;
|
||||
final String passwordSuccessText;
|
||||
final String passwordErrorText;
|
||||
final String oldPasswordLabel;
|
||||
final String newPasswordLabel;
|
||||
final String confirmPasswordLabel;
|
||||
final String savePasswordLabel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (section) {
|
||||
case ProfileActionSection.language:
|
||||
return const LocalePicker();
|
||||
case ProfileActionSection.password:
|
||||
return AccountPassword(
|
||||
successText: passwordSuccessText,
|
||||
errorText: passwordErrorText,
|
||||
oldPasswordLabel: oldPasswordLabel,
|
||||
newPasswordLabel: newPasswordLabel,
|
||||
confirmPasswordLabel: confirmPasswordLabel,
|
||||
savePassword: savePasswordLabel,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pweb/controllers/settings/profile_actions.dart';
|
||||
import 'package:pweb/models/settings/profile_action_section.dart';
|
||||
import 'package:pweb/pages/settings/profile/actions/button.dart';
|
||||
|
||||
|
||||
class ProfileLanguageActionButton extends StatelessWidget {
|
||||
const ProfileLanguageActionButton({super.key, required this.label});
|
||||
|
||||
final String label;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = context.watch<ProfileActionsController>();
|
||||
|
||||
return ProfileActionButton(
|
||||
icon: Icons.language_outlined,
|
||||
label: label,
|
||||
isSelected: controller.isExpanded(ProfileActionSection.language),
|
||||
onPressed: () => controller.toggle(ProfileActionSection.language),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pweb/controllers/settings/profile_actions.dart';
|
||||
import 'package:pweb/pages/settings/profile/actions/button.dart';
|
||||
|
||||
|
||||
class ProfileNameActionButton extends StatelessWidget {
|
||||
const ProfileNameActionButton({super.key, required this.label});
|
||||
|
||||
final String label;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = context.watch<ProfileActionsController>();
|
||||
|
||||
return ProfileActionButton(
|
||||
icon: Icons.edit_outlined,
|
||||
label: label,
|
||||
isSelected: controller.isEditingName,
|
||||
onPressed: controller.toggleNameEditing,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pweb/controllers/settings/profile_actions.dart';
|
||||
import 'package:pweb/models/settings/profile_action_section.dart';
|
||||
import 'package:pweb/pages/settings/profile/actions/button.dart';
|
||||
|
||||
|
||||
class ProfilePasswordActionButton extends StatelessWidget {
|
||||
const ProfilePasswordActionButton({super.key, required this.label});
|
||||
|
||||
final String label;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = context.watch<ProfileActionsController>();
|
||||
|
||||
return ProfileActionButton(
|
||||
icon: Icons.lock_outline,
|
||||
label: label,
|
||||
isSelected: controller.isExpanded(ProfileActionSection.password),
|
||||
onPressed: () => controller.toggle(ProfileActionSection.password),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pweb/controllers/auth/account_name.dart';
|
||||
import 'package:pweb/controllers/settings/profile_actions.dart';
|
||||
import 'package:pweb/pages/settings/profile/actions/body.dart';
|
||||
|
||||
|
||||
class ProfileActionsSection extends StatelessWidget {
|
||||
const ProfileActionsSection({
|
||||
super.key,
|
||||
required this.nameLabel,
|
||||
required this.languageLabel,
|
||||
required this.passwordLabel,
|
||||
required this.passwordSuccessText,
|
||||
required this.passwordErrorText,
|
||||
required this.oldPasswordLabel,
|
||||
required this.newPasswordLabel,
|
||||
required this.confirmPasswordLabel,
|
||||
required this.savePasswordLabel,
|
||||
});
|
||||
|
||||
final String nameLabel;
|
||||
final String languageLabel;
|
||||
final String passwordLabel;
|
||||
final String passwordSuccessText;
|
||||
final String passwordErrorText;
|
||||
final String oldPasswordLabel;
|
||||
final String newPasswordLabel;
|
||||
final String confirmPasswordLabel;
|
||||
final String savePasswordLabel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ChangeNotifierProxyProvider<
|
||||
AccountNameController,
|
||||
ProfileActionsController
|
||||
>(
|
||||
create: (_) => ProfileActionsController(),
|
||||
update: (_, accountNameController, controller) =>
|
||||
controller!..updateAccountNameController(accountNameController),
|
||||
child: ProfileActionsSectionBody(
|
||||
nameLabel: nameLabel,
|
||||
languageLabel: languageLabel,
|
||||
passwordLabel: passwordLabel,
|
||||
passwordSuccessText: passwordSuccessText,
|
||||
passwordErrorText: passwordErrorText,
|
||||
oldPasswordLabel: oldPasswordLabel,
|
||||
newPasswordLabel: newPasswordLabel,
|
||||
confirmPasswordLabel: confirmPasswordLabel,
|
||||
savePasswordLabel: savePasswordLabel,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user