spotube/flutter/dev/bots/tool_subsharding.dart
Rahul Sahani b5a8835c28 Enhance media controls and add social sharing features
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.
2025-03-09 13:34:56 +05:30

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;
}
}