feat: Implement room themes

pull/1432/head
Krille 4 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:badges/badges.dart';
@ -128,7 +130,6 @@ class ChatView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
if (controller.room.membership == Membership.invite) {
showFutureLoadingDialog(
context: context,
@ -154,9 +155,21 @@ class ChatView extends StatelessWidget {
stream: controller.room.client.onRoomState.stream
.where((update) => update.roomId == controller.room.id)
.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,
builder: (BuildContext context, snapshot) {
final theme = Theme.of(context);
var appbarBottomHeight = 0.0;
if (controller.room.pinnedEventIds.isNotEmpty) {
appbarBottomHeight += ChatAppBarListTile.fixedHeight;
@ -188,10 +201,12 @@ class ChatView extends StatelessWidget {
.client
.onSync
.stream
.where((syncUpdate) => syncUpdate.hasRoomUpdate),
.where(
(syncUpdate) => syncUpdate.hasRoomUpdate),
builder: (context, _) => UnreadRoomsBadge(
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()),
),
),
@ -260,11 +275,11 @@ class ChatView extends StatelessWidget {
onDragExited: controller.onDragExited,
child: Stack(
children: <Widget>[
if (accountConfig.wallpaperUrl != null)
if (roomWallpaper != null)
Opacity(
opacity: accountConfig.wallpaperOpacity ?? 1,
child: MxcImage(
uri: accountConfig.wallpaperUrl,
uri: roomWallpaper,
fit: BoxFit.cover,
isThumbnail: true,
width: FluffyThemes.columnWidth * 4,
@ -282,7 +297,8 @@ class ChatView extends StatelessWidget {
builder: (context) {
if (controller.timeline == null) {
return const Center(
child: CircularProgressIndicator.adaptive(
child: CircularProgressIndicator
.adaptive(
strokeWidth: 2,
),
);
@ -308,11 +324,13 @@ class ChatView extends StatelessWidget {
alignment: Alignment.center,
child: Material(
clipBehavior: Clip.hardEdge,
color: theme.colorScheme.surfaceContainerHigh,
color:
theme.colorScheme.surfaceContainerHigh,
borderRadius: const BorderRadius.all(
Radius.circular(24),
),
child: controller.room.isAbandonedDMRoom == true
child: controller.room.isAbandonedDMRoom ==
true
? Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
@ -342,7 +360,8 @@ class ChatView extends StatelessWidget {
icon: const Icon(
Icons.forum_outlined,
),
onPressed: controller.recreateChat,
onPressed:
controller.recreateChat,
label: Text(
L10n.of(context).reopenChat,
),
@ -366,7 +385,8 @@ class ChatView extends StatelessWidget {
),
if (controller.dragging)
Container(
color: theme.scaffoldBackgroundColor.withOpacity(0.9),
color:
theme.scaffoldBackgroundColor.withOpacity(0.9),
alignment: Alignment.center,
child: const Icon(
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