mirror of
https://github.com/flutter/packages.git
synced 2025-08-06 17:28:42 +08:00
Merge null-safety plugins (#3324)
This commit is contained in:
@ -1,3 +1,11 @@
|
||||
## 3.0.0-nullsafety.1
|
||||
|
||||
* Bump Dart SDK to support null safety.
|
||||
|
||||
## 3.0.0-nullsafety
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 2.0.3
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
4
packages/connectivity/connectivity/analysis_options.yaml
Normal file
4
packages/connectivity/connectivity/analysis_options.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
include: ../../../analysis_options.yaml
|
||||
analyzer:
|
||||
enable-experiment:
|
||||
- non-nullable
|
@ -40,7 +40,7 @@ class MyApp extends StatelessWidget {
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
MyHomePage({Key key, this.title}) : super(key: key);
|
||||
MyHomePage({Key? key, required this.title}) : super(key: key);
|
||||
|
||||
final String title;
|
||||
|
||||
@ -51,7 +51,7 @@ class MyHomePage extends StatefulWidget {
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
String _connectionStatus = 'Unknown';
|
||||
final Connectivity _connectivity = Connectivity();
|
||||
StreamSubscription<ConnectivityResult> _connectivitySubscription;
|
||||
late StreamSubscription<ConnectivityResult> _connectivitySubscription;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -69,7 +69,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
|
||||
// Platform messages are asynchronous, so we initialize in an async method.
|
||||
Future<void> initConnectivity() async {
|
||||
ConnectivityResult result;
|
||||
ConnectivityResult result = ConnectivityResult.none;
|
||||
// Platform messages may fail, so we use a try/catch PlatformException.
|
||||
try {
|
||||
result = await _connectivity.checkConnectivity();
|
||||
|
@ -10,9 +10,10 @@ dependencies:
|
||||
dev_dependencies:
|
||||
flutter_driver:
|
||||
sdk: flutter
|
||||
test: ^1.10.0-nullsafety.1
|
||||
integration_test:
|
||||
path: ../../../integration_test
|
||||
pedantic: ^1.8.0
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
@ -2,6 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// TODO(cyanglaz): Remove once https://github.com/flutter/plugins/pull/3158 is landed.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:connectivity/connectivity.dart';
|
||||
|
@ -2,6 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// TODO(cyanglaz): Remove once https://github.com/flutter/plugins/pull/3158 is landed.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:connectivity/connectivity.dart';
|
||||
|
@ -22,12 +22,12 @@ class Connectivity {
|
||||
if (_singleton == null) {
|
||||
_singleton = Connectivity._();
|
||||
}
|
||||
return _singleton;
|
||||
return _singleton!;
|
||||
}
|
||||
|
||||
Connectivity._();
|
||||
|
||||
static Connectivity _singleton;
|
||||
static Connectivity? _singleton;
|
||||
|
||||
static ConnectivityPlatform get _platform => ConnectivityPlatform.instance;
|
||||
|
||||
|
@ -2,7 +2,7 @@ name: connectivity
|
||||
description: Flutter plugin for discovering the state of the network (WiFi &
|
||||
mobile/cellular) connectivity on Android and iOS.
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity
|
||||
version: 2.0.3
|
||||
version: 3.0.0-nullsafety.1
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
@ -21,21 +21,24 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
meta: ^1.0.5
|
||||
connectivity_platform_interface: ^1.0.2
|
||||
connectivity_macos: ^0.1.0
|
||||
connectivity_for_web: ^0.3.0
|
||||
connectivity_platform_interface: ^2.0.0-nullsafety.1
|
||||
#TODO(cyanglaz): re-endorse the below plugins when they have migrated to nnbd.
|
||||
# https://github.com/flutter/flutter/issues/68669
|
||||
connectivity_macos: ^0.2.0-nullsafety
|
||||
# connectivity_for_web: ^0.3.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_driver:
|
||||
sdk: flutter
|
||||
test: ^1.10.0-nullsafety.1
|
||||
integration_test:
|
||||
path: ../../integration_test
|
||||
mockito: ^4.1.1
|
||||
plugin_platform_interface: ^1.0.0
|
||||
pedantic: ^1.8.0
|
||||
plugin_platform_interface: ^1.1.0-nullsafety.1
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.12.13+hotfix.5"
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
// TODO(cyanglaz): Remove once Mockito is migrated to null safety.
|
||||
// @dart = 2.9
|
||||
import 'package:connectivity/connectivity.dart';
|
||||
import 'package:connectivity_platform_interface/connectivity_platform_interface.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
## 0.2.0-nullsafety
|
||||
|
||||
* Update Dart SDK constraint.
|
||||
|
||||
## 0.1.0+8
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
@ -3,7 +3,7 @@ description: macOS implementation of the connectivity plugin.
|
||||
# 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump
|
||||
# the version to 2.0.0.
|
||||
# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
|
||||
version: 0.1.0+8
|
||||
version: 0.2.0-nullsafety
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_macos
|
||||
|
||||
flutter:
|
||||
@ -13,7 +13,7 @@ flutter:
|
||||
pluginClass: ConnectivityPlugin
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.10.0"
|
||||
|
||||
dependencies:
|
||||
|
@ -1,3 +1,11 @@
|
||||
## 2.0.0-nullsafety.1
|
||||
|
||||
* Bump Dart SDK to support null safety.
|
||||
|
||||
## 2.0.0-nullsafety
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 1.0.7
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
@ -0,0 +1,4 @@
|
||||
include: ../../../analysis_options.yaml
|
||||
analyzer:
|
||||
enable-experiment:
|
||||
- non-nullable
|
@ -50,17 +50,17 @@ abstract class ConnectivityPlatform extends PlatformInterface {
|
||||
}
|
||||
|
||||
/// Obtains the wifi name (SSID) of the connected network
|
||||
Future<String> getWifiName() {
|
||||
Future<String?> getWifiName() {
|
||||
throw UnimplementedError('getWifiName() has not been implemented.');
|
||||
}
|
||||
|
||||
/// Obtains the wifi BSSID of the connected network.
|
||||
Future<String> getWifiBSSID() {
|
||||
Future<String?> getWifiBSSID() {
|
||||
throw UnimplementedError('getWifiBSSID() has not been implemented.');
|
||||
}
|
||||
|
||||
/// Obtains the IP address of the connected wifi network
|
||||
Future<String> getWifiIP() {
|
||||
Future<String?> getWifiIP() {
|
||||
throw UnimplementedError('getWifiIP() has not been implemented.');
|
||||
}
|
||||
|
||||
|
@ -22,29 +22,29 @@ class MethodChannelConnectivity extends ConnectivityPlatform {
|
||||
EventChannel eventChannel =
|
||||
EventChannel('plugins.flutter.io/connectivity_status');
|
||||
|
||||
Stream<ConnectivityResult> _onConnectivityChanged;
|
||||
Stream<ConnectivityResult>? _onConnectivityChanged;
|
||||
|
||||
/// Fires whenever the connectivity state changes.
|
||||
Stream<ConnectivityResult> get onConnectivityChanged {
|
||||
if (_onConnectivityChanged == null) {
|
||||
_onConnectivityChanged = eventChannel
|
||||
.receiveBroadcastStream()
|
||||
.map((dynamic result) => result.toString())
|
||||
.map(parseConnectivityResult);
|
||||
_onConnectivityChanged =
|
||||
eventChannel.receiveBroadcastStream().map((dynamic result) {
|
||||
return result != null ? result.toString() : '';
|
||||
}).map(parseConnectivityResult);
|
||||
}
|
||||
return _onConnectivityChanged;
|
||||
return _onConnectivityChanged!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ConnectivityResult> checkConnectivity() {
|
||||
return methodChannel
|
||||
.invokeMethod<String>('check')
|
||||
.then(parseConnectivityResult);
|
||||
Future<ConnectivityResult> checkConnectivity() async {
|
||||
final String checkResult =
|
||||
await methodChannel.invokeMethod<String>('check') ?? '';
|
||||
return parseConnectivityResult(checkResult);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> getWifiName() async {
|
||||
String wifiName = await methodChannel.invokeMethod<String>('wifiName');
|
||||
Future<String?> getWifiName() async {
|
||||
String? wifiName = await methodChannel.invokeMethod<String>('wifiName');
|
||||
// as Android might return <unknown ssid>, uniforming result
|
||||
// our iOS implementation will return null
|
||||
if (wifiName == '<unknown ssid>') {
|
||||
@ -54,29 +54,31 @@ class MethodChannelConnectivity extends ConnectivityPlatform {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> getWifiBSSID() {
|
||||
Future<String?> getWifiBSSID() {
|
||||
return methodChannel.invokeMethod<String>('wifiBSSID');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> getWifiIP() {
|
||||
Future<String?> getWifiIP() {
|
||||
return methodChannel.invokeMethod<String>('wifiIPAddress');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LocationAuthorizationStatus> requestLocationServiceAuthorization({
|
||||
bool requestAlwaysLocationUsage = false,
|
||||
}) {
|
||||
return methodChannel.invokeMethod<String>(
|
||||
'requestLocationServiceAuthorization', <bool>[
|
||||
requestAlwaysLocationUsage
|
||||
]).then(parseLocationAuthorizationStatus);
|
||||
}) async {
|
||||
final String requestLocationServiceResult = await methodChannel
|
||||
.invokeMethod<String>('requestLocationServiceAuthorization',
|
||||
<bool>[requestAlwaysLocationUsage]) ??
|
||||
'';
|
||||
return parseLocationAuthorizationStatus(requestLocationServiceResult);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LocationAuthorizationStatus> getLocationServiceAuthorization() {
|
||||
return methodChannel
|
||||
.invokeMethod<String>('getLocationServiceAuthorization')
|
||||
.then(parseLocationAuthorizationStatus);
|
||||
Future<LocationAuthorizationStatus> getLocationServiceAuthorization() async {
|
||||
final String getLocationServiceResult = await methodChannel
|
||||
.invokeMethod<String>('getLocationServiceAuthorization') ??
|
||||
'';
|
||||
return parseLocationAuthorizationStatus(getLocationServiceResult);
|
||||
}
|
||||
}
|
||||
|
@ -3,19 +3,19 @@ description: A common platform interface for the connectivity plugin.
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_platform_interface
|
||||
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
|
||||
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
|
||||
version: 1.0.7
|
||||
version: 2.0.0-nullsafety.1
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
meta: ^1.0.5
|
||||
plugin_platform_interface: ^1.0.1
|
||||
meta: ^1.3.0-nullsafety.3
|
||||
plugin_platform_interface: ^1.1.0-nullsafety.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
pedantic: ^1.8.0
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.12.13+hotfix.5"
|
||||
|
@ -12,7 +12,7 @@ void main() {
|
||||
|
||||
group('$MethodChannelConnectivity', () {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
MethodChannelConnectivity methodChannelConnectivity;
|
||||
late MethodChannelConnectivity methodChannelConnectivity;
|
||||
|
||||
setUp(() async {
|
||||
methodChannelConnectivity = MethodChannelConnectivity();
|
||||
@ -42,7 +42,7 @@ void main() {
|
||||
.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
switch (methodCall.method) {
|
||||
case 'listen':
|
||||
await ServicesBinding.instance.defaultBinaryMessenger
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger
|
||||
.handlePlatformMessage(
|
||||
methodChannelConnectivity.eventChannel.name,
|
||||
methodChannelConnectivity.eventChannel.codec
|
||||
@ -64,7 +64,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('getWifiName', () async {
|
||||
final String result = await methodChannelConnectivity.getWifiName();
|
||||
final String? result = await methodChannelConnectivity.getWifiName();
|
||||
expect(result, '1337wifi');
|
||||
expect(
|
||||
log,
|
||||
@ -78,7 +78,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('getWifiBSSID', () async {
|
||||
final String result = await methodChannelConnectivity.getWifiBSSID();
|
||||
final String? result = await methodChannelConnectivity.getWifiBSSID();
|
||||
expect(result, 'c0:ff:33:c0:d3:55');
|
||||
expect(
|
||||
log,
|
||||
@ -92,7 +92,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('getWifiIP', () async {
|
||||
final String result = await methodChannelConnectivity.getWifiIP();
|
||||
final String? result = await methodChannelConnectivity.getWifiIP();
|
||||
expect(result, '127.0.0.1');
|
||||
expect(
|
||||
log,
|
||||
|
@ -1,3 +1,11 @@
|
||||
## 2.0.0-nullsafety.1
|
||||
|
||||
* Bump Dart SDK to support null safety.
|
||||
|
||||
## 2.0.0-nullsafety
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 1.0.1
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
4
packages/device_info/device_info/analysis_options.yaml
Normal file
4
packages/device_info/device_info/analysis_options.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
include: ../../../analysis_options.yaml
|
||||
analyzer:
|
||||
enable-experiment:
|
||||
- non-nullable
|
@ -2,6 +2,9 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// TODO(cyanglaz): Remove once https://github.com/flutter/plugins/pull/3158 is landed.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:io';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:device_info/device_info.dart';
|
||||
|
@ -36,7 +36,7 @@ class _MyAppState extends State<MyApp> {
|
||||
}
|
||||
|
||||
Future<void> initPlatformState() async {
|
||||
Map<String, dynamic> deviceData;
|
||||
Map<String, dynamic> deviceData = <String, dynamic>{};
|
||||
|
||||
try {
|
||||
if (Platform.isAndroid) {
|
||||
|
@ -12,11 +12,11 @@ dev_dependencies:
|
||||
sdk: flutter
|
||||
integration_test:
|
||||
path: ../../../integration_test
|
||||
pedantic: ^1.8.0
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0<3.0.0"
|
||||
sdk: ">=2.10.0-56.0.dev <3.0.0"
|
||||
flutter: ">=1.12.13+hotfix.5 <2.0.0"
|
||||
|
@ -2,6 +2,9 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// TODO(cyanglaz): Remove once https://github.com/flutter/flutter/issues/59879 is fixed.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
@ -15,7 +15,7 @@ class DeviceInfoPlugin {
|
||||
DeviceInfoPlugin();
|
||||
|
||||
/// This information does not change from call to call. Cache it.
|
||||
AndroidDeviceInfo _cachedAndroidDeviceInfo;
|
||||
AndroidDeviceInfo? _cachedAndroidDeviceInfo;
|
||||
|
||||
/// Information derived from `android.os.Build`.
|
||||
///
|
||||
@ -25,7 +25,7 @@ class DeviceInfoPlugin {
|
||||
await DeviceInfoPlatform.instance.androidInfo();
|
||||
|
||||
/// This information does not change from call to call. Cache it.
|
||||
IosDeviceInfo _cachedIosDeviceInfo;
|
||||
IosDeviceInfo? _cachedIosDeviceInfo;
|
||||
|
||||
/// Information derived from `UIDevice`.
|
||||
///
|
||||
|
@ -2,7 +2,10 @@ name: device_info
|
||||
description: Flutter plugin providing detailed information about the device
|
||||
(make, model, etc.), and Android or iOS version the app is running on.
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/device_info
|
||||
version: 1.0.1
|
||||
# 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump
|
||||
# the version to 2.0.0.
|
||||
# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
|
||||
version: 2.0.0-nullsafety.1
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
@ -16,14 +19,13 @@ flutter:
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
device_info_platform_interface: ^1.0.0
|
||||
|
||||
device_info_platform_interface: ^2.0.0-nullsafety.1
|
||||
dev_dependencies:
|
||||
test: ^1.3.0
|
||||
test: ^1.10.0-nullsafety.1
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
pedantic: ^1.8.0
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0<3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.12.13+hotfix.5"
|
||||
|
@ -1,3 +1,16 @@
|
||||
## 2.0.0-nullsafety.2
|
||||
|
||||
* Make `baseOS`, `previewSdkInt`, and `securityPatch` nullable types.
|
||||
* Remove default values for non-nullable types.
|
||||
|
||||
## 2.0.0-nullsafety.1
|
||||
|
||||
* Bump Dart SDK to support null safety.
|
||||
|
||||
## 2.0.0-nullsafety
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 1.0.2
|
||||
|
||||
- Update Flutter SDK constraint.
|
||||
|
@ -0,0 +1,4 @@
|
||||
include: ../../../analysis_options.yaml
|
||||
analyzer:
|
||||
enable-experiment:
|
||||
- non-nullable
|
@ -8,27 +8,27 @@
|
||||
class AndroidDeviceInfo {
|
||||
/// Android device Info class.
|
||||
AndroidDeviceInfo({
|
||||
this.version,
|
||||
this.board,
|
||||
this.bootloader,
|
||||
this.brand,
|
||||
this.device,
|
||||
this.display,
|
||||
this.fingerprint,
|
||||
this.hardware,
|
||||
this.host,
|
||||
this.id,
|
||||
this.manufacturer,
|
||||
this.model,
|
||||
this.product,
|
||||
List<String> supported32BitAbis,
|
||||
List<String> supported64BitAbis,
|
||||
List<String> supportedAbis,
|
||||
this.tags,
|
||||
this.type,
|
||||
this.isPhysicalDevice,
|
||||
this.androidId,
|
||||
List<String> systemFeatures,
|
||||
required this.version,
|
||||
required this.board,
|
||||
required this.bootloader,
|
||||
required this.brand,
|
||||
required this.device,
|
||||
required this.display,
|
||||
required this.fingerprint,
|
||||
required this.hardware,
|
||||
required this.host,
|
||||
required this.id,
|
||||
required this.manufacturer,
|
||||
required this.model,
|
||||
required this.product,
|
||||
required List<String> supported32BitAbis,
|
||||
required List<String> supported64BitAbis,
|
||||
required List<String> supportedAbis,
|
||||
required this.tags,
|
||||
required this.type,
|
||||
required this.isPhysicalDevice,
|
||||
required this.androidId,
|
||||
required List<String> systemFeatures,
|
||||
}) : supported32BitAbis = List<String>.unmodifiable(supported32BitAbis),
|
||||
supported64BitAbis = List<String>.unmodifiable(supported64BitAbis),
|
||||
supportedAbis = List<String>.unmodifiable(supportedAbis),
|
||||
@ -113,28 +113,28 @@ class AndroidDeviceInfo {
|
||||
/// Deserializes from the message received from [_kChannel].
|
||||
static AndroidDeviceInfo fromMap(Map<String, dynamic> map) {
|
||||
return AndroidDeviceInfo(
|
||||
version: AndroidBuildVersion._fromMap(
|
||||
map['version']?.cast<String, dynamic>() ?? {}),
|
||||
board: map['board'],
|
||||
bootloader: map['bootloader'],
|
||||
brand: map['brand'],
|
||||
device: map['device'],
|
||||
display: map['display'],
|
||||
fingerprint: map['fingerprint'],
|
||||
hardware: map['hardware'],
|
||||
host: map['host'],
|
||||
id: map['id'],
|
||||
manufacturer: map['manufacturer'],
|
||||
model: map['model'],
|
||||
product: map['product'],
|
||||
supported32BitAbis: _fromList(map['supported32BitAbis'] ?? []),
|
||||
supported64BitAbis: _fromList(map['supported64BitAbis'] ?? []),
|
||||
supportedAbis: _fromList(map['supportedAbis'] ?? []),
|
||||
tags: map['tags'],
|
||||
type: map['type'],
|
||||
isPhysicalDevice: map['isPhysicalDevice'],
|
||||
androidId: map['androidId'],
|
||||
systemFeatures: _fromList(map['systemFeatures'] ?? []),
|
||||
version:
|
||||
AndroidBuildVersion._fromMap(map['version']!.cast<String, dynamic>()),
|
||||
board: map['board']!,
|
||||
bootloader: map['bootloader']!,
|
||||
brand: map['brand']!,
|
||||
device: map['device']!,
|
||||
display: map['display']!,
|
||||
fingerprint: map['fingerprint']!,
|
||||
hardware: map['hardware']!,
|
||||
host: map['host']!,
|
||||
id: map['id']!,
|
||||
manufacturer: map['manufacturer']!,
|
||||
model: map['model']!,
|
||||
product: map['product']!,
|
||||
supported32BitAbis: _fromList(map['supported32BitAbis']!),
|
||||
supported64BitAbis: _fromList(map['supported64BitAbis']!),
|
||||
supportedAbis: _fromList(map['supportedAbis']!),
|
||||
tags: map['tags']!,
|
||||
type: map['type']!,
|
||||
isPhysicalDevice: map['isPhysicalDevice']!,
|
||||
androidId: map['androidId']!,
|
||||
systemFeatures: _fromList(map['systemFeatures']!),
|
||||
);
|
||||
}
|
||||
|
||||
@ -152,16 +152,25 @@ class AndroidDeviceInfo {
|
||||
class AndroidBuildVersion {
|
||||
AndroidBuildVersion._({
|
||||
this.baseOS,
|
||||
this.codename,
|
||||
this.incremental,
|
||||
this.previewSdkInt,
|
||||
this.release,
|
||||
this.sdkInt,
|
||||
this.securityPatch,
|
||||
required this.codename,
|
||||
required this.incremental,
|
||||
required this.release,
|
||||
required this.sdkInt,
|
||||
});
|
||||
|
||||
/// The base OS build the product is based on.
|
||||
final String baseOS;
|
||||
/// This is only available on Android 6.0 or above.
|
||||
String? baseOS;
|
||||
|
||||
/// The developer preview revision of a prerelease SDK.
|
||||
/// This is only available on Android 6.0 or above.
|
||||
int? previewSdkInt;
|
||||
|
||||
/// The user-visible security patch level.
|
||||
/// This is only available on Android 6.0 or above.
|
||||
final String? securityPatch;
|
||||
|
||||
/// The current development codename, or the string "REL" if this is a release build.
|
||||
final String codename;
|
||||
@ -169,9 +178,6 @@ class AndroidBuildVersion {
|
||||
/// The internal value used by the underlying source control to represent this build.
|
||||
final String incremental;
|
||||
|
||||
/// The developer preview revision of a prerelease SDK.
|
||||
final int previewSdkInt;
|
||||
|
||||
/// The user-visible version string.
|
||||
final String release;
|
||||
|
||||
@ -180,19 +186,16 @@ class AndroidBuildVersion {
|
||||
/// Possible values are defined in: https://developer.android.com/reference/android/os/Build.VERSION_CODES.html
|
||||
final int sdkInt;
|
||||
|
||||
/// The user-visible security patch level.
|
||||
final String securityPatch;
|
||||
|
||||
/// Deserializes from the map message received from [_kChannel].
|
||||
static AndroidBuildVersion _fromMap(Map<String, dynamic> map) {
|
||||
return AndroidBuildVersion._(
|
||||
baseOS: map['baseOS'],
|
||||
codename: map['codename'],
|
||||
incremental: map['incremental'],
|
||||
previewSdkInt: map['previewSdkInt'],
|
||||
release: map['release'],
|
||||
sdkInt: map['sdkInt'],
|
||||
securityPatch: map['securityPatch'],
|
||||
codename: map['codename']!,
|
||||
incremental: map['incremental']!,
|
||||
release: map['release']!,
|
||||
sdkInt: map['sdkInt']!,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,14 @@
|
||||
class IosDeviceInfo {
|
||||
/// IOS device info class.
|
||||
IosDeviceInfo({
|
||||
this.name,
|
||||
this.systemName,
|
||||
this.systemVersion,
|
||||
this.model,
|
||||
this.localizedModel,
|
||||
this.identifierForVendor,
|
||||
this.isPhysicalDevice,
|
||||
this.utsname,
|
||||
required this.name,
|
||||
required this.systemName,
|
||||
required this.systemVersion,
|
||||
required this.model,
|
||||
required this.localizedModel,
|
||||
required this.identifierForVendor,
|
||||
required this.isPhysicalDevice,
|
||||
required this.utsname,
|
||||
});
|
||||
|
||||
/// Device name.
|
||||
@ -45,15 +45,14 @@ class IosDeviceInfo {
|
||||
/// Deserializes from the map message received from [_kChannel].
|
||||
static IosDeviceInfo fromMap(Map<String, dynamic> map) {
|
||||
return IosDeviceInfo(
|
||||
name: map['name'],
|
||||
systemName: map['systemName'],
|
||||
systemVersion: map['systemVersion'],
|
||||
model: map['model'],
|
||||
localizedModel: map['localizedModel'],
|
||||
identifierForVendor: map['identifierForVendor'],
|
||||
name: map['name']!,
|
||||
systemName: map['systemName']!,
|
||||
systemVersion: map['systemVersion']!,
|
||||
model: map['model']!,
|
||||
localizedModel: map['localizedModel']!,
|
||||
identifierForVendor: map['identifierForVendor']!,
|
||||
isPhysicalDevice: map['isPhysicalDevice'] == 'true',
|
||||
utsname:
|
||||
IosUtsname._fromMap(map['utsname']?.cast<String, dynamic>() ?? {}),
|
||||
utsname: IosUtsname._fromMap(map['utsname']!.cast<String, dynamic>()),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -62,11 +61,11 @@ class IosDeviceInfo {
|
||||
/// See http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysutsname.h.html for details.
|
||||
class IosUtsname {
|
||||
IosUtsname._({
|
||||
this.sysname,
|
||||
this.nodename,
|
||||
this.release,
|
||||
this.version,
|
||||
this.machine,
|
||||
required this.sysname,
|
||||
required this.nodename,
|
||||
required this.release,
|
||||
required this.version,
|
||||
required this.machine,
|
||||
});
|
||||
|
||||
/// Operating system name.
|
||||
@ -87,11 +86,11 @@ class IosUtsname {
|
||||
/// Deserializes from the map message received from [_kChannel].
|
||||
static IosUtsname _fromMap(Map<String, dynamic> map) {
|
||||
return IosUtsname._(
|
||||
sysname: map['sysname'],
|
||||
nodename: map['nodename'],
|
||||
release: map['release'],
|
||||
version: map['version'],
|
||||
machine: map['machine'],
|
||||
sysname: map['sysname']!,
|
||||
nodename: map['nodename']!,
|
||||
release: map['release']!,
|
||||
version: map['version']!,
|
||||
machine: map['machine']!,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3,20 +3,20 @@ description: A common platform interface for the device_info plugin.
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/device_info
|
||||
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
|
||||
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
|
||||
version: 1.0.2
|
||||
version: 2.0.0-nullsafety.2
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
meta: ^1.1.8
|
||||
plugin_platform_interface: ^1.0.2
|
||||
meta: ^1.3.0-nullsafety.3
|
||||
plugin_platform_interface: ^1.1.0-nullsafety.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
mockito: ^4.1.1
|
||||
pedantic: ^1.8.0
|
||||
test: ^1.10.0-nullsafety.1
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.7.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.9.1+hotfix.4"
|
||||
|
@ -2,11 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// TODO(cyanglaz): Remove once https://github.com/flutter/flutter/issues/59879 is fixed.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:device_info_platform_interface/device_info_platform_interface.dart';
|
||||
|
||||
import 'package:device_info_platform_interface/method_channel/method_channel_device_info.dart';
|
||||
|
||||
void main() {
|
||||
@ -23,11 +24,68 @@ void main() {
|
||||
switch (methodCall.method) {
|
||||
case 'getAndroidDeviceInfo':
|
||||
return ({
|
||||
"brand": "Google",
|
||||
"version": <String, dynamic>{
|
||||
"securityPatch": "2018-09-05",
|
||||
"sdkInt": 28,
|
||||
"release": "9",
|
||||
"previewSdkInt": 0,
|
||||
"incremental": "5124027",
|
||||
"codename": "REL",
|
||||
"baseOS": "",
|
||||
},
|
||||
"board": "goldfish_x86_64",
|
||||
"bootloader": "unknown",
|
||||
"brand": "google",
|
||||
"device": "generic_x86_64",
|
||||
"display": "PSR1.180720.075",
|
||||
"fingerprint":
|
||||
"google/sdk_gphone_x86_64/generic_x86_64:9/PSR1.180720.075/5124027:user/release-keys",
|
||||
"hardware": "ranchu",
|
||||
"host": "abfarm730",
|
||||
"id": "PSR1.180720.075",
|
||||
"manufacturer": "Google",
|
||||
"model": "Android SDK built for x86_64",
|
||||
"product": "sdk_gphone_x86_64",
|
||||
"supported32BitAbis": <String>[
|
||||
"x86",
|
||||
],
|
||||
"supported64BitAbis": <String>[
|
||||
"x86_64",
|
||||
],
|
||||
"supportedAbis": <String>[
|
||||
"x86_64",
|
||||
"x86",
|
||||
],
|
||||
"tags": "release-keys",
|
||||
"type": "user",
|
||||
"isPhysicalDevice": false,
|
||||
"androidId": "f47571f3b4648f45",
|
||||
"systemFeatures": <String>[
|
||||
"android.hardware.sensor.proximity",
|
||||
"android.software.adoptable_storage",
|
||||
"android.hardware.sensor.accelerometer",
|
||||
"android.hardware.faketouch",
|
||||
"android.software.backup",
|
||||
"android.hardware.touchscreen",
|
||||
],
|
||||
});
|
||||
case 'getIosDeviceInfo':
|
||||
return ({
|
||||
"name": "iPhone 10",
|
||||
"name": "iPhone 13",
|
||||
"systemName": "iOS",
|
||||
"systemVersion": "13.0",
|
||||
"model": "iPhone",
|
||||
"localizedModel": "iPhone",
|
||||
"identifierForVendor": "88F59280-55AD-402C-B922-3203B4794C06",
|
||||
"isPhysicalDevice": false,
|
||||
"utsname": <String, dynamic>{
|
||||
"sysname": "Darwin",
|
||||
"nodename": "host",
|
||||
"release": "19.6.0",
|
||||
"version":
|
||||
"Darwin Kernel Version 19.6.0: Thu Jun 18 20:49:00 PDT 2020; root:xnu-6153.141.1~1/RELEASE_X86_64",
|
||||
"machine": "x86_64",
|
||||
}
|
||||
});
|
||||
default:
|
||||
return null;
|
||||
@ -38,12 +96,66 @@ void main() {
|
||||
test("androidInfo", () async {
|
||||
final AndroidDeviceInfo result =
|
||||
await methodChannelDeviceInfo.androidInfo();
|
||||
expect(result.brand, "Google");
|
||||
|
||||
expect(result.version.securityPatch, "2018-09-05");
|
||||
expect(result.version.sdkInt, 28);
|
||||
expect(result.version.release, "9");
|
||||
expect(result.version.previewSdkInt, 0);
|
||||
expect(result.version.incremental, "5124027");
|
||||
expect(result.version.codename, "REL");
|
||||
expect(result.board, "goldfish_x86_64");
|
||||
expect(result.bootloader, "unknown");
|
||||
expect(result.brand, "google");
|
||||
expect(result.device, "generic_x86_64");
|
||||
expect(result.display, "PSR1.180720.075");
|
||||
expect(result.fingerprint,
|
||||
"google/sdk_gphone_x86_64/generic_x86_64:9/PSR1.180720.075/5124027:user/release-keys");
|
||||
expect(result.hardware, "ranchu");
|
||||
expect(result.host, "abfarm730");
|
||||
expect(result.id, "PSR1.180720.075");
|
||||
expect(result.manufacturer, "Google");
|
||||
expect(result.model, "Android SDK built for x86_64");
|
||||
expect(result.product, "sdk_gphone_x86_64");
|
||||
expect(result.supported32BitAbis, <String>[
|
||||
"x86",
|
||||
]);
|
||||
expect(result.supported64BitAbis, <String>[
|
||||
"x86_64",
|
||||
]);
|
||||
expect(result.supportedAbis, <String>[
|
||||
"x86_64",
|
||||
"x86",
|
||||
]);
|
||||
expect(result.tags, "release-keys");
|
||||
expect(result.type, "user");
|
||||
expect(result.isPhysicalDevice, false);
|
||||
expect(result.androidId, "f47571f3b4648f45");
|
||||
expect(result.systemFeatures, <String>[
|
||||
"android.hardware.sensor.proximity",
|
||||
"android.software.adoptable_storage",
|
||||
"android.hardware.sensor.accelerometer",
|
||||
"android.hardware.faketouch",
|
||||
"android.software.backup",
|
||||
"android.hardware.touchscreen",
|
||||
]);
|
||||
});
|
||||
|
||||
test("iosInfo", () async {
|
||||
final IosDeviceInfo result = await methodChannelDeviceInfo.iosInfo();
|
||||
expect(result.name, "iPhone 10");
|
||||
expect(result.name, "iPhone 13");
|
||||
expect(result.systemName, "iOS");
|
||||
expect(result.systemVersion, "13.0");
|
||||
expect(result.model, "iPhone");
|
||||
expect(result.localizedModel, "iPhone");
|
||||
expect(
|
||||
result.identifierForVendor, "88F59280-55AD-402C-B922-3203B4794C06");
|
||||
expect(result.isPhysicalDevice, false);
|
||||
expect(result.utsname.sysname, "Darwin");
|
||||
expect(result.utsname.nodename, "host");
|
||||
expect(result.utsname.release, "19.6.0");
|
||||
expect(result.utsname.version,
|
||||
"Darwin Kernel Version 19.6.0: Thu Jun 18 20:49:00 PDT 2020; root:xnu-6153.141.1~1/RELEASE_X86_64");
|
||||
expect(result.utsname.machine, "x86_64");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
## 2.0.0-nullsafety.1
|
||||
|
||||
* Fix example app SDK.
|
||||
|
||||
## 2.0.0-nullsafety
|
||||
|
||||
* Bump Dart SDK.
|
||||
|
||||
## 1.0.12
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
@ -3,7 +3,7 @@ description: Demonstrates how to use the flutter_plugin_android_lifecycle plugin
|
||||
publish_to: 'none'
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
@ -1,10 +1,10 @@
|
||||
name: flutter_plugin_android_lifecycle
|
||||
description: Flutter plugin for accessing an Android Lifecycle within other plugins.
|
||||
version: 1.0.12
|
||||
version: 2.0.0-nullsafety.1
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/flutter_plugin_android_lifecycle
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.12.13"
|
||||
|
||||
dependencies:
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
## 1.0.0-nullsafety
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 0.6.3+5
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
@ -25,14 +25,14 @@ class AndroidAuthMessages {
|
||||
this.goToSettingsDescription,
|
||||
});
|
||||
|
||||
final String fingerprintHint;
|
||||
final String fingerprintNotRecognized;
|
||||
final String fingerprintSuccess;
|
||||
final String cancelButton;
|
||||
final String signInTitle;
|
||||
final String fingerprintRequiredTitle;
|
||||
final String goToSettingsButton;
|
||||
final String goToSettingsDescription;
|
||||
final String? fingerprintHint;
|
||||
final String? fingerprintNotRecognized;
|
||||
final String? fingerprintSuccess;
|
||||
final String? cancelButton;
|
||||
final String? signInTitle;
|
||||
final String? fingerprintRequiredTitle;
|
||||
final String? goToSettingsButton;
|
||||
final String? goToSettingsDescription;
|
||||
|
||||
Map<String, String> get args {
|
||||
return <String, String>{
|
||||
@ -62,10 +62,10 @@ class IOSAuthMessages {
|
||||
this.cancelButton,
|
||||
});
|
||||
|
||||
final String lockOut;
|
||||
final String goToSettingsButton;
|
||||
final String goToSettingsDescription;
|
||||
final String cancelButton;
|
||||
final String? lockOut;
|
||||
final String? goToSettingsButton;
|
||||
final String? goToSettingsDescription;
|
||||
final String? cancelButton;
|
||||
|
||||
Map<String, String> get args {
|
||||
return <String, String>{
|
||||
|
@ -67,7 +67,7 @@ class LocalAuthentication {
|
||||
/// [PlatformException] with error code [otherOperatingSystem] on the iOS
|
||||
/// simulator.
|
||||
Future<bool> authenticateWithBiometrics({
|
||||
@required String localizedReason,
|
||||
required String localizedReason,
|
||||
bool useErrorDialogs = true,
|
||||
bool stickyAuth = false,
|
||||
AndroidAuthMessages androidAuthStrings = const AndroidAuthMessages(),
|
||||
@ -92,8 +92,9 @@ class LocalAuthentication {
|
||||
'operating systems.',
|
||||
details: 'Your operating system is ${_platform.operatingSystem}');
|
||||
}
|
||||
return await _channel.invokeMethod<bool>(
|
||||
'authenticateWithBiometrics', args);
|
||||
final bool? result =
|
||||
await _channel.invokeMethod<bool>('authenticateWithBiometrics', args);
|
||||
return result!;
|
||||
}
|
||||
|
||||
/// Returns true if auth was cancelled successfully.
|
||||
@ -101,18 +102,20 @@ class LocalAuthentication {
|
||||
/// Returns false if there was some error or no auth in progress.
|
||||
///
|
||||
/// Returns [Future] bool true or false:
|
||||
Future<bool> stopAuthentication() {
|
||||
Future<bool> stopAuthentication() async {
|
||||
if (_platform.isAndroid) {
|
||||
return _channel.invokeMethod<bool>('stopAuthentication');
|
||||
final bool? result =
|
||||
await _channel.invokeMethod<bool>('stopAuthentication');
|
||||
return result!;
|
||||
}
|
||||
return Future<bool>.sync(() => true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns true if device is capable of checking biometrics
|
||||
///
|
||||
/// Returns a [Future] bool true or false:
|
||||
Future<bool> get canCheckBiometrics async =>
|
||||
(await _channel.invokeListMethod<String>('getAvailableBiometrics'))
|
||||
(await _channel.invokeListMethod<String>('getAvailableBiometrics'))!
|
||||
.isNotEmpty;
|
||||
|
||||
/// Returns a list of enrolled biometrics
|
||||
@ -122,10 +125,10 @@ class LocalAuthentication {
|
||||
/// - BiometricType.fingerprint
|
||||
/// - BiometricType.iris (not yet implemented)
|
||||
Future<List<BiometricType>> getAvailableBiometrics() async {
|
||||
final List<String> result =
|
||||
(await _channel.invokeListMethod<String>('getAvailableBiometrics'));
|
||||
final List<String>? result =
|
||||
await _channel.invokeListMethod<String>('getAvailableBiometrics');
|
||||
final List<BiometricType> biometrics = <BiometricType>[];
|
||||
result.forEach((String value) {
|
||||
result!.forEach((String value) {
|
||||
switch (value) {
|
||||
case 'face':
|
||||
biometrics.add(BiometricType.face);
|
||||
|
@ -2,7 +2,7 @@ name: local_auth
|
||||
description: Flutter plugin for Android and iOS device authentication sensors
|
||||
such as Fingerprint Reader and Touch ID.
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth
|
||||
version: 0.6.3+5
|
||||
version: 1.0.0-nullsafety
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
@ -16,10 +16,10 @@ flutter:
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
meta: ^1.0.5
|
||||
intl: ">=0.15.1 <0.17.0"
|
||||
platform: ">=2.0.0 <4.0.0"
|
||||
flutter_plugin_android_lifecycle: ^1.0.2
|
||||
meta: ^1.3.0-nullsafety.3
|
||||
intl: ^0.17.0-nullsafety.2
|
||||
platform: ^3.0.0-nullsafety.4
|
||||
flutter_plugin_android_lifecycle: ^2.0.0-nullsafety
|
||||
|
||||
dev_dependencies:
|
||||
integration_test:
|
||||
@ -28,8 +28,8 @@ dev_dependencies:
|
||||
sdk: flutter
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
pedantic: ^1.8.0
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.12.13+hotfix.5"
|
||||
|
@ -19,7 +19,7 @@ void main() {
|
||||
);
|
||||
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
LocalAuthentication localAuthentication;
|
||||
late LocalAuthentication localAuthentication;
|
||||
|
||||
setUp(() {
|
||||
channel.setMockMethodCallHandler((MethodCall methodCall) {
|
||||
|
@ -1,3 +1,7 @@
|
||||
## 2.0.0-nullsafety
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 1.0.5
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
@ -40,26 +40,26 @@ abstract class PathProviderPlatform extends PlatformInterface {
|
||||
|
||||
/// Path to the temporary directory on the device that is not backed up and is
|
||||
/// suitable for storing caches of downloaded files.
|
||||
Future<String> getTemporaryPath() {
|
||||
Future<String?> getTemporaryPath() {
|
||||
throw UnimplementedError('getTemporaryPath() has not been implemented.');
|
||||
}
|
||||
|
||||
/// Path to a directory where the application may place application support
|
||||
/// files.
|
||||
Future<String> getApplicationSupportPath() {
|
||||
Future<String?> getApplicationSupportPath() {
|
||||
throw UnimplementedError(
|
||||
'getApplicationSupportPath() has not been implemented.');
|
||||
}
|
||||
|
||||
/// Path to the directory where application can store files that are persistent,
|
||||
/// backed up, and not visible to the user, such as sqlite.db.
|
||||
Future<String> getLibraryPath() {
|
||||
Future<String?> getLibraryPath() {
|
||||
throw UnimplementedError('getLibraryPath() has not been implemented.');
|
||||
}
|
||||
|
||||
/// Path to a directory where the application may place data that is
|
||||
/// user-generated, or that cannot otherwise be recreated by your application.
|
||||
Future<String> getApplicationDocumentsPath() {
|
||||
Future<String?> getApplicationDocumentsPath() {
|
||||
throw UnimplementedError(
|
||||
'getApplicationDocumentsPath() has not been implemented.');
|
||||
}
|
||||
@ -67,7 +67,7 @@ abstract class PathProviderPlatform extends PlatformInterface {
|
||||
/// Path to a directory where the application may access top level storage.
|
||||
/// The current operating system should be determined before issuing this
|
||||
/// function call, as this functionality is only available on Android.
|
||||
Future<String> getExternalStoragePath() {
|
||||
Future<String?> getExternalStoragePath() {
|
||||
throw UnimplementedError(
|
||||
'getExternalStoragePath() has not been implemented.');
|
||||
}
|
||||
@ -76,7 +76,7 @@ abstract class PathProviderPlatform extends PlatformInterface {
|
||||
/// stored. These paths typically reside on external storage like separate
|
||||
/// partitions or SD cards. Phones may have multiple storage directories
|
||||
/// available.
|
||||
Future<List<String>> getExternalCachePaths() {
|
||||
Future<List<String>?> getExternalCachePaths() {
|
||||
throw UnimplementedError(
|
||||
'getExternalCachePaths() has not been implemented.');
|
||||
}
|
||||
@ -84,10 +84,10 @@ abstract class PathProviderPlatform extends PlatformInterface {
|
||||
/// Paths to directories where application specific data can be stored.
|
||||
/// These paths typically reside on external storage like separate partitions
|
||||
/// or SD cards. Phones may have multiple storage directories available.
|
||||
Future<List<String>> getExternalStoragePaths({
|
||||
Future<List<String>?> getExternalStoragePaths({
|
||||
/// Optional parameter. See [StorageDirectory] for more informations on
|
||||
/// how this type translates to Android storage directories.
|
||||
StorageDirectory type,
|
||||
StorageDirectory? type,
|
||||
}) {
|
||||
throw UnimplementedError(
|
||||
'getExternalStoragePaths() has not been implemented.');
|
||||
@ -95,7 +95,7 @@ abstract class PathProviderPlatform extends PlatformInterface {
|
||||
|
||||
/// Path to the directory where downloaded files can be stored.
|
||||
/// This is typically only relevant on desktop operating systems.
|
||||
Future<String> getDownloadsPath() {
|
||||
Future<String?> getDownloadsPath() {
|
||||
throw UnimplementedError('getDownloadsPath() has not been implemented.');
|
||||
}
|
||||
}
|
||||
|
@ -30,34 +30,34 @@ class MethodChannelPathProvider extends PathProviderPlatform {
|
||||
_platform = platform;
|
||||
}
|
||||
|
||||
Future<String> getTemporaryPath() {
|
||||
Future<String?> getTemporaryPath() {
|
||||
return methodChannel.invokeMethod<String>('getTemporaryDirectory');
|
||||
}
|
||||
|
||||
Future<String> getApplicationSupportPath() {
|
||||
Future<String?> getApplicationSupportPath() {
|
||||
return methodChannel.invokeMethod<String>('getApplicationSupportDirectory');
|
||||
}
|
||||
|
||||
Future<String> getLibraryPath() {
|
||||
Future<String?> getLibraryPath() {
|
||||
if (!_platform.isIOS && !_platform.isMacOS) {
|
||||
throw UnsupportedError('Functionality only available on iOS/macOS');
|
||||
}
|
||||
return methodChannel.invokeMethod<String>('getLibraryDirectory');
|
||||
}
|
||||
|
||||
Future<String> getApplicationDocumentsPath() {
|
||||
Future<String?> getApplicationDocumentsPath() {
|
||||
return methodChannel
|
||||
.invokeMethod<String>('getApplicationDocumentsDirectory');
|
||||
}
|
||||
|
||||
Future<String> getExternalStoragePath() {
|
||||
Future<String?> getExternalStoragePath() {
|
||||
if (!_platform.isAndroid) {
|
||||
throw UnsupportedError('Functionality only available on Android');
|
||||
}
|
||||
return methodChannel.invokeMethod<String>('getStorageDirectory');
|
||||
}
|
||||
|
||||
Future<List<String>> getExternalCachePaths() {
|
||||
Future<List<String>?> getExternalCachePaths() {
|
||||
if (!_platform.isAndroid) {
|
||||
throw UnsupportedError('Functionality only available on Android');
|
||||
}
|
||||
@ -65,8 +65,8 @@ class MethodChannelPathProvider extends PathProviderPlatform {
|
||||
.invokeListMethod<String>('getExternalCacheDirectories');
|
||||
}
|
||||
|
||||
Future<List<String>> getExternalStoragePaths({
|
||||
StorageDirectory type,
|
||||
Future<List<String>?> getExternalStoragePaths({
|
||||
StorageDirectory? type,
|
||||
}) async {
|
||||
if (!_platform.isAndroid) {
|
||||
throw UnsupportedError('Functionality only available on Android');
|
||||
@ -77,7 +77,7 @@ class MethodChannelPathProvider extends PathProviderPlatform {
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> getDownloadsPath() {
|
||||
Future<String?> getDownloadsPath() {
|
||||
if (!_platform.isMacOS) {
|
||||
throw UnsupportedError('Functionality only available on macOS');
|
||||
}
|
||||
|
@ -3,20 +3,20 @@ description: A common platform interface for the path_provider plugin.
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_platform_interface
|
||||
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
|
||||
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
|
||||
version: 1.0.5
|
||||
version: 2.0.0-nullsafety
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
meta: ^1.0.5
|
||||
platform: ">=2.0.0 <4.0.0"
|
||||
plugin_platform_interface: ^1.0.1
|
||||
meta: ^1.3.0-nullsafety.3
|
||||
platform: ^3.0.0-nullsafety.4
|
||||
plugin_platform_interface: ^1.1.0-nullsafety
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
pedantic: ^1.8.0
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.10.0"
|
||||
|
@ -19,7 +19,7 @@ void main() {
|
||||
const String kDownloadsPath = 'downloadsPath';
|
||||
|
||||
group('$MethodChannelPathProvider', () {
|
||||
MethodChannelPathProvider methodChannelPathProvider;
|
||||
late MethodChannelPathProvider methodChannelPathProvider;
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
setUp(() async {
|
||||
@ -59,7 +59,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('getTemporaryPath', () async {
|
||||
final String path = await methodChannelPathProvider.getTemporaryPath();
|
||||
final String? path = await methodChannelPathProvider.getTemporaryPath();
|
||||
expect(
|
||||
log,
|
||||
<Matcher>[isMethodCall('getTemporaryDirectory', arguments: null)],
|
||||
@ -68,7 +68,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('getApplicationSupportPath', () async {
|
||||
final String path =
|
||||
final String? path =
|
||||
await methodChannelPathProvider.getApplicationSupportPath();
|
||||
expect(
|
||||
log,
|
||||
@ -92,7 +92,7 @@ void main() {
|
||||
methodChannelPathProvider
|
||||
.setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios'));
|
||||
|
||||
final String path = await methodChannelPathProvider.getLibraryPath();
|
||||
final String? path = await methodChannelPathProvider.getLibraryPath();
|
||||
expect(
|
||||
log,
|
||||
<Matcher>[isMethodCall('getLibraryDirectory', arguments: null)],
|
||||
@ -104,7 +104,7 @@ void main() {
|
||||
methodChannelPathProvider
|
||||
.setMockPathProviderPlatform(FakePlatform(operatingSystem: 'macos'));
|
||||
|
||||
final String path = await methodChannelPathProvider.getLibraryPath();
|
||||
final String? path = await methodChannelPathProvider.getLibraryPath();
|
||||
expect(
|
||||
log,
|
||||
<Matcher>[isMethodCall('getLibraryDirectory', arguments: null)],
|
||||
@ -113,7 +113,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('getApplicationDocumentsPath', () async {
|
||||
final String path =
|
||||
final String? path =
|
||||
await methodChannelPathProvider.getApplicationDocumentsPath();
|
||||
expect(
|
||||
log,
|
||||
@ -125,13 +125,13 @@ void main() {
|
||||
});
|
||||
|
||||
test('getExternalCachePaths android succeeds', () async {
|
||||
final List<String> result =
|
||||
final List<String>? result =
|
||||
await methodChannelPathProvider.getExternalCachePaths();
|
||||
expect(
|
||||
log,
|
||||
<Matcher>[isMethodCall('getExternalCacheDirectories', arguments: null)],
|
||||
);
|
||||
expect(result.length, 1);
|
||||
expect(result!.length, 1);
|
||||
expect(result.first, kExternalCachePaths);
|
||||
});
|
||||
|
||||
@ -147,10 +147,12 @@ void main() {
|
||||
}
|
||||
});
|
||||
|
||||
for (StorageDirectory type
|
||||
in StorageDirectory.values + <StorageDirectory>[null]) {
|
||||
for (StorageDirectory? type in <StorageDirectory?>[
|
||||
null,
|
||||
...StorageDirectory.values
|
||||
]) {
|
||||
test('getExternalStoragePaths (type: $type) android succeeds', () async {
|
||||
final List<String> result =
|
||||
final List<String>? result =
|
||||
await methodChannelPathProvider.getExternalStoragePaths(type: type);
|
||||
expect(
|
||||
log,
|
||||
@ -162,7 +164,7 @@ void main() {
|
||||
],
|
||||
);
|
||||
|
||||
expect(result.length, 1);
|
||||
expect(result!.length, 1);
|
||||
expect(result.first, kExternalStoragePaths);
|
||||
});
|
||||
|
||||
@ -182,7 +184,7 @@ void main() {
|
||||
test('getDownloadsPath macos succeeds', () async {
|
||||
methodChannelPathProvider
|
||||
.setMockPathProviderPlatform(FakePlatform(operatingSystem: 'macos'));
|
||||
final String result = await methodChannelPathProvider.getDownloadsPath();
|
||||
final String? result = await methodChannelPathProvider.getDownloadsPath();
|
||||
expect(
|
||||
log,
|
||||
<Matcher>[isMethodCall('getDownloadsDirectory', arguments: null)],
|
||||
|
@ -1,3 +1,11 @@
|
||||
## 1.1.0-nullsafety.1
|
||||
|
||||
* Bump Dart SDK to support null safety.
|
||||
|
||||
## 1.1.0-nullsafety
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 1.0.3
|
||||
|
||||
* Fix homepage in `pubspec.yaml`.
|
||||
|
4
packages/plugin_platform_interface/analysis_options.yaml
Normal file
4
packages/plugin_platform_interface/analysis_options.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
include: ../../analysis_options.yaml
|
||||
analyzer:
|
||||
enable-experiment:
|
||||
- non-nullable
|
@ -41,7 +41,7 @@ import 'package:meta/meta.dart';
|
||||
/// [MockPlatformInterfaceMixin] for a sample of using Mockito to mock a platform interface.
|
||||
abstract class PlatformInterface {
|
||||
/// Pass a private, class-specific `const Object()` as the `token`.
|
||||
PlatformInterface({@required Object token}) : _instanceToken = token;
|
||||
PlatformInterface({required Object token}) : _instanceToken = token;
|
||||
|
||||
final Object _instanceToken;
|
||||
|
||||
|
@ -12,17 +12,17 @@ description: Reusable base class for Flutter plugin platform interfaces.
|
||||
# be done when absolutely necessary and after the ecosystem has already migrated to 1.X.Y version
|
||||
# that is forward compatible with 2.0.0 (ideally the ecosystem have migrated to depend on:
|
||||
# `plugin_platform_interface: >=1.X.Y <3.0.0`).
|
||||
version: 1.0.3
|
||||
version: 1.1.0-nullsafety.1
|
||||
|
||||
repository: https://github.com/flutter/plugins/tree/master/packages/plugin_platform_interface
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
meta: ^1.0.0
|
||||
meta: ^1.3.0-nullsafety.3
|
||||
|
||||
dev_dependencies:
|
||||
mockito: ^4.1.1
|
||||
test: ^1.9.4
|
||||
pedantic: ^1.8.0
|
||||
test: ^1.10.0-nullsafety.1
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// TODO(egarciad): Remove once Mockito is migrated to null safety.
|
||||
// @dart = 2.9
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
// @dart = 2.9
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
@ -1,3 +1,11 @@
|
||||
## 6.0.0-nullsafety.1
|
||||
|
||||
* Bump Dart SDK to support null safety.
|
||||
|
||||
## 6.0.0-nullsafety
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 5.7.13
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
4
packages/url_launcher/url_launcher/analysis_options.yaml
Normal file
4
packages/url_launcher/url_launcher/analysis_options.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
include: ../../../analysis_options.yaml
|
||||
analyzer:
|
||||
enable-experiment:
|
||||
- non-nullable
|
@ -2,6 +2,9 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// TODO(egarciad): Remove once integration_test is migrated to null safety.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
|
@ -27,7 +27,7 @@ class MyApp extends StatelessWidget {
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
MyHomePage({Key key, this.title}) : super(key: key);
|
||||
MyHomePage({Key? key, required this.title}) : super(key: key);
|
||||
final String title;
|
||||
|
||||
@override
|
||||
@ -35,7 +35,7 @@ class MyHomePage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
Future<void> _launched;
|
||||
Future<void>? _launched;
|
||||
String _phone = '';
|
||||
|
||||
Future<void> _launchInBrowser(String url) async {
|
||||
|
@ -12,9 +12,9 @@ dev_dependencies:
|
||||
path: ../../../integration_test
|
||||
flutter_driver:
|
||||
sdk: flutter
|
||||
pedantic: ^1.8.0
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
mockito: ^4.1.1
|
||||
plugin_platform_interface: ^1.0.0
|
||||
plugin_platform_interface: ^1.1.0-nullsafety.1
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
@ -1,3 +1,10 @@
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// TODO(egarciad): Remove once mockito is migrated to null safety.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
@ -2,6 +2,9 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// TODO(egarciad): Remove once flutter_driver is migrated to null safety.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
@ -40,7 +40,7 @@ class Link extends StatelessWidget implements LinkInfo {
|
||||
final LinkWidgetBuilder builder;
|
||||
|
||||
/// The destination that this link leads to.
|
||||
final Uri uri;
|
||||
final Uri? uri;
|
||||
|
||||
/// The target indicating where to open the link.
|
||||
final LinkTarget target;
|
||||
@ -51,12 +51,11 @@ class Link extends StatelessWidget implements LinkInfo {
|
||||
/// Creates a widget that renders a real link on the web, and uses WebViews in
|
||||
/// native platforms to open links.
|
||||
Link({
|
||||
Key key,
|
||||
@required this.uri,
|
||||
LinkTarget target,
|
||||
@required this.builder,
|
||||
}) : target = target ?? LinkTarget.defaultTarget,
|
||||
super(key: key);
|
||||
Key? key,
|
||||
required this.uri,
|
||||
this.target = LinkTarget.defaultTarget,
|
||||
required this.builder,
|
||||
}) : super(key: key);
|
||||
|
||||
LinkDelegate get _effectiveDelegate {
|
||||
return UrlLauncherPlatform.instance.linkDelegate ??
|
||||
@ -90,16 +89,17 @@ class DefaultLinkDelegate extends StatelessWidget {
|
||||
bool get _useWebView {
|
||||
if (link.target == LinkTarget.self) return true;
|
||||
if (link.target == LinkTarget.blank) return false;
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<void> _followLink(BuildContext context) async {
|
||||
if (!link.uri.hasScheme) {
|
||||
if (!link.uri!.hasScheme) {
|
||||
// A uri that doesn't have a scheme is an internal route name. In this
|
||||
// case, we push it via Flutter's navigation system instead of letting the
|
||||
// browser handle it.
|
||||
final String routeName = link.uri.toString();
|
||||
return pushRouteNameToFramework(context, routeName);
|
||||
await pushRouteNameToFramework(context, routeName);
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point, we know that the link is external. So we use the `launch`
|
||||
@ -119,7 +119,6 @@ class DefaultLinkDelegate extends StatelessWidget {
|
||||
context: ErrorDescription('during launching a link'),
|
||||
));
|
||||
}
|
||||
return Future<void>.value(null);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -62,16 +62,15 @@ import 'package:url_launcher_platform_interface/url_launcher_platform_interface.
|
||||
/// is set to true and the universal link failed to launch.
|
||||
Future<bool> launch(
|
||||
String urlString, {
|
||||
bool forceSafariVC,
|
||||
bool forceWebView,
|
||||
bool enableJavaScript,
|
||||
bool enableDomStorage,
|
||||
bool universalLinksOnly,
|
||||
Map<String, String> headers,
|
||||
Brightness statusBarBrightness,
|
||||
String webOnlyWindowName,
|
||||
bool forceSafariVC = true,
|
||||
bool forceWebView = false,
|
||||
bool enableJavaScript = false,
|
||||
bool enableDomStorage = false,
|
||||
bool universalLinksOnly = false,
|
||||
Map<String, String> headers = const <String, String>{},
|
||||
Brightness? statusBarBrightness,
|
||||
String? webOnlyWindowName,
|
||||
}) async {
|
||||
assert(urlString != null);
|
||||
final Uri url = Uri.parse(urlString.trimLeft());
|
||||
final bool isWebURL = url.scheme == 'http' || url.scheme == 'https';
|
||||
if ((forceSafariVC == true || forceWebView == true) && !isWebURL) {
|
||||
@ -84,29 +83,32 @@ Future<bool> launch(
|
||||
/// [true] so that ui is automatically computed if [statusBarBrightness] is set.
|
||||
bool previousAutomaticSystemUiAdjustment = true;
|
||||
if (statusBarBrightness != null &&
|
||||
defaultTargetPlatform == TargetPlatform.iOS) {
|
||||
defaultTargetPlatform == TargetPlatform.iOS &&
|
||||
WidgetsBinding.instance != null) {
|
||||
previousAutomaticSystemUiAdjustment =
|
||||
WidgetsBinding.instance.renderView.automaticSystemUiAdjustment;
|
||||
WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = false;
|
||||
WidgetsBinding.instance!.renderView.automaticSystemUiAdjustment;
|
||||
WidgetsBinding.instance!.renderView.automaticSystemUiAdjustment = false;
|
||||
SystemChrome.setSystemUIOverlayStyle(statusBarBrightness == Brightness.light
|
||||
? SystemUiOverlayStyle.dark
|
||||
: SystemUiOverlayStyle.light);
|
||||
}
|
||||
|
||||
final bool result = await UrlLauncherPlatform.instance.launch(
|
||||
urlString,
|
||||
useSafariVC: forceSafariVC ?? isWebURL,
|
||||
useWebView: forceWebView ?? false,
|
||||
enableJavaScript: enableJavaScript ?? false,
|
||||
enableDomStorage: enableDomStorage ?? false,
|
||||
universalLinksOnly: universalLinksOnly ?? false,
|
||||
headers: headers ?? <String, String>{},
|
||||
useSafariVC: forceSafariVC,
|
||||
useWebView: forceWebView,
|
||||
enableJavaScript: enableJavaScript,
|
||||
enableDomStorage: enableDomStorage,
|
||||
universalLinksOnly: universalLinksOnly,
|
||||
headers: headers,
|
||||
webOnlyWindowName: webOnlyWindowName,
|
||||
);
|
||||
assert(previousAutomaticSystemUiAdjustment != null);
|
||||
if (statusBarBrightness != null) {
|
||||
WidgetsBinding.instance.renderView.automaticSystemUiAdjustment =
|
||||
|
||||
if (statusBarBrightness != null && WidgetsBinding.instance != null) {
|
||||
WidgetsBinding.instance!.renderView.automaticSystemUiAdjustment =
|
||||
previousAutomaticSystemUiAdjustment;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -118,9 +120,6 @@ Future<bool> launch(
|
||||
/// For more information see the [Managing package visibility](https://developer.android.com/training/basics/intents/package-visibility)
|
||||
/// article in the Android docs.
|
||||
Future<bool> canLaunch(String urlString) async {
|
||||
if (urlString == null) {
|
||||
return false;
|
||||
}
|
||||
return await UrlLauncherPlatform.instance.canLaunch(urlString);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ name: url_launcher
|
||||
description: Flutter plugin for launching a URL on Android and iOS. Supports
|
||||
web, phone, SMS, and email schemes.
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher
|
||||
version: 5.7.13
|
||||
version: 6.0.0-nullsafety.1
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
@ -12,8 +12,9 @@ flutter:
|
||||
pluginClass: UrlLauncherPlugin
|
||||
ios:
|
||||
pluginClass: FLTURLLauncherPlugin
|
||||
web:
|
||||
default_package: url_launcher_web
|
||||
# TODO(mvanbeusekom): Temporary disabled until web is migrated to nnbd (advised by @blasten).
|
||||
#web:
|
||||
# default_package: url_launcher_web
|
||||
linux:
|
||||
default_package: url_laucher_linux
|
||||
macos:
|
||||
@ -24,25 +25,26 @@ flutter:
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
url_launcher_platform_interface: ^1.0.9
|
||||
url_launcher_platform_interface: ^2.0.0-nullsafety
|
||||
# The design on https://flutter.dev/go/federated-plugins was to leave
|
||||
# this constraint as "any". We cannot do it right now as it fails pub publish
|
||||
# validation, so we set a ^ constraint.
|
||||
# TODO(amirh): Revisit this (either update this part in the design or the pub tool).
|
||||
# https://github.com/flutter/flutter/issues/46264
|
||||
url_launcher_web: ^0.1.5
|
||||
url_launcher_linux: ^0.0.1
|
||||
url_launcher_macos: ^0.0.1
|
||||
url_launcher_windows: ^0.0.1
|
||||
url_launcher_linux: ^0.1.0-nullsafety
|
||||
url_launcher_macos: ^0.1.0-nullsafety
|
||||
url_launcher_windows: ^0.1.0-nullsafety
|
||||
# TODO(mvanbeusekom): Temporary disabled until web is migrated to nnbd (advised by @blasten).
|
||||
#url_launcher_web: ^0.1.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
test: ^1.3.0
|
||||
test: ^1.10.0-nullsafety.1
|
||||
mockito: ^4.1.1
|
||||
plugin_platform_interface: ^1.0.0
|
||||
pedantic: ^1.8.0
|
||||
plugin_platform_interface: ^1.1.0-nullsafety.1
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.12.13+hotfix.5"
|
||||
|
@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
// TODO(egarciad): Remove once Mockito has been migrated to null safety.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -2,10 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
// TODO(mvanbeusekom): Remove once Mockito is migrated to null safety.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@ -41,10 +43,6 @@ void main() {
|
||||
});
|
||||
});
|
||||
group('launch', () {
|
||||
test('requires a non-null urlString', () {
|
||||
expect(() => launch(null), throwsAssertionError);
|
||||
});
|
||||
|
||||
test('default behavior', () async {
|
||||
await launch('http://flutter.dev/');
|
||||
expect(
|
||||
|
@ -1,3 +1,7 @@
|
||||
## 0.1.0-nullsafety.1
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 0.0.2+1
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
@ -1,6 +1,6 @@
|
||||
name: url_launcher_linux
|
||||
description: Linux implementation of the url_launcher plugin.
|
||||
version: 0.0.2+1
|
||||
version: 0.1.0-nullsafety.1
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux
|
||||
|
||||
flutter:
|
||||
@ -10,7 +10,7 @@ flutter:
|
||||
pluginClass: UrlLauncherPlugin
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.12.8"
|
||||
|
||||
dependencies:
|
||||
|
@ -1,3 +1,11 @@
|
||||
# 0.1.0-nullsafety.1
|
||||
|
||||
* Bump SDK to support null safety.
|
||||
|
||||
# 0.1.0-nullsafety
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 0.0.2+1
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
@ -3,7 +3,7 @@ description: macOS implementation of the url_launcher plugin.
|
||||
# 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump
|
||||
# the version to 2.0.0.
|
||||
# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
|
||||
version: 0.0.2+1
|
||||
version: 0.1.0-nullsafety.1
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_macos
|
||||
|
||||
flutter:
|
||||
@ -14,7 +14,7 @@ flutter:
|
||||
fileName: url_launcher_macos.dart
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.12.8"
|
||||
|
||||
dependencies:
|
||||
|
@ -1,3 +1,11 @@
|
||||
## 2.0.0-nullsafety.1
|
||||
|
||||
* Bump Dart SDK to support null safety.
|
||||
|
||||
## 2.0.0-nullsafety
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 1.0.10
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
@ -0,0 +1,4 @@
|
||||
include: ../../../analysis_options.yaml
|
||||
analyzer:
|
||||
enable-experiment:
|
||||
- non-nullable
|
@ -16,7 +16,7 @@ typedef FollowLink = Future<void> Function();
|
||||
/// the widget tree under it.
|
||||
typedef LinkWidgetBuilder = Widget Function(
|
||||
BuildContext context,
|
||||
FollowLink followLink,
|
||||
FollowLink? followLink,
|
||||
);
|
||||
|
||||
/// Signature for a delegate function to build the [Link] widget.
|
||||
@ -31,7 +31,7 @@ final MethodCodec _codec = const JSONMethodCodec();
|
||||
class LinkTarget {
|
||||
/// Const private constructor with a [debugLabel] to allow the creation of
|
||||
/// multiple distinct const instances.
|
||||
const LinkTarget._({this.debugLabel});
|
||||
const LinkTarget._({required this.debugLabel});
|
||||
|
||||
/// Used to distinguish multiple const instances of [LinkTarget].
|
||||
final String debugLabel;
|
||||
@ -64,7 +64,7 @@ abstract class LinkInfo {
|
||||
LinkWidgetBuilder get builder;
|
||||
|
||||
/// The destination that this link leads to.
|
||||
Uri get uri;
|
||||
Uri? get uri;
|
||||
|
||||
/// The target indicating where to open the link.
|
||||
LinkTarget get target;
|
||||
@ -80,10 +80,14 @@ Future<ByteData> pushRouteNameToFramework(
|
||||
String routeName, {
|
||||
@visibleForTesting bool debugForceRouter = false,
|
||||
}) {
|
||||
final PlatformMessageCallback? onPlatformMessage = window.onPlatformMessage;
|
||||
if (onPlatformMessage == null) {
|
||||
return Future<ByteData>.value(null);
|
||||
}
|
||||
final Completer<ByteData> completer = Completer<ByteData>();
|
||||
if (debugForceRouter || _hasRouter(context)) {
|
||||
SystemNavigator.routeInformationUpdated(location: routeName);
|
||||
window.onPlatformMessage(
|
||||
onPlatformMessage(
|
||||
'flutter/navigation',
|
||||
_codec.encodeMethodCall(
|
||||
MethodCall('pushRouteInformation', <dynamic, dynamic>{
|
||||
@ -94,7 +98,7 @@ Future<ByteData> pushRouteNameToFramework(
|
||||
completer.complete,
|
||||
);
|
||||
} else {
|
||||
window.onPlatformMessage(
|
||||
onPlatformMessage(
|
||||
'flutter/navigation',
|
||||
_codec.encodeMethodCall(MethodCall('pushRoute', routeName)),
|
||||
completer.complete,
|
||||
|
@ -5,7 +5,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:meta/meta.dart' show required;
|
||||
|
||||
import 'link.dart';
|
||||
import 'url_launcher_platform_interface.dart';
|
||||
@ -15,14 +14,14 @@ const MethodChannel _channel = MethodChannel('plugins.flutter.io/url_launcher');
|
||||
/// An implementation of [UrlLauncherPlatform] that uses method channels.
|
||||
class MethodChannelUrlLauncher extends UrlLauncherPlatform {
|
||||
@override
|
||||
final LinkDelegate linkDelegate = null;
|
||||
final LinkDelegate? linkDelegate = null;
|
||||
|
||||
@override
|
||||
Future<bool> canLaunch(String url) {
|
||||
return _channel.invokeMethod<bool>(
|
||||
'canLaunch',
|
||||
<String, Object>{'url': url},
|
||||
);
|
||||
).then((value) => value ?? false);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -33,13 +32,13 @@ class MethodChannelUrlLauncher extends UrlLauncherPlatform {
|
||||
@override
|
||||
Future<bool> launch(
|
||||
String url, {
|
||||
@required bool useSafariVC,
|
||||
@required bool useWebView,
|
||||
@required bool enableJavaScript,
|
||||
@required bool enableDomStorage,
|
||||
@required bool universalLinksOnly,
|
||||
@required Map<String, String> headers,
|
||||
String webOnlyWindowName,
|
||||
required bool useSafariVC,
|
||||
required bool useWebView,
|
||||
required bool enableJavaScript,
|
||||
required bool enableDomStorage,
|
||||
required bool universalLinksOnly,
|
||||
required Map<String, String> headers,
|
||||
String? webOnlyWindowName,
|
||||
}) {
|
||||
return _channel.invokeMethod<bool>(
|
||||
'launch',
|
||||
@ -52,6 +51,6 @@ class MethodChannelUrlLauncher extends UrlLauncherPlatform {
|
||||
'universalLinksOnly': universalLinksOnly,
|
||||
'headers': headers,
|
||||
},
|
||||
);
|
||||
).then((value) => value ?? false);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:meta/meta.dart' show required;
|
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||
import 'package:url_launcher_platform_interface/link.dart';
|
||||
|
||||
@ -40,7 +39,7 @@ abstract class UrlLauncherPlatform extends PlatformInterface {
|
||||
}
|
||||
|
||||
/// The delegate used by the Link widget to build itself.
|
||||
LinkDelegate get linkDelegate;
|
||||
LinkDelegate? get linkDelegate;
|
||||
|
||||
/// Returns `true` if this platform is able to launch [url].
|
||||
Future<bool> canLaunch(String url) {
|
||||
@ -53,13 +52,13 @@ abstract class UrlLauncherPlatform extends PlatformInterface {
|
||||
/// in `package:url_launcher/url_launcher.dart`.
|
||||
Future<bool> launch(
|
||||
String url, {
|
||||
@required bool useSafariVC,
|
||||
@required bool useWebView,
|
||||
@required bool enableJavaScript,
|
||||
@required bool enableDomStorage,
|
||||
@required bool universalLinksOnly,
|
||||
@required Map<String, String> headers,
|
||||
String webOnlyWindowName,
|
||||
required bool useSafariVC,
|
||||
required bool useWebView,
|
||||
required bool enableJavaScript,
|
||||
required bool enableDomStorage,
|
||||
required bool universalLinksOnly,
|
||||
required Map<String, String> headers,
|
||||
String? webOnlyWindowName,
|
||||
}) {
|
||||
throw UnimplementedError('launch() has not been implemented.');
|
||||
}
|
||||
|
@ -3,20 +3,19 @@ description: A common platform interface for the url_launcher plugin.
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_platform_interface
|
||||
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
|
||||
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
|
||||
version: 1.0.10
|
||||
version: 2.0.0-nullsafety.1
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
meta: ^1.0.5
|
||||
plugin_platform_interface: ^1.0.1
|
||||
plugin_platform_interface: ^1.1.0-nullsafety.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
mockito: ^4.1.1
|
||||
pedantic: ^1.8.0
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.22.0"
|
||||
|
@ -2,6 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// TODO(egarciad): Remove once Mockito has been migrated to null safety.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// TODO(mvanbeusekom): Remove once Mockito is migrated to null safety.
|
||||
// @dart = 2.9
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
@ -42,6 +44,10 @@ void main() {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
channel.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
|
||||
// Return null explicitly instead of relying on the implicit null
|
||||
// returned by the method channel if no return statement is specified.
|
||||
return null;
|
||||
});
|
||||
|
||||
final MethodChannelUrlLauncher launcher = MethodChannelUrlLauncher();
|
||||
@ -62,6 +68,12 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
test('canLaunch should return false if platform returns null', () async {
|
||||
final canLaunch = await launcher.canLaunch('http://example.com/');
|
||||
|
||||
expect(canLaunch, false);
|
||||
});
|
||||
|
||||
test('launch', () async {
|
||||
await launcher.launch(
|
||||
'http://example.com/',
|
||||
@ -270,6 +282,20 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
test('launch should return false if platform returns null', () async {
|
||||
final launched = await launcher.launch(
|
||||
'http://example.com/',
|
||||
useSafariVC: true,
|
||||
useWebView: false,
|
||||
enableJavaScript: false,
|
||||
enableDomStorage: false,
|
||||
universalLinksOnly: false,
|
||||
headers: const <String, String>{},
|
||||
);
|
||||
|
||||
expect(launched, false);
|
||||
});
|
||||
|
||||
test('closeWebView default behavior', () async {
|
||||
await launcher.closeWebView();
|
||||
expect(
|
||||
|
@ -15,6 +15,12 @@ flutter:
|
||||
|
||||
dependencies:
|
||||
url_launcher_platform_interface: ^1.0.9
|
||||
# TODO(mvanbeusekom): Update to use pub.dev once null safety version is published.
|
||||
# url_launcher_platform_interface:
|
||||
# git:
|
||||
# url: https://github.com/flutter/plugins.git
|
||||
# ref: nnbd
|
||||
# path: packages/url_launcher/url_launcher_platform_interface
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_web_plugins:
|
||||
@ -25,6 +31,9 @@ dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
url_launcher: ^5.2.5
|
||||
# TODO(mvanbeusekom): Update to use pub.dev once null safety version is published.
|
||||
# url_launcher:
|
||||
# path: ../url_launcher
|
||||
pedantic: ^1.8.0
|
||||
mockito: ^4.1.1
|
||||
integration_test:
|
||||
|
@ -2,7 +2,7 @@ name: regular_integration_tests
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ">=2.2.2 <3.0.0"
|
||||
sdk: ">=2.10.0-56.0.dev <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
@ -1,3 +1,11 @@
|
||||
## 0.1.0-nullsafety.1
|
||||
|
||||
* Bump Dart SDK to support null safety.
|
||||
|
||||
## 0.1.0-nullsafety
|
||||
|
||||
* Migrate to null-safety.
|
||||
|
||||
## 0.0.2+1
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
@ -3,7 +3,7 @@ description: Windows implementation of the url_launcher plugin.
|
||||
# 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump
|
||||
# the version to 2.0.0.
|
||||
# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
|
||||
version: 0.0.2+1
|
||||
version: 0.1.0-nullsafety.1
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_windows
|
||||
|
||||
flutter:
|
||||
@ -13,7 +13,7 @@ flutter:
|
||||
pluginClass: UrlLauncherPlugin
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.12.8"
|
||||
|
||||
dependencies:
|
||||
|
@ -1,3 +1,19 @@
|
||||
## 2.0.0-nullsafety.3
|
||||
|
||||
* Dart null safety requires `2.12`.
|
||||
|
||||
## 2.0.0-nullsafety.2
|
||||
|
||||
* Bump SDK version.
|
||||
|
||||
## 2.0.0-nullsafety.1
|
||||
|
||||
* Merge master.
|
||||
|
||||
## 2.0.0-nullsafety
|
||||
|
||||
* Migration to null safety.
|
||||
|
||||
## 1.0.2
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
4
packages/video_player/video_player/analysis_options.yaml
Normal file
4
packages/video_player/video_player/analysis_options.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
include: ../../../analysis_options.yaml
|
||||
analyzer:
|
||||
enable-experiment:
|
||||
- non-nullable
|
@ -1,4 +1,4 @@
|
||||
// Autogenerated from Pigeon (v0.1.7), do not edit directly.
|
||||
// Autogenerated from Pigeon (v0.1.12), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
|
||||
package io.flutter.plugins.videoplayer;
|
||||
@ -597,7 +597,7 @@ public class Messages {
|
||||
private static HashMap wrapError(Exception exception) {
|
||||
HashMap<String, Object> errorMap = new HashMap<>();
|
||||
errorMap.put("message", exception.toString());
|
||||
errorMap.put("code", null);
|
||||
errorMap.put("code", exception.getClass().getSimpleName());
|
||||
errorMap.put("details", null);
|
||||
return errorMap;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ const Duration _playDuration = Duration(seconds: 1);
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
VideoPlayerController _controller;
|
||||
late VideoPlayerController _controller;
|
||||
tearDown(() async => _controller.dispose());
|
||||
|
||||
group('asset videos', () {
|
||||
@ -22,7 +22,7 @@ void main() {
|
||||
testWidgets('can be initialized', (WidgetTester tester) async {
|
||||
await _controller.initialize();
|
||||
|
||||
expect(_controller.value.initialized, true);
|
||||
expect(_controller.value.isInitialized, true);
|
||||
expect(_controller.value.position, const Duration(seconds: 0));
|
||||
expect(_controller.value.isPlaying, false);
|
||||
expect(_controller.value.duration,
|
||||
|
@ -108,7 +108,7 @@ class _ButterFlyAssetVideoInList extends StatelessWidget {
|
||||
|
||||
/// A filler card to show the video in a list of scrolling contents.
|
||||
class _ExampleCard extends StatelessWidget {
|
||||
const _ExampleCard({Key key, this.title}) : super(key: key);
|
||||
const _ExampleCard({Key? key, required this.title}) : super(key: key);
|
||||
|
||||
final String title;
|
||||
|
||||
@ -150,7 +150,7 @@ class _ButterFlyAssetVideo extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ButterFlyAssetVideoState extends State<_ButterFlyAssetVideo> {
|
||||
VideoPlayerController _controller;
|
||||
late VideoPlayerController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -206,7 +206,7 @@ class _BumbleBeeRemoteVideo extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _BumbleBeeRemoteVideoState extends State<_BumbleBeeRemoteVideo> {
|
||||
VideoPlayerController _controller;
|
||||
late VideoPlayerController _controller;
|
||||
|
||||
Future<ClosedCaptionFile> _loadCaptions() async {
|
||||
final String fileContents = await DefaultAssetBundle.of(context)
|
||||
@ -265,7 +265,8 @@ class _BumbleBeeRemoteVideoState extends State<_BumbleBeeRemoteVideo> {
|
||||
}
|
||||
|
||||
class _ControlsOverlay extends StatelessWidget {
|
||||
const _ControlsOverlay({Key key, this.controller}) : super(key: key);
|
||||
const _ControlsOverlay({Key? key, required this.controller})
|
||||
: super(key: key);
|
||||
|
||||
static const _examplePlaybackRates = [
|
||||
0.25,
|
||||
@ -345,7 +346,7 @@ class _PlayerVideoAndPopPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _PlayerVideoAndPopPageState extends State<_PlayerVideoAndPopPage> {
|
||||
VideoPlayerController _videoPlayerController;
|
||||
late VideoPlayerController _videoPlayerController;
|
||||
bool startedPlaying = false;
|
||||
|
||||
@override
|
||||
|
@ -16,7 +16,8 @@ dev_dependencies:
|
||||
sdk: flutter
|
||||
integration_test:
|
||||
path: ../../../integration_test
|
||||
pedantic: ^1.8.0
|
||||
test: any
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
@ -2,6 +2,9 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// TODO(egarciad): Remove once Flutter driver is migrated to null safety.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
@ -0,0 +1,14 @@
|
||||
// Copyright 2019, the Chromium project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// TODO(egarciad): Remove once Flutter driver is migrated to null safety.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
import 'package:video_player_example/main.dart' as app;
|
||||
|
||||
void main() {
|
||||
enableFlutterDriverExtension();
|
||||
app.main();
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
// Copyright 2019, the Chromium project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// TODO(egarciad): Remove once Flutter driver is migrated to null safety.
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:flutter_driver/flutter_driver.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
final FlutterDriver driver = await FlutterDriver.connect();
|
||||
tearDownAll(() async {
|
||||
await driver.close();
|
||||
});
|
||||
|
||||
//TODO(cyanglaz): Use TabBar tabs to navigate between pages after https://github.com/flutter/flutter/issues/16991 is fixed.
|
||||
//TODO(cyanglaz): Un-skip the test after https://github.com/flutter/flutter/issues/43012 is fixed
|
||||
test('Push a page contains video and pop back, do not crash.', () async {
|
||||
final SerializableFinder pushTab = find.byValueKey('push_tab');
|
||||
await driver.waitFor(pushTab);
|
||||
await driver.tap(pushTab);
|
||||
await driver.waitForAbsent(pushTab);
|
||||
await driver.waitFor(find.byValueKey('home_page'));
|
||||
await driver.waitUntilNoTransientCallbacks();
|
||||
final Health health = await driver.checkHealth();
|
||||
expect(health.status, HealthStatus.ok);
|
||||
}, skip: 'Cirrus CI currently hangs while playing videos');
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Autogenerated from Pigeon (v0.1.7), do not edit directly.
|
||||
// Autogenerated from Pigeon (v0.1.12), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
#import <Foundation/Foundation.h>
|
||||
@protocol FlutterBinaryMessenger;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Autogenerated from Pigeon (v0.1.7), do not edit directly.
|
||||
// Autogenerated from Pigeon (v0.1.12), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
#import "messages.h"
|
||||
#import <Flutter/Flutter.h>
|
||||
@ -7,6 +7,7 @@
|
||||
#error File requires ARC to be enabled.
|
||||
#endif
|
||||
|
||||
#ifndef __clang_analyzer__
|
||||
static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) {
|
||||
NSDictionary *errorDict = (NSDictionary *)[NSNull null];
|
||||
if (error) {
|
||||
@ -59,8 +60,8 @@ static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) {
|
||||
return result;
|
||||
}
|
||||
- (NSDictionary *)toMap {
|
||||
return [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]),
|
||||
return
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]),
|
||||
@"textureId", nil];
|
||||
}
|
||||
@end
|
||||
@ -112,10 +113,9 @@ static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) {
|
||||
}
|
||||
- (NSDictionary *)toMap {
|
||||
return [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]),
|
||||
@"textureId",
|
||||
(self.isLooping != nil ? self.isLooping : [NSNull null]),
|
||||
@"isLooping", nil];
|
||||
dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId",
|
||||
(self.isLooping ? self.isLooping : [NSNull null]), @"isLooping",
|
||||
nil];
|
||||
}
|
||||
@end
|
||||
|
||||
@ -134,9 +134,8 @@ static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) {
|
||||
}
|
||||
- (NSDictionary *)toMap {
|
||||
return [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]),
|
||||
@"textureId", (self.volume != nil ? self.volume : [NSNull null]),
|
||||
@"volume", nil];
|
||||
dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId",
|
||||
(self.volume ? self.volume : [NSNull null]), @"volume", nil];
|
||||
}
|
||||
@end
|
||||
|
||||
@ -155,9 +154,8 @@ static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) {
|
||||
}
|
||||
- (NSDictionary *)toMap {
|
||||
return [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]),
|
||||
@"textureId", (self.speed != nil ? self.speed : [NSNull null]),
|
||||
@"speed", nil];
|
||||
dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId",
|
||||
(self.speed ? self.speed : [NSNull null]), @"speed", nil];
|
||||
}
|
||||
@end
|
||||
|
||||
@ -176,10 +174,9 @@ static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) {
|
||||
}
|
||||
- (NSDictionary *)toMap {
|
||||
return [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]),
|
||||
@"textureId",
|
||||
(self.position != nil ? self.position : [NSNull null]),
|
||||
@"position", nil];
|
||||
dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId",
|
||||
(self.position ? self.position : [NSNull null]), @"position",
|
||||
nil];
|
||||
}
|
||||
@end
|
||||
|
||||
@ -194,7 +191,7 @@ static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) {
|
||||
}
|
||||
- (NSDictionary *)toMap {
|
||||
return [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:(self.mixWithOthers != nil ? self.mixWithOthers : [NSNull null]),
|
||||
dictionaryWithObjectsAndKeys:(self.mixWithOthers ? self.mixWithOthers : [NSNull null]),
|
||||
@"mixWithOthers", nil];
|
||||
}
|
||||
@end
|
||||
@ -365,3 +362,4 @@ void FLTVideoPlayerApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<FLTVi
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -31,7 +31,11 @@ class Caption {
|
||||
///
|
||||
/// This is not recommended for direct use unless you are writing a parser for
|
||||
/// a new closed captioning file type.
|
||||
const Caption({this.number, this.start, this.end, this.text});
|
||||
const Caption(
|
||||
{required this.number,
|
||||
required this.start,
|
||||
required this.end,
|
||||
required this.text});
|
||||
|
||||
/// The number that this caption was assigned.
|
||||
final int number;
|
||||
@ -46,6 +50,11 @@ class Caption {
|
||||
/// and [end].
|
||||
final String text;
|
||||
|
||||
/// A no caption object. This is a caption with [start] and [end] durations of zero,
|
||||
/// and an empty [text] string.
|
||||
static const Caption none =
|
||||
Caption(number: 0, start: Duration.zero, end: Duration.zero, text: '');
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '$runtimeType('
|
||||
|
@ -41,8 +41,7 @@ List<Caption> _parseCaptionsFromSubRipString(String file) {
|
||||
end: startAndEnd.end,
|
||||
text: text,
|
||||
);
|
||||
|
||||
if (newCaption.start != null && newCaption.end != null) {
|
||||
if (newCaption.start != newCaption.end) {
|
||||
captions.add(newCaption);
|
||||
}
|
||||
}
|
||||
@ -64,7 +63,7 @@ class _StartAndEnd {
|
||||
RegExp(_subRipTimeStamp + _subRipArrow + _subRipTimeStamp);
|
||||
|
||||
if (!format.hasMatch(line)) {
|
||||
return _StartAndEnd(null, null);
|
||||
return _StartAndEnd(Duration.zero, Duration.zero);
|
||||
}
|
||||
|
||||
final List<String> times = line.split(_subRipArrow);
|
||||
@ -84,7 +83,7 @@ class _StartAndEnd {
|
||||
// Duration(hours: 0, minutes: 1, seconds: 59, milliseconds: 084)
|
||||
Duration _parseSubRipTimestamp(String timestampString) {
|
||||
if (!RegExp(_subRipTimeStamp).hasMatch(timestampString)) {
|
||||
return null;
|
||||
return Duration.zero;
|
||||
}
|
||||
|
||||
final List<String> commaSections = timestampString.split(',');
|
||||
|
@ -28,11 +28,12 @@ class VideoPlayerValue {
|
||||
/// Constructs a video with the given values. Only [duration] is required. The
|
||||
/// rest will initialize with default values when unset.
|
||||
VideoPlayerValue({
|
||||
@required this.duration,
|
||||
this.size,
|
||||
this.position = const Duration(),
|
||||
this.caption = const Caption(),
|
||||
required this.duration,
|
||||
this.size = Size.zero,
|
||||
this.position = Duration.zero,
|
||||
this.caption = Caption.none,
|
||||
this.buffered = const <DurationRange>[],
|
||||
this.isInitialized = false,
|
||||
this.isPlaying = false,
|
||||
this.isLooping = false,
|
||||
this.isBuffering = false,
|
||||
@ -41,17 +42,20 @@ class VideoPlayerValue {
|
||||
this.errorDescription,
|
||||
});
|
||||
|
||||
/// Returns an instance with a `null` [Duration].
|
||||
VideoPlayerValue.uninitialized() : this(duration: null);
|
||||
/// Returns an instance for a video that hasn't been loaded.
|
||||
VideoPlayerValue.uninitialized()
|
||||
: this(duration: Duration.zero, isInitialized: false);
|
||||
|
||||
/// Returns an instance with a `null` [Duration] and the given
|
||||
/// [errorDescription].
|
||||
/// Returns an instance with the given [errorDescription].
|
||||
VideoPlayerValue.erroneous(String errorDescription)
|
||||
: this(duration: null, errorDescription: errorDescription);
|
||||
: this(
|
||||
duration: Duration.zero,
|
||||
isInitialized: false,
|
||||
errorDescription: errorDescription);
|
||||
|
||||
/// The total duration of the video.
|
||||
///
|
||||
/// Is null when [initialized] is false.
|
||||
/// The duration is [Duration.zero] if the video hasn't been initialized.
|
||||
final Duration duration;
|
||||
|
||||
/// The current playback position.
|
||||
@ -60,7 +64,7 @@ class VideoPlayerValue {
|
||||
/// The [Caption] that should be displayed based on the current [position].
|
||||
///
|
||||
/// This field will never be null. If there is no caption for the current
|
||||
/// [position], this will be an empty [Caption] object.
|
||||
/// [position], this will be a [Caption.none] object.
|
||||
final Caption caption;
|
||||
|
||||
/// The currently buffered ranges.
|
||||
@ -84,7 +88,7 @@ class VideoPlayerValue {
|
||||
/// A description of the error if present.
|
||||
///
|
||||
/// If [hasError] is false this is [null].
|
||||
final String errorDescription;
|
||||
final String? errorDescription;
|
||||
|
||||
/// The [size] of the currently loaded video.
|
||||
///
|
||||
@ -92,7 +96,7 @@ class VideoPlayerValue {
|
||||
final Size size;
|
||||
|
||||
/// Indicates whether or not the video has been loaded and is ready to play.
|
||||
bool get initialized => duration != null;
|
||||
final bool isInitialized;
|
||||
|
||||
/// Indicates whether or not the video is in an error state. If this is true
|
||||
/// [errorDescription] should have information about the problem.
|
||||
@ -101,7 +105,7 @@ class VideoPlayerValue {
|
||||
/// Returns [size.width] / [size.height] when size is non-null, or `1.0.` when
|
||||
/// size is null or the aspect ratio would be less than or equal to 0.0.
|
||||
double get aspectRatio {
|
||||
if (size == null || size.width == 0 || size.height == 0) {
|
||||
if (!isInitialized || size.width == 0 || size.height == 0) {
|
||||
return 1.0;
|
||||
}
|
||||
final double aspectRatio = size.width / size.height;
|
||||
@ -114,17 +118,18 @@ class VideoPlayerValue {
|
||||
/// Returns a new instance that has the same values as this current instance,
|
||||
/// except for any overrides passed in as arguments to [copyWidth].
|
||||
VideoPlayerValue copyWith({
|
||||
Duration duration,
|
||||
Size size,
|
||||
Duration position,
|
||||
Caption caption,
|
||||
List<DurationRange> buffered,
|
||||
bool isPlaying,
|
||||
bool isLooping,
|
||||
bool isBuffering,
|
||||
double volume,
|
||||
double playbackSpeed,
|
||||
String errorDescription,
|
||||
Duration? duration,
|
||||
Size? size,
|
||||
Duration? position,
|
||||
Caption? caption,
|
||||
List<DurationRange>? buffered,
|
||||
bool? isInitialized,
|
||||
bool? isPlaying,
|
||||
bool? isLooping,
|
||||
bool? isBuffering,
|
||||
double? volume,
|
||||
double? playbackSpeed,
|
||||
String? errorDescription,
|
||||
}) {
|
||||
return VideoPlayerValue(
|
||||
duration: duration ?? this.duration,
|
||||
@ -132,6 +137,7 @@ class VideoPlayerValue {
|
||||
position: position ?? this.position,
|
||||
caption: caption ?? this.caption,
|
||||
buffered: buffered ?? this.buffered,
|
||||
isInitialized: isInitialized ?? this.isInitialized,
|
||||
isPlaying: isPlaying ?? this.isPlaying,
|
||||
isLooping: isLooping ?? this.isLooping,
|
||||
isBuffering: isBuffering ?? this.isBuffering,
|
||||
@ -149,6 +155,7 @@ class VideoPlayerValue {
|
||||
'position: $position, '
|
||||
'caption: $caption, '
|
||||
'buffered: [${buffered.join(', ')}], '
|
||||
'isInitialized: $isInitialized, '
|
||||
'isPlaying: $isPlaying, '
|
||||
'isLooping: $isLooping, '
|
||||
'isBuffering: $isBuffering, '
|
||||
@ -178,7 +185,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
{this.package, this.closedCaptionFile, this.videoPlayerOptions})
|
||||
: dataSourceType = DataSourceType.asset,
|
||||
formatHint = null,
|
||||
super(VideoPlayerValue(duration: null));
|
||||
super(VideoPlayerValue(duration: Duration.zero));
|
||||
|
||||
/// Constructs a [VideoPlayerController] playing a video from obtained from
|
||||
/// the network.
|
||||
@ -191,7 +198,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
{this.formatHint, this.closedCaptionFile, this.videoPlayerOptions})
|
||||
: dataSourceType = DataSourceType.network,
|
||||
package = null,
|
||||
super(VideoPlayerValue(duration: null));
|
||||
super(VideoPlayerValue(duration: Duration.zero));
|
||||
|
||||
/// Constructs a [VideoPlayerController] playing a video from a file.
|
||||
///
|
||||
@ -203,9 +210,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
dataSourceType = DataSourceType.file,
|
||||
package = null,
|
||||
formatHint = null,
|
||||
super(VideoPlayerValue(duration: null));
|
||||
|
||||
int _textureId;
|
||||
super(VideoPlayerValue(duration: Duration.zero));
|
||||
|
||||
/// The URI to the video file. This will be in different formats depending on
|
||||
/// the [DataSourceType] of the original video.
|
||||
@ -213,31 +218,36 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
|
||||
/// **Android only**. Will override the platform's generic file format
|
||||
/// detection with whatever is set here.
|
||||
final VideoFormat formatHint;
|
||||
final VideoFormat? formatHint;
|
||||
|
||||
/// Describes the type of data source this [VideoPlayerController]
|
||||
/// is constructed with.
|
||||
final DataSourceType dataSourceType;
|
||||
|
||||
/// Provide additional configuration options (optional). Like setting the audio mode to mix
|
||||
final VideoPlayerOptions videoPlayerOptions;
|
||||
final VideoPlayerOptions? videoPlayerOptions;
|
||||
|
||||
/// Only set for [asset] videos. The package that the asset was loaded from.
|
||||
final String package;
|
||||
final String? package;
|
||||
|
||||
/// Optional field to specify a file containing the closed
|
||||
/// captioning.
|
||||
///
|
||||
/// This future will be awaited and the file will be loaded when
|
||||
/// [initialize()] is called.
|
||||
final Future<ClosedCaptionFile> closedCaptionFile;
|
||||
final Future<ClosedCaptionFile>? closedCaptionFile;
|
||||
|
||||
ClosedCaptionFile _closedCaptionFile;
|
||||
Timer _timer;
|
||||
ClosedCaptionFile? _closedCaptionFile;
|
||||
Timer? _timer;
|
||||
bool _isDisposed = false;
|
||||
Completer<void> _creatingCompleter;
|
||||
StreamSubscription<dynamic> _eventSubscription;
|
||||
_VideoAppLifeCycleObserver _lifeCycleObserver;
|
||||
Completer<void>? _creatingCompleter;
|
||||
StreamSubscription<dynamic>? _eventSubscription;
|
||||
late _VideoAppLifeCycleObserver _lifeCycleObserver;
|
||||
|
||||
/// The id of a texture that hasn't been initialized.
|
||||
@visibleForTesting
|
||||
static const int kUninitializedTextureId = -1;
|
||||
int _textureId = kUninitializedTextureId;
|
||||
|
||||
/// This is just exposed for testing. It shouldn't be used by anyone depending
|
||||
/// on the plugin.
|
||||
@ -250,7 +260,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
_lifeCycleObserver.initialize();
|
||||
_creatingCompleter = Completer<void>();
|
||||
|
||||
DataSource dataSourceDescription;
|
||||
late DataSource dataSourceDescription;
|
||||
switch (dataSourceType) {
|
||||
case DataSourceType.asset:
|
||||
dataSourceDescription = DataSource(
|
||||
@ -276,11 +286,12 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
|
||||
if (videoPlayerOptions?.mixWithOthers != null) {
|
||||
await _videoPlayerPlatform
|
||||
.setMixWithOthers(videoPlayerOptions.mixWithOthers);
|
||||
.setMixWithOthers(videoPlayerOptions!.mixWithOthers);
|
||||
}
|
||||
|
||||
_textureId = await _videoPlayerPlatform.create(dataSourceDescription);
|
||||
_creatingCompleter.complete(null);
|
||||
_textureId = (await _videoPlayerPlatform.create(dataSourceDescription)) ??
|
||||
kUninitializedTextureId;
|
||||
_creatingCompleter!.complete(null);
|
||||
final Completer<void> initializingCompleter = Completer<void>();
|
||||
|
||||
void eventListener(VideoEvent event) {
|
||||
@ -293,6 +304,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
value = value.copyWith(
|
||||
duration: event.duration,
|
||||
size: event.size,
|
||||
isInitialized: event.duration != null,
|
||||
);
|
||||
initializingCompleter.complete(null);
|
||||
_applyLooping();
|
||||
@ -325,8 +337,8 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
}
|
||||
|
||||
void errorListener(Object obj) {
|
||||
final PlatformException e = obj;
|
||||
value = VideoPlayerValue.erroneous(e.message);
|
||||
final PlatformException e = obj as PlatformException;
|
||||
value = VideoPlayerValue.erroneous(e.message!);
|
||||
_timer?.cancel();
|
||||
if (!initializingCompleter.isCompleted) {
|
||||
initializingCompleter.completeError(obj);
|
||||
@ -342,7 +354,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
if (_creatingCompleter != null) {
|
||||
await _creatingCompleter.future;
|
||||
await _creatingCompleter!.future;
|
||||
if (!_isDisposed) {
|
||||
_isDisposed = true;
|
||||
_timer?.cancel();
|
||||
@ -379,14 +391,14 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
}
|
||||
|
||||
Future<void> _applyLooping() async {
|
||||
if (!value.initialized || _isDisposed) {
|
||||
if (!value.isInitialized || _isDisposed) {
|
||||
return;
|
||||
}
|
||||
await _videoPlayerPlatform.setLooping(_textureId, value.isLooping);
|
||||
}
|
||||
|
||||
Future<void> _applyPlayPause() async {
|
||||
if (!value.initialized || _isDisposed) {
|
||||
if (!value.isInitialized || _isDisposed) {
|
||||
return;
|
||||
}
|
||||
if (value.isPlaying) {
|
||||
@ -400,8 +412,8 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
if (_isDisposed) {
|
||||
return;
|
||||
}
|
||||
final Duration newPosition = await position;
|
||||
if (_isDisposed) {
|
||||
final Duration? newPosition = await position;
|
||||
if (newPosition == null) {
|
||||
return;
|
||||
}
|
||||
_updatePosition(newPosition);
|
||||
@ -419,14 +431,14 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
}
|
||||
|
||||
Future<void> _applyVolume() async {
|
||||
if (!value.initialized || _isDisposed) {
|
||||
if (!value.isInitialized || _isDisposed) {
|
||||
return;
|
||||
}
|
||||
await _videoPlayerPlatform.setVolume(_textureId, value.volume);
|
||||
}
|
||||
|
||||
Future<void> _applyPlaybackSpeed() async {
|
||||
if (!value.initialized || _isDisposed) {
|
||||
if (!value.isInitialized || _isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -442,7 +454,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
}
|
||||
|
||||
/// The position in the current video.
|
||||
Future<Duration> get position async {
|
||||
Future<Duration?> get position async {
|
||||
if (_isDisposed) {
|
||||
return null;
|
||||
}
|
||||
@ -519,17 +531,17 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
|
||||
/// [Caption].
|
||||
Caption _getCaptionAt(Duration position) {
|
||||
if (_closedCaptionFile == null) {
|
||||
return Caption();
|
||||
return Caption.none;
|
||||
}
|
||||
|
||||
// TODO: This would be more efficient as a binary search.
|
||||
for (final caption in _closedCaptionFile.captions) {
|
||||
for (final caption in _closedCaptionFile!.captions) {
|
||||
if (caption.start <= position && caption.end >= position) {
|
||||
return caption;
|
||||
}
|
||||
}
|
||||
|
||||
return Caption();
|
||||
return Caption.none;
|
||||
}
|
||||
|
||||
void _updatePosition(Duration position) {
|
||||
@ -545,7 +557,7 @@ class _VideoAppLifeCycleObserver extends Object with WidgetsBindingObserver {
|
||||
final VideoPlayerController _controller;
|
||||
|
||||
void initialize() {
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
WidgetsBinding.instance!.addObserver(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -565,7 +577,7 @@ class _VideoAppLifeCycleObserver extends Object with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
WidgetsBinding.instance!.removeObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -594,8 +606,9 @@ class _VideoPlayerState extends State<VideoPlayer> {
|
||||
};
|
||||
}
|
||||
|
||||
VoidCallback _listener;
|
||||
int _textureId;
|
||||
late VoidCallback _listener;
|
||||
|
||||
late int _textureId;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -622,7 +635,7 @@ class _VideoPlayerState extends State<VideoPlayer> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _textureId == null
|
||||
return _textureId == VideoPlayerController.kUninitializedTextureId
|
||||
? Container()
|
||||
: _videoPlayerPlatform.buildView(_textureId);
|
||||
}
|
||||
@ -646,7 +659,7 @@ class VideoProgressColors {
|
||||
/// [backgroundColor] defaults to gray at 50% opacity. This is the background
|
||||
/// color behind both [playedColor] and [bufferedColor] to denote the total
|
||||
/// size of the video compared to either of those values.
|
||||
VideoProgressColors({
|
||||
const VideoProgressColors({
|
||||
this.playedColor = const Color.fromRGBO(255, 0, 0, 0.7),
|
||||
this.bufferedColor = const Color.fromRGBO(50, 50, 200, 0.2),
|
||||
this.backgroundColor = const Color.fromRGBO(200, 200, 200, 0.5),
|
||||
@ -670,8 +683,8 @@ class VideoProgressColors {
|
||||
|
||||
class _VideoScrubber extends StatefulWidget {
|
||||
_VideoScrubber({
|
||||
@required this.child,
|
||||
@required this.controller,
|
||||
required this.child,
|
||||
required this.controller,
|
||||
});
|
||||
|
||||
final Widget child;
|
||||
@ -689,7 +702,7 @@ class _VideoScrubberState extends State<_VideoScrubber> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
void seekToRelativePosition(Offset globalPosition) {
|
||||
final RenderBox box = context.findRenderObject();
|
||||
final RenderBox box = context.findRenderObject() as RenderBox;
|
||||
final Offset tapPos = box.globalToLocal(globalPosition);
|
||||
final double relative = tapPos.dx / box.size.width;
|
||||
final Duration position = controller.value.duration * relative;
|
||||
@ -700,7 +713,7 @@ class _VideoScrubberState extends State<_VideoScrubber> {
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: widget.child,
|
||||
onHorizontalDragStart: (DragStartDetails details) {
|
||||
if (!controller.value.initialized) {
|
||||
if (!controller.value.isInitialized) {
|
||||
return;
|
||||
}
|
||||
_controllerWasPlaying = controller.value.isPlaying;
|
||||
@ -709,7 +722,7 @@ class _VideoScrubberState extends State<_VideoScrubber> {
|
||||
}
|
||||
},
|
||||
onHorizontalDragUpdate: (DragUpdateDetails details) {
|
||||
if (!controller.value.initialized) {
|
||||
if (!controller.value.isInitialized) {
|
||||
return;
|
||||
}
|
||||
seekToRelativePosition(details.globalPosition);
|
||||
@ -720,7 +733,7 @@ class _VideoScrubberState extends State<_VideoScrubber> {
|
||||
}
|
||||
},
|
||||
onTapDown: (TapDownDetails details) {
|
||||
if (!controller.value.initialized) {
|
||||
if (!controller.value.isInitialized) {
|
||||
return;
|
||||
}
|
||||
seekToRelativePosition(details.globalPosition);
|
||||
@ -745,10 +758,10 @@ class VideoProgressIndicator extends StatefulWidget {
|
||||
/// to `top: 5.0`.
|
||||
VideoProgressIndicator(
|
||||
this.controller, {
|
||||
VideoProgressColors colors,
|
||||
this.allowScrubbing,
|
||||
this.colors = const VideoProgressColors(),
|
||||
required this.allowScrubbing,
|
||||
this.padding = const EdgeInsets.only(top: 5.0),
|
||||
}) : colors = colors ?? VideoProgressColors();
|
||||
});
|
||||
|
||||
/// The [VideoPlayerController] that actually associates a video with this
|
||||
/// widget.
|
||||
@ -785,7 +798,7 @@ class _VideoProgressIndicatorState extends State<VideoProgressIndicator> {
|
||||
};
|
||||
}
|
||||
|
||||
VoidCallback listener;
|
||||
late VoidCallback listener;
|
||||
|
||||
VideoPlayerController get controller => widget.controller;
|
||||
|
||||
@ -806,7 +819,7 @@ class _VideoProgressIndicatorState extends State<VideoProgressIndicator> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget progressIndicator;
|
||||
if (controller.value.initialized) {
|
||||
if (controller.value.isInitialized) {
|
||||
final int duration = controller.value.duration.inMilliseconds;
|
||||
final int position = controller.value.position.inMilliseconds;
|
||||
|
||||
@ -878,17 +891,17 @@ class ClosedCaption extends StatelessWidget {
|
||||
/// [VideoPlayerValue.caption].
|
||||
///
|
||||
/// If [text] is null, nothing will be displayed.
|
||||
const ClosedCaption({Key key, this.text, this.textStyle}) : super(key: key);
|
||||
const ClosedCaption({Key? key, this.text, this.textStyle}) : super(key: key);
|
||||
|
||||
/// The text that will be shown in the closed caption, or null if no caption
|
||||
/// should be shown.
|
||||
final String text;
|
||||
final String? text;
|
||||
|
||||
/// Specifies how the text in the closed caption should look.
|
||||
///
|
||||
/// If null, defaults to [DefaultTextStyle.of(context).style] with size 36
|
||||
/// font colored white.
|
||||
final TextStyle textStyle;
|
||||
final TextStyle? textStyle;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -913,7 +926,7 @@ class ClosedCaption extends StatelessWidget {
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2.0),
|
||||
child: Text(text, style: effectiveTextStyle),
|
||||
child: Text(text!, style: effectiveTextStyle),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -1,3 +1,5 @@
|
||||
// @dart = 2.9
|
||||
|
||||
import 'package:pigeon/pigeon_lib.dart';
|
||||
|
||||
class TextureMessage {
|
||||
|
@ -1,7 +1,10 @@
|
||||
name: video_player
|
||||
description: Flutter plugin for displaying inline video with other Flutter
|
||||
widgets on Android, iOS, and web.
|
||||
version: 1.0.2
|
||||
# 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump
|
||||
# the version to 2.0.0.
|
||||
# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
|
||||
version: 2.0.0-nullsafety.3
|
||||
homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player
|
||||
|
||||
flutter:
|
||||
@ -16,15 +19,15 @@ flutter:
|
||||
default_package: video_player_web
|
||||
|
||||
dependencies:
|
||||
meta: ^1.0.5
|
||||
video_player_platform_interface: ^2.2.0
|
||||
meta: ^1.3.0-nullsafety.3
|
||||
video_player_platform_interface: ^3.0.0-nullsafety.3
|
||||
|
||||
# The design on https://flutter.dev/go/federated-plugins was to leave
|
||||
# this constraint as "any". We cannot do it right now as it fails pub publish
|
||||
# validation, so we set a ^ constraint.
|
||||
# TODO(amirh): Revisit this (either update this part in the design or the pub tool).
|
||||
# https://github.com/flutter/flutter/issues/46264
|
||||
video_player_web: ">=0.1.4 <2.0.0"
|
||||
video_player_web: ^2.0.0-nullsafety.1
|
||||
|
||||
flutter:
|
||||
sdk: flutter
|
||||
@ -32,9 +35,9 @@ dependencies:
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
pedantic: ^1.8.0
|
||||
pedantic: ^1.10.0-nullsafety.1
|
||||
pigeon: 0.1.7
|
||||
|
||||
environment:
|
||||
sdk: ">=2.8.0 <3.0.0"
|
||||
sdk: ">=2.12.0-0 <3.0.0"
|
||||
flutter: ">=1.12.13+hotfix.5"
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
@ -18,7 +16,7 @@ import 'package:video_player_platform_interface/video_player_platform_interface.
|
||||
|
||||
class FakeController extends ValueNotifier<VideoPlayerValue>
|
||||
implements VideoPlayerController {
|
||||
FakeController() : super(VideoPlayerValue(duration: null));
|
||||
FakeController() : super(VideoPlayerValue(duration: Duration.zero));
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
@ -26,7 +24,7 @@ class FakeController extends ValueNotifier<VideoPlayerValue>
|
||||
}
|
||||
|
||||
@override
|
||||
int textureId;
|
||||
int textureId = VideoPlayerController.kUninitializedTextureId;
|
||||
|
||||
@override
|
||||
String get dataSource => '';
|
||||
@ -35,7 +33,7 @@ class FakeController extends ValueNotifier<VideoPlayerValue>
|
||||
DataSourceType get dataSourceType => DataSourceType.file;
|
||||
|
||||
@override
|
||||
String get package => null;
|
||||
String get package => '';
|
||||
|
||||
@override
|
||||
Future<Duration> get position async => value.position;
|
||||
@ -62,13 +60,13 @@ class FakeController extends ValueNotifier<VideoPlayerValue>
|
||||
Future<void> setLooping(bool looping) async {}
|
||||
|
||||
@override
|
||||
VideoFormat get formatHint => null;
|
||||
VideoFormat? get formatHint => null;
|
||||
|
||||
@override
|
||||
Future<ClosedCaptionFile> get closedCaptionFile => _loadClosedCaption();
|
||||
|
||||
@override
|
||||
VideoPlayerOptions get videoPlayerOptions => null;
|
||||
VideoPlayerOptions? get videoPlayerOptions => null;
|
||||
}
|
||||
|
||||
Future<ClosedCaptionFile> _loadClosedCaption() async =>
|
||||
@ -80,11 +78,13 @@ class _FakeClosedCaptionFile extends ClosedCaptionFile {
|
||||
return <Caption>[
|
||||
Caption(
|
||||
text: 'one',
|
||||
number: 0,
|
||||
start: Duration(milliseconds: 100),
|
||||
end: Duration(milliseconds: 200),
|
||||
),
|
||||
Caption(
|
||||
text: 'two',
|
||||
number: 1,
|
||||
start: Duration(milliseconds: 300),
|
||||
end: Duration(milliseconds: 400),
|
||||
),
|
||||
@ -101,6 +101,7 @@ void main() {
|
||||
controller.textureId = 123;
|
||||
controller.value = controller.value.copyWith(
|
||||
duration: const Duration(milliseconds: 100),
|
||||
isInitialized: true,
|
||||
);
|
||||
|
||||
await tester.pump();
|
||||
@ -133,8 +134,8 @@ void main() {
|
||||
await tester.pumpWidget(MaterialApp(home: ClosedCaption(text: text)));
|
||||
|
||||
final Text textWidget = tester.widget<Text>(find.text(text));
|
||||
expect(textWidget.style.fontSize, 36.0);
|
||||
expect(textWidget.style.color, Colors.white);
|
||||
expect(textWidget.style!.fontSize, 36.0);
|
||||
expect(textWidget.style!.color, Colors.white);
|
||||
});
|
||||
|
||||
testWidgets('uses given text and style', (WidgetTester tester) async {
|
||||
@ -149,7 +150,7 @@ void main() {
|
||||
expect(find.text(text), findsOneWidget);
|
||||
|
||||
final Text textWidget = tester.widget<Text>(find.text(text));
|
||||
expect(textWidget.style.fontSize, textStyle.fontSize);
|
||||
expect(textWidget.style!.fontSize, textStyle.fontSize);
|
||||
});
|
||||
|
||||
testWidgets('handles null text', (WidgetTester tester) async {
|
||||
@ -173,7 +174,7 @@ void main() {
|
||||
});
|
||||
|
||||
group('VideoPlayerController', () {
|
||||
FakeVideoPlayerPlatform fakeVideoPlayerPlatform;
|
||||
late FakeVideoPlayerPlatform fakeVideoPlayerPlatform;
|
||||
|
||||
setUp(() {
|
||||
fakeVideoPlayerPlatform = FakeVideoPlayerPlatform();
|
||||
@ -221,7 +222,7 @@ void main() {
|
||||
'http://testing.com/invalid_url',
|
||||
);
|
||||
try {
|
||||
dynamic error;
|
||||
late dynamic error;
|
||||
fakeVideoPlayerPlatform.forceInitError = true;
|
||||
await controller.initialize().catchError((dynamic e) => error = e);
|
||||
final PlatformException platformEx = error;
|
||||
@ -245,13 +246,14 @@ void main() {
|
||||
final VideoPlayerController controller = VideoPlayerController.network(
|
||||
'https://127.0.0.1',
|
||||
);
|
||||
expect(controller.textureId, isNull);
|
||||
expect(
|
||||
controller.textureId, VideoPlayerController.kUninitializedTextureId);
|
||||
expect(await controller.position, const Duration(seconds: 0));
|
||||
await controller.initialize();
|
||||
|
||||
await controller.dispose();
|
||||
|
||||
expect(controller.textureId, isNotNull);
|
||||
expect(controller.textureId, 0);
|
||||
expect(await controller.position, isNull);
|
||||
});
|
||||
|
||||
@ -390,19 +392,19 @@ void main() {
|
||||
|
||||
await controller.initialize();
|
||||
expect(controller.value.position, const Duration());
|
||||
expect(controller.value.caption.text, isNull);
|
||||
expect(controller.value.caption.text, '');
|
||||
|
||||
await controller.seekTo(const Duration(milliseconds: 100));
|
||||
expect(controller.value.caption.text, 'one');
|
||||
|
||||
await controller.seekTo(const Duration(milliseconds: 250));
|
||||
expect(controller.value.caption.text, isNull);
|
||||
expect(controller.value.caption.text, '');
|
||||
|
||||
await controller.seekTo(const Duration(milliseconds: 300));
|
||||
expect(controller.value.caption.text, 'two');
|
||||
|
||||
await controller.seekTo(const Duration(milliseconds: 500));
|
||||
expect(controller.value.caption.text, isNull);
|
||||
expect(controller.value.caption.text, '');
|
||||
|
||||
await controller.seekTo(const Duration(milliseconds: 300));
|
||||
expect(controller.value.caption.text, 'two');
|
||||
@ -419,8 +421,7 @@ void main() {
|
||||
await controller.play();
|
||||
expect(controller.value.isPlaying, isTrue);
|
||||
final FakeVideoEventStream fakeVideoEventStream =
|
||||
fakeVideoPlayerPlatform.streams[controller.textureId];
|
||||
assert(fakeVideoEventStream != null);
|
||||
fakeVideoPlayerPlatform.streams[controller.textureId]!;
|
||||
|
||||
fakeVideoEventStream.eventsChannel
|
||||
.sendEvent(<String, dynamic>{'event': 'completed'});
|
||||
@ -438,8 +439,7 @@ void main() {
|
||||
expect(controller.value.isBuffering, false);
|
||||
expect(controller.value.buffered, isEmpty);
|
||||
final FakeVideoEventStream fakeVideoEventStream =
|
||||
fakeVideoPlayerPlatform.streams[controller.textureId];
|
||||
assert(fakeVideoEventStream != null);
|
||||
fakeVideoPlayerPlatform.streams[controller.textureId]!;
|
||||
|
||||
fakeVideoEventStream.eventsChannel
|
||||
.sendEvent(<String, dynamic>{'event': 'bufferingStart'});
|
||||
@ -496,9 +496,9 @@ void main() {
|
||||
test('uninitialized()', () {
|
||||
final VideoPlayerValue uninitialized = VideoPlayerValue.uninitialized();
|
||||
|
||||
expect(uninitialized.duration, isNull);
|
||||
expect(uninitialized.position, equals(const Duration(seconds: 0)));
|
||||
expect(uninitialized.caption, equals(const Caption()));
|
||||
expect(uninitialized.duration, equals(Duration.zero));
|
||||
expect(uninitialized.position, equals(Duration.zero));
|
||||
expect(uninitialized.caption, equals(Caption.none));
|
||||
expect(uninitialized.buffered, isEmpty);
|
||||
expect(uninitialized.isPlaying, isFalse);
|
||||
expect(uninitialized.isLooping, isFalse);
|
||||
@ -506,9 +506,8 @@ void main() {
|
||||
expect(uninitialized.volume, 1.0);
|
||||
expect(uninitialized.playbackSpeed, 1.0);
|
||||
expect(uninitialized.errorDescription, isNull);
|
||||
expect(uninitialized.size, isNull);
|
||||
expect(uninitialized.size, isNull);
|
||||
expect(uninitialized.initialized, isFalse);
|
||||
expect(uninitialized.size, equals(Size.zero));
|
||||
expect(uninitialized.isInitialized, isFalse);
|
||||
expect(uninitialized.hasError, isFalse);
|
||||
expect(uninitialized.aspectRatio, 1.0);
|
||||
});
|
||||
@ -517,9 +516,9 @@ void main() {
|
||||
const String errorMessage = 'foo';
|
||||
final VideoPlayerValue error = VideoPlayerValue.erroneous(errorMessage);
|
||||
|
||||
expect(error.duration, isNull);
|
||||
expect(error.position, equals(const Duration(seconds: 0)));
|
||||
expect(error.caption, equals(const Caption()));
|
||||
expect(error.duration, equals(Duration.zero));
|
||||
expect(error.position, equals(Duration.zero));
|
||||
expect(error.caption, equals(Caption.none));
|
||||
expect(error.buffered, isEmpty);
|
||||
expect(error.isPlaying, isFalse);
|
||||
expect(error.isLooping, isFalse);
|
||||
@ -527,9 +526,8 @@ void main() {
|
||||
expect(error.volume, 1.0);
|
||||
expect(error.playbackSpeed, 1.0);
|
||||
expect(error.errorDescription, errorMessage);
|
||||
expect(error.size, isNull);
|
||||
expect(error.size, isNull);
|
||||
expect(error.initialized, isFalse);
|
||||
expect(error.size, equals(Size.zero));
|
||||
expect(error.isInitialized, isFalse);
|
||||
expect(error.hasError, isTrue);
|
||||
expect(error.aspectRatio, 1.0);
|
||||
});
|
||||
@ -538,10 +536,12 @@ void main() {
|
||||
const Duration duration = Duration(seconds: 5);
|
||||
const Size size = Size(400, 300);
|
||||
const Duration position = Duration(seconds: 1);
|
||||
const Caption caption = Caption(text: 'foo');
|
||||
const Caption caption = Caption(
|
||||
text: 'foo', number: 0, start: Duration.zero, end: Duration.zero);
|
||||
final List<DurationRange> buffered = <DurationRange>[
|
||||
DurationRange(const Duration(seconds: 0), const Duration(seconds: 4))
|
||||
];
|
||||
const bool isInitialized = true;
|
||||
const bool isPlaying = true;
|
||||
const bool isLooping = true;
|
||||
const bool isBuffering = true;
|
||||
@ -554,6 +554,7 @@ void main() {
|
||||
position: position,
|
||||
caption: caption,
|
||||
buffered: buffered,
|
||||
isInitialized: isInitialized,
|
||||
isPlaying: isPlaying,
|
||||
isLooping: isLooping,
|
||||
isBuffering: isBuffering,
|
||||
@ -568,6 +569,7 @@ void main() {
|
||||
'position: 0:00:01.000000, '
|
||||
'caption: Caption(number: null, start: null, end: null, text: foo), '
|
||||
'buffered: [DurationRange(start: 0:00:00.000000, end: 0:00:04.000000)], '
|
||||
'isInitialized: true, '
|
||||
'isPlaying: true, '
|
||||
'isLooping: true, '
|
||||
'isBuffering: true, '
|
||||
@ -586,15 +588,16 @@ void main() {
|
||||
group('aspectRatio', () {
|
||||
test('640x480 -> 4:3', () {
|
||||
final value = VideoPlayerValue(
|
||||
isInitialized: true,
|
||||
size: Size(640, 480),
|
||||
duration: Duration(seconds: 1),
|
||||
);
|
||||
expect(value.aspectRatio, 4 / 3);
|
||||
});
|
||||
|
||||
test('null size -> 1.0', () {
|
||||
test('no size -> 1.0', () {
|
||||
final value = VideoPlayerValue(
|
||||
size: null,
|
||||
isInitialized: true,
|
||||
duration: Duration(seconds: 1),
|
||||
);
|
||||
expect(value.aspectRatio, 1.0);
|
||||
@ -602,6 +605,7 @@ void main() {
|
||||
|
||||
test('height = 0 -> 1.0', () {
|
||||
final value = VideoPlayerValue(
|
||||
isInitialized: true,
|
||||
size: Size(640, 0),
|
||||
duration: Duration(seconds: 1),
|
||||
);
|
||||
@ -610,6 +614,7 @@ void main() {
|
||||
|
||||
test('width = 0 -> 1.0', () {
|
||||
final value = VideoPlayerValue(
|
||||
isInitialized: true,
|
||||
size: Size(0, 480),
|
||||
duration: Duration(seconds: 1),
|
||||
);
|
||||
@ -618,6 +623,7 @@ void main() {
|
||||
|
||||
test('negative aspect ratio -> 1.0', () {
|
||||
final value = VideoPlayerValue(
|
||||
isInitialized: true,
|
||||
size: Size(640, -480),
|
||||
duration: Duration(seconds: 1),
|
||||
);
|
||||
@ -646,7 +652,7 @@ void main() {
|
||||
File(''),
|
||||
videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true));
|
||||
await controller.initialize();
|
||||
expect(controller.videoPlayerOptions.mixWithOthers, true);
|
||||
expect(controller.videoPlayerOptions!.mixWithOthers, true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -706,7 +712,7 @@ class FakeVideoPlayerPlatform extends TestHostVideoPlayerApi {
|
||||
@override
|
||||
void seekTo(PositionMessage arg) {
|
||||
calls.add('seekTo');
|
||||
_positions[arg.textureId] = Duration(milliseconds: arg.position);
|
||||
_positions[arg.textureId!] = Duration(milliseconds: arg.position!);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -742,7 +748,7 @@ class FakeVideoEventStream {
|
||||
int height;
|
||||
Duration duration;
|
||||
bool initWithError;
|
||||
FakeEventsChannel eventsChannel;
|
||||
late FakeEventsChannel eventsChannel;
|
||||
|
||||
void onListen() {
|
||||
if (!initWithError) {
|
||||
@ -764,7 +770,7 @@ class FakeEventsChannel {
|
||||
eventsMethodChannel.setMockMethodCallHandler(onMethodCall);
|
||||
}
|
||||
|
||||
MethodChannel eventsMethodChannel;
|
||||
late MethodChannel eventsMethodChannel;
|
||||
VoidCallback onListen;
|
||||
|
||||
Future<dynamic> onMethodCall(MethodCall call) {
|
||||
@ -780,7 +786,7 @@ class FakeEventsChannel {
|
||||
_sendMessage(const StandardMethodCodec().encodeSuccessEnvelope(event));
|
||||
}
|
||||
|
||||
void sendError(String code, [String message, dynamic details]) {
|
||||
void sendError(String code, [String? message, dynamic details]) {
|
||||
_sendMessage(const StandardMethodCodec().encodeErrorEnvelope(
|
||||
code: code,
|
||||
message: message,
|
||||
@ -794,6 +800,6 @@ class FakeEventsChannel {
|
||||
// available on all the versions of Flutter that we test.
|
||||
// ignore: deprecated_member_use
|
||||
defaultBinaryMessenger.handlePlatformMessage(
|
||||
eventsMethodChannel.name, data, (ByteData data) {});
|
||||
eventsMethodChannel.name, data, (ByteData? data) {});
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,19 @@
|
||||
## 3.0.0-nullsafety.3
|
||||
|
||||
* `messages.dart` sets Dart `2.12`.
|
||||
|
||||
## 3.0.0-nullsafety.2
|
||||
|
||||
* Bump Dart SDK to support null safety.
|
||||
|
||||
## 3.0.0-nullsafety.1
|
||||
|
||||
* Make DataSource's `uri` parameter nullable.
|
||||
|
||||
## 3.0.0-nullsafety
|
||||
|
||||
* Migrate to null safety.
|
||||
|
||||
## 2.2.1
|
||||
|
||||
* Update Flutter SDK constraint.
|
||||
|
@ -0,0 +1,4 @@
|
||||
include: ../../../analysis_options.yaml
|
||||
analyzer:
|
||||
enable-experiment:
|
||||
- non-nullable
|
@ -1,13 +1,13 @@
|
||||
// Autogenerated from Pigeon (v0.1.7), do not edit directly.
|
||||
// Autogenerated from Pigeon (v0.1.12), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import
|
||||
// @dart = 2.8
|
||||
// @dart = 2.12
|
||||
import 'dart:async';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;
|
||||
|
||||
class TextureMessage {
|
||||
int textureId;
|
||||
int? textureId;
|
||||
// ignore: unused_element
|
||||
Map<dynamic, dynamic> _toMap() {
|
||||
final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
|
||||
@ -17,9 +17,6 @@ class TextureMessage {
|
||||
|
||||
// ignore: unused_element
|
||||
static TextureMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
|
||||
if (pigeonMap == null) {
|
||||
return null;
|
||||
}
|
||||
final TextureMessage result = TextureMessage();
|
||||
result.textureId = pigeonMap['textureId'];
|
||||
return result;
|
||||
@ -27,10 +24,10 @@ class TextureMessage {
|
||||
}
|
||||
|
||||
class CreateMessage {
|
||||
String asset;
|
||||
String uri;
|
||||
String packageName;
|
||||
String formatHint;
|
||||
String? asset;
|
||||
String? uri;
|
||||
String? packageName;
|
||||
String? formatHint;
|
||||
// ignore: unused_element
|
||||
Map<dynamic, dynamic> _toMap() {
|
||||
final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
|
||||
@ -43,9 +40,6 @@ class CreateMessage {
|
||||
|
||||
// ignore: unused_element
|
||||
static CreateMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
|
||||
if (pigeonMap == null) {
|
||||
return null;
|
||||
}
|
||||
final CreateMessage result = CreateMessage();
|
||||
result.asset = pigeonMap['asset'];
|
||||
result.uri = pigeonMap['uri'];
|
||||
@ -56,8 +50,8 @@ class CreateMessage {
|
||||
}
|
||||
|
||||
class LoopingMessage {
|
||||
int textureId;
|
||||
bool isLooping;
|
||||
int? textureId;
|
||||
bool? isLooping;
|
||||
// ignore: unused_element
|
||||
Map<dynamic, dynamic> _toMap() {
|
||||
final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
|
||||
@ -68,9 +62,6 @@ class LoopingMessage {
|
||||
|
||||
// ignore: unused_element
|
||||
static LoopingMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
|
||||
if (pigeonMap == null) {
|
||||
return null;
|
||||
}
|
||||
final LoopingMessage result = LoopingMessage();
|
||||
result.textureId = pigeonMap['textureId'];
|
||||
result.isLooping = pigeonMap['isLooping'];
|
||||
@ -79,8 +70,8 @@ class LoopingMessage {
|
||||
}
|
||||
|
||||
class VolumeMessage {
|
||||
int textureId;
|
||||
double volume;
|
||||
int? textureId;
|
||||
double? volume;
|
||||
// ignore: unused_element
|
||||
Map<dynamic, dynamic> _toMap() {
|
||||
final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
|
||||
@ -91,9 +82,6 @@ class VolumeMessage {
|
||||
|
||||
// ignore: unused_element
|
||||
static VolumeMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
|
||||
if (pigeonMap == null) {
|
||||
return null;
|
||||
}
|
||||
final VolumeMessage result = VolumeMessage();
|
||||
result.textureId = pigeonMap['textureId'];
|
||||
result.volume = pigeonMap['volume'];
|
||||
@ -102,8 +90,8 @@ class VolumeMessage {
|
||||
}
|
||||
|
||||
class PlaybackSpeedMessage {
|
||||
int textureId;
|
||||
double speed;
|
||||
int? textureId;
|
||||
double? speed;
|
||||
// ignore: unused_element
|
||||
Map<dynamic, dynamic> _toMap() {
|
||||
final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
|
||||
@ -114,9 +102,6 @@ class PlaybackSpeedMessage {
|
||||
|
||||
// ignore: unused_element
|
||||
static PlaybackSpeedMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
|
||||
if (pigeonMap == null) {
|
||||
return null;
|
||||
}
|
||||
final PlaybackSpeedMessage result = PlaybackSpeedMessage();
|
||||
result.textureId = pigeonMap['textureId'];
|
||||
result.speed = pigeonMap['speed'];
|
||||
@ -125,8 +110,8 @@ class PlaybackSpeedMessage {
|
||||
}
|
||||
|
||||
class PositionMessage {
|
||||
int textureId;
|
||||
int position;
|
||||
int? textureId;
|
||||
int? position;
|
||||
// ignore: unused_element
|
||||
Map<dynamic, dynamic> _toMap() {
|
||||
final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
|
||||
@ -137,9 +122,6 @@ class PositionMessage {
|
||||
|
||||
// ignore: unused_element
|
||||
static PositionMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
|
||||
if (pigeonMap == null) {
|
||||
return null;
|
||||
}
|
||||
final PositionMessage result = PositionMessage();
|
||||
result.textureId = pigeonMap['textureId'];
|
||||
result.position = pigeonMap['position'];
|
||||
@ -148,7 +130,7 @@ class PositionMessage {
|
||||
}
|
||||
|
||||
class MixWithOthersMessage {
|
||||
bool mixWithOthers;
|
||||
bool? mixWithOthers;
|
||||
// ignore: unused_element
|
||||
Map<dynamic, dynamic> _toMap() {
|
||||
final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
|
||||
@ -158,9 +140,6 @@ class MixWithOthersMessage {
|
||||
|
||||
// ignore: unused_element
|
||||
static MixWithOthersMessage _fromMap(Map<dynamic, dynamic> pigeonMap) {
|
||||
if (pigeonMap == null) {
|
||||
return null;
|
||||
}
|
||||
final MixWithOthersMessage result = MixWithOthersMessage();
|
||||
result.mixWithOthers = pigeonMap['mixWithOthers'];
|
||||
return result;
|
||||
@ -172,7 +151,7 @@ class VideoPlayerApi {
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.initialize', StandardMessageCodec());
|
||||
|
||||
final Map<dynamic, dynamic> replyMap = await channel.send(null);
|
||||
final Map<dynamic, dynamic>? replyMap = await channel.send(null);
|
||||
if (replyMap == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -194,7 +173,7 @@ class VideoPlayerApi {
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec());
|
||||
|
||||
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
|
||||
final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
|
||||
if (replyMap == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -216,7 +195,7 @@ class VideoPlayerApi {
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec());
|
||||
|
||||
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
|
||||
final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
|
||||
if (replyMap == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -238,7 +217,7 @@ class VideoPlayerApi {
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.setLooping', StandardMessageCodec());
|
||||
|
||||
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
|
||||
final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
|
||||
if (replyMap == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -260,7 +239,7 @@ class VideoPlayerApi {
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.setVolume', StandardMessageCodec());
|
||||
|
||||
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
|
||||
final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
|
||||
if (replyMap == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -283,7 +262,7 @@ class VideoPlayerApi {
|
||||
'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed',
|
||||
StandardMessageCodec());
|
||||
|
||||
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
|
||||
final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
|
||||
if (replyMap == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -305,7 +284,7 @@ class VideoPlayerApi {
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec());
|
||||
|
||||
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
|
||||
final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
|
||||
if (replyMap == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -327,7 +306,7 @@ class VideoPlayerApi {
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec());
|
||||
|
||||
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
|
||||
final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
|
||||
if (replyMap == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -349,7 +328,7 @@ class VideoPlayerApi {
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec());
|
||||
|
||||
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
|
||||
final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
|
||||
if (replyMap == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -371,7 +350,7 @@ class VideoPlayerApi {
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec());
|
||||
|
||||
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
|
||||
final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
|
||||
if (replyMap == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -394,7 +373,7 @@ class VideoPlayerApi {
|
||||
'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers',
|
||||
StandardMessageCodec());
|
||||
|
||||
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
|
||||
final Map<dynamic, dynamic>? replyMap = await channel.send(requestMap);
|
||||
if (replyMap == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -424,19 +403,26 @@ abstract class TestHostVideoPlayerApi {
|
||||
void seekTo(PositionMessage arg);
|
||||
void pause(TextureMessage arg);
|
||||
void setMixWithOthers(MixWithOthersMessage arg);
|
||||
static void setup(TestHostVideoPlayerApi api) {
|
||||
static void setup(TestHostVideoPlayerApi? api) {
|
||||
{
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.initialize',
|
||||
StandardMessageCodec());
|
||||
if (api == null) {
|
||||
channel.setMockMessageHandler(null);
|
||||
} else {
|
||||
channel.setMockMessageHandler((dynamic message) async {
|
||||
api.initialize();
|
||||
return <dynamic, dynamic>{};
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec());
|
||||
if (api == null) {
|
||||
channel.setMockMessageHandler(null);
|
||||
} else {
|
||||
channel.setMockMessageHandler((dynamic message) async {
|
||||
final Map<dynamic, dynamic> mapMessage =
|
||||
message as Map<dynamic, dynamic>;
|
||||
@ -445,9 +431,13 @@ abstract class TestHostVideoPlayerApi {
|
||||
return <dynamic, dynamic>{'result': output._toMap()};
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec());
|
||||
if (api == null) {
|
||||
channel.setMockMessageHandler(null);
|
||||
} else {
|
||||
channel.setMockMessageHandler((dynamic message) async {
|
||||
final Map<dynamic, dynamic> mapMessage =
|
||||
message as Map<dynamic, dynamic>;
|
||||
@ -456,10 +446,14 @@ abstract class TestHostVideoPlayerApi {
|
||||
return <dynamic, dynamic>{};
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.setLooping',
|
||||
StandardMessageCodec());
|
||||
if (api == null) {
|
||||
channel.setMockMessageHandler(null);
|
||||
} else {
|
||||
channel.setMockMessageHandler((dynamic message) async {
|
||||
final Map<dynamic, dynamic> mapMessage =
|
||||
message as Map<dynamic, dynamic>;
|
||||
@ -468,10 +462,14 @@ abstract class TestHostVideoPlayerApi {
|
||||
return <dynamic, dynamic>{};
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.setVolume',
|
||||
StandardMessageCodec());
|
||||
if (api == null) {
|
||||
channel.setMockMessageHandler(null);
|
||||
} else {
|
||||
channel.setMockMessageHandler((dynamic message) async {
|
||||
final Map<dynamic, dynamic> mapMessage =
|
||||
message as Map<dynamic, dynamic>;
|
||||
@ -480,10 +478,14 @@ abstract class TestHostVideoPlayerApi {
|
||||
return <dynamic, dynamic>{};
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed',
|
||||
StandardMessageCodec());
|
||||
if (api == null) {
|
||||
channel.setMockMessageHandler(null);
|
||||
} else {
|
||||
channel.setMockMessageHandler((dynamic message) async {
|
||||
final Map<dynamic, dynamic> mapMessage =
|
||||
message as Map<dynamic, dynamic>;
|
||||
@ -493,9 +495,13 @@ abstract class TestHostVideoPlayerApi {
|
||||
return <dynamic, dynamic>{};
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec());
|
||||
if (api == null) {
|
||||
channel.setMockMessageHandler(null);
|
||||
} else {
|
||||
channel.setMockMessageHandler((dynamic message) async {
|
||||
final Map<dynamic, dynamic> mapMessage =
|
||||
message as Map<dynamic, dynamic>;
|
||||
@ -504,9 +510,13 @@ abstract class TestHostVideoPlayerApi {
|
||||
return <dynamic, dynamic>{};
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec());
|
||||
if (api == null) {
|
||||
channel.setMockMessageHandler(null);
|
||||
} else {
|
||||
channel.setMockMessageHandler((dynamic message) async {
|
||||
final Map<dynamic, dynamic> mapMessage =
|
||||
message as Map<dynamic, dynamic>;
|
||||
@ -515,9 +525,13 @@ abstract class TestHostVideoPlayerApi {
|
||||
return <dynamic, dynamic>{'result': output._toMap()};
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec());
|
||||
if (api == null) {
|
||||
channel.setMockMessageHandler(null);
|
||||
} else {
|
||||
channel.setMockMessageHandler((dynamic message) async {
|
||||
final Map<dynamic, dynamic> mapMessage =
|
||||
message as Map<dynamic, dynamic>;
|
||||
@ -526,9 +540,13 @@ abstract class TestHostVideoPlayerApi {
|
||||
return <dynamic, dynamic>{};
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec());
|
||||
if (api == null) {
|
||||
channel.setMockMessageHandler(null);
|
||||
} else {
|
||||
channel.setMockMessageHandler((dynamic message) async {
|
||||
final Map<dynamic, dynamic> mapMessage =
|
||||
message as Map<dynamic, dynamic>;
|
||||
@ -537,10 +555,14 @@ abstract class TestHostVideoPlayerApi {
|
||||
return <dynamic, dynamic>{};
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
|
||||
'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers',
|
||||
StandardMessageCodec());
|
||||
if (api == null) {
|
||||
channel.setMockMessageHandler(null);
|
||||
} else {
|
||||
channel.setMockMessageHandler((dynamic message) async {
|
||||
final Map<dynamic, dynamic> mapMessage =
|
||||
message as Map<dynamic, dynamic>;
|
||||
@ -551,4 +573,5 @@ abstract class TestHostVideoPlayerApi {
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user