fix: фикс отступов, фикс перемещения чатов при запуске
This commit is contained in:
@@ -598,6 +598,7 @@ class AccountModule {
|
||||
profile.id,
|
||||
config.cast<dynamic, dynamic>(),
|
||||
);
|
||||
await chats.applyFavorites(profile.id);
|
||||
final userConfig = config['user'];
|
||||
if (userConfig is Map) {
|
||||
await AppDatabase.savePrivacyConfig(profile.id, jsonEncode(userConfig));
|
||||
|
||||
@@ -163,13 +163,14 @@ _resolveLastMessage(dynamic lastMsg) {
|
||||
Map<int, CachedChat> existing,
|
||||
) {
|
||||
final config = chatsConfig[id.toString()] ?? chatsConfig[id];
|
||||
final ex = existing[id];
|
||||
if (config is Map) {
|
||||
final configFav = config['favIndex'] as int?;
|
||||
return (
|
||||
favIndex: config['favIndex'] as int?,
|
||||
favIndex: (configFav != null && configFav > 0) ? configFav : ex?.favIndex,
|
||||
dontDisturbUntil: (config['dontDisturbUntil'] as int?) ?? 0,
|
||||
);
|
||||
}
|
||||
final ex = existing[id];
|
||||
if (ex != null) {
|
||||
return (favIndex: ex.favIndex, dontDisturbUntil: ex.dontDisturbUntil);
|
||||
}
|
||||
|
||||
@@ -745,10 +745,7 @@ class MessageBubble extends StatelessWidget {
|
||||
if (showAvatar)
|
||||
_buildLeadingAvatar(cs)
|
||||
else if (showAvatarSlot && chatType == "CHAT")
|
||||
const CircleAvatar(
|
||||
radius: 15,
|
||||
backgroundColor: Color(0x00000000),
|
||||
),
|
||||
const SizedBox(width: 30),
|
||||
Column(
|
||||
crossAxisAlignment: isMe
|
||||
? CrossAxisAlignment.end
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:komet/backend/modules/chat_parsing.dart';
|
||||
import 'package:komet/backend/modules/chats.dart';
|
||||
|
||||
const int _me = 4242;
|
||||
const int _chatId = -1000000000001;
|
||||
|
||||
CachedChat _cached({int? favIndex}) => CachedChat(
|
||||
id: _chatId,
|
||||
accountId: _me,
|
||||
type: 'CHAT',
|
||||
title: 'pinned chat',
|
||||
unreadCount: 0,
|
||||
lastEventTime: 1700000000000,
|
||||
cachedAt: 0,
|
||||
favIndex: favIndex,
|
||||
dontDisturbUntil: 0,
|
||||
isOnline: false,
|
||||
seenTime: 0,
|
||||
participants: {_me: 1700000000000},
|
||||
);
|
||||
|
||||
CachedChat _parse({
|
||||
Map<dynamic, dynamic> chatsConfig = const {},
|
||||
CachedChat? existing,
|
||||
}) => parseChatRow(
|
||||
{
|
||||
'id': _chatId,
|
||||
'type': 'CHAT',
|
||||
'title': 'pinned chat',
|
||||
'lastEventTime': 1700000000000,
|
||||
'participants': {'$_me': 1700000000000},
|
||||
},
|
||||
_me,
|
||||
_me,
|
||||
const {},
|
||||
chatsConfig,
|
||||
const {},
|
||||
existing == null ? const {} : {_chatId: existing},
|
||||
0,
|
||||
)!;
|
||||
|
||||
void main() {
|
||||
group('login sync keeps pins', () {
|
||||
test('a zero favIndex in the config does not unpin a cached chat', () {
|
||||
final parsed = _parse(
|
||||
chatsConfig: {
|
||||
'$_chatId': {'favIndex': 0, 'dontDisturbUntil': 0},
|
||||
},
|
||||
existing: _cached(favIndex: 3),
|
||||
);
|
||||
expect(parsed.favIndex, 3);
|
||||
});
|
||||
|
||||
test('a real favIndex from the config wins', () {
|
||||
final parsed = _parse(
|
||||
chatsConfig: {
|
||||
'$_chatId': {'favIndex': 2, 'dontDisturbUntil': 0},
|
||||
},
|
||||
existing: _cached(favIndex: 3),
|
||||
);
|
||||
expect(parsed.favIndex, 2);
|
||||
});
|
||||
|
||||
test('mute settings still come from the config', () {
|
||||
final parsed = _parse(
|
||||
chatsConfig: {
|
||||
'$_chatId': {'favIndex': 0, 'dontDisturbUntil': -1},
|
||||
},
|
||||
existing: _cached(favIndex: 3),
|
||||
);
|
||||
expect(parsed.dontDisturbUntil, -1);
|
||||
expect(parsed.isMuted, isTrue);
|
||||
});
|
||||
|
||||
test('a chat with no cached pin stays unpinned', () {
|
||||
final parsed = _parse(
|
||||
chatsConfig: {
|
||||
'$_chatId': {'favIndex': 0, 'dontDisturbUntil': 0},
|
||||
},
|
||||
);
|
||||
expect(parsed.favIndex, isNull);
|
||||
});
|
||||
|
||||
test('without a config entry the cached pin survives', () {
|
||||
expect(_parse(existing: _cached(favIndex: 5)).favIndex, 5);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -35,6 +35,56 @@ CachedMessage _message({
|
||||
: null,
|
||||
);
|
||||
|
||||
Future<void> _pumpColumn(
|
||||
WidgetTester tester,
|
||||
List<CachedMessage> messages, {
|
||||
required String chatType,
|
||||
double textScale = 1,
|
||||
}) async {
|
||||
tester.view.physicalSize = const Size(1080, 2400);
|
||||
tester.view.devicePixelRatio = 2.5;
|
||||
addTearDown(tester.view.reset);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
locale: const Locale('ru'),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: Scaffold(
|
||||
body: MediaQuery(
|
||||
data: MediaQueryData(textScaler: TextScaler.linear(textScale)),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
for (var i = 0; i < messages.length; i++)
|
||||
MessageBubble(
|
||||
key: ValueKey('bubble$i'),
|
||||
message: messages[i],
|
||||
prevMessage: i > 0 ? messages[i - 1] : null,
|
||||
nextMessage: i < messages.length - 1 ? messages[i + 1] : null,
|
||||
isMe: false,
|
||||
myId: _me,
|
||||
chatType: chatType,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
}
|
||||
|
||||
Rect _bubbleRect(WidgetTester tester, int index, String text) {
|
||||
final label = find.descendant(
|
||||
of: find.byKey(ValueKey('bubble$index')),
|
||||
matching: find.text(text),
|
||||
);
|
||||
final box = find.ancestor(of: label, matching: find.byType(Container)).first;
|
||||
return tester.getTopLeft(box) & tester.getSize(box);
|
||||
}
|
||||
|
||||
Future<void> _pumpBubble(WidgetTester tester, CachedMessage message) async {
|
||||
tester.view.physicalSize = const Size(1080, 2400);
|
||||
tester.view.devicePixelRatio = 2.5;
|
||||
@@ -103,6 +153,36 @@ void main() {
|
||||
expect(clock.right, closeTo(header.right, 1));
|
||||
});
|
||||
|
||||
testWidgets('grouped bubbles keep the same gap with and without avatars', (
|
||||
tester,
|
||||
) async {
|
||||
final stream = [
|
||||
for (var i = 0; i < 4; i++)
|
||||
CachedMessage(
|
||||
id: '$i',
|
||||
accountId: _me,
|
||||
chatId: 2,
|
||||
senderId: 404,
|
||||
text: 'm$i',
|
||||
time: DateTime(2026, 1, 1, 12, 54).millisecondsSinceEpoch + i * 1000,
|
||||
status: 'sent',
|
||||
),
|
||||
];
|
||||
|
||||
double gapAt(WidgetTester tester, int index) =>
|
||||
_bubbleRect(tester, index + 1, 'm${index + 1}').top -
|
||||
_bubbleRect(tester, index, 'm$index').bottom;
|
||||
|
||||
await _pumpColumn(tester, stream, chatType: 'DIALOG', textScale: 0.35);
|
||||
final dialogGaps = [for (var i = 0; i < 3; i++) gapAt(tester, i)];
|
||||
|
||||
await _pumpColumn(tester, stream, chatType: 'CHAT', textScale: 0.35);
|
||||
final groupGaps = [for (var i = 0; i < 3; i++) gapAt(tester, i)];
|
||||
|
||||
expect(dialogGaps, everyElement(2.0));
|
||||
expect(groupGaps, dialogGaps);
|
||||
});
|
||||
|
||||
testWidgets('a bubble without a header or reply still hugs its text', (
|
||||
tester,
|
||||
) async {
|
||||
|
||||
Reference in New Issue
Block a user