diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d55e7ed..2750d58 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -45,10 +45,10 @@ PODS: - Firebase/Messaging (11.15.0): - Firebase/CoreOnly - FirebaseMessaging (~> 11.15.0) - - firebase_core (3.15.0): + - firebase_core (3.15.1): - Firebase/CoreOnly (= 11.15.0) - Flutter - - firebase_messaging (15.2.8): + - firebase_messaging (15.2.9): - Firebase/Messaging (= 11.15.0) - firebase_core - Flutter @@ -130,7 +130,7 @@ PODS: - Flutter - irondash_engine_context (0.0.1): - Flutter - - Kingfisher (8.3.3) + - Kingfisher (8.4.0) - livekit_client (2.4.9): - Flutter - flutter_webrtc @@ -178,18 +178,18 @@ PODS: - sqflite_darwin (0.0.4): - Flutter - FlutterMacOS - - sqlite3 (3.50.1): - - sqlite3/common (= 3.50.1) - - sqlite3/common (3.50.1) - - sqlite3/dbstatvtab (3.50.1): + - sqlite3 (3.50.2): + - sqlite3/common (= 3.50.2) + - sqlite3/common (3.50.2) + - sqlite3/dbstatvtab (3.50.2): - sqlite3/common - - sqlite3/fts5 (3.50.1): + - sqlite3/fts5 (3.50.2): - sqlite3/common - - sqlite3/math (3.50.1): + - sqlite3/math (3.50.2): - sqlite3/common - - sqlite3/perf-threadsafe (3.50.1): + - sqlite3/perf-threadsafe (3.50.2): - sqlite3/common - - sqlite3/rtree (3.50.1): + - sqlite3/rtree (3.50.2): - sqlite3/common - sqlite3_flutter_libs (0.0.1): - Flutter @@ -362,8 +362,8 @@ SPEC CHECKSUMS: DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e - firebase_core: c727a02c560a53f1f1e56e18f16515eb5753c492 - firebase_messaging: 4158969b04b667f5435731ec9d6e453bb58b0c4c + firebase_core: ece862f94b2bc72ee0edbeec7ab5c7cb09fe1ab5 + firebase_messaging: e1a5fae495603115be1d0183bc849da748734e2b FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 @@ -382,9 +382,9 @@ SPEC CHECKSUMS: GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486 - Kingfisher: ff82cb91d9266ddb56cbb2f72d32c26f00d3e5be + Kingfisher: b14cc47bbfa7a3c150dd12962ee9c86338545629 livekit_client: 3f79d79233a5bd13d5b541732624ef959d7c538e - local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391 + local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19 media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854 media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 @@ -403,7 +403,7 @@ SPEC CHECKSUMS: shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 sign_in_with_apple: c5dcc141574c8c54d5ac99dd2163c0c72ad22418 sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 - sqlite3: 1d85290c3321153511f6e900ede7a1608718bbd5 + sqlite3: 3e82a2daae39ba3b41ae6ee84a130494585460fc sqlite3_flutter_libs: e7fc8c9ea2200ff3271f08f127842131746b70e2 super_native_extensions: b763c02dc3a8fd078389f410bf15149179020cb4 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index a8d5ad0..24233e4 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -27,6 +27,7 @@ import UIKit UNUserNotificationCenter.current().setNotificationCategories([replyableMessageCategory]) GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard index f3c2851..d503a63 100644 --- a/ios/Runner/Base.lproj/Main.storyboard +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -1,8 +1,10 @@ - - + + + - + + @@ -14,13 +16,14 @@ - + - + + diff --git a/ios/Runner/Views/VideoPlayerView.swift b/ios/Runner/Views/VideoPlayerView.swift new file mode 100644 index 0000000..ee943fa --- /dev/null +++ b/ios/Runner/Views/VideoPlayerView.swift @@ -0,0 +1,200 @@ +import Flutter +import UIKit +import AVKit + +// Factory to create the native video player view +class VideoPlayerViewFactory: NSObject, FlutterPlatformViewFactory { + private var messenger: FlutterBinaryMessenger + + init(messenger: FlutterBinaryMessenger) { + self.messenger = messenger + super.init() + } + + func create( + withFrame frame: CGRect, + viewIdentifier viewId: Int64, + arguments args: Any? + ) -> FlutterPlatformView { + return VideoPlayerView( + frame: frame, + viewIdentifier: viewId, + arguments: args, + binaryMessenger: messenger) + } + + // This is required by the protocol, but we don't need to implement it for this case + public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { + return FlutterStandardMessageCodec.sharedInstance() + } +} + +// The actual PlatformView that holds the AVPlayerViewController +class VideoPlayerView: NSObject, FlutterPlatformView { + private var playerViewController: AVPlayerViewController? + private var player: AVPlayer? + private var activityIndicator: UIActivityIndicatorView! + private var progressLabel: UILabel! + private var progressStack: UIStackView! + + // KVO contexts + private var playerStatusContext = 0 + private var playerLoadedTimeRangesContext = 0 + + init( + frame: CGRect, + viewIdentifier viewId: Int64, + arguments args: Any?, + binaryMessenger messenger: FlutterBinaryMessenger? + ) { + super.init() + + // Ensure we have a valid URL from Flutter + guard let args = args as? [String: Any], + let videoUrlString = args["videoUrl"] as? String, + let videoUrl = URL(string: videoUrlString) else { + // Initialize playerViewController even if URL is invalid + playerViewController = AVPlayerViewController() + playerViewController!.showsPlaybackControls = false // Hide controls for invalid URL + + let label = UILabel() + label.text = "Invalid video URL" + label.textAlignment = .center + label.textColor = .white + label.translatesAutoresizingMaskIntoConstraints = false + playerViewController!.contentOverlayView?.addSubview(label) + + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: playerViewController!.contentOverlayView!.centerXAnchor), + label.centerYAnchor.constraint(equalTo: playerViewController!.contentOverlayView!.centerYAnchor) + ]) + return + } + + // --- Player --- + player = AVPlayer(url: videoUrl) + + // --- PlayerViewController --- + playerViewController = AVPlayerViewController() + playerViewController!.player = player + playerViewController!.view.frame = frame // Set the frame directly + playerViewController!.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] + playerViewController!.showsPlaybackControls = true + + // --- Loading Indicator (spinner) --- + activityIndicator = UIActivityIndicatorView(style: .large) + activityIndicator.color = .white + activityIndicator.translatesAutoresizingMaskIntoConstraints = false + activityIndicator.isUserInteractionEnabled = false // Allow touches to pass through + + // --- Progress Percentage Label --- + progressLabel = UILabel() + progressLabel.textColor = .white + progressLabel.textAlignment = .center + progressLabel.translatesAutoresizingMaskIntoConstraints = false + progressLabel.isUserInteractionEnabled = false // Allow touches to pass through + + playerViewController!.contentOverlayView?.addSubview(activityIndicator) + playerViewController!.contentOverlayView?.addSubview(progressLabel) + + // Center the activity indicator and place the progress label below it + NSLayoutConstraint.activate([ + activityIndicator.centerXAnchor.constraint(equalTo: playerViewController!.contentOverlayView!.centerXAnchor), + activityIndicator.centerYAnchor.constraint(equalTo: playerViewController!.contentOverlayView!.centerYAnchor), + + progressLabel.topAnchor.constraint(equalTo: activityIndicator.bottomAnchor, constant: 16), + progressLabel.centerXAnchor.constraint(equalTo: playerViewController!.contentOverlayView!.centerXAnchor), + ]) + + // Add Key-Value Observers + addObservers() + + activityIndicator.startAnimating() + } + + func view() -> UIView { + return playerViewController!.view + } + + private func addObservers() { + player?.addObserver(self, forKeyPath: #keyPath(AVPlayer.status), options: [.new, .initial], context: &playerStatusContext) + player?.currentItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.loadedTimeRanges), options: [.new], context: &playerLoadedTimeRangesContext) + } + + private func removeObservers() { + // Check if observers are registered before removing them to avoid crashes. + // A simple way is to use a flag or check the player object, but for KVO, + // it's often safer to just ensure they are added once and removed once. + // Given the lifecycle here, direct removal in deinit is okay. + player?.removeObserver(self, forKeyPath: #keyPath(AVPlayer.status), context: &playerStatusContext) + player?.currentItem?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.loadedTimeRanges), context: &playerLoadedTimeRangesContext) + } + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { + // Dispatch to main queue to ensure thread safety + DispatchQueue.main.async { + guard self.player != nil else { + return + } + + if context == &self.playerStatusContext { + self.handlePlayerStatusChange(change: change) + } else if context == &self.playerLoadedTimeRangesContext { + self.handleLoadedTimeRangesChange() + } + } + } + + private func handlePlayerStatusChange(change: [NSKeyValueChangeKey : Any]?) { + guard let statusValue = change?[.newKey] as? Int, let status = AVPlayer.Status(rawValue: statusValue) else { return } + + DispatchQueue.main.async { + switch status { + case .readyToPlay: + self.activityIndicator.stopAnimating() + self.progressLabel.isHidden = true + self.player?.play() + case .failed: + self.activityIndicator.stopAnimating() + // Optionally: show an error message to the user + let label = UILabel() + label.text = "Failed to load video" + label.textColor = .white + label.textAlignment = .center + label.frame = self.playerViewController!.view.bounds + self.playerViewController!.view.addSubview(label) + case .unknown: + self.activityIndicator.startAnimating() + @unknown default: + break + } + } + } + + private func handleLoadedTimeRangesChange() { + guard let playerItem = player?.currentItem, + let timeRange = playerItem.loadedTimeRanges.first?.timeRangeValue, + !CMTIME_IS_INDEFINITE(playerItem.duration) else { + return + } + + let startSeconds = CMTimeGetSeconds(timeRange.start) + let durationSeconds = CMTimeGetSeconds(timeRange.duration) + let totalBuffer = startSeconds + durationSeconds + let totalDuration = CMTimeGetSeconds(playerItem.duration) + + let progress = Float(totalBuffer / totalDuration) + + DispatchQueue.main.async { + self.progressLabel.text = "\(Int(progress * 100))%" + + if progress >= 0.99 { + self.progressLabel.isHidden = true + } + } + } + + deinit { + removeObservers() + } +} diff --git a/lib/widgets/content/attachment_preview.dart b/lib/widgets/content/attachment_preview.dart index 0d6c171..abbc083 100644 --- a/lib/widgets/content/attachment_preview.dart +++ b/lib/widgets/content/attachment_preview.dart @@ -29,9 +29,12 @@ class AttachmentPreview extends StatelessWidget { @override Widget build(BuildContext context) { + var ratio = + (item.isOnCloud ? (item.data.fileMeta?['ratio'] ?? 1) : 1).toDouble(); + if (ratio == 0) ratio = 1.0; + return AspectRatio( - aspectRatio: - (item.isOnCloud ? (item.data.fileMeta?['ratio'] ?? 1) : 1).toDouble(), + aspectRatio: ratio, child: ClipRRect( borderRadius: BorderRadius.circular(8), child: Stack( diff --git a/lib/widgets/content/cloud_file_collection.dart b/lib/widgets/content/cloud_file_collection.dart index 1502989..caa5dab 100644 --- a/lib/widgets/content/cloud_file_collection.dart +++ b/lib/widgets/content/cloud_file_collection.dart @@ -37,13 +37,10 @@ class CloudFileList extends HookConsumerWidget { double calculateAspectRatio() { double total = 0; - for (var ratio in files.map( - (e) => - e.fileMeta?['ratio'] ?? - ((e.mimeType?.startsWith('image') ?? false) ? 1 : 16 / 9), - )) { + for (var ratio in files.map((e) => e.fileMeta?['ratio'] ?? 1)) { total += ratio; } + if (total == 0) return 1; return total / files.length; } diff --git a/lib/widgets/content/cloud_files.dart b/lib/widgets/content/cloud_files.dart index 5e6ab0a..cade2f5 100644 --- a/lib/widgets/content/cloud_files.dart +++ b/lib/widgets/content/cloud_files.dart @@ -27,20 +27,19 @@ class CloudFileWidget extends ConsumerWidget { final serverUrl = ref.watch(serverUrlProvider); final uri = '$serverUrl/api/files/${item.id}'; + var ratio = (item.fileMeta?['ratio'] ?? 1).toDouble(); + if (ratio == 0) ratio = 1.0; final content = switch (item.mimeType?.split('/').firstOrNull) { "image" => AspectRatio( - aspectRatio: (item.fileMeta?['ratio'] ?? 1).toDouble(), + aspectRatio: ratio, child: UniversalImage( uri: uri, blurHash: noBlurhash ? null : item.fileMeta?['blur'], ), ), "video" => AspectRatio( - aspectRatio: (item.fileMeta?['ratio'] ?? 16 / 9).toDouble(), - child: UniversalVideo( - uri: uri, - aspectRatio: (item.fileMeta?['ratio'] ?? 16 / 9).toDouble(), - ), + aspectRatio: ratio, + child: UniversalVideo(uri: uri, aspectRatio: ratio), ), _ => Text('Unable render for ${item.mimeType}'), }; diff --git a/lib/widgets/content/video.native.dart b/lib/widgets/content/video.native.dart index a41d880..bba219c 100644 --- a/lib/widgets/content/video.native.dart +++ b/lib/widgets/content/video.native.dart @@ -70,7 +70,7 @@ class _UniversalVideoState extends ConsumerState { return Video( controller: _videoController!, - aspectRatio: widget.aspectRatio, + aspectRatio: widget.aspectRatio != 1 ? widget.aspectRatio : null, controls: !kIsWeb && (Platform.isAndroid || Platform.isIOS) ? MaterialVideoControls diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 1b67433..0f0927f 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -55,7 +55,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin")) IrondashEngineContextPlugin.register(with: registry.registrar(forPlugin: "IrondashEngineContextPlugin")) LiveKitPlugin.register(with: registry.registrar(forPlugin: "LiveKitPlugin")) - FLALocalAuthPlugin.register(with: registry.registrar(forPlugin: "FLALocalAuthPlugin")) + LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin")) MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index a1fc3dd..d38d360 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -16,10 +16,10 @@ PODS: - Firebase/Messaging (11.15.0): - Firebase/CoreOnly - FirebaseMessaging (~> 11.15.0) - - firebase_core (3.15.0): + - firebase_core (3.15.1): - Firebase/CoreOnly (~> 11.15.0) - FlutterMacOS - - firebase_messaging (15.2.8): + - firebase_messaging (15.2.9): - Firebase/CoreOnly (~> 11.15.0) - Firebase/Messaging (~> 11.15.0) - firebase_core @@ -292,8 +292,8 @@ SPEC CHECKSUMS: file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31 Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e - firebase_core: 177f51be1650b15d2d5b9f1abf48792619288070 - firebase_messaging: 8748a5d4bb435993cffa7f5501292f3e914a23d7 + firebase_core: 8dc569d17b3a9fc3ee5ebc21b322411b4a796833 + firebase_messaging: adaf7fc22897a7aa49410d15f8a595bef2dbca2d FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 @@ -310,7 +310,7 @@ SPEC CHECKSUMS: GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 irondash_engine_context: 893c7d96d20ce361d7e996f39d360c4c2f9869ba livekit_client: c9d9f41996f5cf22b9ba0e8483e6af4ca5094059 - local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391 + local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19 media_kit_libs_macos_video: 85a23e549b5f480e72cae3e5634b5514bc692f65 media_kit_video: fa6564e3799a0a28bff39442334817088b7ca758 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 diff --git a/pubspec.lock b/pubspec.lock index 89aa24f..f87734c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: "50e24b769bd1e725732f0aff18b806b8731c1fbcf4e8018ab98e7c4805a2a52f" + sha256: a5788040810bd84400bc209913fbc40f388cded7cdf95ee2f5d2bff7e38d5241 url: "https://pub.dev" source: hosted - version: "1.3.57" + version: "1.3.58" analyzer: dependency: transitive description: @@ -349,10 +349,10 @@ packages: dependency: transitive description: name: coverage - sha256: aa07dbe5f2294c827b7edb9a87bba44a9c15a3cc81bc8da2ca19b37322d30080 + sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" url: "https://pub.dev" source: hosted - version: "1.14.1" + version: "1.15.0" croppy: dependency: "direct main" description: @@ -629,50 +629,50 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: "5bba5924139e91d26446fd2601c18a6aa62c1161c768a989bb5e245dcdc20644" + sha256: c6e8a6bf883d8ddd0dec39be90872daca65beaa6f4cff0051ed3b16c56b82e9f url: "https://pub.dev" source: hosted - version: "3.15.0" + version: "3.15.1" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: "5d2ab45779d91af2aa0252dec9fe4ee1caa015d83377de255454dcaa1526a0e0" + sha256: "5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb" url: "https://pub.dev" source: hosted - version: "5.4.1" + version: "6.0.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: eb3afccfc452b2b2075acbe0c4b27de62dd596802b4e5e19869c1e926cbb20b3 + sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" url: "https://pub.dev" source: hosted - version: "2.24.0" + version: "2.24.1" firebase_messaging: dependency: "direct main" description: name: firebase_messaging - sha256: c6711cf2f455532b84a94022c7aaf85088849763af2f01b775ca79d82d10a01a + sha256: "0f3363f97672eb9f65609fa00ed2f62cc8ec93e7e2d4def99726f9165d3d8a73" url: "https://pub.dev" source: hosted - version: "15.2.8" + version: "15.2.9" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface - sha256: "1c9dacccb1aee1bf17ba519dda5563a16fdd2ec1e79b5f2e421cb4bf75a166f7" + sha256: "7a05ef119a14c5f6a9440d1e0223bcba20c8daf555450e119c4c477bf2c3baa9" url: "https://pub.dev" source: hosted - version: "4.6.8" + version: "4.6.9" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web - sha256: "54317c26fa92f0d90a2017977ac791cb0504eca29fcf397f06adf727d4a7a2d5" + sha256: a4547f76da2a905190f899eb4d0150e1d0fd52206fce469d9f05ae15bb68b2c5 url: "https://pub.dev" source: hosted - version: "3.10.8" + version: "3.10.9" fixnum: dependency: transitive description: @@ -1049,18 +1049,18 @@ packages: dependency: "direct dev" description: name: freezed - sha256: "6022db4c7bfa626841b2a10f34dd1e1b68e8f8f9650db6112dcdeeca45ca793c" + sha256: "2d399f823b8849663744d2a9ddcce01c49268fb4170d0442a655bf6a2f47be22" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.1.0" freezed_annotation: dependency: "direct main" description: name: freezed_annotation - sha256: c87ff004c8aa6af2d531668b46a4ea379f7191dc6dfa066acd53d506da6e044b + sha256: "7294967ff0a6d98638e7acb774aac3af2550777accd8149c90af5b014e6d44d8" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.0" frontend_server_client: dependency: transitive description: @@ -1385,10 +1385,10 @@ packages: dependency: transitive description: name: local_auth_darwin - sha256: "630996cd7b7f28f5ab92432c4b35d055dd03a747bc319e5ffbb3c4806a3e50d2" + sha256: "25163ce60a5a6c468cf7a0e3dc8a165f824cabc2aa9e39a5e9fc5c2311b7686f" url: "https://pub.dev" source: hosted - version: "1.4.3" + version: "1.5.0" local_auth_platform_interface: dependency: transitive description: @@ -2174,10 +2174,10 @@ packages: dependency: transitive description: name: source_helper - sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" + sha256: "4f81479fe5194a622cdd1713fe1ecb683a6e6c85cd8cec8e2e35ee5ab3fdf2a1" url: "https://pub.dev" source: hosted - version: "1.3.5" + version: "1.3.6" source_map_stack_trace: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bbc2414..8477461 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 3.0.0+112 +version: 3.1.0+113 environment: sdk: ^3.7.2