Skip to content

Commit

Permalink
first draft
Browse files Browse the repository at this point in the history
  • Loading branch information
Daviiddoo committed Jul 21, 2024
1 parent 9d86d2d commit 6f21b1c
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 1 deletion.
13 changes: 12 additions & 1 deletion forui/lib/src/theme/theme_data.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:forui/src/widgets/avatar.dart';

import 'package:meta/meta.dart';

Expand Down Expand Up @@ -28,6 +29,9 @@ final class FThemeData with Diagnosticable {
/// The alert styles.
final FAlertStyles alertStyles;

/// The avatar styles.
final FAvatarStyle avatarStyle;

/// The badge styles.
final FBadgeStyles badgeStyles;

Expand Down Expand Up @@ -78,12 +82,13 @@ final class FThemeData with Diagnosticable {
/// widget styles.
FThemeData({
required this.colorScheme,
required this.alertStyles,
required this.avatarStyle,
required this.badgeStyles,
required this.bottomNavigationBarStyle,
required this.buttonStyles,
required this.calendarStyle,
required this.cardStyle,
required this.alertStyles,
required this.checkboxStyle,
required this.dialogStyle,
required this.headerStyle,
Expand All @@ -110,6 +115,7 @@ final class FThemeData with Diagnosticable {
typography: typography,
style: style,
alertStyles: FAlertStyles.inherit(colorScheme: colorScheme, typography: typography, style: style),
avatarStyle: FAvatarStyle.inherit(colorScheme: colorScheme, typography: typography),
badgeStyles: FBadgeStyles.inherit(colorScheme: colorScheme, typography: typography, style: style),
bottomNavigationBarStyle: FBottomNavigationBarStyle.inherit(colorScheme: colorScheme, typography: typography),
buttonStyles: FButtonStyles.inherit(colorScheme: colorScheme, typography: typography, style: style),
Expand Down Expand Up @@ -149,6 +155,7 @@ final class FThemeData with Diagnosticable {
FTypography? typography,
FStyle? style,
FAlertStyles? alertStyles,
FAvatarStyle? avatarStyle,
FBadgeStyles? badgeStyles,
FBottomNavigationBarStyle? bottomNavigationBarStyle,
FButtonStyles? buttonStyles,
Expand All @@ -169,6 +176,7 @@ final class FThemeData with Diagnosticable {
typography: typography ?? this.typography,
style: style ?? this.style,
alertStyles: alertStyles ?? this.alertStyles,
avatarStyle: avatarStyle ?? this.avatarStyle,
badgeStyles: badgeStyles ?? this.badgeStyles,
bottomNavigationBarStyle: bottomNavigationBarStyle ?? this.bottomNavigationBarStyle,
buttonStyles: buttonStyles ?? this.buttonStyles,
Expand All @@ -193,6 +201,7 @@ final class FThemeData with Diagnosticable {
..add(DiagnosticsProperty('typography', typography, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('alertStyles', alertStyles, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('avatarStyle', avatarStyle))
..add(DiagnosticsProperty('badgeStyles', badgeStyles, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('bottomNavigationBarStyle', bottomNavigationBarStyle, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('buttonStyles', buttonStyles, level: DiagnosticLevel.debug))
Expand All @@ -218,6 +227,7 @@ final class FThemeData with Diagnosticable {
typography == other.typography &&
style == other.style &&
alertStyles == other.alertStyles &&
avatarStyle == other.avatarStyle &&
badgeStyles == other.badgeStyles &&
bottomNavigationBarStyle == other.bottomNavigationBarStyle &&
buttonStyles == other.buttonStyles &&
Expand All @@ -239,6 +249,7 @@ final class FThemeData with Diagnosticable {
typography.hashCode ^
style.hashCode ^
alertStyles.hashCode ^
avatarStyle.hashCode ^
badgeStyles.hashCode ^
bottomNavigationBarStyle.hashCode ^
buttonStyles.hashCode ^
Expand Down
163 changes: 163 additions & 0 deletions forui/lib/src/widgets/avatar.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:forui/forui.dart';
import 'package:meta/meta.dart';

/// An image element with a fallback for representing the user.
///
/// Typically used with a user's profile image, or, in the absence of
/// such an image, the user's initials. A given user's initials should
/// always be paired with the same background color, for consistency.
///
/// If [backgroundImage] fails then [FAvatarStyle.backgroundColor] is used.
///
/// The [onBackgroundImageError] parameter must be null if the [backgroundImage]
/// is null.
///
class FAvatar extends StatelessWidget {
/// The style. Defaults to [FThemeData.avatarStyle].
final FAvatarStyle? style;

/// The background image of the circle. Changing the background
/// image will cause the avatar to animate to the new image.
///
/// If the [FAvatar] is to have the user's initials, use [child] instead.
final ImageProvider? backgroundImage;

/// An optional error callback for errors emitted when loading
/// [backgroundImage].
final ImageErrorListener? onBackgroundImageError;

/// The widget below this widget in the tree.
///
/// If the avatar is to just have the user's initials, they are typically
/// provided using a [Text] widget as the [child] and a [backgroundColor]:
///
/// If the [FAvatar] is to have an image, use [backgroundImage] instead.
final Widget? child;

/// Creates an [FAvatar].
const FAvatar({
super.key,
this.style,
this.backgroundImage,
this.onBackgroundImageError,
this.child,
}) : assert(
backgroundImage != null || onBackgroundImageError == null,
'The [onBackgroundImageError] parameter must be null if the [backgroundImage] is null.',
);

@override
Widget build(BuildContext context) {
final style = this.style ?? context.theme.avatarStyle;

return AnimatedContainer(
constraints: style.constraints,
duration: const Duration(milliseconds: 200),
decoration: BoxDecoration(
color: style.backgroundColor,
image: backgroundImage != null
? DecorationImage(
image: backgroundImage!,
onError: onBackgroundImageError,
fit: BoxFit.cover,
)
: null,
shape: BoxShape.circle,
),
child: child == null
? null
: Center(
// Need to disable text scaling here so that the text doesn't
// escape the avatar when the textScaleFactor is large.
child: MediaQuery.withNoTextScaling(
child: DefaultTextStyle(
style: style.text,
child: child!,
),
),
),
);
}

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty('style', style))
..add(DiagnosticsProperty('backgroundImage', backgroundImage))
..add(ObjectFlagProperty<ImageErrorListener?>.has('onBackgroundImageError', onBackgroundImageError));
}
}

/// [FAvatar]'s style.
final class FAvatarStyle with Diagnosticable {
/// The background color.
final Color backgroundColor;

/// The box constraints.
final BoxConstraints constraints;

/// The text style for the
final TextStyle text;

/// Creates a [FAvatarStyle].
FAvatarStyle({
required this.backgroundColor,
required this.constraints,
required this.text,
});

/// Creates a [FCardStyle] that inherits its properties from [colorScheme] and [typography].
FAvatarStyle.inherit({required FColorScheme colorScheme, required FTypography typography})
: backgroundColor = colorScheme.muted,
constraints = const BoxConstraints(minHeight: 40.0, minWidth: 40.0, maxHeight: 40.0, maxWidth: 40.0),
text = typography.base.copyWith(color: colorScheme.mutedForeground);

/// Returns a copy of this [FAvatarStyle] with the given properties replaced.
///
/// ```dart
/// final style = FAvatarStyle(
/// backgroundColor: ...,
/// constraints: ...,
/// );
///
/// final copy = style.copyWith(constraints: ...);
///
/// print(style.backgroundColor == copy.backgroundColor); // true
/// print(style.constraints == copy.constraints); // false
/// ```
@useResult
FAvatarStyle copyWith({
Color? backgroundColor,
BoxConstraints? constraints,
TextStyle? text,
}) =>
FAvatarStyle(
backgroundColor: backgroundColor ?? this.backgroundColor,
constraints: constraints ?? this.constraints,
text: text ?? this.text,
);

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(ColorProperty('backgroundColor', backgroundColor))
..add(DiagnosticsProperty('constraints', constraints))
..add(DiagnosticsProperty('text', text));
}

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is FAvatarStyle &&
runtimeType == other.runtimeType &&
backgroundColor == other.backgroundColor &&
constraints == other.constraints &&
text == other.text;

@override
int get hashCode => backgroundColor.hashCode ^ constraints.hashCode ^ text.hashCode;
}

0 comments on commit 6f21b1c

Please sign in to comment.