Initial commit

This commit is contained in:
admin1
2026-07-14 11:11:36 +08:00
commit 656499cf94
604 changed files with 119518 additions and 0 deletions
@@ -0,0 +1,171 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:smplayer/core/contracts/library.dart';
import 'package:smplayer/features/aggregated/aggregated_grouping.dart';
import 'package:smplayer/features/history/widgets/history_source_picker.dart';
void main() {
testWidgets('shows each server independent playback progress', (
tester,
) async {
final now = DateTime(2026, 7, 11, 12);
final partiallyWatchedSource = _entrySource(
serverId: 'alpha',
serverName: 'Alpha',
itemId: 'alpha-movie',
playbackPositionTicks: 600000000,
runtimeTicks: 1200000000,
lastPlayedDate: now.subtract(const Duration(hours: 1)),
);
final completedSource = _entrySource(
serverId: 'beta',
serverName: 'Beta',
itemId: 'beta-movie',
played: true,
runtimeTicks: 1200000000,
lastPlayedDate: now.subtract(const Duration(hours: 2)),
);
final unknownProgressSource = _entrySource(
serverId: 'gamma',
serverName: 'Gamma',
itemId: 'gamma-movie',
);
final entry = AggregatedEntry(
item: partiallyWatchedSource.item,
source: partiallyWatchedSource.source,
sources: [partiallyWatchedSource, completedSource, unknownProgressSource],
);
AggregatedEntrySource? selectedSource;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: HistorySourcePickerContent(
entry: entry,
now: now,
onSourceSelected: (source) => selectedSource = source,
),
),
),
);
expect(find.text('最近播放'), findsOneWidget);
expect(find.text('已看 50% · 剩余 1 分钟 · 1 小时前'), findsOneWidget);
expect(find.text('已看完 · 2 小时前'), findsOneWidget);
expect(find.text('进度未知 · 未记录播放时间'), findsOneWidget);
final progressIndicators = tester.widgetList<LinearProgressIndicator>(
find.byType(LinearProgressIndicator),
);
expect(progressIndicators.map((indicator) => indicator.value), [0.5, 1, 0]);
await tester.tap(find.text('Beta'));
await tester.pump();
expect(selectedSource, same(completedSource));
});
testWidgets('adaptive picker lets the user choose another server', (
tester,
) async {
tester.view.physicalSize = const Size(480, 800);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetDevicePixelRatio);
final now = DateTime(2026, 7, 11, 12);
final alphaSource = _entrySource(
serverId: 'alpha',
serverName: 'Alpha',
itemId: 'alpha-movie',
playbackPositionTicks: 600000000,
runtimeTicks: 1200000000,
lastPlayedDate: now.subtract(const Duration(hours: 1)),
);
final betaSource = _entrySource(
serverId: 'beta',
serverName: 'Beta',
itemId: 'beta-movie',
playbackPositionTicks: 300000000,
runtimeTicks: 1200000000,
lastPlayedDate: now.subtract(const Duration(hours: 2)),
);
final entry = AggregatedEntry(
item: alphaSource.item,
source: alphaSource.source,
sources: [alphaSource, betaSource],
);
AggregatedEntrySource? selectedSource;
await tester.pumpWidget(
ProviderScope(
child: MaterialApp(
home: Scaffold(
body: Builder(
builder: (context) => TextButton(
onPressed: () async {
selectedSource = await showHistorySourcePicker(
context,
entry: entry,
now: now,
);
},
child: const Text('打开服务器选择'),
),
),
),
),
),
);
await tester.tap(find.text('打开服务器选择'));
await tester.pumpAndSettle();
expect(find.text('选择服务器'), findsOneWidget);
expect(find.text('Alpha'), findsOneWidget);
expect(find.text('Beta'), findsOneWidget);
await tester.tap(find.text('Beta'));
await tester.pumpAndSettle();
expect(selectedSource, same(betaSource));
expect(find.text('选择服务器'), findsNothing);
});
}
AggregatedEntrySource _entrySource({
required String serverId,
required String serverName,
required String itemId,
int? playbackPositionTicks,
int? runtimeTicks,
bool? played,
DateTime? lastPlayedDate,
}) {
final item = EmbyRawItem(
Id: itemId,
Name: 'Movie',
Type: 'Movie',
RunTimeTicks: runtimeTicks,
UserData: playbackPositionTicks != null || played != null
? EmbyRawUserData(
PlaybackPositionTicks: playbackPositionTicks,
Played: played,
)
: null,
extra: {
if (lastPlayedDate != null)
'UserData': {'LastPlayedDate': lastPlayedDate},
},
);
final serverResult = GlobalSearchServerResult(
serverId: serverId,
serverName: serverName,
serverUrl: 'https://$serverId.example',
token: 'token-$serverId',
userId: 'user-$serverId',
items: [item],
);
return AggregatedEntrySource(item: item, source: serverResult);
}