diff --git a/airhub_app/lib/features/device/domain/entities/device.dart b/airhub_app/lib/features/device/domain/entities/device.dart index 6ef7e40..fac6279 100644 --- a/airhub_app/lib/features/device/domain/entities/device.dart +++ b/airhub_app/lib/features/device/domain/entities/device.dart @@ -29,6 +29,7 @@ abstract class DeviceInfo with _$DeviceInfo { String? macAddress, @Default('') String name, @Default('in_stock') String status, + @Default(false) bool isOnline, @Default('') String firmwareVersion, String? lastOnlineAt, String? createdAt, diff --git a/airhub_app/lib/features/device/domain/entities/device.freezed.dart b/airhub_app/lib/features/device/domain/entities/device.freezed.dart index a40b797..63b6df9 100644 --- a/airhub_app/lib/features/device/domain/entities/device.freezed.dart +++ b/airhub_app/lib/features/device/domain/entities/device.freezed.dart @@ -296,7 +296,7 @@ as String?, /// @nodoc mixin _$DeviceInfo { - int get id; String get sn; DeviceType? get deviceType; DeviceType? get deviceTypeInfo; String? get macAddress; String get name; String get status; String get firmwareVersion; String? get lastOnlineAt; String? get createdAt; + int get id; String get sn; DeviceType? get deviceType; DeviceType? get deviceTypeInfo; String? get macAddress; String get name; String get status; bool get isOnline; String get firmwareVersion; String? get lastOnlineAt; String? get createdAt; /// Create a copy of DeviceInfo /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -309,16 +309,16 @@ $DeviceInfoCopyWith get copyWith => _$DeviceInfoCopyWithImpl Object.hash(runtimeType,id,sn,deviceType,deviceTypeInfo,macAddress,name,status,firmwareVersion,lastOnlineAt,createdAt); +int get hashCode => Object.hash(runtimeType,id,sn,deviceType,deviceTypeInfo,macAddress,name,status,isOnline,firmwareVersion,lastOnlineAt,createdAt); @override String toString() { - return 'DeviceInfo(id: $id, sn: $sn, deviceType: $deviceType, deviceTypeInfo: $deviceTypeInfo, macAddress: $macAddress, name: $name, status: $status, firmwareVersion: $firmwareVersion, lastOnlineAt: $lastOnlineAt, createdAt: $createdAt)'; + return 'DeviceInfo(id: $id, sn: $sn, deviceType: $deviceType, deviceTypeInfo: $deviceTypeInfo, macAddress: $macAddress, name: $name, status: $status, isOnline: $isOnline, firmwareVersion: $firmwareVersion, lastOnlineAt: $lastOnlineAt, createdAt: $createdAt)'; } @@ -329,7 +329,7 @@ abstract mixin class $DeviceInfoCopyWith<$Res> { factory $DeviceInfoCopyWith(DeviceInfo value, $Res Function(DeviceInfo) _then) = _$DeviceInfoCopyWithImpl; @useResult $Res call({ - int id, String sn, DeviceType? deviceType, DeviceType? deviceTypeInfo, String? macAddress, String name, String status, String firmwareVersion, String? lastOnlineAt, String? createdAt + int id, String sn, DeviceType? deviceType, DeviceType? deviceTypeInfo, String? macAddress, String name, String status, bool isOnline, String firmwareVersion, String? lastOnlineAt, String? createdAt }); @@ -346,7 +346,7 @@ class _$DeviceInfoCopyWithImpl<$Res> /// Create a copy of DeviceInfo /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? sn = null,Object? deviceType = freezed,Object? deviceTypeInfo = freezed,Object? macAddress = freezed,Object? name = null,Object? status = null,Object? firmwareVersion = null,Object? lastOnlineAt = freezed,Object? createdAt = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? sn = null,Object? deviceType = freezed,Object? deviceTypeInfo = freezed,Object? macAddress = freezed,Object? name = null,Object? status = null,Object? isOnline = null,Object? firmwareVersion = null,Object? lastOnlineAt = freezed,Object? createdAt = freezed,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as int,sn: null == sn ? _self.sn : sn // ignore: cast_nullable_to_non_nullable @@ -355,7 +355,8 @@ as DeviceType?,deviceTypeInfo: freezed == deviceTypeInfo ? _self.deviceTypeInfo as DeviceType?,macAddress: freezed == macAddress ? _self.macAddress : macAddress // ignore: cast_nullable_to_non_nullable as String?,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable as String,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable -as String,firmwareVersion: null == firmwareVersion ? _self.firmwareVersion : firmwareVersion // ignore: cast_nullable_to_non_nullable +as String,isOnline: null == isOnline ? _self.isOnline : isOnline // ignore: cast_nullable_to_non_nullable +as bool,firmwareVersion: null == firmwareVersion ? _self.firmwareVersion : firmwareVersion // ignore: cast_nullable_to_non_nullable as String,lastOnlineAt: freezed == lastOnlineAt ? _self.lastOnlineAt : lastOnlineAt // ignore: cast_nullable_to_non_nullable as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as String?, @@ -467,10 +468,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( int id, String sn, DeviceType? deviceType, DeviceType? deviceTypeInfo, String? macAddress, String name, String status, String firmwareVersion, String? lastOnlineAt, String? createdAt)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( int id, String sn, DeviceType? deviceType, DeviceType? deviceTypeInfo, String? macAddress, String name, String status, bool isOnline, String firmwareVersion, String? lastOnlineAt, String? createdAt)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _DeviceInfo() when $default != null: -return $default(_that.id,_that.sn,_that.deviceType,_that.deviceTypeInfo,_that.macAddress,_that.name,_that.status,_that.firmwareVersion,_that.lastOnlineAt,_that.createdAt);case _: +return $default(_that.id,_that.sn,_that.deviceType,_that.deviceTypeInfo,_that.macAddress,_that.name,_that.status,_that.isOnline,_that.firmwareVersion,_that.lastOnlineAt,_that.createdAt);case _: return orElse(); } @@ -488,10 +489,10 @@ return $default(_that.id,_that.sn,_that.deviceType,_that.deviceTypeInfo,_that.ma /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( int id, String sn, DeviceType? deviceType, DeviceType? deviceTypeInfo, String? macAddress, String name, String status, String firmwareVersion, String? lastOnlineAt, String? createdAt) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( int id, String sn, DeviceType? deviceType, DeviceType? deviceTypeInfo, String? macAddress, String name, String status, bool isOnline, String firmwareVersion, String? lastOnlineAt, String? createdAt) $default,) {final _that = this; switch (_that) { case _DeviceInfo(): -return $default(_that.id,_that.sn,_that.deviceType,_that.deviceTypeInfo,_that.macAddress,_that.name,_that.status,_that.firmwareVersion,_that.lastOnlineAt,_that.createdAt);case _: +return $default(_that.id,_that.sn,_that.deviceType,_that.deviceTypeInfo,_that.macAddress,_that.name,_that.status,_that.isOnline,_that.firmwareVersion,_that.lastOnlineAt,_that.createdAt);case _: throw StateError('Unexpected subclass'); } @@ -508,10 +509,10 @@ return $default(_that.id,_that.sn,_that.deviceType,_that.deviceTypeInfo,_that.ma /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( int id, String sn, DeviceType? deviceType, DeviceType? deviceTypeInfo, String? macAddress, String name, String status, String firmwareVersion, String? lastOnlineAt, String? createdAt)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( int id, String sn, DeviceType? deviceType, DeviceType? deviceTypeInfo, String? macAddress, String name, String status, bool isOnline, String firmwareVersion, String? lastOnlineAt, String? createdAt)? $default,) {final _that = this; switch (_that) { case _DeviceInfo() when $default != null: -return $default(_that.id,_that.sn,_that.deviceType,_that.deviceTypeInfo,_that.macAddress,_that.name,_that.status,_that.firmwareVersion,_that.lastOnlineAt,_that.createdAt);case _: +return $default(_that.id,_that.sn,_that.deviceType,_that.deviceTypeInfo,_that.macAddress,_that.name,_that.status,_that.isOnline,_that.firmwareVersion,_that.lastOnlineAt,_that.createdAt);case _: return null; } @@ -523,7 +524,7 @@ return $default(_that.id,_that.sn,_that.deviceType,_that.deviceTypeInfo,_that.ma @JsonSerializable() class _DeviceInfo implements DeviceInfo { - const _DeviceInfo({required this.id, required this.sn, this.deviceType, this.deviceTypeInfo, this.macAddress, this.name = '', this.status = 'in_stock', this.firmwareVersion = '', this.lastOnlineAt, this.createdAt}); + const _DeviceInfo({required this.id, required this.sn, this.deviceType, this.deviceTypeInfo, this.macAddress, this.name = '', this.status = 'in_stock', this.isOnline = false, this.firmwareVersion = '', this.lastOnlineAt, this.createdAt}); factory _DeviceInfo.fromJson(Map json) => _$DeviceInfoFromJson(json); @override final int id; @@ -533,6 +534,7 @@ class _DeviceInfo implements DeviceInfo { @override final String? macAddress; @override@JsonKey() final String name; @override@JsonKey() final String status; +@override@JsonKey() final bool isOnline; @override@JsonKey() final String firmwareVersion; @override final String? lastOnlineAt; @override final String? createdAt; @@ -550,16 +552,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _DeviceInfo&&(identical(other.id, id) || other.id == id)&&(identical(other.sn, sn) || other.sn == sn)&&(identical(other.deviceType, deviceType) || other.deviceType == deviceType)&&(identical(other.deviceTypeInfo, deviceTypeInfo) || other.deviceTypeInfo == deviceTypeInfo)&&(identical(other.macAddress, macAddress) || other.macAddress == macAddress)&&(identical(other.name, name) || other.name == name)&&(identical(other.status, status) || other.status == status)&&(identical(other.firmwareVersion, firmwareVersion) || other.firmwareVersion == firmwareVersion)&&(identical(other.lastOnlineAt, lastOnlineAt) || other.lastOnlineAt == lastOnlineAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _DeviceInfo&&(identical(other.id, id) || other.id == id)&&(identical(other.sn, sn) || other.sn == sn)&&(identical(other.deviceType, deviceType) || other.deviceType == deviceType)&&(identical(other.deviceTypeInfo, deviceTypeInfo) || other.deviceTypeInfo == deviceTypeInfo)&&(identical(other.macAddress, macAddress) || other.macAddress == macAddress)&&(identical(other.name, name) || other.name == name)&&(identical(other.status, status) || other.status == status)&&(identical(other.isOnline, isOnline) || other.isOnline == isOnline)&&(identical(other.firmwareVersion, firmwareVersion) || other.firmwareVersion == firmwareVersion)&&(identical(other.lastOnlineAt, lastOnlineAt) || other.lastOnlineAt == lastOnlineAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,sn,deviceType,deviceTypeInfo,macAddress,name,status,firmwareVersion,lastOnlineAt,createdAt); +int get hashCode => Object.hash(runtimeType,id,sn,deviceType,deviceTypeInfo,macAddress,name,status,isOnline,firmwareVersion,lastOnlineAt,createdAt); @override String toString() { - return 'DeviceInfo(id: $id, sn: $sn, deviceType: $deviceType, deviceTypeInfo: $deviceTypeInfo, macAddress: $macAddress, name: $name, status: $status, firmwareVersion: $firmwareVersion, lastOnlineAt: $lastOnlineAt, createdAt: $createdAt)'; + return 'DeviceInfo(id: $id, sn: $sn, deviceType: $deviceType, deviceTypeInfo: $deviceTypeInfo, macAddress: $macAddress, name: $name, status: $status, isOnline: $isOnline, firmwareVersion: $firmwareVersion, lastOnlineAt: $lastOnlineAt, createdAt: $createdAt)'; } @@ -570,7 +572,7 @@ abstract mixin class _$DeviceInfoCopyWith<$Res> implements $DeviceInfoCopyWith<$ factory _$DeviceInfoCopyWith(_DeviceInfo value, $Res Function(_DeviceInfo) _then) = __$DeviceInfoCopyWithImpl; @override @useResult $Res call({ - int id, String sn, DeviceType? deviceType, DeviceType? deviceTypeInfo, String? macAddress, String name, String status, String firmwareVersion, String? lastOnlineAt, String? createdAt + int id, String sn, DeviceType? deviceType, DeviceType? deviceTypeInfo, String? macAddress, String name, String status, bool isOnline, String firmwareVersion, String? lastOnlineAt, String? createdAt }); @@ -587,7 +589,7 @@ class __$DeviceInfoCopyWithImpl<$Res> /// Create a copy of DeviceInfo /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? sn = null,Object? deviceType = freezed,Object? deviceTypeInfo = freezed,Object? macAddress = freezed,Object? name = null,Object? status = null,Object? firmwareVersion = null,Object? lastOnlineAt = freezed,Object? createdAt = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? sn = null,Object? deviceType = freezed,Object? deviceTypeInfo = freezed,Object? macAddress = freezed,Object? name = null,Object? status = null,Object? isOnline = null,Object? firmwareVersion = null,Object? lastOnlineAt = freezed,Object? createdAt = freezed,}) { return _then(_DeviceInfo( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as int,sn: null == sn ? _self.sn : sn // ignore: cast_nullable_to_non_nullable @@ -596,7 +598,8 @@ as DeviceType?,deviceTypeInfo: freezed == deviceTypeInfo ? _self.deviceTypeInfo as DeviceType?,macAddress: freezed == macAddress ? _self.macAddress : macAddress // ignore: cast_nullable_to_non_nullable as String?,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable as String,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable -as String,firmwareVersion: null == firmwareVersion ? _self.firmwareVersion : firmwareVersion // ignore: cast_nullable_to_non_nullable +as String,isOnline: null == isOnline ? _self.isOnline : isOnline // ignore: cast_nullable_to_non_nullable +as bool,firmwareVersion: null == firmwareVersion ? _self.firmwareVersion : firmwareVersion // ignore: cast_nullable_to_non_nullable as String,lastOnlineAt: freezed == lastOnlineAt ? _self.lastOnlineAt : lastOnlineAt // ignore: cast_nullable_to_non_nullable as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as String?, diff --git a/airhub_app/lib/features/device/domain/entities/device.g.dart b/airhub_app/lib/features/device/domain/entities/device.g.dart index 733476b..9e87185 100644 --- a/airhub_app/lib/features/device/domain/entities/device.g.dart +++ b/airhub_app/lib/features/device/domain/entities/device.g.dart @@ -39,6 +39,7 @@ _DeviceInfo _$DeviceInfoFromJson(Map json) => _DeviceInfo( macAddress: json['mac_address'] as String?, name: json['name'] as String? ?? '', status: json['status'] as String? ?? 'in_stock', + isOnline: json['is_online'] as bool? ?? false, firmwareVersion: json['firmware_version'] as String? ?? '', lastOnlineAt: json['last_online_at'] as String?, createdAt: json['created_at'] as String?, @@ -53,6 +54,7 @@ Map _$DeviceInfoToJson(_DeviceInfo instance) => 'mac_address': instance.macAddress, 'name': instance.name, 'status': instance.status, + 'is_online': instance.isOnline, 'firmware_version': instance.firmwareVersion, 'last_online_at': instance.lastOnlineAt, 'created_at': instance.createdAt, diff --git a/airhub_app/lib/pages/story_detail_page.dart b/airhub_app/lib/pages/story_detail_page.dart index cd88c9f..dc73c53 100644 --- a/airhub_app/lib/pages/story_detail_page.dart +++ b/airhub_app/lib/pages/story_detail_page.dart @@ -4,6 +4,7 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/services.dart' show PlatformException; import 'package:just_audio/just_audio.dart'; +import 'package:video_player/video_player.dart'; import '../theme/design_tokens.dart'; import '../widgets/gradient_button.dart'; import '../widgets/pill_progress_button.dart'; @@ -34,6 +35,10 @@ class _StoryDetailPageState extends State bool _hasGeneratedVideo = false; bool _isLoadingVideo = false; + // Video Player + VideoPlayerController? _videoController; + bool _videoInitialized = false; + // TTS — uses global TTSService singleton final TTSService _ttsService = TTSService.instance; final AudioPlayer _audioPlayer = AudioPlayer(); @@ -108,6 +113,15 @@ class _StoryDetailPageState extends State debugPrint('durationStream error (ignored): $e'); }); + // Auto-show video tab if story already has a video + final hasVideo = _currentStory['has_video'] == true; + final videoUrl = _currentStory['video_url'] as String? ?? ''; + if (hasVideo && videoUrl.isNotEmpty) { + _hasGeneratedVideo = true; + _activeTab = 'video'; + _initVideoPlayer(videoUrl); + } + // Check if audio already exists debugPrint('[StoryDetail] story keys: ${_currentStory.keys.toList()}'); debugPrint('[StoryDetail] audio_url value: "${_currentStory['audio_url']}"'); @@ -151,12 +165,33 @@ class _StoryDetailPageState extends State setState(() {}); } + Future _initVideoPlayer(String url) async { + try { + final controller = VideoPlayerController.networkUrl(Uri.parse(url)); + _videoController = controller; + controller.addListener(_onVideoChanged); + await controller.initialize(); + if (mounted) { + setState(() => _videoInitialized = true); + } + } catch (e) { + debugPrint('Video init error: $e'); + } + } + + void _onVideoChanged() { + if (!mounted) return; + setState(() {}); + } + @override void dispose() { _ttsService.removeListener(_onTTSChanged); _positionSub?.cancel(); _playerStateSub?.cancel(); _audioPlayer.dispose(); + _videoController?.removeListener(_onVideoChanged); + _videoController?.dispose(); _genieController?.dispose(); super.dispose(); } @@ -171,7 +206,8 @@ class _StoryDetailPageState extends State if (_ttsService.error != null && !_ttsService.isGenerating && - _ttsService.audioUrl == null) { + _ttsService.audioUrl == null && + _ttsService.errorTitle == title) { return TTSButtonState.error; } if (_ttsService.isGeneratingFor(title)) { @@ -518,28 +554,58 @@ class _StoryDetailPageState extends State ); } - return Stack( - alignment: Alignment.center, - children: [ - AspectRatio( - aspectRatio: 16 / 9, - child: Container( - color: Colors.black, - child: const Center( - child: Icon(Icons.videocam, color: Colors.white54, size: 48), + // Not yet initialized — black + spinner while video loads + if (!_videoInitialized || _videoController == null) { + return const AspectRatio( + aspectRatio: 16 / 9, + child: ColoredBox( + color: Colors.black, + child: Center( + child: CircularProgressIndicator(color: Colors.white54, strokeWidth: 3), + ), + ), + ); + } + + // Initialized: VideoPlayer shows frame 0 naturally as thumbnail when paused + final isPlaying = _videoController!.value.isPlaying; + + return AspectRatio( + aspectRatio: _videoController!.value.aspectRatio, + child: Stack( + alignment: Alignment.center, + children: [ + // Video fills the area (Positioned.fill avoids StackFit.expand distortion) + Positioned.fill(child: VideoPlayer(_videoController!)), + // Full-area tap handler + Positioned.fill( + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () async { + if (_videoController!.value.isPlaying) { + await _videoController!.pause(); + } else { + await _videoController!.play(); + } + if (mounted) setState(() {}); + }, ), ), - ), - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.8), - shape: BoxShape.circle, - ), - child: const Icon(Icons.play_arrow, color: Colors.black), - ), - ], + // Play button — IgnorePointer lets taps pass through to GestureDetector below + if (!isPlaying) + IgnorePointer( + child: Container( + width: 48, + height: 48, + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.8), + shape: BoxShape.circle, + ), + child: const Icon(Icons.play_arrow, color: Colors.black), + ), + ), + ], + ), ); } diff --git a/airhub_app/lib/services/tts_service.dart b/airhub_app/lib/services/tts_service.dart index 97e1650..830896f 100644 --- a/airhub_app/lib/services/tts_service.dart +++ b/airhub_app/lib/services/tts_service.dart @@ -29,6 +29,7 @@ class TTSService extends ChangeNotifier { // ── Error ── String? _error; + String? _errorTitle; // Which story the error belongs to // ── Getters ── bool get isGenerating => _isGenerating; @@ -39,6 +40,7 @@ class TTSService extends ChangeNotifier { String? get completedStoryTitle => _completedStoryTitle; bool get justCompleted => _justCompleted; String? get error => _error; + String? get errorTitle => _errorTitle; /// Check if audio is ready for a specific story. bool hasAudioFor(String title) { @@ -182,6 +184,7 @@ class TTSService extends ChangeNotifier { _isGenerating = false; if (_audioUrl == null) { _error = '未获取到音频'; + _errorTitle = title; _statusMessage = '生成失败'; } notifyListeners(); @@ -190,6 +193,7 @@ class TTSService extends ChangeNotifier { _isGenerating = false; _progress = 0.0; _error = e.toString(); + _errorTitle = title; _statusMessage = '生成失败'; _justCompleted = false; notifyListeners(); @@ -212,6 +216,7 @@ class TTSService extends ChangeNotifier { _completedStoryTitle = null; _justCompleted = false; _error = null; + _errorTitle = null; notifyListeners(); } } diff --git a/airhub_app/macos/Flutter/GeneratedPluginRegistrant.swift b/airhub_app/macos/Flutter/GeneratedPluginRegistrant.swift index 6b54f39..b2cf42f 100644 --- a/airhub_app/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/airhub_app/macos/Flutter/GeneratedPluginRegistrant.swift @@ -10,6 +10,7 @@ import file_selector_macos import flutter_blue_plus_darwin import just_audio import shared_preferences_foundation +import video_player_avfoundation import webview_flutter_wkwebview func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { @@ -18,5 +19,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterBluePlusPlugin.register(with: registry.registrar(forPlugin: "FlutterBluePlusPlugin")) JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) } diff --git a/airhub_app/pubspec.lock b/airhub_app/pubspec.lock index 0f96872..7393331 100644 --- a/airhub_app/pubspec.lock +++ b/airhub_app/pubspec.lock @@ -232,6 +232,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.7" + csslib: + dependency: transitive + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" custom_lint: dependency: transitive description: @@ -540,6 +548,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.3.0" + html: + dependency: transitive + description: + name: html + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + url: "https://pub.dev" + source: hosted + version: "0.15.6" http: dependency: "direct main" description: @@ -1265,6 +1281,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + video_player: + dependency: "direct main" + description: + name: video_player + sha256: "08bfba72e311d48219acad4e191b1f9c27ff8cf928f2c7234874592d9c9d7341" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + video_player_android: + dependency: transitive + description: + name: video_player_android + sha256: "9862c67c4661c98f30fe707bc1a4f97d6a0faa76784f485d282668e4651a7ac3" + url: "https://pub.dev" + source: hosted + version: "2.9.4" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + sha256: f93b93a3baa12ca0ff7d00ca8bc60c1ecd96865568a01ff0c18a99853ee201a5 + url: "https://pub.dev" + source: hosted + version: "2.9.3" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + sha256: "57c5d73173f76d801129d0531c2774052c5a7c11ccb962f1830630decd9f24ec" + url: "https://pub.dev" + source: hosted + version: "6.6.0" + video_player_web: + dependency: transitive + description: + name: video_player_web + sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb" + url: "https://pub.dev" + source: hosted + version: "2.4.0" vm_service: dependency: transitive description: diff --git a/airhub_app/pubspec.yaml b/airhub_app/pubspec.yaml index 3a07761..3869e7b 100644 --- a/airhub_app/pubspec.yaml +++ b/airhub_app/pubspec.yaml @@ -67,6 +67,7 @@ dependencies: image_picker: ^1.2.1 just_audio: ^0.9.42 http: ^1.2.0 + video_player: ^2.9.2 flutter: uses-material-design: true