feat: image fullscreen viewer, public room browser
- Chat: tap any image to open fullscreen InteractiveViewer (pinch/zoom) - Rooms: public room browser (Find rooms FAB + empty state button) searches Matrix room directory via queryPublicRooms, join from results - Rooms: empty state now shows 'Find rooms' button to onboard new users Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Version: 1.2.0 | Created: 2026-04-01 | Updated: 2026-04-10
|
||||
// Version: 1.3.0 | Created: 2026-04-01 | Updated: 2026-04-27
|
||||
// Message bubble widget. Handles text, images, files, redacted, replies.
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
@@ -172,11 +172,15 @@ class _ImageContent extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (message.mediaUrl != null) {
|
||||
return ClipRRect(
|
||||
final url = message.mediaUrl;
|
||||
if (url == null) return const Icon(Icons.image_not_supported);
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => _openFullscreen(context, url, message.body),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: message.mediaUrl!,
|
||||
imageUrl: url,
|
||||
width: 240,
|
||||
fit: BoxFit.cover,
|
||||
placeholder: (_, __) => const SizedBox(
|
||||
@@ -188,9 +192,60 @@ class _ImageContent extends StatelessWidget {
|
||||
child: Center(child: Icon(Icons.broken_image)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return const Icon(Icons.image_not_supported);
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _openFullscreen(BuildContext context, String url, String? caption) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => _ImageViewer(url: url, caption: caption),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ImageViewer extends StatelessWidget {
|
||||
const _ImageViewer({required this.url, this.caption});
|
||||
|
||||
final String url;
|
||||
final String? caption;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.black,
|
||||
foregroundColor: Colors.white,
|
||||
title: caption != null
|
||||
? Text(
|
||||
caption!,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
body: Center(
|
||||
child: InteractiveViewer(
|
||||
minScale: 0.5,
|
||||
maxScale: 4,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: url,
|
||||
fit: BoxFit.contain,
|
||||
placeholder: (_, __) => const CircularProgressIndicator(
|
||||
color: Colors.white,
|
||||
),
|
||||
errorWidget: (_, __, ___) => const Icon(
|
||||
Icons.broken_image,
|
||||
color: Colors.white,
|
||||
size: 64,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user