Import IKAR messenger client and server

This commit is contained in:
sevenhill
2026-10-07 22:06:07 +03:00
commit 69ea5091eb
1951 changed files with 424546 additions and 0 deletions
+243
View File
@@ -0,0 +1,243 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:ikar/frontend/widgets/keyboard_dismissal.dart';
Widget _app(Widget body, {List<NavigatorObserver> observers = const []}) {
return MaterialApp(
navigatorObservers: observers,
builder: (context, child) => KeyboardDismissal(child: child!),
home: Scaffold(body: body),
);
}
final _ios = TargetPlatformVariant.only(TargetPlatform.iOS);
void main() {
late FocusNode focus;
setUp(() => focus = FocusNode());
tearDown(() => focus.dispose());
Future<void> focusField(WidgetTester tester) async {
await tester.tap(find.byKey(const ValueKey('field')));
await tester.pump();
expect(focus.hasFocus, isTrue);
}
testWidgets('iOS: a short tap outside the field hides the keyboard', (
tester,
) async {
await tester.pumpWidget(
_app(
Column(
children: [
TextField(key: const ValueKey('field'), focusNode: focus),
const SizedBox(key: ValueKey('outside'), height: 300),
],
),
),
);
await focusField(tester);
await tester.tap(find.byKey(const ValueKey('outside')));
await tester.pump();
expect(focus.hasFocus, isFalse);
}, variant: _ios);
testWidgets('iOS: a long press or a drag keeps the keyboard', (tester) async {
await tester.pumpWidget(
_app(
Column(
children: [
TextField(key: const ValueKey('field'), focusNode: focus),
const SizedBox(key: ValueKey('outside'), height: 300),
],
),
),
);
await focusField(tester);
final hold = await tester.startGesture(
tester.getCenter(find.byKey(const ValueKey('outside'))),
);
await tester.pump(const Duration(seconds: 1));
await hold.up(timeStamp: const Duration(seconds: 1));
await tester.pump();
expect(focus.hasFocus, isTrue);
await tester.dragFrom(
tester.getCenter(find.byKey(const ValueKey('outside'))),
const Offset(120, 0),
);
await tester.pump();
expect(focus.hasFocus, isTrue);
}, variant: _ios);
testWidgets('iOS: buttons inside TextFieldTapRegion keep the keyboard', (
tester,
) async {
var sent = 0;
await tester.pumpWidget(
_app(
TextFieldTapRegion(
child: Row(
children: [
Expanded(
child: TextField(
key: const ValueKey('field'),
focusNode: focus,
),
),
IconButton(
key: const ValueKey('send'),
onPressed: () => sent++,
icon: const Icon(Icons.send),
),
],
),
),
),
);
await focusField(tester);
await tester.tap(find.byKey(const ValueKey('send')));
await tester.pump();
expect(sent, 1);
expect(focus.hasFocus, isTrue);
}, variant: _ios);
testWidgets(
'iOS: vertical scrolling hides the keyboard, horizontal does not',
(tester) async {
await tester.pumpWidget(
_app(
Column(
children: [
TextField(key: const ValueKey('field'), focusNode: focus),
SizedBox(
height: 80,
child: ListView(
key: const ValueKey('row'),
scrollDirection: Axis.horizontal,
children: [
for (var i = 0; i < 20; i++)
SizedBox(width: 80, child: Text('h$i')),
],
),
),
Expanded(
child: ListView(
key: const ValueKey('list'),
children: [
for (var i = 0; i < 40; i++)
SizedBox(height: 60, child: Text('v$i')),
],
),
),
],
),
),
);
await focusField(tester);
await tester.drag(
find.byKey(const ValueKey('row')),
const Offset(-200, 0),
);
await tester.pump();
expect(focus.hasFocus, isTrue);
await tester.drag(
find.byKey(const ValueKey('list')),
const Offset(0, -200),
);
await tester.pump();
expect(focus.hasFocus, isFalse);
},
variant: _ios,
);
testWidgets('iOS: scrolling inside a multiline field keeps the keyboard', (
tester,
) async {
await tester.pumpWidget(
_app(
ListView(
children: [
TextField(
key: const ValueKey('field'),
focusNode: focus,
maxLines: 3,
controller: TextEditingController(
text: List.generate(30, (i) => 'строка $i').join('\n'),
),
),
],
),
),
);
await focusField(tester);
await tester.drag(find.byType(EditableText), const Offset(0, -60));
await tester.pump();
expect(focus.hasFocus, isTrue);
}, variant: _ios);
testWidgets('iOS: opening a screen hides the keyboard', (tester) async {
final navigator = GlobalKey<NavigatorState>();
await tester.pumpWidget(
MaterialApp(
navigatorKey: navigator,
navigatorObservers: [KeyboardNavigatorObserver()],
home: Scaffold(
body: TextField(key: const ValueKey('field'), focusNode: focus),
),
),
);
await focusField(tester);
navigator.currentState!.push(
MaterialPageRoute<void>(builder: (_) => const Scaffold()),
);
await tester.pumpAndSettle();
expect(focus.hasFocus, isFalse);
}, variant: _ios);
testWidgets('iOS: starting the back swipe hides the keyboard', (
tester,
) async {
await tester.pumpWidget(
_app(TextField(key: const ValueKey('field'), focusNode: focus)),
);
await focusField(tester);
KeyboardNavigatorObserver().didStartUserGesture(
MaterialPageRoute<void>(builder: (_) => const SizedBox()),
null,
);
await tester.pump();
expect(focus.hasFocus, isFalse);
}, variant: _ios);
testWidgets(
'Android keeps the default: a tap outside keeps the keyboard',
(tester) async {
await tester.pumpWidget(
_app(
Column(
children: [
TextField(key: const ValueKey('field'), focusNode: focus),
const SizedBox(key: ValueKey('outside'), height: 300),
],
),
),
);
await focusField(tester);
await tester.tap(find.byKey(const ValueKey('outside')));
await tester.pump();
expect(focus.hasFocus, isTrue);
},
variant: TargetPlatformVariant.only(TargetPlatform.android),
);
}