import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:photo_view/photo_view.dart'; import '../api/errors/error_mapper.dart'; import 'a11y/a11y_labels.dart'; import 'app_progress_indicator.dart'; import 'placeholder_view.dart'; import 'user_avatar.dart'; /// Full-screen avatar. Loads the bytes itself instead of handing the URL to an /// [ImageProvider]: Nextcloud and Spreed serve generated avatars as SVG, which /// no codec can decode ("Invalid image data") — those get an [SvgPicture] /// instead of the zoomable [PhotoView]. class LargeProfilePictureView extends StatefulWidget { final String id; final bool isGroup; const LargeProfilePictureView({ required this.id, this.isGroup = false, super.key, }); @override State createState() => _LargeProfilePictureViewState(); } class _LargeProfilePictureViewState extends State { late Future _payload; @override void initState() { super.initState(); _payload = loadAvatarPayload( id: widget.id, isGroup: widget.isGroup, size: 1024, ); } @override Widget build(BuildContext context) { final label = widget.isGroup ? A11yLabels.groupPicture : A11yLabels.profilePicture; final background = Theme.of(context).colorScheme.surface; return Scaffold( appBar: AppBar(title: Text(label)), body: Semantics( image: true, label: label, child: FutureBuilder( future: _payload, builder: (context, snapshot) { if (snapshot.connectionState != ConnectionState.done) { return const Center(child: AppProgressIndicator.large()); } final payload = snapshot.data; if (snapshot.hasError) { return PlaceholderView( icon: Icons.broken_image_outlined, text: errorToUserMessage(snapshot.error), ); } // No avatar on the server — the same icon the small avatar shows. if (payload == null) { return PlaceholderView( icon: widget.isGroup ? Icons.group : Icons.person, text: 'Kein Bild hinterlegt.', ); } if (payload.isSvg) { return ColoredBox( color: background, child: InteractiveViewer( minScale: 0.5, maxScale: 3, child: SvgPicture.memory(payload.bytes, fit: BoxFit.contain), ), ); } return PhotoView( minScale: 0.5, maxScale: 3.0, imageProvider: MemoryImage(payload.bytes), backgroundDecoration: BoxDecoration(color: background), ); }, ), ), ); } }