212 lines
7.0 KiB
Dart
212 lines
7.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:ikar/backend/modules/messages.dart';
|
|
import 'package:ikar/frontend/widgets/liquid_glass.dart';
|
|
import 'package:ikar/frontend/widgets/photo_viewer.dart';
|
|
import 'package:ikar/l10n/app_localizations.dart';
|
|
import 'package:ikar/models/attachment.dart';
|
|
import 'package:material_symbols_icons/symbols.dart';
|
|
|
|
const _video = VideoAttachment(
|
|
videoId: 42,
|
|
videoToken: 'synthetic-token',
|
|
duration: 12000,
|
|
width: 1280,
|
|
height: 720,
|
|
);
|
|
|
|
final _message = CachedMessage(
|
|
id: 'synthetic-message',
|
|
accountId: 1,
|
|
chatId: 2,
|
|
senderId: 3,
|
|
text: 'Синтетическая подпись',
|
|
time: DateTime(2026, 1, 2, 12, 34).millisecondsSinceEpoch,
|
|
attachments: const [_video],
|
|
);
|
|
|
|
Future<void> _pumpVideo(
|
|
WidgetTester tester, {
|
|
PhotoViewerActions? actions,
|
|
Size size = const Size(1200, 1800),
|
|
}) async {
|
|
tester.view.physicalSize = size;
|
|
tester.view.devicePixelRatio = 2;
|
|
addTearDown(tester.view.reset);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
locale: const Locale('ru'),
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
home: PhotoViewerScreen.video(
|
|
attachment: _video,
|
|
initialVideoSources: const {
|
|
'720p': 'https://media.example.test/video-720.mp4',
|
|
'360p': 'https://media.example.test/video-360.mp4',
|
|
},
|
|
message: _message,
|
|
actions: actions,
|
|
sourceName: 'Тестовый чат',
|
|
),
|
|
),
|
|
);
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 50));
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('video uses the shared media chrome and advanced controls', (
|
|
tester,
|
|
) async {
|
|
await _pumpVideo(tester);
|
|
|
|
expect(find.text('1 из 1'), findsOneWidget);
|
|
expect(find.textContaining('Тестовый чат'), findsOneWidget);
|
|
expect(find.text('00:00'), findsOneWidget);
|
|
expect(find.text('00:12'), findsOneWidget);
|
|
expect(find.byKey(const ValueKey('video-play-toggle')), findsOneWidget);
|
|
expect(find.byKey(const ValueKey('video-settings')), findsOneWidget);
|
|
expect(find.byKey(const ValueKey('downloads-button')), findsNothing);
|
|
expect(find.byIcon(Symbols.rotate_90_degrees_ccw), findsOneWidget);
|
|
expect(find.byIcon(Symbols.download), findsNothing);
|
|
expect(find.byType(GlassSurface), findsOneWidget);
|
|
expect(find.text('Синтетическая подпись'), findsOneWidget);
|
|
|
|
final playCenter = tester.getCenter(
|
|
find.byKey(const ValueKey('video-play-toggle')),
|
|
);
|
|
expect(playCenter.dx, closeTo(tester.view.physicalSize.width / 4, 0.1));
|
|
});
|
|
|
|
testWidgets('landscape folds the controls into one row clear of the video', (
|
|
tester,
|
|
) async {
|
|
await _pumpVideo(tester, size: const Size(1800, 720));
|
|
final height =
|
|
tester.view.physicalSize.height / tester.view.devicePixelRatio;
|
|
|
|
final play = tester.getCenter(
|
|
find.byKey(const ValueKey('video-play-toggle')),
|
|
);
|
|
expect(tester.getCenter(find.text('00:12')).dy, closeTo(play.dy, 0.5));
|
|
expect(
|
|
tester.getCenter(find.byKey(const ValueKey('video-settings'))).dy,
|
|
closeTo(play.dy, 0.5),
|
|
);
|
|
|
|
expect(tester.getCenter(find.text('1 из 1')).dy, lessThan(height / 4));
|
|
expect(
|
|
tester.getCenter(find.byIcon(Symbols.rotate_90_degrees_ccw)).dy,
|
|
lessThan(height / 4),
|
|
);
|
|
expect(
|
|
tester.getTopLeft(find.byType(GlassSurface)).dy,
|
|
greaterThan(height * 0.7),
|
|
);
|
|
});
|
|
|
|
testWidgets('video rotates left inside the shared viewer', (tester) async {
|
|
await _pumpVideo(tester);
|
|
|
|
RotatedBox rotation() =>
|
|
tester.widget<RotatedBox>(find.byKey(const ValueKey('video-rotation')));
|
|
|
|
expect(rotation().quarterTurns, 0);
|
|
await tester.tap(find.byIcon(Symbols.rotate_90_degrees_ccw));
|
|
await tester.pump();
|
|
expect(rotation().quarterTurns, 3);
|
|
});
|
|
|
|
testWidgets('settings contain playback speed and available qualities', (
|
|
tester,
|
|
) async {
|
|
await _pumpVideo(tester);
|
|
|
|
await tester.tap(find.byKey(const ValueKey('video-settings')));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 300));
|
|
|
|
expect(find.text('Скорость'), findsOneWidget);
|
|
expect(find.text('0.5x'), findsOneWidget);
|
|
expect(find.text('1.0x'), findsOneWidget);
|
|
expect(find.text('2x'), findsOneWidget);
|
|
expect(find.text('Качество'), findsOneWidget);
|
|
expect(find.text('720p'), findsOneWidget);
|
|
expect(find.text('360p'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('video menu reuses media actions without frame sharing', (
|
|
tester,
|
|
) async {
|
|
await _pumpVideo(
|
|
tester,
|
|
actions: PhotoViewerActions(
|
|
goToMessage: (_, _) {},
|
|
forward: (_) {},
|
|
delete: (_, _) {},
|
|
viewAllMedia: () {},
|
|
),
|
|
);
|
|
|
|
await tester.tap(find.byIcon(Symbols.more_vert));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 300));
|
|
|
|
expect(find.text('Перейти к сообщению'), findsOneWidget);
|
|
expect(find.text('Переслать'), findsOneWidget);
|
|
expect(find.text('Удалить'), findsOneWidget);
|
|
expect(find.text('Сохранить как…'), findsOneWidget);
|
|
expect(find.text('Все медиа чата'), findsOneWidget);
|
|
expect(find.textContaining('Share at'), findsNothing);
|
|
expect(find.textContaining('Copy Frame'), findsNothing);
|
|
});
|
|
|
|
testWidgets('a video that fails to load can be closed from the error view', (
|
|
tester,
|
|
) async {
|
|
tester.view.physicalSize = const Size(1200, 1800);
|
|
tester.view.devicePixelRatio = 2;
|
|
addTearDown(tester.view.reset);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
locale: const Locale('ru'),
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
home: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: TextButton(
|
|
onPressed: () => Navigator.of(context).push(
|
|
MaterialPageRoute<void>(
|
|
builder: (_) => PhotoViewerScreen.video(
|
|
attachment: _video,
|
|
initialVideoSources: const {
|
|
'720p': 'https://media.example.test/video-720.mp4',
|
|
},
|
|
message: _message,
|
|
),
|
|
),
|
|
),
|
|
child: const Text('Открыть'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.tap(find.text('Открыть'));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 500));
|
|
|
|
expect(find.text('Не удалось воспроизвести видео'), findsOneWidget);
|
|
expect(find.text('Повторить'), findsOneWidget);
|
|
|
|
await tester.tap(find.text('Закрыть'));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 500));
|
|
|
|
expect(find.byType(PhotoViewerScreen), findsNothing);
|
|
expect(find.text('Открыть'), findsOneWidget);
|
|
});
|
|
}
|