Skip to content

Commit 7a10be3

Browse files
authored
feat: get current source (#1350)
* feat: set source and get source * feat: button to get source * fix: scrollToAndTap * feat: scroll to and tap * increase timeout * add test for #setSource
1 parent 0bdde4d commit 7a10be3

7 files changed

Lines changed: 85 additions & 29 deletions

File tree

packages/audioplayers/example/integration_test/tabs/controls_tab.dart

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ Future<void> testControlsTab(
1717
await tester.tap(find.byKey(const Key('controlsTab')));
1818
await tester.pumpAndSettle();
1919

20-
// Live stream takes some time to get initialized
21-
final timeout = Duration(seconds: audioSourceTestData.isLiveStream ? 8 : 1);
20+
// Sources take some time to get initialized
21+
const timeout = Duration(seconds: 8);
2222

2323
if (features.hasVolume) {
2424
await tester.testVolume('0.5', timeout: timeout);
@@ -75,7 +75,7 @@ Future<void> testControlsTab(
7575
await tester.resume();
7676
await tester.pump(const Duration(seconds: 1));
7777
// Test pause
78-
await tester.tap(find.byKey(const Key('control-pause')));
78+
await tester.scrollToAndTap(const Key('control-pause'));
7979
await tester.resume();
8080
await tester.pump(const Duration(seconds: 1));
8181
await tester.stop();
@@ -130,14 +130,14 @@ Future<void> testControlsTab(
130130

131131
extension ControlsWidgetTester on WidgetTester {
132132
Future<void> resume() async {
133-
await tap(find.byKey(const Key('control-resume')));
133+
await scrollToAndTap(const Key('control-resume'));
134134
await pumpAndSettle();
135135
}
136136

137137
Future<void> stop() async {
138138
final st = StackTrace.current.toString();
139139

140-
await tap(find.byKey(const Key('control-stop')));
140+
await scrollToAndTap(const Key('control-stop'));
141141
await waitOneshot(const Key('toast-player-stopped-0'), stackTrace: st);
142142
await pumpAndSettle();
143143
}
@@ -147,7 +147,7 @@ extension ControlsWidgetTester on WidgetTester {
147147
Duration timeout = const Duration(seconds: 1),
148148
}) async {
149149
printOnFailure('Test Volume: $volume');
150-
await tap(find.byKey(Key('control-volume-$volume')));
150+
await scrollToAndTap(Key('control-volume-$volume'));
151151
await resume();
152152
// TODO(Gustl22): get volume from native implementation
153153
await pump(timeout);
@@ -159,7 +159,7 @@ extension ControlsWidgetTester on WidgetTester {
159159
Duration timeout = const Duration(seconds: 1),
160160
}) async {
161161
printOnFailure('Test Balance: $balance');
162-
await tap(find.byKey(Key('control-balance-$balance')));
162+
await scrollToAndTap(Key('control-balance-$balance'));
163163
await resume();
164164
// TODO(novikov): get balance from native implementation
165165
await pump(timeout);
@@ -171,7 +171,7 @@ extension ControlsWidgetTester on WidgetTester {
171171
Duration timeout = const Duration(seconds: 2),
172172
}) async {
173173
printOnFailure('Test Rate: $rate');
174-
await tap(find.byKey(Key('control-rate-$rate')));
174+
await scrollToAndTap(Key('control-rate-$rate'));
175175
await resume();
176176
// TODO(Gustl22): get rate from native implementation
177177
await pump(timeout);
@@ -185,7 +185,7 @@ extension ControlsWidgetTester on WidgetTester {
185185
printOnFailure('Test Seek: $seek');
186186
final st = StackTrace.current.toString();
187187

188-
await tap(find.byKey(Key('control-seek-$seek')));
188+
await scrollToAndTap(Key('control-seek-$seek'));
189189

190190
await waitOneshot(const Key('toast-seek-complete-0'), stackTrace: st);
191191

@@ -198,7 +198,7 @@ extension ControlsWidgetTester on WidgetTester {
198198
printOnFailure('Test Player Mode: ${mode.name}');
199199
final st = StackTrace.current.toString();
200200

201-
await tap(find.byKey(Key('control-player-mode-${mode.name}')));
201+
await scrollToAndTap(Key('control-player-mode-${mode.name}'));
202202
await waitFor(
203203
() async => expectEnumToggleHasSelected(
204204
const Key('control-player-mode'),
@@ -212,7 +212,7 @@ extension ControlsWidgetTester on WidgetTester {
212212
printOnFailure('Test Release Mode: ${mode.name}');
213213
final st = StackTrace.current.toString();
214214

215-
await tap(find.byKey(Key('control-release-mode-${mode.name}')));
215+
await scrollToAndTap(Key('control-release-mode-${mode.name}'));
216216
await waitFor(
217217
() async => expectEnumToggleHasSelected(
218218
const Key('control-release-mode'),

packages/audioplayers/example/integration_test/tabs/source_tab.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ extension ControlsWidgetTester on WidgetTester {
2222
printOnFailure('Test setting source: $sourceKey');
2323
final st = StackTrace.current.toString();
2424
final sourceWidgetKey = Key('setSource-$sourceKey');
25-
await scrollTo(sourceWidgetKey);
26-
await tap(find.byKey(sourceWidgetKey));
25+
await scrollToAndTap(sourceWidgetKey);
2726

2827
await waitOneshot(const Key('toast-source-set'), stackTrace: st);
2928
}

packages/audioplayers/example/integration_test/tabs/stream_tab.dart

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ Future<void> testStreamsTab(
3131
await tester.testDuration(audioSourceTestData.duration);
3232
}
3333

34-
// Live stream takes some time to get initialized
35-
final timeout = Duration(seconds: audioSourceTestData.isLiveStream ? 8 : 1);
34+
// Sources take some time to get initialized
35+
const timeout = Duration(seconds: 8);
3636

3737
await tester.pumpAndSettle();
38-
await tester.tap(find.byKey(const Key('play_button')));
38+
await tester.scrollToAndTap(const Key('play_button'));
3939
await tester.pumpAndSettle();
4040

4141
// Cannot test more precisely as it is dependent on pollInterval
@@ -79,7 +79,7 @@ Future<void> testStreamsTab(
7979
await tester.testPlayerState(PlayerState.completed);
8080
await tester.testOnPlayerState(PlayerState.completed);
8181
} else if (audioSourceTestData.duration > const Duration(seconds: 5)) {
82-
await tester.tap(find.byKey(const Key('pause_button')));
82+
await tester.scrollToAndTap(const Key('pause_button'));
8383
await tester.pumpAndSettle();
8484
await tester.testPlayerState(PlayerState.paused);
8585
await tester.testOnPlayerState(PlayerState.paused);
@@ -141,7 +141,7 @@ extension StreamWidgetTester on WidgetTester {
141141
Future<void> stopStream() async {
142142
final st = StackTrace.current.toString();
143143

144-
await tap(find.byKey(const Key('stop_button')));
144+
await scrollToAndTap(const Key('stop_button'));
145145
await waitOneshot(const Key('toast-player-stopped-0'), stackTrace: st);
146146
await pumpAndSettle();
147147
}
@@ -154,7 +154,7 @@ extension StreamWidgetTester on WidgetTester {
154154
final st = StackTrace.current.toString();
155155
await waitFor(
156156
() async {
157-
await tap(find.byKey(const Key('getDuration')));
157+
await scrollToAndTap(const Key('getDuration'));
158158
await pump();
159159
expectWidgetHasDuration(
160160
const Key('durationText'),
@@ -176,7 +176,7 @@ extension StreamWidgetTester on WidgetTester {
176176
final st = StackTrace.current.toString();
177177
await waitFor(
178178
() async {
179-
await tap(find.byKey(const Key('getPosition')));
179+
await scrollToAndTap(const Key('getPosition'));
180180
await pump();
181181
expectWidgetHasDuration(
182182
const Key('positionText'),
@@ -196,7 +196,7 @@ extension StreamWidgetTester on WidgetTester {
196196
final st = StackTrace.current.toString();
197197
await waitFor(
198198
() async {
199-
await tap(find.byKey(const Key('getPlayerState')));
199+
await scrollToAndTap(const Key('getPlayerState'));
200200
await pump();
201201
expectWidgetHasText(
202202
const Key('playerStateText'),
@@ -210,7 +210,7 @@ extension StreamWidgetTester on WidgetTester {
210210

211211
Future<void> testOnDuration(
212212
Duration duration, {
213-
Duration timeout = const Duration(seconds: 8),
213+
Duration timeout = const Duration(seconds: 10),
214214
}) async {
215215
printOnFailure('Test OnDuration: $duration');
216216
final st = StackTrace.current.toString();
@@ -227,7 +227,7 @@ extension StreamWidgetTester on WidgetTester {
227227
Future<void> testOnPosition(
228228
Duration position, {
229229
Matcher Function(Duration) matcher = equals,
230-
Duration timeout = const Duration(seconds: 8),
230+
Duration timeout = const Duration(seconds: 10),
231231
}) async {
232232
printOnFailure('Test OnPosition: $position');
233233
final st = StackTrace.current.toString();
@@ -244,7 +244,7 @@ extension StreamWidgetTester on WidgetTester {
244244

245245
Future<void> testOnPlayerState(
246246
PlayerState playerState, {
247-
Duration timeout = const Duration(seconds: 8),
247+
Duration timeout = const Duration(seconds: 10),
248248
}) async {
249249
printOnFailure('Test OnState: $playerState');
250250
final st = StackTrace.current.toString();

packages/audioplayers/example/integration_test/test_utils.dart

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,20 @@ $lastFailureMsg''',
109109
}
110110
}
111111

112+
Future<void> scrollToAndTap(Key widgetKey) async {
113+
await scrollTo(widgetKey);
114+
await tap(find.byKey(widgetKey));
115+
}
116+
112117
Future<void> scrollTo(Key widgetKey) async {
113-
await dragUntilVisible(
114-
find.byKey(widgetKey),
115-
find.byType(SingleChildScrollView).first,
116-
const Offset(0, 100),
117-
);
118+
final finder = find.byKey(widgetKey);
119+
if (finder.hitTestable().evaluate().isEmpty) {
120+
await scrollUntilVisible(
121+
finder,
122+
100,
123+
scrollable: find.byType(Scrollable).first,
124+
);
125+
}
118126
await pumpAndSettle();
119127
}
120128
}

packages/audioplayers/example/lib/tabs/streams.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class _StreamsTabState extends State<StreamsTab>
2020
with AutomaticKeepAliveClientMixin<StreamsTab> {
2121
Duration? position, duration;
2222
PlayerState? state;
23+
Source? source;
2324
late List<StreamSubscription> streams;
2425

2526
Duration? streamDuration, streamPosition;
@@ -67,6 +68,10 @@ class _StreamsTabState extends State<StreamsTab>
6768
setState(() => state = widget.player.state);
6869
}
6970

71+
Future<void> getSource() async {
72+
setState(() => source = widget.player.source);
73+
}
74+
7075
@override
7176
Widget build(BuildContext context) {
7277
super.build(context);
@@ -114,6 +119,20 @@ class _StreamsTabState extends State<StreamsTab>
114119
),
115120
],
116121
),
122+
Row(
123+
children: [
124+
Btn(
125+
key: const Key('getSource'),
126+
txt: 'Get Source',
127+
onPressed: getSource,
128+
),
129+
const Pad(width: 8.0),
130+
Text(
131+
source?.toString() ?? '-',
132+
key: const Key('sourceText'),
133+
),
134+
],
135+
),
117136
const Divider(color: Colors.black),
118137
const Text('Streams'),
119138
Text(

packages/audioplayers/lib/src/audioplayer.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'dart:async';
2+
23
// TODO(gustl22): remove when upgrading min Flutter version to >=3.3.0
34
// ignore: unnecessary_import
45
import 'dart:typed_data';
@@ -29,6 +30,10 @@ class AudioPlayer {
2930

3031
PlayerState get state => _playerState;
3132

33+
Source? _source;
34+
35+
Source? get source => _source;
36+
3237
set state(PlayerState state) {
3338
if (!_playerStateController.isClosed) {
3439
_playerStateController.add(state);
@@ -94,6 +99,9 @@ class AudioPlayer {
9499
AudioPlayer({String? playerId}) : playerId = playerId ?? _uuid.v4() {
95100
_onPlayerCompleteStreamSubscription = onPlayerComplete.listen((_) {
96101
state = PlayerState.completed;
102+
if (releaseMode == ReleaseMode.release) {
103+
_source = null;
104+
}
97105
});
98106
}
99107

@@ -164,6 +172,7 @@ class AudioPlayer {
164172
Future<void> release() async {
165173
await _platform.release(playerId);
166174
state = PlayerState.stopped;
175+
_source = null;
167176
}
168177

169178
/// Moves the cursor to the desired position.
@@ -217,6 +226,7 @@ class AudioPlayer {
217226
/// The resources will start being fetched or buffered as soon as you call
218227
/// this method.
219228
Future<void> setSourceUrl(String url) {
229+
_source = UrlSource(url);
220230
return _platform.setSourceUrl(playerId, url, isLocal: false);
221231
}
222232

@@ -225,6 +235,7 @@ class AudioPlayer {
225235
/// The resources will start being fetched or buffered as soon as you call
226236
/// this method.
227237
Future<void> setSourceDeviceFile(String path) {
238+
_source = DeviceFileSource(path);
228239
return _platform.setSourceUrl(playerId, path, isLocal: true);
229240
}
230241

@@ -234,11 +245,13 @@ class AudioPlayer {
234245
/// The resources will start being fetched or buffered as soon as you call
235246
/// this method.
236247
Future<void> setSourceAsset(String path) async {
248+
_source = AssetSource(path);
237249
final url = await audioCache.load(path);
238250
return _platform.setSourceUrl(playerId, url.path, isLocal: true);
239251
}
240252

241253
Future<void> setSourceBytes(Uint8List bytes) {
254+
_source = BytesSource(bytes);
242255
return _platform.setSourceBytes(playerId, bytes);
243256
}
244257

@@ -277,6 +290,8 @@ class AudioPlayer {
277290
_onPlayerCompleteStreamSubscription.cancel()
278291
];
279292

293+
_source = null;
294+
280295
await Future.wait<dynamic>(futures);
281296
}
282297
}

packages/audioplayers/test/audioplayers_test.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ void main() {
2727
}
2828

2929
group('AudioPlayers', () {
30+
test('#setSource', () async {
31+
calls.clear();
32+
final player = AudioPlayer();
33+
expect(player.source, null);
34+
35+
await player.setSource(UrlSource('internet.com/file.mp3'));
36+
expect(popLastCall().method, 'setSourceUrl');
37+
expect(player.source, isInstanceOf<UrlSource>());
38+
final urlSource = player.source as UrlSource?;
39+
expect(urlSource?.url, 'internet.com/file.mp3');
40+
41+
await player.release();
42+
expect(player.source, null);
43+
});
44+
3045
test('#play', () async {
3146
calls.clear();
3247
final player = AudioPlayer();

0 commit comments

Comments
 (0)