From 171ce42a72df069aef53d2774e5a8646c040a3e2 Mon Sep 17 00:00:00 2001 From: jganenok Date: Fri, 5 Dec 2025 16:21:15 +0700 Subject: [PATCH] =?UTF-8?q?Revert=20"Reapply=20"=D0=BF=D0=BE=D1=87=D0=B8?= =?UTF-8?q?=D0=BD=D0=B8=D0=BB=20=D0=B2=D1=8B=D1=85=D0=BE=D0=B4,=20=D0=BD?= =?UTF-8?q?=D0=B0=D0=BA=D0=BE=D0=BD=D0=B5=D1=86-=D1=82=D0=BE.=20=D0=A1?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20=D0=BD=D0=B5=D0=B4=D0=BE=20?= =?UTF-8?q?=D0=B6=D0=B5=D1=81=D1=82=D1=8B,=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D0=BB=20=D1=8D=D0=BA=D1=81=D0=BF=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D0=BB=D0=B1=D0=BD=D1=8B=D0=B5=20?= =?UTF-8?q?=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B7=D0=B0=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=86=D0=B2=D0=B5=D1=82=D0=B0=20=D1=83=20?= =?UTF-8?q?=D0=B1=D0=BE=D0=BA=D0=BE=D0=B2=D0=BE=D0=B9=20=D0=BF=D0=B0=D0=BD?= =?UTF-8?q?=D0=B5=D0=BB=D0=B8=20=D0=B8=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=87=D0=B0=D1=82=D0=BE=D0=B2,=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B9=D0=BA=D1=83=20=D0=BE=D1=82=D1=81=D1=82=D1=83=D0=BF=D0=B0?= =?UTF-8?q?=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B0=D0=BD=D0=B4=D1=80=D0=BE=D0=B5=D0=B4=D0=B0?= =?UTF-8?q?=D1=85=20=D0=B0=20=D1=82=D0=BE=20=D0=BC=D0=BE=D0=B6=D0=B5=D1=82?= =?UTF-8?q?=20=D1=83=20=D0=BA=D0=BE=D0=B3=D0=BE=20=D1=82=D0=BE=20=D0=BB?= =?UTF-8?q?=D0=BE=D0=BC=D0=B0=D1=82=D1=8C=D1=81=D1=8F""?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit ceeab44b7b5bf18f68f7b18f25443f3b8ddc6cd8. --- lib/screens/chat_screen.dart | 920 +++++++++--------- lib/screens/chats_screen.dart | 393 +++----- .../settings/customization_screen.dart | 321 ------ lib/utils/theme_provider.dart | 247 ----- 4 files changed, 568 insertions(+), 1313 deletions(-) diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart index ede3788..65b6126 100644 --- a/lib/screens/chat_screen.dart +++ b/lib/screens/chat_screen.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:ui'; import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/scheduler.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; @@ -2973,530 +2972,499 @@ class _ChatScreenState extends State { Widget build(BuildContext context) { final theme = context.watch(); - final isDesktop = - kIsWeb || - defaultTargetPlatform == TargetPlatform.windows || - defaultTargetPlatform == TargetPlatform.linux || - defaultTargetPlatform == TargetPlatform.macOS; - - final body = Stack( - children: [ - Positioned.fill(child: _buildChatWallpaper(theme)), - Column( - children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 250), - switchInCurve: Curves.easeInOutCubic, - switchOutCurve: Curves.easeInOutCubic, - transitionBuilder: (child, animation) { - return SlideTransition( - position: Tween( - begin: const Offset(0, -0.5), - end: Offset.zero, - ).animate(animation), - child: FadeTransition(opacity: animation, child: child), - ); - }, - child: _pinnedMessage != null - ? SafeArea( - key: ValueKey(_pinnedMessage!.id), - child: InkWell( - onTap: _scrollToPinnedMessage, - child: PinnedMessageWidget( - pinnedMessage: _pinnedMessage!, - contacts: _contactDetailsCache, - myId: _actualMyId ?? 0, + return Scaffold( + extendBodyBehindAppBar: theme.useGlassPanels, + resizeToAvoidBottomInset: false, + appBar: _buildAppBar(), + body: Stack( + children: [ + Positioned.fill(child: _buildChatWallpaper(theme)), + Column( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 250), + switchInCurve: Curves.easeInOutCubic, + switchOutCurve: Curves.easeInOutCubic, + transitionBuilder: (child, animation) { + return SlideTransition( + position: Tween( + begin: const Offset(0, -0.5), + end: Offset.zero, + ).animate(animation), + child: FadeTransition(opacity: animation, child: child), + ); + }, + child: _pinnedMessage != null + ? SafeArea( + key: ValueKey(_pinnedMessage!.id), + child: InkWell( onTap: _scrollToPinnedMessage, - onClose: () { - setState(() { - _pinnedMessage = null; - }); - }, - ), - ), - ) - : const SizedBox.shrink(key: ValueKey('empty')), - ), - Expanded( - child: Stack( - children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - switchInCurve: Curves.easeInOutCubic, - switchOutCurve: Curves.easeInOutCubic, - transitionBuilder: (child, animation) { - return FadeTransition( - opacity: animation, - child: ScaleTransition( - scale: Tween(begin: 0.8, end: 1.0).animate( - CurvedAnimation( - parent: animation, - curve: Curves.easeOutCubic, - ), + child: PinnedMessageWidget( + pinnedMessage: _pinnedMessage!, + contacts: _contactDetailsCache, + myId: _actualMyId ?? 0, + onTap: _scrollToPinnedMessage, + onClose: () { + setState(() { + _pinnedMessage = null; + }); + }, ), - child: child, ), - ); - }, - child: (!_isIdReady || _isLoadingHistory) - ? const Center( - key: ValueKey('loading'), - child: CircularProgressIndicator(), - ) - : _messages.isEmpty && !widget.isChannel - ? _EmptyChatWidget( - sticker: _emptyChatSticker, - onStickerTap: _sendEmptyChatSticker, - ) - : AnimatedPadding( - key: const ValueKey('chat_list'), - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOutCubic, - padding: EdgeInsets.only( - bottom: () { - final baseInset = MediaQuery.of( - context, - ).viewInsets.bottom; - final isAndroid = - defaultTargetPlatform == - TargetPlatform.android; - if (!isAndroid) { - return baseInset; - } - final keyboardVisible = baseInset > 0.0; - if (keyboardVisible && - theme - .ignoreMobileBottomPaddingWhenKeyboard) { - return baseInset; - } - return baseInset + - theme.mobileChatBottomPadding; - }(), - ), - child: ScrollablePositionedList.builder( - itemScrollController: _itemScrollController, - itemPositionsListener: _itemPositionsListener, - reverse: true, - padding: EdgeInsets.fromLTRB( - 8.0, - 8.0, - 8.0, - widget.isChannel - ? 24.0 - : (isDesktop ? 100.0 : 0.0), + ) + : const SizedBox.shrink(key: ValueKey('empty')), + ), + Expanded( + child: Stack( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + switchInCurve: Curves.easeInOutCubic, + switchOutCurve: Curves.easeInOutCubic, + transitionBuilder: (child, animation) { + return FadeTransition( + opacity: animation, + child: ScaleTransition( + scale: Tween(begin: 0.8, end: 1.0).animate( + CurvedAnimation( + parent: animation, + curve: Curves.easeOutCubic, ), - itemCount: _chatItems.length, - itemBuilder: (context, index) { - final mappedIndex = - _chatItems.length - 1 - index; - final item = _chatItems[mappedIndex]; - final isLastVisual = - index == _chatItems.length - 1; + ), + child: child, + ), + ); + }, + child: (!_isIdReady || _isLoadingHistory) + ? const Center( + key: ValueKey('loading'), + child: CircularProgressIndicator(), + ) + : _messages.isEmpty && !widget.isChannel + ? _EmptyChatWidget( + sticker: _emptyChatSticker, + onStickerTap: _sendEmptyChatSticker, + ) + : AnimatedPadding( + key: const ValueKey('chat_list'), + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOutCubic, + padding: EdgeInsets.only( + bottom: MediaQuery.of( + context, + ).viewInsets.bottom, + ), + child: ScrollablePositionedList.builder( + itemScrollController: _itemScrollController, + itemPositionsListener: _itemPositionsListener, + reverse: true, + padding: EdgeInsets.fromLTRB( + 8.0, + 8.0, + 8.0, + widget.isChannel ? 16.0 : 100.0, + ), + itemCount: _chatItems.length, + itemBuilder: (context, index) { + final mappedIndex = + _chatItems.length - 1 - index; + final item = _chatItems[mappedIndex]; + final isLastVisual = + index == _chatItems.length - 1; - // Убрали вызов _loadMore() отсюда - он вызывается из _itemPositionsListener - // чтобы избежать setState() во время build фазы + // Убрали вызов _loadMore() отсюда - он вызывается из _itemPositionsListener + // чтобы избежать setState() во время build фазы - if (item is MessageItem) { - final message = item.message; - final key = _messageKeys.putIfAbsent( - message.id, - () => GlobalKey(), - ); - final bool isHighlighted = - _isSearching && - _searchResults.isNotEmpty && - _currentResultIndex != -1 && - message.id == - _searchResults[_currentResultIndex] - .id; - - final isControlMessage = message.attaches.any( - (a) => a['_type'] == 'CONTROL', - ); - if (isControlMessage) { - return _ControlMessageChip( - message: message, - contacts: _contactDetailsCache, - myId: _actualMyId ?? widget.myId, + if (item is MessageItem) { + final message = item.message; + final key = _messageKeys.putIfAbsent( + message.id, + () => GlobalKey(), ); - } + final bool isHighlighted = + _isSearching && + _searchResults.isNotEmpty && + _currentResultIndex != -1 && + message.id == + _searchResults[_currentResultIndex] + .id; - final bool isMe = - item.message.senderId == _actualMyId; - - MessageReadStatus? readStatus; - if (isMe) { - final messageId = item.message.id; - if (messageId.startsWith('local_')) { - readStatus = MessageReadStatus.sending; - } else { - readStatus = MessageReadStatus.sent; + final isControlMessage = message.attaches + .any((a) => a['_type'] == 'CONTROL'); + if (isControlMessage) { + return _ControlMessageChip( + message: message, + contacts: _contactDetailsCache, + myId: _actualMyId ?? widget.myId, + ); } - } - String? forwardedFrom; - String? forwardedFromAvatarUrl; - if (message.isForwarded) { - final link = message.link; - if (link is Map) { - final chatName = - link['chatName'] as String?; - final chatIconUrl = - link['chatIconUrl'] as String?; + final bool isMe = + item.message.senderId == _actualMyId; - if (chatName != null) { - forwardedFrom = chatName; - forwardedFromAvatarUrl = chatIconUrl; + MessageReadStatus? readStatus; + if (isMe) { + final messageId = item.message.id; + if (messageId.startsWith('local_')) { + readStatus = MessageReadStatus.sending; } else { - final forwardedMessage = - link['message'] - as Map?; - final originalSenderId = - forwardedMessage?['sender'] as int?; - if (originalSenderId != null) { - final originalSenderContact = - _contactDetailsCache[originalSenderId]; - if (originalSenderContact == null) { - _loadContactIfNeeded( - originalSenderId, - ); - forwardedFrom = - 'Участник $originalSenderId'; - forwardedFromAvatarUrl = null; - } else { - forwardedFrom = - originalSenderContact.name; - forwardedFromAvatarUrl = - originalSenderContact - .photoBaseUrl; + readStatus = MessageReadStatus.sent; + } + } + + String? forwardedFrom; + String? forwardedFromAvatarUrl; + if (message.isForwarded) { + final link = message.link; + if (link is Map) { + final chatName = + link['chatName'] as String?; + final chatIconUrl = + link['chatIconUrl'] as String?; + + if (chatName != null) { + forwardedFrom = chatName; + forwardedFromAvatarUrl = chatIconUrl; + } else { + final forwardedMessage = + link['message'] + as Map?; + final originalSenderId = + forwardedMessage?['sender'] + as int?; + if (originalSenderId != null) { + final originalSenderContact = + _contactDetailsCache[originalSenderId]; + if (originalSenderContact == null) { + _loadContactIfNeeded( + originalSenderId, + ); + forwardedFrom = + 'Участник $originalSenderId'; + forwardedFromAvatarUrl = null; + } else { + forwardedFrom = + originalSenderContact.name; + forwardedFromAvatarUrl = + originalSenderContact + .photoBaseUrl; + } } } } } - } - String? senderName; - if (widget.isGroupChat && !isMe) { - bool shouldShowName = true; - if (mappedIndex > 0) { - final previousItem = - _chatItems[mappedIndex - 1]; - if (previousItem is MessageItem) { - final previousMessage = - previousItem.message; - if (previousMessage.senderId == - message.senderId) { - final timeDifferenceInMinutes = - (message.time - - previousMessage.time) / - (1000 * 60); - if (timeDifferenceInMinutes < 5) { - shouldShowName = false; + String? senderName; + if (widget.isGroupChat && !isMe) { + bool shouldShowName = true; + if (mappedIndex > 0) { + final previousItem = + _chatItems[mappedIndex - 1]; + if (previousItem is MessageItem) { + final previousMessage = + previousItem.message; + if (previousMessage.senderId == + message.senderId) { + final timeDifferenceInMinutes = + (message.time - + previousMessage.time) / + (1000 * 60); + if (timeDifferenceInMinutes < 5) { + shouldShowName = false; + } } } } - } - if (shouldShowName) { - final senderContact = - _contactDetailsCache[message - .senderId]; - if (senderContact != null) { - senderName = getContactDisplayName( - contactId: senderContact.id, - originalName: senderContact.name, - originalFirstName: - senderContact.firstName, - originalLastName: - senderContact.lastName, - ); - } else { - senderName = 'ID ${message.senderId}'; - _loadContactIfNeeded(message.senderId); + if (shouldShowName) { + final senderContact = + _contactDetailsCache[message + .senderId]; + if (senderContact != null) { + senderName = getContactDisplayName( + contactId: senderContact.id, + originalName: senderContact.name, + originalFirstName: + senderContact.firstName, + originalLastName: + senderContact.lastName, + ); + } else { + senderName = 'ID ${message.senderId}'; + _loadContactIfNeeded( + message.senderId, + ); + } } } - } - final hasPhoto = item.message.attaches.any( - (a) => a['_type'] == 'PHOTO', - ); - final isNew = !_animatedMessageIds.contains( - item.message.id, - ); - final deferImageLoading = - hasPhoto && - isNew && - !_anyOptimize && - !context - .read() - .animatePhotoMessages; + final hasPhoto = item.message.attaches.any( + (a) => a['_type'] == 'PHOTO', + ); + final isNew = !_animatedMessageIds.contains( + item.message.id, + ); + final deferImageLoading = + hasPhoto && + isNew && + !_anyOptimize && + !context + .read() + .animatePhotoMessages; - String? decryptedText; - if (_isEncryptionPasswordSetForCurrentChat && - _encryptionConfigForCurrentChat != null && - _encryptionConfigForCurrentChat! - .password - .isNotEmpty && - item.message.text.startsWith( - ChatEncryptionService.encryptedPrefix, - )) { - decryptedText = - ChatEncryptionService.decryptWithPassword( - _encryptionConfigForCurrentChat! - .password, - item.message.text, + String? decryptedText; + if (_isEncryptionPasswordSetForCurrentChat && + _encryptionConfigForCurrentChat != + null && + _encryptionConfigForCurrentChat! + .password + .isNotEmpty && + item.message.text.startsWith( + ChatEncryptionService.encryptedPrefix, + )) { + decryptedText = + ChatEncryptionService.decryptWithPassword( + _encryptionConfigForCurrentChat! + .password, + item.message.text, + ); + } + + final bubble = ChatMessageBubble( + key: key, + message: item.message, + isMe: isMe, + readStatus: readStatus, + isReactionSending: _sendingReactions + .contains(item.message.id), + deferImageLoading: deferImageLoading, + myUserId: _actualMyId, + chatId: widget.chatId, + isEncryptionPasswordSet: + _isEncryptionPasswordSetForCurrentChat, + decryptedText: decryptedText, + onReply: widget.isChannel + ? null + : () => _replyToMessage(item.message), + onForward: () => + _forwardMessage(item.message), + onEdit: isMe + ? () => _editMessage(item.message) + : null, + canEditMessage: isMe + ? item.message.canEdit(_actualMyId!) + : null, + onDeleteForMe: isMe + ? () async { + await ApiService.instance + .deleteMessage( + widget.chatId, + item.message.id, + forMe: true, + ); + widget.onChatUpdated?.call(); + } + : null, + onDeleteForAll: isMe + ? () async { + await ApiService.instance + .deleteMessage( + widget.chatId, + item.message.id, + forMe: false, + ); + widget.onChatUpdated?.call(); + } + : null, + onReaction: (emoji) { + _updateReactionOptimistically( + item.message.id, + emoji, ); - } - - final bubble = ChatMessageBubble( - key: key, - message: item.message, - isMe: isMe, - readStatus: readStatus, - isReactionSending: _sendingReactions - .contains(item.message.id), - deferImageLoading: deferImageLoading, - myUserId: _actualMyId, - chatId: widget.chatId, - isEncryptionPasswordSet: - _isEncryptionPasswordSetForCurrentChat, - decryptedText: decryptedText, - onReply: widget.isChannel - ? null - : () => _replyToMessage(item.message), - onForward: () => - _forwardMessage(item.message), - onEdit: isMe - ? () => _editMessage(item.message) - : null, - canEditMessage: isMe - ? item.message.canEdit(_actualMyId!) - : null, - onDeleteForMe: isMe - ? () async { - await ApiService.instance - .deleteMessage( - widget.chatId, - item.message.id, - forMe: true, - ); - widget.onChatUpdated?.call(); - } - : null, - onDeleteForAll: isMe - ? () async { - await ApiService.instance - .deleteMessage( - widget.chatId, - item.message.id, - forMe: false, - ); - widget.onChatUpdated?.call(); - } - : null, - onReaction: (emoji) { - _updateReactionOptimistically( - item.message.id, - emoji, - ); - ApiService.instance.sendReaction( - widget.chatId, - item.message.id, - emoji, - ); - widget.onChatUpdated?.call(); - }, - onRemoveReaction: () { - _removeReactionOptimistically( - item.message.id, - ); - ApiService.instance.removeReaction( - widget.chatId, - item.message.id, - ); - widget.onChatUpdated?.call(); - }, - isGroupChat: widget.isGroupChat, - isChannel: widget.isChannel, - senderName: senderName, - forwardedFrom: forwardedFrom, - forwardedFromAvatarUrl: - forwardedFromAvatarUrl, - contactDetailsCache: _contactDetailsCache, - onReplyTap: _scrollToMessage, - useAutoReplyColor: context - .read() - .useAutoReplyColor, - customReplyColor: context - .read() - .customReplyColor, - isFirstInGroup: item.isFirstInGroup, - isLastInGroup: item.isLastInGroup, - isGrouped: item.isGrouped, - avatarVerticalOffset: - -8.0, // Смещение аватарки вверх на 8px - onComplain: () => - _showComplaintDialog(item.message.id), - ); - - Widget finalMessageWidget = bubble as Widget; - - if (isHighlighted) { - return TweenAnimationBuilder( - duration: const Duration( - milliseconds: 600, - ), - tween: Tween( - begin: 0.3, - end: 0.6, - ), - curve: Curves.easeInOut, - builder: (context, value, child) { - return Container( - margin: const EdgeInsets.symmetric( - vertical: 2, - ), - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .primaryContainer - .withOpacity(value), - borderRadius: BorderRadius.circular( - 16, - ), - border: Border.all( - color: Theme.of( - context, - ).colorScheme.primary, - width: 1.5, - ), - ), - child: child, + ApiService.instance.sendReaction( + widget.chatId, + item.message.id, + emoji, ); + widget.onChatUpdated?.call(); }, - child: finalMessageWidget, + onRemoveReaction: () { + _removeReactionOptimistically( + item.message.id, + ); + ApiService.instance.removeReaction( + widget.chatId, + item.message.id, + ); + widget.onChatUpdated?.call(); + }, + isGroupChat: widget.isGroupChat, + isChannel: widget.isChannel, + senderName: senderName, + forwardedFrom: forwardedFrom, + forwardedFromAvatarUrl: + forwardedFromAvatarUrl, + contactDetailsCache: _contactDetailsCache, + onReplyTap: _scrollToMessage, + useAutoReplyColor: context + .read() + .useAutoReplyColor, + customReplyColor: context + .read() + .customReplyColor, + isFirstInGroup: item.isFirstInGroup, + isLastInGroup: item.isLastInGroup, + isGrouped: item.isGrouped, + avatarVerticalOffset: + -8.0, // Смещение аватарки вверх на 8px + onComplain: () => + _showComplaintDialog(item.message.id), ); - } - // Плавное появление новых сообщений - if (isNew && !_anyOptimize) { + Widget finalMessageWidget = + bubble as Widget; + + if (isHighlighted) { + return TweenAnimationBuilder( + duration: const Duration( + milliseconds: 600, + ), + tween: Tween( + begin: 0.3, + end: 0.6, + ), + curve: Curves.easeInOut, + builder: (context, value, child) { + return Container( + margin: const EdgeInsets.symmetric( + vertical: 2, + ), + decoration: BoxDecoration( + color: Theme.of(context) + .colorScheme + .primaryContainer + .withOpacity(value), + borderRadius: + BorderRadius.circular(16), + border: Border.all( + color: Theme.of( + context, + ).colorScheme.primary, + width: 1.5, + ), + ), + child: child, + ); + }, + child: finalMessageWidget, + ); + } + + // Плавное появление новых сообщений + if (isNew && !_anyOptimize) { + return TweenAnimationBuilder( + duration: const Duration( + milliseconds: 400, + ), + tween: Tween( + begin: 0.0, + end: 1.0, + ), + curve: Curves.easeOutCubic, + builder: (context, value, child) { + return Opacity( + opacity: value, + child: Transform.translate( + offset: Offset( + 0, + 20 * (1 - value), + ), + child: child, + ), + ); + }, + child: finalMessageWidget, + ); + } + + return finalMessageWidget; + } else if (item is DateSeparatorItem) { + return _DateSeparatorChip(date: item.date); + } + if (isLastVisual && _isLoadingMore) { return TweenAnimationBuilder( duration: const Duration( - milliseconds: 400, + milliseconds: 300, ), tween: Tween( begin: 0.0, end: 1.0, ), - curve: Curves.easeOutCubic, + curve: Curves.easeOut, builder: (context, value, child) { return Opacity( opacity: value, - child: Transform.translate( - offset: Offset(0, 20 * (1 - value)), + child: Transform.scale( + scale: 0.7 + (0.3 * value), child: child, ), ); }, - child: finalMessageWidget, + child: const Padding( + padding: EdgeInsets.symmetric( + vertical: 12, + ), + child: Center( + child: CircularProgressIndicator(), + ), + ), ); } - - return finalMessageWidget; - } else if (item is DateSeparatorItem) { - return _DateSeparatorChip(date: item.date); - } - if (isLastVisual && _isLoadingMore) { - return TweenAnimationBuilder( - duration: const Duration(milliseconds: 300), - tween: Tween(begin: 0.0, end: 1.0), - curve: Curves.easeOut, - builder: (context, value, child) { - return Opacity( - opacity: value, - child: Transform.scale( - scale: 0.7 + (0.3 * value), - child: child, - ), - ); - }, - child: const Padding( - padding: EdgeInsets.symmetric( - vertical: 12, - ), - child: Center( - child: CircularProgressIndicator(), - ), - ), - ); - } - return const SizedBox.shrink(); - }, + return const SizedBox.shrink(); + }, + ), ), + ), + AnimatedPositioned( + duration: const Duration(milliseconds: 100), + curve: Curves.easeOutQuad, + right: 16, + bottom: + MediaQuery.of(context).viewInsets.bottom + + MediaQuery.of(context).padding.bottom + + 100, + child: AnimatedScale( + duration: const Duration(milliseconds: 200), + curve: Curves.easeOutBack, + scale: _showScrollToBottomNotifier.value ? 1.0 : 0.0, + child: AnimatedOpacity( + duration: const Duration(milliseconds: 150), + opacity: _showScrollToBottomNotifier.value + ? 1.0 + : 0.0, + child: FloatingActionButton( + mini: true, + onPressed: _scrollToBottom, + elevation: 4, + child: const Icon(Icons.arrow_downward_rounded), ), - ), - AnimatedPositioned( - duration: const Duration(milliseconds: 100), - curve: Curves.easeOutQuad, - right: 16, - bottom: - MediaQuery.of(context).viewInsets.bottom + - MediaQuery.of(context).padding.bottom + - 100, - child: AnimatedScale( - duration: const Duration(milliseconds: 200), - curve: Curves.easeOutBack, - scale: _showScrollToBottomNotifier.value ? 1.0 : 0.0, - child: AnimatedOpacity( - duration: const Duration(milliseconds: 150), - opacity: _showScrollToBottomNotifier.value ? 1.0 : 0.0, - child: FloatingActionButton( - mini: true, - onPressed: _scrollToBottom, - elevation: 4, - child: const Icon(Icons.arrow_downward_rounded), ), ), ), - ), - ], + ], + ), ), - ), - ], - ), - AnimatedPositioned( - duration: const Duration(milliseconds: 100), - curve: Curves.easeOutQuad, - left: 8, - right: 8, - bottom: - MediaQuery.of(context).viewInsets.bottom + - MediaQuery.of(context).padding.bottom + - 12, - child: _buildTextInput(), - ), - ], - ); - - if (isDesktop) { - return Scaffold( - extendBodyBehindAppBar: theme.useGlassPanels, - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(), - body: body, - ); - } - - return GestureDetector( - behavior: HitTestBehavior.opaque, - onHorizontalDragEnd: (details) { - final velocity = details.primaryVelocity ?? 0; - if (velocity > 400) { - Navigator.of(context).maybePop(); - } - }, - child: Scaffold( - extendBodyBehindAppBar: theme.useGlassPanels, - resizeToAvoidBottomInset: false, - appBar: _buildAppBar(), - body: body, + ], + ), + AnimatedPositioned( + duration: const Duration(milliseconds: 100), + curve: Curves.easeOutQuad, + left: 8, + right: 8, + bottom: + MediaQuery.of(context).viewInsets.bottom + + MediaQuery.of(context).padding.bottom + + 12, + child: _buildTextInput(), + ), + ], ), ); } diff --git a/lib/screens/chats_screen.dart b/lib/screens/chats_screen.dart index 27d3f29..751af6b 100644 --- a/lib/screens/chats_screen.dart +++ b/lib/screens/chats_screen.dart @@ -1997,63 +1997,13 @@ class _ChatsScreenState extends State ], ); - final themeProvider = context.watch(); - Widget? chatsListBackground; - if (themeProvider.useExperimentalChatsListBackground) { - switch (themeProvider.experimentalChatsListBackgroundType) { - case ChatWallpaperType.solid: - chatsListBackground = Container(color: themeProvider.experimentalChatsListBackgroundColor1); - break; - case ChatWallpaperType.gradient: - chatsListBackground = Container( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - themeProvider.experimentalChatsListBackgroundColor1, - themeProvider.experimentalChatsListBackgroundColor2, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - ); - break; - case ChatWallpaperType.image: - if (themeProvider.experimentalChatsListBackgroundImagePath != null) { - chatsListBackground = Image.file( - File(themeProvider.experimentalChatsListBackgroundImagePath!), - fit: BoxFit.cover, - width: double.infinity, - height: double.infinity, - ); - } - break; - case ChatWallpaperType.video: - break; - } - } - - final bodyContentWithBackground = chatsListBackground != null - ? Stack( - children: [ - Positioned.fill(child: chatsListBackground), - bodyContent, - ], - ) - : bodyContent; - if (widget.hasScaffold) { return Builder( builder: (context) { - final platform = Theme.of(context).platform; - final isMobile = - platform == TargetPlatform.android || - platform == TargetPlatform.iOS; - - Widget scaffold = Scaffold( + return Scaffold( appBar: _buildAppBar(context), drawer: _buildAppDrawer(context), - body: Row(children: [Expanded(child: bodyContentWithBackground)]), + body: Row(children: [Expanded(child: bodyContent)]), floatingActionButton: FloatingActionButton( onPressed: () { _showAddMenu(context); @@ -2063,50 +2013,10 @@ class _ChatsScreenState extends State child: const Icon(Icons.edit), ), ); - - if (!isMobile) return scaffold; - - final scaffoldKey = GlobalKey(); - scaffold = Scaffold( - key: scaffoldKey, - appBar: _buildAppBar(context), - drawer: _buildAppDrawer(context), - body: GestureDetector( - behavior: HitTestBehavior.opaque, - onHorizontalDragEnd: (details) { - final velocity = details.primaryVelocity ?? 0; - // Делаем жест проще: реагируем на более медленный свайп - if (velocity < -150) { - if (_folderTabController.length > 0 && - _folderTabController.index == - _folderTabController.length - 1) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (ctx) => const SettingsScreen(), - ), - ); - } else { - scaffoldKey.currentState?.openDrawer(); - } - } - }, - child: Row(children: [Expanded(child: bodyContentWithBackground)]), - ), - floatingActionButton: FloatingActionButton( - onPressed: () { - _showAddMenu(context); - }, - tooltip: 'Создать', - heroTag: 'create_menu', - child: const Icon(Icons.edit), - ), - ); - - return scaffold; }, ); } else { - return bodyContentWithBackground; + return bodyContent; } } @@ -2116,49 +2026,6 @@ class _ChatsScreenState extends State final themeProvider = context.watch(); final isDarkMode = themeProvider.themeMode == ThemeMode.dark; - Widget? _buildBackgroundWidget(ChatWallpaperType type, Color color1, Color color2, String? imagePath) { - switch (type) { - case ChatWallpaperType.solid: - return Container(color: color1); - case ChatWallpaperType.gradient: - return Container( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [color1, color2], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - ); - case ChatWallpaperType.image: - if (imagePath != null) { - return Image.file( - File(imagePath), - fit: BoxFit.cover, - width: double.infinity, - height: double.infinity, - ); - } - return null; - case ChatWallpaperType.video: - return null; - } - } - - final drawerTopBackground = _buildBackgroundWidget( - themeProvider.drawerTopBackgroundType, - themeProvider.drawerTopBackgroundColor1, - themeProvider.drawerTopBackgroundColor2, - themeProvider.drawerTopBackgroundImagePath, - ); - - final drawerBottomBackground = _buildBackgroundWidget( - themeProvider.drawerBottomBackgroundType, - themeProvider.drawerBottomBackgroundColor1, - themeProvider.drawerBottomBackgroundColor2, - themeProvider.drawerBottomBackgroundImagePath, - ); - return Drawer( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -2171,136 +2038,132 @@ class _ChatsScreenState extends State final currentAccount = accountManager.currentAccount; final hasMultipleAccounts = accounts.length > 1; - return Stack( + return Column( children: [ - if (drawerTopBackground != null) - Positioned.fill(child: drawerTopBackground), - Column( - children: [ - Container( - width: double.infinity, - padding: EdgeInsets.only( - top: MediaQuery.of(context).padding.top + 16.0, - left: 16.0, - right: 16.0, - bottom: 16.0, - ), - decoration: BoxDecoration(color: drawerTopBackground != null ? Colors.transparent : colors.primaryContainer), - child: Column( + Container( + width: double.infinity, + padding: EdgeInsets.only( + top: MediaQuery.of(context).padding.top + 16.0, + left: 16.0, + right: 16.0, + bottom: 16.0, + ), + decoration: BoxDecoration(color: colors.primaryContainer), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - CircleAvatar( - radius: 30, // Чуть крупнее - backgroundColor: colors.primary, - backgroundImage: - _isProfileLoading || - _myProfile?.photoBaseUrl == null - ? null - : NetworkImage(_myProfile!.photoBaseUrl!), - child: _isProfileLoading - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - color: Colors.white, - ), - ) - : (_myProfile?.photoBaseUrl == null - ? Text( - _myProfile - ?.displayName - .isNotEmpty == - true - ? _myProfile!.displayName[0] - .toUpperCase() - : '?', - style: TextStyle( - color: colors.onPrimary, - fontSize: 28, // Крупнее - ), - ) - : null), - ), - IconButton( - icon: Icon( - isDarkMode - ? Icons.brightness_7 - : Icons.brightness_4, // Солнце / Луна - color: colors.onPrimaryContainer, - size: 26, - ), - onPressed: () { - themeProvider.toggleTheme(); - }, - tooltip: isDarkMode - ? 'Светлая тема' - : 'Темная тема', - ), - ], - ), - const SizedBox(height: 12), - - Text( - _myProfile?.displayName ?? 'Загрузка...', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: colors.onPrimaryContainer, - ), - ), - const SizedBox(height: 4), - - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - _myProfile?.formattedPhone ?? '', - style: TextStyle( - color: colors.onPrimaryContainer.withOpacity( - 0.8, + CircleAvatar( + radius: 30, // Чуть крупнее + backgroundColor: colors.primary, + backgroundImage: + _isProfileLoading || + _myProfile?.photoBaseUrl == null + ? null + : NetworkImage(_myProfile!.photoBaseUrl!), + child: _isProfileLoading + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, ), - fontSize: 14, - ), - ), - ), - InkWell( - onTap: () { - setState(() { - _isAccountsExpanded = !_isAccountsExpanded; - }); - }, - child: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Icon( - _isAccountsExpanded - ? Icons.expand_less - : Icons.expand_more, - color: colors.onPrimaryContainer, - size: 24, - ), - ), - ), - ], + ) + : (_myProfile?.photoBaseUrl == null + ? Text( + _myProfile + ?.displayName + .isNotEmpty == + true + ? _myProfile!.displayName[0] + .toUpperCase() + : '?', + style: TextStyle( + color: colors.onPrimary, + fontSize: 28, // Крупнее + ), + ) + : null), + ), + IconButton( + icon: Icon( + isDarkMode + ? Icons.brightness_7 + : Icons.brightness_4, // Солнце / Луна + color: colors.onPrimaryContainer, + size: 26, + ), + onPressed: () { + themeProvider.toggleTheme(); + }, + tooltip: isDarkMode + ? 'Светлая тема' + : 'Темная тема', ), ], ), - ), + const SizedBox(height: 12), - ClipRect( - child: AnimatedSize( - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOutCubic, - child: _isAccountsExpanded - ? Column( - children: [ - if (hasMultipleAccounts) - ...accounts.map((account) { + Text( + _myProfile?.displayName ?? 'Загрузка...', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: colors.onPrimaryContainer, + ), + ), + const SizedBox(height: 4), + + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + _myProfile?.formattedPhone ?? '', + style: TextStyle( + color: colors.onPrimaryContainer.withOpacity( + 0.8, + ), + fontSize: 14, + ), + ), + ), + InkWell( + onTap: () { + setState(() { + _isAccountsExpanded = !_isAccountsExpanded; + }); + }, + child: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Icon( + _isAccountsExpanded + ? Icons.expand_less + : Icons.expand_more, + color: colors.onPrimaryContainer, + size: 24, + ), + ), + ), + ], + ), + ], + ), + ), + + ClipRect( + child: AnimatedSize( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOutCubic, + child: _isAccountsExpanded + ? Column( + children: [ + if (hasMultipleAccounts) + ...accounts.map((account) { final isCurrent = account.id == currentAccount?.id; return ListTile( @@ -2426,22 +2289,16 @@ class _ChatsScreenState extends State ], ) : const SizedBox.shrink(), - ), - ), - ], + ), ), ], ); }, ), Expanded( - child: Stack( + child: Column( children: [ - if (drawerBottomBackground != null) - Positioned.fill(child: drawerBottomBackground), - Column( - children: [ - _buildAccountsSection(context, colors), + _buildAccountsSection(context, colors), ListTile( leading: const Icon(Icons.person_outline), title: const Text('Мой профиль'), @@ -2584,8 +2441,6 @@ class _ChatsScreenState extends State }, ), const SizedBox(height: 8), // Небольшой отступ снизу - ], - ), ], ), ), diff --git a/lib/screens/settings/customization_screen.dart b/lib/screens/settings/customization_screen.dart index 37ef18b..e0f9d76 100644 --- a/lib/screens/settings/customization_screen.dart +++ b/lib/screens/settings/customization_screen.dart @@ -535,37 +535,6 @@ class _CustomizationScreenState extends State { ), ), const SizedBox(height: 8), - - _ExpandableSection( - title: "Отступ внизу чата", - initiallyExpanded: false, - children: [ - _SliderTile( - icon: Icons.vertical_align_bottom, - label: "Доп. отступ снизу (мобилы)", - value: theme.mobileChatBottomPadding, - min: 60, - max: 240, - divisions: 18, - onChanged: (value) => - theme.setMobileChatBottomPadding(value), - displayValue: - "${theme.mobileChatBottomPadding.toStringAsFixed(0)} px", - ), - const SizedBox(height: 8), - _CustomSettingTile( - icon: Icons.keyboard, - title: "Убирать отступ при открытой клавиатуре", - subtitle: - "Только Android. Когда вводите текст — отступ снизу не добавляется", - child: Switch( - value: theme.ignoreMobileBottomPaddingWhenKeyboard, - onChanged: (value) => theme - .setIgnoreMobileBottomPaddingWhenKeyboard(value), - ), - ), - ], - ), // Развернуть настройки _ExpandableSection( @@ -613,296 +582,6 @@ class _CustomizationScreenState extends State { ), ], ), - const SizedBox(height: 24), - _ModernSection( - title: "Экспериментальные настройки фона", - children: [ - Container( - padding: const EdgeInsets.all(12), - margin: const EdgeInsets.only(bottom: 16), - decoration: BoxDecoration( - color: colors.errorContainer.withOpacity(0.3), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: colors.error.withOpacity(0.5), - width: 1, - ), - ), - child: Row( - children: [ - Icon(Icons.science, color: colors.error, size: 20), - const SizedBox(width: 8), - Expanded( - child: Text( - "Экспериментальные функции. Могут работать нестабильно.", - style: TextStyle( - fontSize: 12, - color: colors.onErrorContainer, - ), - ), - ), - ], - ), - ), - _ExpandableSection( - title: "Фон списка чатов", - initiallyExpanded: false, - children: [ - _CustomSettingTile( - icon: Icons.science, - title: "Использовать экспериментальный фон", - subtitle: "Фон для экрана со списком чатов", - child: Switch( - value: theme.useExperimentalChatsListBackground, - onChanged: (value) => - theme.setUseExperimentalChatsListBackground(value), - ), - ), - if (theme.useExperimentalChatsListBackground) ...[ - const Divider(height: 24), - _CustomSettingTile( - icon: Icons.image, - title: "Тип фона", - child: DropdownButton( - value: theme.experimentalChatsListBackgroundType, - onChanged: (value) { - if (value != null) { - theme.setExperimentalChatsListBackgroundType(value); - } - }, - items: [ - ChatWallpaperType.solid, - ChatWallpaperType.gradient, - ChatWallpaperType.image, - ].map((type) { - return DropdownMenuItem( - value: type, - child: Text(type.displayName), - ); - }).toList(), - ), - ), - if (theme.experimentalChatsListBackgroundType == - ChatWallpaperType.solid || - theme.experimentalChatsListBackgroundType == - ChatWallpaperType.gradient) ...[ - const SizedBox(height: 16), - _ColorPickerTile( - title: "Цвет 1", - subtitle: "Основной цвет", - color: theme.experimentalChatsListBackgroundColor1, - onColorChanged: (color) => - theme.setExperimentalChatsListBackgroundColor1(color), - ), - ], - if (theme.experimentalChatsListBackgroundType == - ChatWallpaperType.gradient) ...[ - const SizedBox(height: 16), - _ColorPickerTile( - title: "Цвет 2", - subtitle: "Дополнительный цвет для градиента", - color: theme.experimentalChatsListBackgroundColor2, - onColorChanged: (color) => - theme.setExperimentalChatsListBackgroundColor2(color), - ), - ], - if (theme.experimentalChatsListBackgroundType == - ChatWallpaperType.image) ...[ - const Divider(height: 24), - ListTile( - contentPadding: EdgeInsets.zero, - leading: const Icon(Icons.photo_library_outlined), - title: const Text("Выбрать изображение"), - trailing: const Icon(Icons.chevron_right), - onTap: () async { - final picker = ImagePicker(); - final image = await picker.pickImage( - source: ImageSource.gallery, - ); - if (image != null) { - theme.setExperimentalChatsListBackgroundImagePath( - image.path, - ); - } - }, - ), - if (theme.experimentalChatsListBackgroundImagePath - ?.isNotEmpty == - true) ...[ - const SizedBox(height: 8), - ListTile( - contentPadding: EdgeInsets.zero, - leading: const Icon(Icons.delete_outline), - title: const Text("Удалить изображение"), - onTap: () { - theme.setExperimentalChatsListBackgroundImagePath(null); - }, - ), - ], - ], - ], - ], - ), - const SizedBox(height: 16), - _ExpandableSection( - title: "Фон боковой панели - верхняя часть (профиль)", - initiallyExpanded: false, - children: [ - _CustomSettingTile( - icon: Icons.image, - title: "Тип фона", - child: DropdownButton( - value: theme.drawerTopBackgroundType, - onChanged: (value) { - if (value != null) { - theme.setDrawerTopBackgroundType(value); - } - }, - items: [ - ChatWallpaperType.solid, - ChatWallpaperType.gradient, - ChatWallpaperType.image, - ].map((type) { - return DropdownMenuItem( - value: type, - child: Text(type.displayName), - ); - }).toList(), - ), - ), - if (theme.drawerTopBackgroundType == ChatWallpaperType.solid || - theme.drawerTopBackgroundType == ChatWallpaperType.gradient) ...[ - const SizedBox(height: 16), - _ColorPickerTile( - title: "Цвет 1", - subtitle: "Основной цвет", - color: theme.drawerTopBackgroundColor1, - onColorChanged: (color) => - theme.setDrawerTopBackgroundColor1(color), - ), - ], - if (theme.drawerTopBackgroundType == ChatWallpaperType.gradient) ...[ - const SizedBox(height: 16), - _ColorPickerTile( - title: "Цвет 2", - subtitle: "Дополнительный цвет для градиента", - color: theme.drawerTopBackgroundColor2, - onColorChanged: (color) => - theme.setDrawerTopBackgroundColor2(color), - ), - ], - if (theme.drawerTopBackgroundType == ChatWallpaperType.image) ...[ - const Divider(height: 24), - ListTile( - contentPadding: EdgeInsets.zero, - leading: const Icon(Icons.photo_library_outlined), - title: const Text("Выбрать изображение"), - trailing: const Icon(Icons.chevron_right), - onTap: () async { - final picker = ImagePicker(); - final image = await picker.pickImage( - source: ImageSource.gallery, - ); - if (image != null) { - theme.setDrawerTopBackgroundImagePath(image.path); - } - }, - ), - if (theme.drawerTopBackgroundImagePath?.isNotEmpty == true) ...[ - const SizedBox(height: 8), - ListTile( - contentPadding: EdgeInsets.zero, - leading: const Icon(Icons.delete_outline), - title: const Text("Удалить изображение"), - onTap: () { - theme.setDrawerTopBackgroundImagePath(null); - }, - ), - ], - ], - ], - ), - const SizedBox(height: 16), - _ExpandableSection( - title: "Фон боковой панели - нижняя часть (меню)", - initiallyExpanded: false, - children: [ - _CustomSettingTile( - icon: Icons.image, - title: "Тип фона", - child: DropdownButton( - value: theme.drawerBottomBackgroundType, - onChanged: (value) { - if (value != null) { - theme.setDrawerBottomBackgroundType(value); - } - }, - items: [ - ChatWallpaperType.solid, - ChatWallpaperType.gradient, - ChatWallpaperType.image, - ].map((type) { - return DropdownMenuItem( - value: type, - child: Text(type.displayName), - ); - }).toList(), - ), - ), - if (theme.drawerBottomBackgroundType == ChatWallpaperType.solid || - theme.drawerBottomBackgroundType == ChatWallpaperType.gradient) ...[ - const SizedBox(height: 16), - _ColorPickerTile( - title: "Цвет 1", - subtitle: "Основной цвет", - color: theme.drawerBottomBackgroundColor1, - onColorChanged: (color) => - theme.setDrawerBottomBackgroundColor1(color), - ), - ], - if (theme.drawerBottomBackgroundType == ChatWallpaperType.gradient) ...[ - const SizedBox(height: 16), - _ColorPickerTile( - title: "Цвет 2", - subtitle: "Дополнительный цвет для градиента", - color: theme.drawerBottomBackgroundColor2, - onColorChanged: (color) => - theme.setDrawerBottomBackgroundColor2(color), - ), - ], - if (theme.drawerBottomBackgroundType == ChatWallpaperType.image) ...[ - const Divider(height: 24), - ListTile( - contentPadding: EdgeInsets.zero, - leading: const Icon(Icons.photo_library_outlined), - title: const Text("Выбрать изображение"), - trailing: const Icon(Icons.chevron_right), - onTap: () async { - final picker = ImagePicker(); - final image = await picker.pickImage( - source: ImageSource.gallery, - ); - if (image != null) { - theme.setDrawerBottomBackgroundImagePath(image.path); - } - }, - ), - if (theme.drawerBottomBackgroundImagePath?.isNotEmpty == true) ...[ - const SizedBox(height: 8), - ListTile( - contentPadding: EdgeInsets.zero, - leading: const Icon(Icons.delete_outline), - title: const Text("Удалить изображение"), - onTap: () { - theme.setDrawerBottomBackgroundImagePath(null); - }, - ), - ], - ], - ], - ), - ], - ), ], ), ); diff --git a/lib/utils/theme_provider.dart b/lib/utils/theme_provider.dart index ee70269..8923963 100644 --- a/lib/utils/theme_provider.dart +++ b/lib/utils/theme_provider.dart @@ -104,25 +104,6 @@ class CustomThemePreset { bool useDesktopLayout; bool useAutoReplyColor; Color? customReplyColor; - double mobileChatBottomPadding; - bool ignoreMobileBottomPaddingWhenKeyboard; - - // Экспериментальные настройки фона - bool useExperimentalChatsListBackground; - ChatWallpaperType experimentalChatsListBackgroundType; - Color experimentalChatsListBackgroundColor1; - Color experimentalChatsListBackgroundColor2; - String? experimentalChatsListBackgroundImagePath; - - ChatWallpaperType drawerTopBackgroundType; - Color drawerTopBackgroundColor1; - Color drawerTopBackgroundColor2; - String? drawerTopBackgroundImagePath; - - ChatWallpaperType drawerBottomBackgroundType; - Color drawerBottomBackgroundColor1; - Color drawerBottomBackgroundColor2; - String? drawerBottomBackgroundImagePath; CustomThemePreset({ required this.id, @@ -174,21 +155,6 @@ class CustomThemePreset { this.useDesktopLayout = true, this.useAutoReplyColor = true, this.customReplyColor, - this.mobileChatBottomPadding = 140.0, - this.ignoreMobileBottomPaddingWhenKeyboard = true, - this.useExperimentalChatsListBackground = false, - this.experimentalChatsListBackgroundType = ChatWallpaperType.solid, - this.experimentalChatsListBackgroundColor1 = const Color(0xFF101010), - this.experimentalChatsListBackgroundColor2 = const Color(0xFF202020), - this.experimentalChatsListBackgroundImagePath, - this.drawerTopBackgroundType = ChatWallpaperType.solid, - this.drawerTopBackgroundColor1 = const Color(0xFF1E1E1E), - this.drawerTopBackgroundColor2 = const Color(0xFF2E2E2E), - this.drawerTopBackgroundImagePath, - this.drawerBottomBackgroundType = ChatWallpaperType.solid, - this.drawerBottomBackgroundColor1 = const Color(0xFF1E1E1E), - this.drawerBottomBackgroundColor2 = const Color(0xFF2E2E2E), - this.drawerBottomBackgroundImagePath, }); factory CustomThemePreset.createDefault() { @@ -245,21 +211,6 @@ class CustomThemePreset { bool? useDesktopLayout, bool? useAutoReplyColor, Color? customReplyColor, - double? mobileChatBottomPadding, - bool? ignoreMobileBottomPaddingWhenKeyboard, - bool? useExperimentalChatsListBackground, - ChatWallpaperType? experimentalChatsListBackgroundType, - Color? experimentalChatsListBackgroundColor1, - Color? experimentalChatsListBackgroundColor2, - String? experimentalChatsListBackgroundImagePath, - ChatWallpaperType? drawerTopBackgroundType, - Color? drawerTopBackgroundColor1, - Color? drawerTopBackgroundColor2, - String? drawerTopBackgroundImagePath, - ChatWallpaperType? drawerBottomBackgroundType, - Color? drawerBottomBackgroundColor1, - Color? drawerBottomBackgroundColor2, - String? drawerBottomBackgroundImagePath, }) { return CustomThemePreset( id: id ?? this.id, @@ -320,35 +271,6 @@ class CustomThemePreset { useDesktopLayout: useDesktopLayout ?? this.useDesktopLayout, useAutoReplyColor: useAutoReplyColor ?? this.useAutoReplyColor, customReplyColor: customReplyColor ?? this.customReplyColor, - mobileChatBottomPadding: - mobileChatBottomPadding ?? this.mobileChatBottomPadding, - ignoreMobileBottomPaddingWhenKeyboard: - ignoreMobileBottomPaddingWhenKeyboard ?? - this.ignoreMobileBottomPaddingWhenKeyboard, - useExperimentalChatsListBackground: useExperimentalChatsListBackground ?? - this.useExperimentalChatsListBackground, - experimentalChatsListBackgroundType: experimentalChatsListBackgroundType ?? - this.experimentalChatsListBackgroundType, - experimentalChatsListBackgroundColor1: experimentalChatsListBackgroundColor1 ?? - this.experimentalChatsListBackgroundColor1, - experimentalChatsListBackgroundColor2: experimentalChatsListBackgroundColor2 ?? - this.experimentalChatsListBackgroundColor2, - experimentalChatsListBackgroundImagePath: experimentalChatsListBackgroundImagePath ?? - this.experimentalChatsListBackgroundImagePath, - drawerTopBackgroundType: drawerTopBackgroundType ?? this.drawerTopBackgroundType, - drawerTopBackgroundColor1: - drawerTopBackgroundColor1 ?? this.drawerTopBackgroundColor1, - drawerTopBackgroundColor2: - drawerTopBackgroundColor2 ?? this.drawerTopBackgroundColor2, - drawerTopBackgroundImagePath: - drawerTopBackgroundImagePath ?? this.drawerTopBackgroundImagePath, - drawerBottomBackgroundType: drawerBottomBackgroundType ?? this.drawerBottomBackgroundType, - drawerBottomBackgroundColor1: - drawerBottomBackgroundColor1 ?? this.drawerBottomBackgroundColor1, - drawerBottomBackgroundColor2: - drawerBottomBackgroundColor2 ?? this.drawerBottomBackgroundColor2, - drawerBottomBackgroundImagePath: - drawerBottomBackgroundImagePath ?? this.drawerBottomBackgroundImagePath, ); } @@ -403,22 +325,6 @@ class CustomThemePreset { 'useDesktopLayout': useDesktopLayout, 'useAutoReplyColor': useAutoReplyColor, 'customReplyColor': customReplyColor?.value, - 'mobileChatBottomPadding': mobileChatBottomPadding, - 'ignoreMobileBottomPaddingWhenKeyboard': - ignoreMobileBottomPaddingWhenKeyboard, - 'useExperimentalChatsListBackground': useExperimentalChatsListBackground, - 'experimentalChatsListBackgroundType': experimentalChatsListBackgroundType.index, - 'experimentalChatsListBackgroundColor1': experimentalChatsListBackgroundColor1.value, - 'experimentalChatsListBackgroundColor2': experimentalChatsListBackgroundColor2.value, - 'experimentalChatsListBackgroundImagePath': experimentalChatsListBackgroundImagePath, - 'drawerTopBackgroundType': drawerTopBackgroundType.index, - 'drawerTopBackgroundColor1': drawerTopBackgroundColor1.value, - 'drawerTopBackgroundColor2': drawerTopBackgroundColor2.value, - 'drawerTopBackgroundImagePath': drawerTopBackgroundImagePath, - 'drawerBottomBackgroundType': drawerBottomBackgroundType.index, - 'drawerBottomBackgroundColor1': drawerBottomBackgroundColor1.value, - 'drawerBottomBackgroundColor2': drawerBottomBackgroundColor2.value, - 'drawerBottomBackgroundImagePath': drawerBottomBackgroundImagePath, }; } @@ -516,44 +422,6 @@ class CustomThemePreset { customReplyColor: json['customReplyColor'] != null ? Color(json['customReplyColor'] as int) : null, - mobileChatBottomPadding: - (json['mobileChatBottomPadding'] as double? ?? 140.0).clamp( - 60.0, - 240.0, - ), - ignoreMobileBottomPaddingWhenKeyboard: - json['ignoreMobileBottomPaddingWhenKeyboard'] as bool? ?? true, - useExperimentalChatsListBackground: json['useExperimentalChatsListBackground'] as bool? ?? false, - experimentalChatsListBackgroundType: () { - final index = json['experimentalChatsListBackgroundType'] as int?; - if (index == null || index < 0 || index >= ChatWallpaperType.values.length) { - return ChatWallpaperType.solid; - } - return ChatWallpaperType.values[index]; - }(), - experimentalChatsListBackgroundColor1: Color(json['experimentalChatsListBackgroundColor1'] as int? ?? const Color(0xFF101010).value), - experimentalChatsListBackgroundColor2: Color(json['experimentalChatsListBackgroundColor2'] as int? ?? const Color(0xFF202020).value), - experimentalChatsListBackgroundImagePath: json['experimentalChatsListBackgroundImagePath'] as String?, - drawerTopBackgroundType: () { - final index = json['drawerTopBackgroundType'] as int?; - if (index == null || index < 0 || index >= ChatWallpaperType.values.length) { - return ChatWallpaperType.solid; - } - return ChatWallpaperType.values[index]; - }(), - drawerTopBackgroundColor1: Color(json['drawerTopBackgroundColor1'] as int? ?? const Color(0xFF1E1E1E).value), - drawerTopBackgroundColor2: Color(json['drawerTopBackgroundColor2'] as int? ?? const Color(0xFF2E2E2E).value), - drawerTopBackgroundImagePath: json['drawerTopBackgroundImagePath'] as String?, - drawerBottomBackgroundType: () { - final index = json['drawerBottomBackgroundType'] as int?; - if (index == null || index < 0 || index >= ChatWallpaperType.values.length) { - return ChatWallpaperType.solid; - } - return ChatWallpaperType.values[index]; - }(), - drawerBottomBackgroundColor1: Color(json['drawerBottomBackgroundColor1'] as int? ?? const Color(0xFF1E1E1E).value), - drawerBottomBackgroundColor2: Color(json['drawerBottomBackgroundColor2'] as int? ?? const Color(0xFF2E2E2E).value), - drawerBottomBackgroundImagePath: json['drawerBottomBackgroundImagePath'] as String?, ); } } @@ -661,26 +529,6 @@ class ThemeProvider with ChangeNotifier { bool get debugShowMessageCount => _debugShowMessageCount; bool get debugReadOnEnter => _debugReadOnEnter; bool get debugReadOnAction => _debugReadOnAction; - double get mobileChatBottomPadding => _activeTheme.mobileChatBottomPadding; - bool get ignoreMobileBottomPaddingWhenKeyboard => - _activeTheme.ignoreMobileBottomPaddingWhenKeyboard; - - // Экспериментальные настройки фона - bool get useExperimentalChatsListBackground => _activeTheme.useExperimentalChatsListBackground; - ChatWallpaperType get experimentalChatsListBackgroundType => _activeTheme.experimentalChatsListBackgroundType; - Color get experimentalChatsListBackgroundColor1 => _activeTheme.experimentalChatsListBackgroundColor1; - Color get experimentalChatsListBackgroundColor2 => _activeTheme.experimentalChatsListBackgroundColor2; - String? get experimentalChatsListBackgroundImagePath => _activeTheme.experimentalChatsListBackgroundImagePath; - - ChatWallpaperType get drawerTopBackgroundType => _activeTheme.drawerTopBackgroundType; - Color get drawerTopBackgroundColor1 => _activeTheme.drawerTopBackgroundColor1; - Color get drawerTopBackgroundColor2 => _activeTheme.drawerTopBackgroundColor2; - String? get drawerTopBackgroundImagePath => _activeTheme.drawerTopBackgroundImagePath; - - ChatWallpaperType get drawerBottomBackgroundType => _activeTheme.drawerBottomBackgroundType; - Color get drawerBottomBackgroundColor1 => _activeTheme.drawerBottomBackgroundColor1; - Color get drawerBottomBackgroundColor2 => _activeTheme.drawerBottomBackgroundColor2; - String? get drawerBottomBackgroundImagePath => _activeTheme.drawerBottomBackgroundImagePath; TransitionOption get chatTransition => _activeTheme.ultraOptimizeChats ? TransitionOption.systemDefault @@ -1364,101 +1212,6 @@ class ThemeProvider with ChangeNotifier { await _saveActiveTheme(); } - Future setMobileChatBottomPadding(double value) async { - final clamped = value.clamp(60.0, 240.0); - _activeTheme = _activeTheme.copyWith( - mobileChatBottomPadding: clamped, - ); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setIgnoreMobileBottomPaddingWhenKeyboard(bool value) async { - _activeTheme = _activeTheme.copyWith( - ignoreMobileBottomPaddingWhenKeyboard: value, - ); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setUseExperimentalChatsListBackground(bool value) async { - _activeTheme = _activeTheme.copyWith(useExperimentalChatsListBackground: value); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setExperimentalChatsListBackgroundType(ChatWallpaperType value) async { - _activeTheme = _activeTheme.copyWith(experimentalChatsListBackgroundType: value); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setExperimentalChatsListBackgroundColor1(Color value) async { - _activeTheme = _activeTheme.copyWith(experimentalChatsListBackgroundColor1: value); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setExperimentalChatsListBackgroundColor2(Color value) async { - _activeTheme = _activeTheme.copyWith(experimentalChatsListBackgroundColor2: value); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setExperimentalChatsListBackgroundImagePath(String? path) async { - _activeTheme = _activeTheme.copyWith(experimentalChatsListBackgroundImagePath: path); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setDrawerTopBackgroundType(ChatWallpaperType value) async { - _activeTheme = _activeTheme.copyWith(drawerTopBackgroundType: value); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setDrawerTopBackgroundColor1(Color value) async { - _activeTheme = _activeTheme.copyWith(drawerTopBackgroundColor1: value); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setDrawerTopBackgroundColor2(Color value) async { - _activeTheme = _activeTheme.copyWith(drawerTopBackgroundColor2: value); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setDrawerTopBackgroundImagePath(String? path) async { - _activeTheme = _activeTheme.copyWith(drawerTopBackgroundImagePath: path); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setDrawerBottomBackgroundType(ChatWallpaperType value) async { - _activeTheme = _activeTheme.copyWith(drawerBottomBackgroundType: value); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setDrawerBottomBackgroundColor1(Color value) async { - _activeTheme = _activeTheme.copyWith(drawerBottomBackgroundColor1: value); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setDrawerBottomBackgroundColor2(Color value) async { - _activeTheme = _activeTheme.copyWith(drawerBottomBackgroundColor2: value); - notifyListeners(); - await _saveActiveTheme(); - } - - Future setDrawerBottomBackgroundImagePath(String? path) async { - _activeTheme = _activeTheme.copyWith(drawerBottomBackgroundImagePath: path); - notifyListeners(); - await _saveActiveTheme(); - } - Future setCustomReplyColor(Color? color) async { _activeTheme = _activeTheme.copyWith(customReplyColor: color); notifyListeners();