mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-29 12:52:13 +02:00
Centralize existing Material and Mornye layout metrics in AppTokens and share adaptive icon selection. Enlarge the Home profile avatar to 44 dp with a 56 dp touch target.
108 lines
3.1 KiB
Dart
108 lines
3.1 KiB
Dart
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:spotiflac_android/l10n/l10n.dart';
|
|
import 'package:spotiflac_android/providers/user_profile_provider.dart';
|
|
import 'package:spotiflac_android/services/shell_navigation_service.dart';
|
|
|
|
class ProfileAvatar extends StatelessWidget {
|
|
const ProfileAvatar({
|
|
super.key,
|
|
this.name = '',
|
|
this.photoPath,
|
|
this.photo,
|
|
this.size = 40,
|
|
});
|
|
|
|
final String name;
|
|
final String? photoPath;
|
|
final Uint8List? photo;
|
|
final double size;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return LayoutBuilder(
|
|
builder: (context, constraints) {
|
|
// ListTile can constrain height more than width. Keep the clipped
|
|
// image square even when the surrounding slot is rectangular.
|
|
final diameter = constraints.biggest.shortestSide.clamp(0.0, size);
|
|
return Align(
|
|
widthFactor: 1,
|
|
heightFactor: 1,
|
|
child: _buildAvatar(context, diameter),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildAvatar(BuildContext context, double diameter) {
|
|
final scheme = Theme.of(context).colorScheme;
|
|
final fallback = ColoredBox(
|
|
color: scheme.primaryContainer,
|
|
child: Center(
|
|
child: name.trim().isEmpty
|
|
? Icon(
|
|
Icons.person,
|
|
size: diameter * 0.55,
|
|
color: scheme.onPrimaryContainer,
|
|
)
|
|
: Text(
|
|
name.trim().characters.first.toUpperCase(),
|
|
style: TextStyle(
|
|
fontSize: diameter * 0.42,
|
|
fontWeight: FontWeight.w600,
|
|
color: scheme.onPrimaryContainer,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
return ExcludeSemantics(
|
|
child: ClipOval(
|
|
child: SizedBox.square(
|
|
dimension: diameter,
|
|
child: photo != null
|
|
? Image.memory(
|
|
photo!,
|
|
fit: BoxFit.cover,
|
|
errorBuilder: (_, _, _) => fallback,
|
|
)
|
|
: photoPath != null
|
|
? Image.file(
|
|
File(photoPath!),
|
|
fit: BoxFit.cover,
|
|
cacheWidth:
|
|
(diameter * MediaQuery.devicePixelRatioOf(context))
|
|
.ceil(),
|
|
errorBuilder: (_, _, _) => fallback,
|
|
)
|
|
: fallback,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class HomeProfileButton extends ConsumerWidget {
|
|
const HomeProfileButton({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final profile = ref.watch(userProfileProvider).value;
|
|
return IconButton(
|
|
tooltip: context.l10n.settingsTitle,
|
|
iconSize: 44,
|
|
padding: const EdgeInsets.all(6),
|
|
constraints: const BoxConstraints(minWidth: 56, minHeight: 56),
|
|
visualDensity: VisualDensity.standard,
|
|
onPressed: () => ShellNavigationService.requestTab(ShellTab.settings),
|
|
icon: ProfileAvatar(
|
|
name: profile?.name ?? '',
|
|
photoPath: profile?.photoPath,
|
|
size: 44,
|
|
),
|
|
);
|
|
}
|
|
}
|