Browse Source

neon: Refactor AccountAvatar into UserAvatar

pull/344/head
jld3103 2 years ago
parent
commit
8209dcd95f
No known key found for this signature in database
GPG Key ID: 9062417B9E8EB7B3
  1. 2
      packages/neon/neon/lib/neon.dart
  2. 4
      packages/neon/neon/lib/src/pages/home.dart
  3. 103
      packages/neon/neon/lib/src/widgets/account_avatar.dart
  4. 2
      packages/neon/neon/lib/src/widgets/account_tile.dart
  5. 126
      packages/neon/neon/lib/src/widgets/user_avatar.dart

2
packages/neon/neon/lib/neon.dart

@ -93,7 +93,6 @@ part 'src/utils/storage.dart';
part 'src/utils/stream_listenable.dart';
part 'src/utils/theme.dart';
part 'src/utils/validators.dart';
part 'src/widgets/account_avatar.dart';
part 'src/widgets/account_settings_tile.dart';
part 'src/widgets/account_tile.dart';
part 'src/widgets/app_implementation_icon.dart';
@ -109,6 +108,7 @@ part 'src/widgets/nextcloud_logo.dart';
part 'src/widgets/relative_time.dart';
part 'src/widgets/result_builder.dart';
part 'src/widgets/text_settings_tile.dart';
part 'src/widgets/user_avatar.dart';
Future runNeon({
required final WidgetsBinding binding,

4
packages/neon/neon/lib/src/pages/home.dart

@ -225,7 +225,7 @@ class _HomePageState extends State<HomePage> {
},
tooltip: account.client.humanReadableID,
icon: IntrinsicHeight(
child: NeonAccountAvatar(
child: NeonUserAvatar(
account: account,
),
),
@ -496,7 +496,7 @@ class _HomePageState extends State<HomePage> {
},
tooltip: AppLocalizations.of(context).settingsAccount,
icon: IntrinsicWidth(
child: NeonAccountAvatar(
child: NeonUserAvatar(
account: account,
),
),

103
packages/neon/neon/lib/src/widgets/account_avatar.dart

@ -1,103 +0,0 @@
part of '../../neon.dart';
const kAvatarSize = 40.0;
class NeonAccountAvatar extends StatelessWidget {
const NeonAccountAvatar({
required this.account,
super.key,
});
final Account account;
@override
Widget build(final BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final size = (kAvatarSize * MediaQuery.of(context).devicePixelRatio).toInt();
final userStatusBloc = Provider.of<AccountsBloc>(context, listen: false).getUserStatusBloc(account);
return SizedBox.square(
dimension: kAvatarSize,
child: Stack(
alignment: Alignment.center,
children: [
CircleAvatar(
child: ClipOval(
child: NeonCachedApiImage(
account: account,
cacheKey: 'avatar-${account.id}-${isDark ? 'dark' : 'light'}$size',
download: () async {
if (isDark) {
return account.client.core.getDarkAvatar(
userId: account.username,
size: size,
);
} else {
return account.client.core.getAvatar(
userId: account.username,
size: size,
);
}
},
),
),
),
ResultBuilder<NextcloudUserStatusStatus?>(
stream: userStatusBloc.userStatus,
builder: (final context, final userStatus) {
final hasEmoji = userStatus.data?.icon != null;
final factor = hasEmoji ? 2 : 3;
return Align(
alignment: Alignment.bottomRight,
child: Container(
height: kAvatarSize / factor,
width: kAvatarSize / factor,
decoration: userStatus.loading || userStatus.error != null || userStatus.data == null || hasEmoji
? null
: BoxDecoration(
shape: BoxShape.circle,
color: _userStatusToColor(userStatus.data!),
),
child: userStatus.loading
? CircularProgressIndicator(
strokeWidth: 1.5,
color: Theme.of(context).colorScheme.onPrimary,
)
: userStatus.error != null &&
(userStatus.error is! NextcloudApiException ||
(userStatus.error! as NextcloudApiException).statusCode != 404)
? NeonException(
userStatus.error,
onRetry: userStatusBloc.refresh,
onlyIcon: true,
iconSize: kAvatarSize / factor,
)
: hasEmoji
? Text(
userStatus.data!.icon!,
style: const TextStyle(
fontSize: 16,
),
)
: null,
),
);
},
),
],
),
);
}
Color _userStatusToColor(final NextcloudUserStatusStatus userStatus) {
switch (userStatus.status) {
case NextcloudUserStatusType.online:
return const Color(0xFF49B382);
case NextcloudUserStatusType.away:
return const Color(0xFFF4A331);
case NextcloudUserStatusType.dnd:
return const Color(0xFFED484C);
default:
return Colors.transparent;
}
}
}

2
packages/neon/neon/lib/src/widgets/account_tile.dart

@ -34,7 +34,7 @@ class NeonAccountTile extends StatelessWidget {
)
: null,
leading: IntrinsicWidth(
child: NeonAccountAvatar(
child: NeonUserAvatar(
account: account,
),
),

126
packages/neon/neon/lib/src/widgets/user_avatar.dart

@ -0,0 +1,126 @@
// ignore_for_file: use_late_for_private_fields_and_variables
// ^ This is a really strange false positive, it goes of at a very random place without any meaning. Hopefully fixed soon?
part of '../../neon.dart';
const kAvatarSize = 40.0;
class NeonUserAvatar extends StatefulWidget {
NeonUserAvatar({
required this.account,
final String? username,
this.showStatus = true,
this.size = kAvatarSize,
super.key,
}) : username = username ?? account.client.username!;
final Account account;
final String username;
final bool showStatus;
final double size;
@override
State<NeonUserAvatar> createState() => _UserAvatarState();
}
class _UserAvatarState extends State<NeonUserAvatar> {
late final _userStatusBloc = Provider.of<AccountsBloc>(context, listen: false).getUserStatusesBloc(widget.account);
@override
void initState() {
super.initState();
unawaited(_userStatusBloc.load(widget.username));
}
@override
Widget build(final BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final size = (widget.size * MediaQuery.of(context).devicePixelRatio).toInt();
return Stack(
alignment: Alignment.center,
children: [
CircleAvatar(
radius: widget.size / 2,
child: ClipOval(
child: NeonCachedApiImage(
account: widget.account,
cacheKey: 'avatar-${widget.username}-${isDark ? 'dark' : 'light'}$size',
download: () async {
if (isDark) {
return widget.account.client.core.getDarkAvatar(
userId: widget.username,
size: size,
);
} else {
return widget.account.client.core.getAvatar(
userId: widget.username,
size: size,
);
}
},
),
),
),
if (widget.showStatus) ...[
ResultBuilder<NextcloudUserStatusPublicStatus?>(
stream: _userStatusBloc.statuses.map((final statuses) => statuses[widget.username]),
builder: _userStatusIconBuilder,
),
],
],
);
}
Widget _userStatusIconBuilder(final BuildContext context, final Result<NextcloudUserStatusPublicStatus?> result) {
final hasEmoji = result.data?.icon != null;
final scaledSize = widget.size / (hasEmoji ? 2 : 3);
Widget? child;
Decoration? decoration;
if (result.loading) {
child = CircularProgressIndicator(
strokeWidth: 1.5,
color: Theme.of(context).colorScheme.onPrimary,
);
} else if (result.error != null) {
child = Icon(
Icons.error_outline,
size: scaledSize,
color: Theme.of(context).colorScheme.error,
);
} else if (hasEmoji) {
child = Text(
result.data!.icon!,
style: const TextStyle(
fontSize: 16,
),
);
} else if (result.data != null) {
decoration = BoxDecoration(
shape: BoxShape.circle,
color: _userStatusToColor(result.data!.status),
);
}
return SizedBox.square(
dimension: widget.size,
child: Align(
alignment: Alignment.bottomRight,
child: Container(
width: scaledSize,
height: scaledSize,
decoration: decoration,
child: child,
),
),
);
}
Color? _userStatusToColor(final NextcloudUserStatusType userStatusType) => switch (userStatusType) {
NextcloudUserStatusType.online => const Color(0xFF49B382),
NextcloudUserStatusType.away => const Color(0xFFF4A331),
NextcloudUserStatusType.dnd => const Color(0xFFED484C),
_ => null,
};
}
Loading…
Cancel
Save