Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avatar Improvements, documentation changes #118

Merged
merged 21 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0a23c6c
improvements to avatar, docs revamp
Daviiddoo Jul 24, 2024
6a0ac1f
Removed references to constructor properties
Daviiddoo Jul 24, 2024
09136f9
Fixed pr issues, need to verify if path works when deployed
Daviiddoo Jul 25, 2024
996ed1d
Commit from GitHub Actions (Forui Samples Presubmit)
Daviiddoo Jul 25, 2024
6f94efb
Commit from GitHub Actions (Forui Presubmit)
Daviiddoo Jul 25, 2024
edb56f1
dart analysis fixes
Daviiddoo Jul 25, 2024
b1c2395
Merge branch 'fix/avatar' of https://github.com/forus-labs/forui into…
Daviiddoo Jul 25, 2024
414d764
Commit from GitHub Actions (Forui Presubmit)
Daviiddoo Jul 25, 2024
1295f4a
Update avatar.dart
Daviiddoo Jul 25, 2024
f3970f2
Merge branch 'fix/avatar' of https://github.com/forus-labs/forui into…
Daviiddoo Jul 25, 2024
cc33634
Commit from GitHub Actions (Forui Samples Presubmit)
Daviiddoo Jul 25, 2024
fdc9c5a
Update avatar.dart
Daviiddoo Jul 25, 2024
e5cfa7a
Merge branch 'fix/avatar' of https://github.com/forus-labs/forui into…
Daviiddoo Jul 25, 2024
69e204d
Fixed pr issues
Daviiddoo Jul 25, 2024
3365b4c
Removed center widget
Daviiddoo Jul 25, 2024
1b35823
Merge branch 'main' into fix/avatar
Daviiddoo Jul 25, 2024
8d6cacb
Apply suggestions from code review
Daviiddoo Jul 26, 2024
c284986
Added more examples to Avatar docs, fixed BoxFit.cover issue
Daviiddoo Jul 26, 2024
beebd9b
Update avatar.dart
Daviiddoo Jul 26, 2024
87ed30d
Final changes?
Daviiddoo Jul 26, 2024
f21bbef
Update forui/lib/src/widgets/avatar/avatar.dart
Daviiddoo Jul 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions docs/pages/docs/avatar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ An image element with a fallback for representing the user.
<Tabs.Tab>
```dart
FAvatar(
image: const NetworkImage('https://picsum.photos/250?image=9'),
image: const NetworkImage('https://raw.githubusercontent.com/forus-labs/forui/main/samples/assets/avatar.png'),
placeholderBuilder: (_) => const Text('MN'),
),
```
Expand All @@ -24,9 +24,50 @@ An image element with a fallback for representing the user.

```dart
FAvatar(
image: const NetworkImage('https://picsum.photos/250?image=9'),
size: 60,
image: const NetworkImage('https://raw.githubusercontent.com/forus-labs/forui/main/samples/assets/avatar.png'),
placeholderBuilder: (_) => const Text('MN'),
),
```

### `FAvatar.raw(...)`

```dart
FButton.raw(
child: const Text('MN'),
size: 60,
);
```


## Examples
Daviiddoo marked this conversation as resolved.
Show resolved Hide resolved

### Invalid image with Placeholder
<Tabs items={['Preview', 'Code']}>
<Tabs.Tab>
<Widget name='avatar' query={{image: 'error'}}/>
</Tabs.Tab>
<Tabs.Tab>
```dart
FAvatar(
image: const NetworkImage(''),
placeholderBuilder: (_) => const Text('MN'),
),
```
</Tabs.Tab>
</Tabs>

### Invalid image without Placeholder
<Tabs items={['Preview', 'Code']}>
<Tabs.Tab>
<Widget name='avatar' query={{image: 'error', child: 'empty'}}/>
</Tabs.Tab>
<Tabs.Tab>
```dart
FAvatar(
image: const NetworkImage(''),
),
```
</Tabs.Tab>
</Tabs>
Daviiddoo marked this conversation as resolved.
Show resolved Hide resolved


156 changes: 101 additions & 55 deletions forui/lib/src/widgets/avatar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,41 @@ import 'package:forui/forui.dart';

