Skip to content

Commit

Permalink
feat: add last name (#1287)
Browse files Browse the repository at this point in the history
  • Loading branch information
ookami-kb authored Feb 26, 2024
1 parent b76e134 commit e41bd28
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 70 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:dfunc/dfunc.dart';
import 'package:flutter/foundation.dart';
import 'package:injectable/injectable.dart';
import 'package:shared_preferences/shared_preferences.dart';
Expand All @@ -11,12 +12,27 @@ class ProfileRepository extends ChangeNotifier {
final SharedPreferences _sharedPreferences;

bool get hasAllRequiredFields =>
firstName.isNotEmpty && email.isNotEmpty && country != null;
firstName.isNotEmpty &&
lastName.isNotEmpty &&
email.isNotEmpty &&
country != null;

String get firstName => _sharedPreferences.getString(nameKey) ?? '';
String get fullName => '$firstName $lastName';

String get initials =>
(substring(firstName, 0, 1) + substring(lastName, 0, 1)).toUpperCase();

String get firstName => _sharedPreferences.getString(firstNameKey) ?? '';

set firstName(String value) {
_sharedPreferences.setString(nameKey, value);
_sharedPreferences.setString(firstNameKey, value);
notifyListeners();
}

String get lastName => _sharedPreferences.getString(lastNameKey) ?? '';

set lastName(String value) {
_sharedPreferences.setString(lastNameKey, value);
notifyListeners();
}

Expand Down Expand Up @@ -53,15 +69,17 @@ class ProfileRepository extends ChangeNotifier {
@disposeMethod
void dispose() {
_sharedPreferences
..remove(nameKey)
..remove(firstNameKey)
..remove(lastNameKey)
..remove(photoKey)
..remove(countryKey)
..remove(emailKey);
super.dispose();
}
}

const nameKey = 'name';
const firstNameKey = 'name';
const lastNameKey = 'lastName';
const photoKey = 'photo';
const countryKey = 'country';
const emailKey = 'email';
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,21 @@ class ManageProfileScreen extends StatefulWidget {
const ManageProfileScreen({
super.key,
required this.onSubmitted,
this.hasBackButton = true,
});

static const route = ManageProfileRoute.new;

final VoidCallback onSubmitted;
final bool hasBackButton;

@override
State<ManageProfileScreen> createState() => _ManageProfileScreenState();
}

class _ManageProfileScreenState extends State<ManageProfileScreen> {
final _nameController = TextEditingController();
final _firstNameController = TextEditingController();
final _lastNameController = TextEditingController();
final _emailController = TextEditingController();
Country? _country;
File? _photo;
Expand All @@ -51,7 +54,8 @@ class _ManageProfileScreenState extends State<ManageProfileScreen> {

final repository = sl<ProfileRepository>();

_nameController.text = repository.firstName;
_firstNameController.text = repository.firstName;
_lastNameController.text = repository.lastName;
_emailController.text = repository.email;

_photo = repository.photoPath?.let(File.new);
Expand All @@ -64,7 +68,8 @@ class _ManageProfileScreenState extends State<ManageProfileScreen> {

@override
void dispose() {
_nameController.dispose();
_firstNameController.dispose();
_lastNameController.dispose();
_emailController.dispose();
super.dispose();
}
Expand All @@ -86,7 +91,8 @@ class _ManageProfileScreenState extends State<ManageProfileScreen> {
}

sl<ProfileRepository>()
..firstName = _nameController.text
..firstName = _firstNameController.text
..lastName = _lastNameController.text
..country = _country?.code
..photoPath = photo?.path
..email = _emailController.text;
Expand All @@ -97,22 +103,27 @@ class _ManageProfileScreenState extends State<ManageProfileScreen> {
);

bool get _isValid =>
_nameController.text.isNotEmpty &&
_firstNameController.text.isNotEmpty &&
_lastNameController.text.isNotEmpty &&
_emailController.text.isValidEmail &&
_country != null;

@override
Widget build(BuildContext context) => CpTheme.black(
child: Scaffold(
appBar: CpAppBar(
leading: CpBackButton(
onPressed: () => context.router.pop(),
),
leading: widget.hasBackButton
? CpBackButton(onPressed: () => context.router.pop())
: null,
),
extendBodyBehindAppBar: true,
body: OnboardingScreen(
footer: ListenableBuilder(
listenable: Listenable.merge([_nameController, _emailController]),
listenable: Listenable.merge([
_firstNameController,
_lastNameController,
_emailController,
]),
builder: (context, child) => OnboardingFooterButton(
text: context.l10n.save,
onPressed: _isValid ? _handleSubmitted : null,
Expand All @@ -122,7 +133,6 @@ class _ManageProfileScreenState extends State<ManageProfileScreen> {
SizedBox(height: MediaQuery.paddingOf(context).top + 24),
ProfileImagePicker(
photo: _photo,
label: context.l10n.uploadPhoto,
onChanged: (File? value) => setState(() => _photo = value),
),
const SizedBox(height: 32),
Expand All @@ -135,11 +145,30 @@ class _ManageProfileScreenState extends State<ManageProfileScreen> {
vertical: 16,
),
placeholder: context.l10n.yourFirstNamePlaceholder,
controller: _nameController,
controller: _firstNameController,
textColor: Colors.white,
placeholderColor: _placeholderTextColor,
backgroundColor: CpColors.blackTextFieldBackgroundColor,
fontSize: 16,
inputType: TextInputType.name,
textCapitalization: TextCapitalization.words,
),
),
OnboardingPadding(
child: CpTextField(
margin: const EdgeInsets.only(top: 16),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 16,
),
placeholder: context.l10n.yourLastNamePlaceholder,
controller: _lastNameController,
textColor: Colors.white,
placeholderColor: _placeholderTextColor,
backgroundColor: CpColors.blackTextFieldBackgroundColor,
fontSize: 16,
inputType: TextInputType.name,
textCapitalization: TextCapitalization.words,
),
),
OnboardingPadding(
Expand All @@ -155,6 +184,7 @@ class _ManageProfileScreenState extends State<ManageProfileScreen> {
placeholderColor: _placeholderTextColor,
backgroundColor: CpColors.blackTextFieldBackgroundColor,
fontSize: 16,
inputType: TextInputType.emailAddress,
),
),
const SizedBox(height: 12),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ class ProfileScreen extends StatelessWidget {
(it) => FileImage(File(it)),
),
userName: sl<ProfileRepository>()
.firstName
.orDefault,
.initials
.ifEmpty(() => 'MW'),
),
),
),
Expand All @@ -86,7 +86,9 @@ class ProfileScreen extends StatelessWidget {
child: ListenableBuilder(
listenable: sl<ProfileRepository>(),
builder: (context, child) => Text(
sl<ProfileRepository>().firstName.orDefault,
sl<ProfileRepository>()
.fullName
.ifEmpty(() => 'My Wallet'),
style: Theme.of(context).textTheme.displaySmall,
),
),
Expand Down Expand Up @@ -124,10 +126,6 @@ class ProfileScreen extends StatelessWidget {
}
}

extension on String {
String get orDefault => ifEmpty(() => 'My Wallet');
}

const double _buttonSpacing = 22;
const double _imageSize = 88;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,11 @@ class ProfileImagePicker extends StatefulWidget {
const ProfileImagePicker({
super.key,
required this.onChanged,
required this.label,
this.onLabelClicked,
this.labelStyle,
this.photo,
});

final TextStyle? labelStyle;
final ValueSetter<File?> onChanged;
final VoidCallback? onLabelClicked;
final File? photo;
final String label;

@override
State<ProfileImagePicker> createState() => _ProfileImagePickerState();
Expand Down Expand Up @@ -98,8 +92,5 @@ class _ProfileImagePickerState extends State<ProfileImagePicker> {
Widget build(BuildContext context) => PickImageContainer(
image: widget.photo,
pickImageClicked: () => _showPicker(context),
labelStyle: widget.labelStyle,
label: widget.label,
onLabelClicked: widget.onLabelClicked,
);
}
6 changes: 3 additions & 3 deletions packages/espressocash_app/lib/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -787,8 +787,6 @@
}
}
},
"uploadPhoto": "Upload A Photo",
"@uploadPhoto": {},
"usdcExplanation": "The USD Coin (USDC) is a digital stablecoin that should be fixed to the United States dollar.",
"@usdcExplanation": {},
"usdcInfo": "The US Dollar Coin (USDC) is a digital stablecoin that should be fixed to the United States dollar. ($1 = 1USDC)",
Expand Down Expand Up @@ -838,8 +836,10 @@
"@yourEmailDisclaimer": {},
"yourEmailPlaceholder": "Email Address",
"@yourEmailPlaceholder": {},
"yourFirstNamePlaceholder": "Your Name",
"yourFirstNamePlaceholder": "First Name",
"@yourFirstNamePlaceholder": {},
"yourLastNamePlaceholder": "Last Name",
"@yourLastNamePlaceholder": {},
"yourLinkIsReady": "Your link is ready",
"@yourLinkIsReady": {},
"yourRecoveryPhrase": "Your Secret Recovery Phrase",
Expand Down
47 changes: 14 additions & 33 deletions packages/espressocash_app/lib/ui/pick_image_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,38 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg_provider/flutter_svg_provider.dart';

import '../gen/assets.gen.dart';
import 'button.dart';

class PickImageContainer extends StatelessWidget {
const PickImageContainer({
super.key,
this.image,
this.pickImageClicked,
this.labelStyle,
required this.label,
required this.onLabelClicked,
});

final File? image;
final VoidCallback? pickImageClicked;
final TextStyle? labelStyle;
final String label;
final VoidCallback? onLabelClicked;

@override
Widget build(BuildContext context) {
final image = this.image;

return GestureDetector(
onTap: pickImageClicked,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 114,
height: 114,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.black,
image: DecorationImage(
fit: BoxFit.cover,
image: image == null
// ignore: avoid-unnecessary-type-casts, needed here
? Svg(Assets.images.imagePickerIcon.path)
as ImageProvider<Object>
: FileImage(image),
),
),
child: Container(
width: 114,
height: 114,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.black,
image: DecorationImage(
fit: BoxFit.cover,
image: image == null
// ignore: avoid-unnecessary-type-casts, needed here
? Svg(Assets.images.imagePickerIcon.path)
as ImageProvider<Object>
: FileImage(image),
),
const SizedBox(height: 12),
CpButton(
text: label,
onPressed: pickImageClicked,
variant: CpButtonVariant.black,
size: CpButtonSize.small,
),
],
),
),
);
}
Expand Down
3 changes: 3 additions & 0 deletions packages/espressocash_app/lib/ui/text_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class CpTextField extends StatelessWidget {
this.textColor = CpColors.primaryTextColor,
this.textInputAction,
this.multiLine = false,
this.textCapitalization = TextCapitalization.none,
});

final TextEditingController? controller;
Expand All @@ -42,6 +43,7 @@ class CpTextField extends StatelessWidget {
final Color? textColor;
final TextInputAction? textInputAction;
final bool? multiLine;
final TextCapitalization textCapitalization;

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -77,6 +79,7 @@ class CpTextField extends StatelessWidget {
),
placeholder: placeholder,
keyboardType: inputType,
textCapitalization: textCapitalization,
keyboardAppearance: Theme.of(context).brightness,
placeholderStyle: TextStyle(color: placeholderColor),
textInputAction: textInputAction,
Expand Down
4 changes: 2 additions & 2 deletions packages/espressocash_app/lib/ui/user_avatar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class CpUserAvatar extends StatelessWidget {
@override
Widget build(BuildContext context) {
final double fontSize = (_fontSizeFactor * radius).roundToDouble();
final String text = substring(userName, 0, 1).toUpperCase();
final String text = substring(userName, 0, 2).toUpperCase();

return CircleAvatar(
radius: radius,
Expand All @@ -40,4 +40,4 @@ class CpUserAvatar extends StatelessWidget {
}
}

const _fontSizeFactor = 1.1667;
const _fontSizeFactor = 1.0;

0 comments on commit e41bd28

Please sign in to comment.