import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:matrix/matrix.dart'; import 'package:pyramid/core/app_state.dart'; import 'package:pyramid/core/matrix_client.dart'; import 'package:pyramid/core/theme.dart'; import 'package:pyramid/widgets/hover_region.dart'; import 'package:pyramid/widgets/mxc_image.dart'; import 'package:pyramid/widgets/pyramid_logo.dart'; final _ownProfileProvider = FutureProvider.autoDispose((ref) async { final client = await ref.watch(matrixClientProvider.future); final userId = client.userID; if (userId == null) return null; try { return await client.getProfileFromUserId(userId); } catch (_) { return null; } }); class UserPanel extends ConsumerWidget { const UserPanel({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final pt = PyramidTheme.of(context); final clientAsync = ref.watch(matrixClientProvider); final profile = ref.watch(_ownProfileProvider).valueOrNull; final client = clientAsync.valueOrNull; final fallbackName = client?.userID?.split(':').first.replaceFirst('@', '') ?? '...'; final displayName = profile?.displayName ?? fallbackName; final avatarUri = profile?.avatarUrl; return Padding( padding: const EdgeInsets.fromLTRB(8, 0, 8, 8), child: Container( decoration: BoxDecoration( color: pt.bg2, borderRadius: BorderRadius.circular(4), border: Border.all(color: pt.border), ), child: _ProfileRow( pt: pt, client: client, avatarUri: avatarUri, displayName: displayName, ref: ref, ), ), ); } } class _ProfileRow extends StatelessWidget { final PyramidTheme pt; final Client? client; final Uri? avatarUri; final String displayName; final WidgetRef ref; const _ProfileRow({ required this.pt, required this.client, required this.avatarUri, required this.displayName, required this.ref, }); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), child: Row( children: [ Stack( clipBehavior: Clip.none, children: [ if (client != null && avatarUri != null) MxcAvatar( mxcUri: avatarUri!, client: client!, size: 32, borderRadius: BorderRadius.circular(4), placeholder: (_) => _InitialAvatar(name: displayName, radius: 4), ) else _InitialAvatar(name: displayName, radius: 4), Positioned( bottom: -2, right: -2, child: PresenceDot(status: 'online', size: 10, borderColor: pt.bg2), ), ], ), const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( displayName, style: TextStyle( color: pt.fg, fontSize: 13, fontWeight: FontWeight.w600, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), Text( 'online', style: TextStyle(color: pt.fgMuted, fontSize: 11), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), PyrIconBtn( size: 28, icon: const Icon(Icons.settings_rounded), tooltip: 'Einstellungen', onPressed: () => ref.read(activeModalProvider.notifier).state = ModalKind.settings, ), ], ), ); } } class _InitialAvatar extends StatelessWidget { static const double _size = 32; final String name; final double radius; const _InitialAvatar({required this.name, required this.radius}); @override Widget build(BuildContext context) { return Container( width: _size, height: _size, decoration: BoxDecoration( gradient: const LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFFFF6B9D), Color(0xFFC471F5)], ), borderRadius: BorderRadius.circular(radius), ), child: Center( child: Text( name.isNotEmpty ? name[0].toUpperCase() : '?', style: TextStyle( color: Colors.white, fontSize: _size * 0.44, fontWeight: FontWeight.w600, ), ), ), ); } }