mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 16:05:18 +00:00

Add enhanced media controls and social sharing features. * **Enhanced Media Controls:** - Add volume control slider to `PlayerControls` widget in `lib/modules/player/player_controls.dart`. - Implement keyboard shortcuts for media controls (play/pause, next/previous track, volume up/down) in `PlayerControls` widget. - Add "lyrics" button to `PlayerView` widget in `lib/modules/player/player.dart`. * **Social Sharing Features:** - Add feature to share the currently playing track on social media platforms in `lib/components/track_tile/track_options.dart`. - Add share button to `TrackPresentationTopSection` widget in `lib/components/track_presentation/presentation_top.dart`. * **Settings:** - Add dark mode toggle in the settings page in `lib/pages/settings/settings.dart`. * **CI Configuration:** - Add `.ci.yaml` file for continuous integration configuration.
98 lines
3.5 KiB
Dart
98 lines
3.5 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
class TestSpecs {
|
|
TestSpecs({required this.path, required this.startTime});
|
|
|
|
final String path;
|
|
int startTime;
|
|
int? _endTime;
|
|
|
|
int get milliseconds => endTime - startTime;
|
|
|
|
set endTime(int value) {
|
|
_endTime = value;
|
|
}
|
|
|
|
int get endTime => _endTime ?? 0;
|
|
|
|
String toJson() {
|
|
return json.encode(<String, String>{'path': path, 'runtime': milliseconds.toString()});
|
|
}
|
|
}
|
|
|
|
class TestFileReporterResults {
|
|
TestFileReporterResults._({
|
|
required this.allTestSpecs,
|
|
required this.hasFailedTests,
|
|
required this.errors,
|
|
});
|
|
|
|
/// Intended to parse the output file of `dart test --file-reporter json:file_name
|
|
factory TestFileReporterResults.fromFile(File metrics) {
|
|
if (!metrics.existsSync()) {
|
|
throw Exception('${metrics.path} does not exist');
|
|
}
|
|
|
|
final Map<int, TestSpecs> testSpecs = <int, TestSpecs>{};
|
|
bool hasFailedTests = true;
|
|
final List<String> errors = <String>[];
|
|
|
|
for (final String metric in metrics.readAsLinesSync()) {
|
|
/// Using print within a test adds the printed content to the json file report
|
|
/// as \u0000 making the file parsing step fail. The content of the json file
|
|
/// is expected to be a json dictionary per line and the following line removes
|
|
/// all the additional content at the beginning of the line until it finds the
|
|
/// first opening curly bracket.
|
|
// TODO(godofredoc): remove when https://github.com/flutter/flutter/issues/145553 is fixed.
|
|
final String sanitizedMetric = metric.replaceAll(RegExp(r'$.*{'), '{');
|
|
final Map<String, Object?> entry = json.decode(sanitizedMetric) as Map<String, Object?>;
|
|
if (entry.containsKey('suite')) {
|
|
final Map<String, Object?> suite = entry['suite']! as Map<String, Object?>;
|
|
addTestSpec(suite, entry['time']! as int, testSpecs);
|
|
} else if (isMetricDone(entry, testSpecs)) {
|
|
final Map<String, Object?> group = entry['group']! as Map<String, Object?>;
|
|
final int suiteID = group['suiteID']! as int;
|
|
addMetricDone(suiteID, entry['time']! as int, testSpecs);
|
|
} else if (entry.containsKey('error')) {
|
|
final String stackTrace =
|
|
entry.containsKey('stackTrace') ? entry['stackTrace']! as String : '';
|
|
errors.add('${entry['error']}\n $stackTrace');
|
|
} else if (entry.containsKey('success') && entry['success'] == true) {
|
|
hasFailedTests = false;
|
|
}
|
|
}
|
|
|
|
return TestFileReporterResults._(
|
|
allTestSpecs: testSpecs,
|
|
hasFailedTests: hasFailedTests,
|
|
errors: errors,
|
|
);
|
|
}
|
|
|
|
final Map<int, TestSpecs> allTestSpecs;
|
|
final bool hasFailedTests;
|
|
final List<String> errors;
|
|
|
|
static void addTestSpec(Map<String, Object?> suite, int time, Map<int, TestSpecs> allTestSpecs) {
|
|
allTestSpecs[suite['id']! as int] = TestSpecs(path: suite['path']! as String, startTime: time);
|
|
}
|
|
|
|
static void addMetricDone(int suiteID, int time, Map<int, TestSpecs> allTestSpecs) {
|
|
final TestSpecs testSpec = allTestSpecs[suiteID]!;
|
|
testSpec.endTime = time;
|
|
}
|
|
|
|
static bool isMetricDone(Map<String, Object?> entry, Map<int, TestSpecs> allTestSpecs) {
|
|
if (entry.containsKey('group') && entry['type']! as String == 'group') {
|
|
final Map<String, Object?> group = entry['group']! as Map<String, Object?>;
|
|
return allTestSpecs.containsKey(group['suiteID']! as int);
|
|
}
|
|
return false;
|
|
}
|
|
}
|