Skip to content

Commit

Permalink
feat: Country selector redesign (#5483)
Browse files Browse the repository at this point in the history
* Redesign of the country selector

* CW

* Search filter

* Fix Lint warning

* Small improvements
  • Loading branch information
g123k committed Jul 20, 2024
1 parent 1118349 commit 1573d32
Show file tree
Hide file tree
Showing 26 changed files with 1,680 additions and 419 deletions.
7 changes: 7 additions & 0 deletions packages/smooth_app/lib/generic_lib/design_constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Widget EMPTY_WIDGET = SizedBox.shrink();

const double VERY_SMALL_SPACE = 4.0;
const double SMALL_SPACE = 8.0;
const double BALANCED_SPACE = 10.0;
const double MEDIUM_SPACE = 12.0;
const double LARGE_SPACE = 16.0;
const double VERY_LARGE_SPACE = 20.0;
Expand All @@ -21,6 +22,12 @@ const Radius ROUNDED_RADIUS = Radius.circular(20.0);
//ignore: non_constant_identifier_names
const BorderRadius ROUNDED_BORDER_RADIUS = BorderRadius.all(ROUNDED_RADIUS);

/// Topbar…
const Radius HEADER_ROUNDED_RADIUS = Radius.circular(30.0);
//ignore: non_constant_identifier_names
const BorderRadius HEADER_BORDER_RADIUS =
BorderRadius.all(HEADER_ROUNDED_RADIUS);

/// Full screen button, e.g. KnowledgePanel
const Radius ANGULAR_RADIUS = Radius.circular(8.0);
//ignore: non_constant_identifier_names
Expand Down
117 changes: 117 additions & 0 deletions packages/smooth_app/lib/helpers/provider_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,65 @@ class _ListenerState<T> extends SingleChildState<Listener<T>> {
}
}

/// Same as [Listener] but for [ValueNotifier] : notifies when the value changes
class ValueNotifierListener<T extends ValueNotifier<S>, S>
extends SingleChildStatefulWidget {
const ValueNotifierListener({
this.listener,
this.listenerWithValueNotifier,
super.key,
super.child,
}) : assert(
listener != null || listenerWithValueNotifier != null,
'At least one listener must be provided',
);

final void Function(
BuildContext context,
S? previousValue,
S currentValue,
)? listener;

final void Function(
BuildContext context,
T valueNotifier,
S? previousValue,
S currentValue,
)? listenerWithValueNotifier;

@override
State<ValueNotifierListener<T, S>> createState() =>
_ValueNotifierListenerState<T, S>();
}

class _ValueNotifierListenerState<T extends ValueNotifier<S>, S>
extends SingleChildState<ValueNotifierListener<T, S>> {
S? _oldValue;

@override
Widget buildWithChild(BuildContext context, Widget? child) {
final S? oldValue = _oldValue;
final T valueNotifier = context.watch<T>();
final S newValue = valueNotifier.value;
_oldValue = newValue;

widget.listener?.call(
context,
oldValue,
newValue,
);

widget.listenerWithValueNotifier?.call(
context,
valueNotifier,
oldValue,
newValue,
);

return child ?? const SizedBox.shrink();
}
}

/// Same as [Consumer] but only rebuilds if [buildWhen] returns true
/// (And on the first build)
class ConsumerFilter<T> extends StatefulWidget {
Expand Down Expand Up @@ -91,6 +150,64 @@ class _ConsumerFilterState<T> extends State<ConsumerFilter<T>> {
}
}

/// Same as [Consumer] for [ValueNotifier] but only rebuilds if [buildWhen]
/// returns true (and on the first build).
class ConsumerValueNotifierFilter<T extends ValueNotifier<S>, S>
extends StatefulWidget {
const ConsumerValueNotifierFilter({
required this.builder,
this.buildWhen,
this.child,
super.key,
});

final Widget Function(
BuildContext context,
S value,
Widget? child,
) builder;
final bool Function(S? previousValue, S currentValue)? buildWhen;

final Widget? child;

@override
State<ConsumerValueNotifierFilter<T, S>> createState() =>
_ConsumerValueNotifierFilterState<T, S>();
}

class _ConsumerValueNotifierFilterState<T extends ValueNotifier<S>, S>
extends State<ConsumerValueNotifierFilter<T, S>> {
S? oldValue;
Widget? oldWidget;

@override
Widget build(BuildContext context) {
return Consumer<T>(
builder: (BuildContext context, T provider, Widget? child) {
if ((widget.buildWhen != null &&
widget.buildWhen!.call(oldValue, provider.value)) ||
widget.buildWhen == null && oldValue != provider.value ||
oldWidget == null) {
oldWidget = widget.builder(
context,
provider.value,
child,
);
}

oldValue = provider.value;

return widget.builder(
context,
provider.value,
oldWidget,
);
},
child: widget.child,
);
}
}