/// An image element with a fallback for representing the user.
///
/// use image property to provide a profile image displayed within the circle.
/// Typically used with a user's profile image. If the image fails to load,
/// [placeholderBuilder] is used instead, which usually displays the user's initials.
/// the placeholderBuilder property is used instead, which usually displays the user's initials.
///
/// If the user's profile has no image, use [placeholderBuilder] to provide
/// If the user's profile has no image, use the placeholderBuilder property to provide
/// the initials using a [Text] widget styled with [FAvatarStyle.backgroundColor].
class FAvatar extends StatelessWidget {
/// The style. Defaults to [FThemeData.avatarStyle].
final FAvatarStyle? style;

/// The profile image displayed within the circle.
///
/// If the user's initials are used, use [placeholderBuilder] instead.
final ImageProvider image;

/// The circle's size.
final double size;

/// The fallback widget displayed if [image] fails to load.
///
/// Typically used to display the user's initials using a [Text] widget
/// styled with [FAvatarStyle.backgroundColor].
///
/// Use [image] to display an image; use [placeholderBuilder] for initials.
final Widget Function(BuildContext)? placeholderBuilder;
/// The child.
final Widget child;

/// Creates an [FAvatar].
const FAvatar({
required this.image,
FAvatar({
required ImageProvider image,
Widget Function(BuildContext)? placeholderBuilder,
this.size = 40.0,
this.style,
super.key,
}) : child = _Avatar(
style: style,
size: size,
image: image,
placeholderBuilder: placeholderBuilder,
);

/// Creates a [FAvatar] with custom child.
const FAvatar.raw({
Daviiddoo marked this conversation as resolved.
Show resolved Hide resolved
required this.child,
Daviiddoo marked this conversation as resolved.
Show resolved Hide resolved
this.size = 40.0,
this.placeholderBuilder,
this.style,
super.key,
});

Expand All @@ -53,51 +57,16 @@ class FAvatar extends StatelessWidget {
shape: BoxShape.circle,
),
clipBehavior: Clip.hardEdge,
child: Center(
child: Image(
filterQuality: FilterQuality.medium,
image: image,
errorBuilder: (context, exception, stacktrace) => DefaultTextStyle(
style: style.text,
child: placeholderBuilder != null ? placeholderBuilder!(context) : _Placeholder(size: size),
),
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
if (wasSynchronouslyLoaded) {
return child;
}
return AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
child: frame == null
? DefaultTextStyle(
style: style.text,
child: placeholderBuilder != null ? placeholderBuilder!(context) : _Placeholder(size: size),
)
: child,
);
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) {
return child;
}
return DefaultTextStyle(
style: style.text,
child: placeholderBuilder != null ? placeholderBuilder!(context) : _Placeholder(size: size),
);
},
fit: BoxFit.cover,
),
),
child: child,
);
}

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty('image', image))
..add(DoubleProperty('size', size))
..add(DiagnosticsProperty('style', style))
..add(ObjectFlagProperty.has('placeholderBuilder', placeholderBuilder));
..add(DiagnosticsProperty('style', style));
}
}

Expand All @@ -113,7 +82,7 @@ final class FAvatarStyle with Diagnosticable {
final TextStyle text;

/// Creates a [FAvatarStyle].
FAvatarStyle({
const FAvatarStyle({
required this.backgroundColor,
required this.fadeInDuration,
required this.text,
Expand Down Expand Up @@ -175,6 +144,83 @@ final class FAvatarStyle with Diagnosticable {
int get hashCode => backgroundColor.hashCode ^ fadeInDuration.hashCode ^ text.hashCode;
}

class _Avatar extends StatelessWidget {
Daviiddoo marked this conversation as resolved.
Show resolved Hide resolved
final FAvatarStyle? style;

/// The circle's size.
final double size;

/// The profile image displayed within the circle.
///
/// If the user's initials are used, use [placeholderBuilder] instead.
final ImageProvider image;

/// The fallback widget displayed if [image] fails to load.
///
/// Typically used to display the user's initials using a [Text] widget
/// styled with [FAvatarStyle.backgroundColor].
///
/// Use [image] to display an image; use [placeholderBuilder] for initials.
final Widget Function(BuildContext)? placeholderBuilder;

const _Avatar({
required this.style,
required this.size,
required this.image,
required this.placeholderBuilder,
});

@override
Widget build(BuildContext context) {
final style = this.style ?? context.theme.avatarStyle;
return Center(
kawaijoe marked this conversation as resolved.
Show resolved Hide resolved
child: Image(
kawaijoe marked this conversation as resolved.
Show resolved Hide resolved
filterQuality: FilterQuality.medium,
image: image,
errorBuilder: (context, exception, stacktrace) => DefaultTextStyle(
style: style.text,
child: placeholderBuilder != null ? placeholderBuilder!(context) : _Placeholder(size: size),
),
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
if (wasSynchronouslyLoaded) {
return child;
}
return AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
child: frame == null
? DefaultTextStyle(
style: style.text,
child: placeholderBuilder != null ? placeholderBuilder!(context) : _Placeholder(size: size),
)
: child,
);
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) {
return child;
}
return DefaultTextStyle(
style: style.text,
child: placeholderBuilder != null ? placeholderBuilder!(context) : _Placeholder(size: size),
);
},
fit: BoxFit.cover,
),
);
}

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty('style', style))
..add(ObjectFlagProperty.has('placeholderBuilder', placeholderBuilder))
..add(DiagnosticsProperty('image', image))
..add(DoubleProperty('size', size))
..add(DiagnosticsProperty('style', style));
}
}

class _Placeholder extends StatelessWidget {
Daviiddoo marked this conversation as resolved.
Show resolved Hide resolved
final double size;

Expand Down
19 changes: 16 additions & 3 deletions samples/lib/widgets/avatar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,33 @@ import 'package:forui/forui.dart';

import 'package:forui_samples/sample_scaffold.dart';

final images = {
'default': const NetworkImage('https://raw.githubusercontent.com/forus-labs/forui/main/samples/assets/avatar.png'),
'error': const NetworkImage(''),
};

final placeholders = {'text': const Text('MN')};

@RoutePage()
class AvatarPage extends SampleScaffold {
final ImageProvider image;
final Widget? placeholder;

AvatarPage({
@queryParam super.theme,
});
@queryParam String image = 'default',
@queryParam String child = 'text',
}) : image = images[image] ?? const NetworkImage(''),
placeholder = placeholders[child];

@override
Widget child(BuildContext context) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FAvatar(
size: 70,
Daviiddoo marked this conversation as resolved.
Show resolved Hide resolved
image: const AssetImage('avatar.png'),
placeholderBuilder: (_) => const Text('MN'),
image: image,
placeholderBuilder: placeholder != null ? (_) => placeholder! : null,
),
],
);
Expand Down
Loading