Merge pull request 'Fixes for Settings Page' (#123) from SEND011 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful

Reviewed-on: #123
Reviewed-by: tech <tech.sendico@proton.me>
This commit was merged in pull request #123.
This commit is contained in:
2025-12-22 19:26:44 +00:00
25 changed files with 1122 additions and 270 deletions

View File

@@ -0,0 +1,20 @@
import 'package:json_annotation/json_annotation.dart';
part 'username.g.dart';
@JsonSerializable()
class ResetUserNameRequest {
final String userName;
const ResetUserNameRequest({
required this.userName,
});
factory ResetUserNameRequest.fromJson(Map<String, dynamic> json) => _$ResetUserNameRequestFromJson(json);
Map<String, dynamic> toJson() => _$ResetUserNameRequestToJson(this);
static ResetUserNameRequest build({
required String userName,
}) => ResetUserNameRequest(userName: userName);
}

View File

@@ -228,6 +228,13 @@ class AccountProvider extends ChangeNotifier {
}
}
Future<Account?> resetUsername(String userName) async {
if (account == null) throw ErrorUnauthorized();
return update(
describable: account!.describable.copyWith(name: userName),
);
}
Future<void> forgotPassword(String email) async {
_setResource(_resource.copyWith(isLoading: true, error: null));
try {

View File

@@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
class ConfirmPasswordField extends StatelessWidget {
const ConfirmPasswordField({
required this.controller,
required this.fieldWidth,
required this.isEnabled,
required this.confirmPasswordLabel,
required this.newPasswordController,
required this.missingPasswordError,
required this.passwordsDoNotMatchError,
});
final TextEditingController controller;
final double fieldWidth;
final bool isEnabled;
final String confirmPasswordLabel;
final TextEditingController newPasswordController;
final String missingPasswordError;
final String passwordsDoNotMatchError;
@override
Widget build(BuildContext context) {
return SizedBox(
width: fieldWidth,
child: TextFormField(
controller: controller,
obscureText: true,
enabled: isEnabled,
decoration: InputDecoration(
labelText: confirmPasswordLabel,
border: const OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.isEmpty) return missingPasswordError;
if (value != newPasswordController.text) {
return passwordsDoNotMatchError;
}
return null;
},
),
);
}
}

View File

@@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
class PasswordField extends StatelessWidget {
const PasswordField({
required this.controller,
required this.labelText,
required this.fieldWidth,
required this.isEnabled,
required this.validator,
});
final TextEditingController controller;
final String labelText;
final double fieldWidth;
final bool isEnabled;
final String? Function(String?) validator;
@override
Widget build(BuildContext context) {
return SizedBox(
width: fieldWidth,
child: TextFormField(
controller: controller,
obscureText: true,
enabled: isEnabled,
decoration: InputDecoration(
labelText: labelText,
border: const OutlineInputBorder(),
),
validator: validator,
),
);
}
}

View File

@@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
import 'package:pshared/widgets/password/confirm_field.dart';
import 'package:pshared/widgets/password/field.dart';
class PasswordFields extends StatelessWidget {
const PasswordFields({
super.key,
required this.oldPasswordController,
required this.newPasswordController,
required this.confirmPasswordController,
required this.oldPasswordLabel,
required this.newPasswordLabel,
required this.confirmPasswordLabel,
required this.missingPasswordError,
required this.passwordsDoNotMatchError,
required this.fieldWidth,
required this.gapSmall,
required this.isEnabled,
});
final TextEditingController oldPasswordController;
final TextEditingController newPasswordController;
final TextEditingController confirmPasswordController;
final String oldPasswordLabel;
final String newPasswordLabel;
final String confirmPasswordLabel;
final String missingPasswordError;
final String passwordsDoNotMatchError;
final double fieldWidth;
final double gapSmall;
final bool isEnabled;
@override
Widget build(BuildContext context) {
return Column(
children: [
PasswordField(
controller: oldPasswordController,
labelText: oldPasswordLabel,
fieldWidth: fieldWidth,
isEnabled: isEnabled,
validator: (value) =>
(value == null || value.isEmpty) ? missingPasswordError : null,
),
SizedBox(height: gapSmall),
PasswordField(
controller: newPasswordController,
labelText: newPasswordLabel,
fieldWidth: fieldWidth,
isEnabled: isEnabled,
validator: (value) =>
(value == null || value.isEmpty) ? missingPasswordError : null,
),
SizedBox(height: gapSmall),
ConfirmPasswordField(
controller: confirmPasswordController,
fieldWidth: fieldWidth,
isEnabled: isEnabled,
confirmPasswordLabel: confirmPasswordLabel,
newPasswordController: newPasswordController,
missingPasswordError: missingPasswordError,
passwordsDoNotMatchError: passwordsDoNotMatchError,
),
],
);
}
}