extension ValueNotifierExtensions<T> on ValueNotifier<T> {
void emit(T value) => this.value = value;
}
4 changes: 4 additions & 0 deletions packages/smooth_app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"@reason": {},
"okay": "Okay",
"@okay": {},
"validate": "Validate",
"@validate": {
"description": "Button label: Validate the input"
},
"create": "Create",
"@create": {
"description": "An action to create"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ class _GuidesParagraphTitle extends StatelessWidget {
child: Padding(
padding: const EdgeInsetsDirectional.symmetric(
horizontal: GuidesParagraph._HORIZONTAL_PADDING,
vertical: 10.0,
vertical: BALANCED_SPACE,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
Expand All @@ -189,7 +189,7 @@ class _GuidesParagraphTitle extends StatelessWidget {
padding: EdgeInsetsDirectional.only(top: 3.3),
child: _GuidesParagraphArrow(),
),
const SizedBox(width: 10.0),
const SizedBox(width: BALANCED_SPACE),
Expanded(
child: Text(
title,
Expand Down Expand Up @@ -244,7 +244,7 @@ class GuidesText extends StatelessWidget {
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsetsDirectional.only(
top: 10.0,
top: BALANCED_SPACE,
start: GuidesParagraph._HORIZONTAL_PADDING,
end: GuidesParagraph._HORIZONTAL_PADDING,
),
Expand Down Expand Up @@ -453,7 +453,7 @@ class GuidesImage extends StatelessWidget {
excludeSemantics: true,
child: Padding(
padding: const EdgeInsetsDirectional.only(
top: 10.0,
top: BALANCED_SPACE,
start: GuidesParagraph._HORIZONTAL_PADDING,
end: GuidesParagraph._HORIZONTAL_PADDING,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class GuidesFooter extends StatelessWidget {
top: _FooterPainter.WAVE_SIZE + MEDIUM_SPACE,
start: VERY_LARGE_SPACE,
end: VERY_LARGE_SPACE,
bottom: 10.0 + MediaQuery.viewPaddingOf(context).bottom,
bottom: BALANCED_SPACE + MediaQuery.viewPaddingOf(context).bottom,
),
child: TextButton(
style: TextButton.styleFrom(
Expand Down
14 changes: 7 additions & 7 deletions packages/smooth_app/lib/pages/guides/helpers/guides_header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class GuidesHeader extends StatelessWidget {
style: const TextStyle(color: Colors.white),
child: SliverPadding(
padding: const EdgeInsetsDirectional.only(
bottom: 10.0,
bottom: BALANCED_SPACE,
),
// Pinned = for the header to stay at the top of the screen
sliver: SliverPersistentHeader(
Expand Down Expand Up @@ -79,7 +79,7 @@ class _GuidesHeaderDelegate extends SliverPersistentHeaderDelegate {
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(30.0 * (1 - progress)),
bottom: HEADER_ROUNDED_RADIUS * (1 - progress),
),
),
color: colors.primaryDark,
Expand Down Expand Up @@ -113,7 +113,7 @@ class _GuidesHeaderDelegate extends SliverPersistentHeaderDelegate {
child: Align(
alignment: Alignment.bottomLeft,
child: Padding(
padding: const EdgeInsets.only(bottom: 10.0),
padding: const EdgeInsets.only(bottom: BALANCED_SPACE),
child: AutoSizeText(
title,
maxLines: 4,
Expand Down Expand Up @@ -193,8 +193,8 @@ class _GuidesHeaderLayout extends MultiChildLayoutDelegate {

@override
void performLayout(Size size) {
final double topMargin = topPadding + 10.0;
final double maxHeight = size.height - topPadding - (10.0 * 2);
final double topMargin = topPadding + BALANCED_SPACE;
final double maxHeight = size.height - topPadding - (BALANCED_SPACE * 2);

final Size closeButtonSize = layoutChild(
_GuidesHeaderLayoutId.closeButton,
Expand Down Expand Up @@ -250,7 +250,7 @@ class _GuidesHeaderLayout extends MultiChildLayoutDelegate {
positionChild(
_GuidesHeaderLayoutId.minimizedTitle,
Offset(
_CloseButtonLayout._CLOSE_BUTTON_SIZE + 10.0,
_CloseButtonLayout._CLOSE_BUTTON_SIZE + BALANCED_SPACE,
topMargin + 5.0,
),
);
Expand Down Expand Up @@ -295,7 +295,7 @@ class _BackButton extends StatelessWidget {
child: ExcludeSemantics(
child: Padding(
padding: const EdgeInsetsDirectional.only(
start: 10.0,
start: BALANCED_SPACE,
end: 24.0,
),
child: Opacity(
Expand Down
4 changes: 2 additions & 2 deletions packages/smooth_app/lib/pages/image_crop_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Future<UserPictureSource?> _getUserPictureSource(
closeButtonSemanticsOrder: 5.0,
body: const _ImageSourcePicker(),
bodyPadding: const EdgeInsetsDirectional.only(
start: 10.0,
start: BALANCED_SPACE,
end: MEDIUM_SPACE,
top: LARGE_SPACE,
bottom: MEDIUM_SPACE,
Expand Down Expand Up @@ -127,7 +127,7 @@ class _ImageSourcePickerState extends State<_ImageSourcePicker> {
children: <Widget>[
IntrinsicHeight(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
padding: const EdgeInsets.symmetric(horizontal: BALANCED_SPACE),
child: Row(
children: <Widget>[
Expanded(
Expand Down
Loading

0 comments on commit 1573d32

Please sign in to comment.