feat: Implement room themes

pull/1432/head
Krille 8 months ago
parent cb32608674
commit 8d91f23f40
No known key found for this signature in database
GPG Key ID: E067ECD60F1A0652

@ -1,3 +1,5 @@
import 'package:fluffychat/utils/room_theme_extension.dart';
import 'package:fluffychat/utils/string_color.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:badges/badges.dart'; import 'package:badges/badges.dart';
@ -128,7 +130,6 @@ class ChatView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context);
if (controller.room.membership == Membership.invite) { if (controller.room.membership == Membership.invite) {
showFutureLoadingDialog( showFutureLoadingDialog(
context: context, context: context,
@ -154,9 +155,21 @@ class ChatView extends StatelessWidget {
stream: controller.room.client.onRoomState.stream stream: controller.room.client.onRoomState.stream
.where((update) => update.roomId == controller.room.id) .where((update) => update.roomId == controller.room.id)
.rateLimit(const Duration(seconds: 1)), .rateLimit(const Duration(seconds: 1)),
builder: (context, snapshot) => FutureBuilder( builder: (context, snapshot) {
final roomTheme = controller.room.roomTheme;
final roomColor = roomTheme?.color;
final roomWallpaper =
roomTheme?.wallpaper ?? accountConfig.wallpaperUrl;
return Theme(
data: Theme.of(context).copyWith(
colorScheme: roomColor == null
? null
: ColorScheme.fromSeed(seedColor: roomColor),
),
child: FutureBuilder(
future: controller.loadTimelineFuture, future: controller.loadTimelineFuture,
builder: (BuildContext context, snapshot) { builder: (BuildContext context, snapshot) {
final theme = Theme.of(context);
var appbarBottomHeight = 0.0; var appbarBottomHeight = 0.0;
if (controller.room.pinnedEventIds.isNotEmpty) { if (controller.room.pinnedEventIds.isNotEmpty) {
appbarBottomHeight += ChatAppBarListTile.fixedHeight; appbarBottomHeight += ChatAppBarListTile.fixedHeight;
@ -188,10 +201,12 @@ class ChatView extends StatelessWidget {
.client .client
.onSync .onSync
.stream .stream
.where((syncUpdate) => syncUpdate.hasRoomUpdate), .where(
(syncUpdate) => syncUpdate.hasRoomUpdate),
builder: (context, _) => UnreadRoomsBadge( builder: (context, _) => UnreadRoomsBadge(
filter: (r) => r.id != controller.roomId, filter: (r) => r.id != controller.roomId,
badgePosition: BadgePosition.topEnd(end: 8, top: 4), badgePosition:
BadgePosition.topEnd(end: 8, top: 4),
child: const Center(child: BackButton()), child: const Center(child: BackButton()),
), ),
), ),
@ -260,11 +275,11 @@ class ChatView extends StatelessWidget {
onDragExited: controller.onDragExited, onDragExited: controller.onDragExited,
child: Stack( child: Stack(
children: <Widget>[ children: <Widget>[
if (accountConfig.wallpaperUrl != null) if (roomWallpaper != null)
Opacity( Opacity(
opacity: accountConfig.wallpaperOpacity ?? 1, opacity: accountConfig.wallpaperOpacity ?? 1,
child: MxcImage( child: MxcImage(
uri: accountConfig.wallpaperUrl, uri: roomWallpaper,
fit: BoxFit.cover, fit: BoxFit.cover,
isThumbnail: true, isThumbnail: true,
width: FluffyThemes.columnWidth * 4, width: FluffyThemes.columnWidth * 4,
@ -282,7 +297,8 @@ class ChatView extends StatelessWidget {
builder: (context) { builder: (context) {
if (controller.timeline == null) { if (controller.timeline == null) {
return const Center( return const Center(
child: CircularProgressIndicator.adaptive( child: CircularProgressIndicator
.adaptive(
strokeWidth: 2, strokeWidth: 2,
), ),
); );
@ -308,11 +324,13 @@ class ChatView extends StatelessWidget {
alignment: Alignment.center, alignment: Alignment.center,
child: Material( child: Material(
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
color: theme.colorScheme.surfaceContainerHigh, color:
theme.colorScheme.surfaceContainerHigh,
borderRadius: const BorderRadius.all( borderRadius: const BorderRadius.all(
Radius.circular(24), Radius.circular(24),
), ),
child: controller.room.isAbandonedDMRoom == true child: controller.room.isAbandonedDMRoom ==
true
? Row( ? Row(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.spaceEvenly, MainAxisAlignment.spaceEvenly,
@ -342,7 +360,8 @@ class ChatView extends StatelessWidget {
icon: const Icon( icon: const Icon(
Icons.forum_outlined, Icons.forum_outlined,
), ),
onPressed: controller.recreateChat, onPressed:
controller.recreateChat,
label: Text( label: Text(
L10n.of(context).reopenChat, L10n.of(context).reopenChat,
), ),
@ -366,7 +385,8 @@ class ChatView extends StatelessWidget {
), ),
if (controller.dragging) if (controller.dragging)
Container( Container(
color: theme.scaffoldBackgroundColor.withOpacity(0.9), color:
theme.scaffoldBackgroundColor.withOpacity(0.9),
alignment: Alignment.center, alignment: Alignment.center,
child: const Icon( child: const Icon(
Icons.upload_outlined, Icons.upload_outlined,
@ -379,6 +399,8 @@ class ChatView extends StatelessWidget {
); );
}, },
), ),
);
},
), ),
); );
} }

@ -0,0 +1,48 @@
import 'package:async/async.dart';
import 'package:flutter/widgets.dart';
import 'package:matrix/matrix.dart' hide Result;
extension RoomThemeExtension on Room {
static const String typeKey = 'im.fluffychat.room.theme';
MatrixRoomTheme? get roomTheme {
final content = getState(typeKey)?.content;
if (content == null) return null;
return MatrixRoomTheme.fromJson(content);
}
Future<void> setRoomTheme(MatrixRoomTheme theme) =>
client.setRoomStateWithKey(
id,
typeKey,
'',
theme.toJson(),
);
}
class MatrixRoomTheme {
final Color? color;
final Uri? wallpaper;
const MatrixRoomTheme({required this.color, required this.wallpaper});
factory MatrixRoomTheme.fromJson(Map<String, Object?> json) {
final colorString = json.tryGet<String>('color');
final colorInt = colorString == null ? null : int.tryParse(colorString);
final color =
colorInt == null ? null : Result(() => Color(colorInt)).asValue?.value;
final wallpaperString = json.tryGet<String>('wallpaper');
final wallpaper =
wallpaperString == null ? null : Uri.tryParse(wallpaperString);
return MatrixRoomTheme(
color: color,
wallpaper: wallpaper,
);
}
Map<String, Object?> toJson() => {
if (color != null) 'color': color?.value,
if (wallpaper != null) 'wallpaper': wallpaper?.toString(),
};
}
Loading…
Cancel
Save