Files
tatuchat/lib/pages/settings_style/settings_style_view.dart
Welton Moura 6f32eb8972 fix: incluir o wallpaper padrao no bundle e mostrar na previa
O Flutter nao empacota subdirectorios de forma recursiva, e assets/logo/ nao estava listado no pubspec, portanto assets/logo/background.png nunca chegava ao bundle e o wallpaper padrao das conversas nao aparecia.

- pubspec: declara assets/logo/background.png
- chat_view: normaliza o path do asset
- settings_style_view: a previa passa a mostrar o wallpaper padrao quando nao ha imagem custom, com opacidade 0.3 e sem blur, em vez de ficar sem fundo
2026-09-25 13:15:03 -03:00

360 lines
16 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// SPDX-FileCopyrightText: 2019-Present Christian Kußowski
// SPDX-FileCopyrightText: 2019-Present Contributors to FluffyChat
//
// SPDX-License-Identifier: AGPL-3.0-or-later
import 'dart:ui';
import 'package:dynamic_color/dynamic_color.dart';
import 'package:tatchat/config/setting_keys.dart';
import 'package:tatchat/config/themes.dart';
import 'package:tatchat/l10n/l10n.dart';
import 'package:tatchat/pages/chat/events/state_message.dart';
import 'package:tatchat/utils/account_config.dart';
import 'package:tatchat/utils/color_value.dart';
import 'package:tatchat/widgets/avatar.dart';
import 'package:tatchat/widgets/layouts/max_width_body.dart';
import 'package:tatchat/widgets/matrix.dart';
import 'package:tatchat/widgets/mxc_image.dart';
import 'package:material_ui/material_ui.dart';
import 'package:matrix/matrix.dart';
import '../../config/app_config.dart';
import 'settings_style.dart';
class SettingsStyleView extends StatelessWidget {
final SettingsStyleController controller;
const SettingsStyleView(this.controller, {super.key});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
const colorPickerSize = 32.0;
final client = Matrix.of(context).client;
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: !FluffyThemes.isColumnMode(context),
centerTitle: FluffyThemes.isColumnMode(context),
title: Text(L10n.of(context).changeTheme),
),
backgroundColor: theme.colorScheme.surface,
body: MaxWidthBody(
child: Column(
crossAxisAlignment: .stretch,
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: SegmentedButton<ThemeMode>(
selected: {controller.currentTheme},
onSelectionChanged: (selected) =>
controller.switchTheme(selected.single),
segments: [
ButtonSegment(
value: ThemeMode.light,
label: Text(L10n.of(context).lightTheme),
icon: const Icon(Icons.light_mode_outlined),
),
ButtonSegment(
value: ThemeMode.dark,
label: Text(L10n.of(context).darkTheme),
icon: const Icon(Icons.dark_mode_outlined),
),
ButtonSegment(
value: ThemeMode.system,
label: Text(L10n.of(context).systemTheme),
icon: const Icon(Icons.auto_mode_outlined),
),
],
),
),
Divider(color: theme.dividerColor),
ListTile(
title: Text(
L10n.of(context).setColorTheme,
style: TextStyle(
color: theme.colorScheme.secondary,
fontWeight: FontWeight.bold,
),
),
),
DynamicColorBuilder(
builder: (light, dark) {
final systemColor =
Theme.of(context).brightness == Brightness.light
? light?.primary
: dark?.primary;
final colors = [null, AppConfig.chatColor, ...Colors.primaries];
if (systemColor == null) {
colors.remove(null);
}
return GridView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 64,
),
itemCount: colors.length,
itemBuilder: (context, i) {
final color = colors[i];
return Padding(
padding: const EdgeInsets.all(12.0),
child: Tooltip(
message: color == null
? L10n.of(context).systemTheme
: '#${color.hexValue.toRadixString(16).toUpperCase()}',
child: InkWell(
borderRadius: BorderRadius.circular(colorPickerSize),
onTap: () => controller.setChatColor(color),
child: Material(
color: color ?? systemColor,
elevation: 6,
borderRadius: BorderRadius.circular(
colorPickerSize,
),
child: SizedBox(
width: colorPickerSize,
height: colorPickerSize,
child: controller.currentColor == color
? Center(
child: Icon(
Icons.check,
size: 16,
color: Theme.of(
context,
).colorScheme.onPrimary,
),
)
: null,
),
),
),
),
);
},
);
},
),
Divider(color: theme.dividerColor),
ListTile(
title: Text(
L10n.of(context).messagesStyle,
style: TextStyle(
color: theme.colorScheme.secondary,
fontWeight: FontWeight.bold,
),
),
),
StreamBuilder(
stream: client.onSync.stream.where(
(syncUpdate) =>
syncUpdate.accountData?.any(
(accountData) =>
accountData.type ==
ApplicationAccountConfigExtension.accountDataKey,
) ??
false,
),
builder: (context, snapshot) {
final accountConfig = client.applicationAccountConfig;
return Column(
mainAxisSize: .min,
children: [
MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaler: TextScaler.linear(
AppSettings.fontSizeFactor.value,
),
),
child: AnimatedContainer(
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
decoration: const BoxDecoration(),
clipBehavior: Clip.hardEdge,
child: Stack(
alignment: Alignment.center,
children: [
Opacity(
opacity: accountConfig.wallpaperUrl != null
? controller.wallpaperOpacity
: 0.3,
child: ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: accountConfig.wallpaperUrl != null
? controller.wallpaperBlur
: 0.0,
sigmaY: accountConfig.wallpaperUrl != null
? controller.wallpaperBlur
: 0.0,
),
child: accountConfig.wallpaperUrl != null
? MxcImage(
key: ValueKey(
accountConfig.wallpaperUrl,
),
uri: accountConfig.wallpaperUrl,
fit: BoxFit.cover,
isThumbnail: true,
width: FluffyThemes.columnWidth * 2,
height: 212,
)
: Image.asset(
'assets/logo/background.png',
fit: BoxFit.cover,
width: FluffyThemes.columnWidth * 2,
height: 212,
),
),
),
Column(
mainAxisSize: .min,
children: [
const SizedBox(height: 16),
StateMessage(
Event(
eventId: 'style_dummy',
room: Room(
id: '!style_dummy',
client: client,
),
content: {'membership': 'join'},
type: EventTypes.RoomMember,
senderId: client.userID!,
originServerTs: DateTime.now(),
stateKey: client.userID,
),
),
Padding(
padding: const EdgeInsets.only(
left: 12 + 12 + Avatar.defaultSize,
right: 12,
top: 12,
bottom: 12,
),
child: DecoratedBox(
decoration: BoxDecoration(
color: theme.bubbleColor,
borderRadius: BorderRadius.circular(
AppConfig.borderRadius,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: Text(
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor',
style: TextStyle(
color: theme.onBubbleColor,
fontSize: AppConfig.messageFontSize,
),
),
),
),
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.only(
right: 12,
left: 12,
top: 12,
bottom: 12,
),
child: Material(
color: theme
.colorScheme
.surfaceContainerHigh,
borderRadius: BorderRadius.circular(
AppConfig.borderRadius,
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: Text(
'Lorem ipsum dolor sit amet',
style: TextStyle(
color: theme.colorScheme.onSurface,
fontSize: AppConfig.messageFontSize,
),
),
),
),
),
),
],
),
],
),
),
),
Divider(color: theme.dividerColor),
ListTile(
title: TextButton.icon(
style: TextButton.styleFrom(
backgroundColor: theme.colorScheme.secondaryContainer,
foregroundColor:
theme.colorScheme.onSecondaryContainer,
),
onPressed: controller.setWallpaper,
icon: const Icon(Icons.edit_outlined),
label: Text(L10n.of(context).setWallpaper),
),
trailing: accountConfig.wallpaperUrl == null
? null
: IconButton(
icon: const Icon(Icons.delete_outlined),
color: theme.colorScheme.error,
onPressed: controller.deleteChatWallpaper,
),
),
if (accountConfig.wallpaperUrl != null) ...[
ListTile(title: Text(L10n.of(context).opacity)),
Slider.adaptive(
min: 0.1,
max: 1.0,
divisions: 9,
semanticFormatterCallback: (d) => d.toString(),
value: controller.wallpaperOpacity,
onChanged: controller.updateWallpaperOpacity,
onChangeEnd: controller.saveWallpaperOpacity,
),
ListTile(title: Text(L10n.of(context).blur)),
Slider.adaptive(
min: 0.0,
max: 10.0,
divisions: 10,
semanticFormatterCallback: (d) => d.toString(),
value: controller.wallpaperBlur,
onChanged: controller.updateWallpaperBlur,
onChangeEnd: controller.saveWallpaperBlur,
),
],
],
);
},
),
ListTile(
title: Text(L10n.of(context).fontSize),
trailing: Text('× ${AppSettings.fontSizeFactor.value}'),
),
Slider.adaptive(
min: 0.5,
max: 2.5,
divisions: 20,
value: AppSettings.fontSizeFactor.value,
semanticFormatterCallback: (d) => d.toString(),
onChanged: controller.changeFontSizeFactor,
),
],
),
),
);
}
}