From b40ce47e89274a94afdccb54031eb088ad0f673e Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Sat, 1 Aug 2026 10:14:24 +0200 Subject: [PATCH] wip --- docs/docs_screenshots/pubspec.yaml | 5 +- melos.yaml | 5 +- packages/stream_chat_flutter/CHANGELOG.md | 1 + .../lib/src/indicators/sending_indicator.dart | 15 +- .../components/stream_message_header.dart | 10 +- .../stream_message_sending_status.dart | 14 +- .../message_widget/stream_message_item.dart | 4 +- packages/stream_chat_flutter/pubspec.yaml | 13 +- .../indicators/sending_indicator_test.dart | 94 ++++++++ .../message_preview_presentation_test.dart | 203 ++++++++++++++++++ .../stream_message_item_preview_test.dart | 87 ++++++++ .../ios/Runner.xcodeproj/project.pbxproj | 129 +++-------- 12 files changed, 445 insertions(+), 135 deletions(-) create mode 100644 packages/stream_chat_flutter/test/src/message_widget/components/message_preview_presentation_test.dart create mode 100644 packages/stream_chat_flutter/test/src/message_widget/stream_message_item_preview_test.dart diff --git a/docs/docs_screenshots/pubspec.yaml b/docs/docs_screenshots/pubspec.yaml index f97017629a..4fcf77fd00 100644 --- a/docs/docs_screenshots/pubspec.yaml +++ b/docs/docs_screenshots/pubspec.yaml @@ -20,10 +20,7 @@ dependencies: record: ^6.2.0 stream_chat_flutter: ^10.2.0 stream_core_flutter: - git: - url: https://github.com/GetStream/stream-core-flutter.git - ref: ab4b1fb0a0be01b4270823c5c2c7b0c21ad886f8 - path: packages/stream_core_flutter + path: /Users/renefloor/Documents/github/stream-core-flutter/packages/stream_core_flutter dev_dependencies: alchemist: ^0.14.0 diff --git a/melos.yaml b/melos.yaml index 795c1b71d1..9a281a0e33 100644 --- a/melos.yaml +++ b/melos.yaml @@ -105,10 +105,7 @@ command: streaming_shared_preferences: ^2.0.0 svg_icon_widget: ^0.0.1 stream_core_flutter: - git: - url: https://github.com/GetStream/stream-core-flutter.git - ref: ab4b1fb0a0be01b4270823c5c2c7b0c21ad886f8 - path: packages/stream_core_flutter + path: /Users/renefloor/Documents/github/stream-core-flutter/packages/stream_core_flutter stream_thumbnail: ^0.1.0 synchronized: ^3.4.0 thumblr: ^0.0.4 diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index d6a3aecb94..059e97d419 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -24,6 +24,7 @@ - Fixed the attachment picker throwing a `Tooltip` assertion error when a custom `TabbedAttachmentPickerOption` is added without a `title`; the tooltip is now only shown when a title is provided. - Fixed the `StreamBackButton` unread badge including the currently open channel in its total count. - Fixed modal dialogs (message actions, delete/flag confirmation) rendering over a white scrim in light theme; they now use the design system's scrim token. +- Fixed the message metadata in the long-press actions modal keeping its muted in-list colors against the dark scrim. The previewed message now renders its annotations ("Saved for later", "Pinned by", "Replied to a thread" + "View", "Reminder set"), username, sending status and read receipts, timestamp, "Edited" label, and thread-reply count in white. Added `StreamSendingIndicator.color` to override the indicator's icon color. ## 10.2.0 diff --git a/packages/stream_chat_flutter/lib/src/indicators/sending_indicator.dart b/packages/stream_chat_flutter/lib/src/indicators/sending_indicator.dart index dc59abe07a..11d463149a 100644 --- a/packages/stream_chat_flutter/lib/src/indicators/sending_indicator.dart +++ b/packages/stream_chat_flutter/lib/src/indicators/sending_indicator.dart @@ -13,6 +13,7 @@ class StreamSendingIndicator extends StatelessWidget { this.isMessageRead = false, this.isMessageDelivered = false, this.size, + this.color, }); /// The message whose sending status is to be shown. @@ -27,6 +28,12 @@ class StreamSendingIndicator extends StatelessWidget { /// The size of the indicator icon. final double? size; + /// The color of the indicator icon. + /// + /// When null, read messages use `StreamColorScheme.accentPrimary` and every + /// other state uses `StreamColorScheme.textSecondary`. + final Color? color; + @override Widget build(BuildContext context) { final colorScheme = context.streamColorScheme; @@ -36,7 +43,7 @@ class StreamSendingIndicator extends StatelessWidget { return Icon( context.streamIcons.checks, size: size, - color: colorScheme.accentPrimary, + color: color ?? colorScheme.accentPrimary, semanticLabel: a11y.messageReadStatusLabel, ); } @@ -45,7 +52,7 @@ class StreamSendingIndicator extends StatelessWidget { return Icon( context.streamIcons.checks, size: size, - color: colorScheme.textSecondary, + color: color ?? colorScheme.textSecondary, semanticLabel: a11y.messageDeliveredStatusLabel, ); } @@ -54,7 +61,7 @@ class StreamSendingIndicator extends StatelessWidget { return Icon( context.streamIcons.checkmark, size: size, - color: colorScheme.textSecondary, + color: color ?? colorScheme.textSecondary, semanticLabel: a11y.messageSentStatusLabel, ); } @@ -63,7 +70,7 @@ class StreamSendingIndicator extends StatelessWidget { return Icon( context.streamIcons.clock, size: size, - color: colorScheme.textSecondary, + color: color ?? colorScheme.textSecondary, semanticLabel: a11y.messageSendingStatusLabel, ); } diff --git a/packages/stream_chat_flutter/lib/src/message_widget/components/stream_message_header.dart b/packages/stream_chat_flutter/lib/src/message_widget/components/stream_message_header.dart index dde68ce5a2..120753b817 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/components/stream_message_header.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/components/stream_message_header.dart @@ -104,12 +104,18 @@ class DefaultStreamMessageHeader extends core.NullableStatelessWidget { final colorScheme = context.streamColorScheme; final crossAxisAlignment = core.StreamMessageLayout.crossAxisAlignmentOf(context); + // Previews sit on the modal scrim, where accent-colored annotations don't + // have enough contrast, so they fall back to the on-scrim color. + final isPreview = core.StreamMessageLayout.presentationOf(context) == .preview; + final accentColor = isPreview ? colorScheme.textOnAccent : colorScheme.accentPrimary; + final linkColor = isPreview ? colorScheme.textOnAccent : colorScheme.textLink; + Widget? savedForLaterAnnotation; if (message.reminder case final reminder? when reminder.remindAt == null) { savedForLaterAnnotation = core.StreamMessageAnnotation( leading: Icon(icons.save), label: Text(translations.savedForLaterLabel), - style: .from(textColor: colorScheme.accentPrimary, iconColor: colorScheme.accentPrimary), + style: .from(textColor: accentColor, iconColor: accentColor), ); } @@ -137,7 +143,7 @@ class DefaultStreamMessageHeader extends core.NullableStatelessWidget { leading: Icon(icons.arrowUpRight), label: Text(annotationLabel), trailing: Text(translations.viewLabel), - style: .from(trailingTextColor: colorScheme.textLink), + style: .from(trailingTextColor: linkColor), ); } diff --git a/packages/stream_chat_flutter/lib/src/message_widget/components/stream_message_sending_status.dart b/packages/stream_chat_flutter/lib/src/message_widget/components/stream_message_sending_status.dart index 684218553c..ed4b20b72d 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/components/stream_message_sending_status.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/components/stream_message_sending_status.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/indicators/sending_indicator.dart'; -import 'package:stream_chat_flutter/src/utils/extensions.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_core_flutter/chat.dart' as core; /// Displays the sending status of a message, including attachment upload /// progress and sent/delivered/read indicators. @@ -51,6 +50,14 @@ class StreamMessageSendingStatus extends StatelessWidget { final channel = StreamChannel.maybeOf(context)?.channel; + // Previews sit on the modal scrim, where neither the accent-colored read + // receipt nor the muted sent/delivered icon has enough contrast, so both + // fall back to the on-scrim color. + final iconColor = switch (core.StreamMessageLayout.presentationOf(context)) { + .preview => context.streamColorScheme.textOnAccent, + .standard => null, + }; + return BetterStreamBuilder>( stream: channel?.state?.readStream, initialData: channel?.state?.read, @@ -65,6 +72,7 @@ class StreamMessageSendingStatus extends StatelessWidget { message: message, isMessageRead: isMessageRead, isMessageDelivered: isMessageDelivered, + color: iconColor, ); }, ); diff --git a/packages/stream_chat_flutter/lib/src/message_widget/stream_message_item.dart b/packages/stream_chat_flutter/lib/src/message_widget/stream_message_item.dart index 2c8d3a359c..0c80b56e1b 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/stream_message_item.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/stream_message_item.dart @@ -850,7 +850,9 @@ class DefaultStreamMessageItem extends StatelessWidget { builder: (_) => StreamChatConfiguration( data: StreamChatConfiguration.of(context), child: StreamMessageLayout( - data: layout, + // The message is re-rendered on top of the modal scrim, so its + // metadata and annotations switch to their on-scrim colors. + data: layout.copyWith(presentation: core.StreamMessagePresentation.preview), child: StreamMessageActionsModal( message: message, messageActions: actions, diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index 153e5138ef..b639d8204f 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -56,18 +56,7 @@ dependencies: shimmer: ^3.0.0 stream_chat_flutter_core: ^10.2.0 stream_core_flutter: - # The ignore below silences `invalid_dependency` because we occasionally - # pin stream_core_flutter to a git ref to iterate on it alongside this - # SDK between its releases. - # - # **Note:** Before publishing stream_chat_flutter, this MUST be swapped - # back to a pub version constraint — git deps are not allowed on pub.dev - # and will block the release. - # ignore: invalid_dependency - git: - url: https://github.com/GetStream/stream-core-flutter.git - ref: ab4b1fb0a0be01b4270823c5c2c7b0c21ad886f8 - path: packages/stream_core_flutter + path: /Users/renefloor/Documents/github/stream-core-flutter/packages/stream_core_flutter stream_thumbnail: ^0.1.0 svg_icon_widget: ^0.0.1 synchronized: ^3.4.0 diff --git a/packages/stream_chat_flutter/test/src/indicators/sending_indicator_test.dart b/packages/stream_chat_flutter/test/src/indicators/sending_indicator_test.dart index 025e91c6a9..a238ecd7ea 100644 --- a/packages/stream_chat_flutter/test/src/indicators/sending_indicator_test.dart +++ b/packages/stream_chat_flutter/test/src/indicators/sending_indicator_test.dart @@ -208,4 +208,98 @@ void main() { ); }, ); + + // An explicit color is what lets the long-press preview draw the indicator in + // white against the modal scrim, where both accentPrimary and textSecondary + // lack contrast. See FLU-647. + group('StreamSendingIndicator color override', () { + const override = Color(0xFF4CAF50); + + Future pumpIndicator( + WidgetTester tester, { + required Message message, + bool isMessageRead = false, + bool isMessageDelivered = false, + Color? color, + }) async { + await tester.pumpWidget( + MaterialApp( + home: StreamChatTheme( + data: StreamChatThemeData(), + child: Scaffold( + body: Center( + child: StreamSendingIndicator( + message: message, + isMessageRead: isMessageRead, + isMessageDelivered: isMessageDelivered, + color: color, + ), + ), + ), + ), + ), + ); + + return tester.widget(find.byType(Icon)); + } + + testWidgets('applies to the read indicator', (tester) async { + final icon = await pumpIndicator( + tester, + message: Message(state: MessageState.sent), + isMessageRead: true, + color: override, + ); + + expect(icon.color, override); + }); + + testWidgets('applies to the delivered indicator', (tester) async { + final icon = await pumpIndicator( + tester, + message: Message(state: MessageState.sent), + isMessageDelivered: true, + color: override, + ); + + expect(icon.color, override); + }); + + testWidgets('applies to the sent indicator', (tester) async { + final icon = await pumpIndicator( + tester, + message: Message(state: MessageState.sent), + color: override, + ); + + expect(icon.color, override); + }); + + testWidgets('applies to the sending indicator', (tester) async { + final icon = await pumpIndicator( + tester, + message: Message(state: MessageState.sending), + color: override, + ); + + expect(icon.color, override); + }); + + testWidgets('falls back to the theme colors when null', (tester) async { + final colorScheme = StreamColorScheme.light(); + + final read = await pumpIndicator( + tester, + message: Message(state: MessageState.sent), + isMessageRead: true, + ); + expect(read.color, colorScheme.accentPrimary); + + final sent = await pumpIndicator( + tester, + message: Message(state: MessageState.sent), + ); + expect(sent.color, colorScheme.textSecondary); + }); + }); } diff --git a/packages/stream_chat_flutter/test/src/message_widget/components/message_preview_presentation_test.dart b/packages/stream_chat_flutter/test/src/message_widget/components/message_preview_presentation_test.dart new file mode 100644 index 0000000000..933ea99576 --- /dev/null +++ b/packages/stream_chat_flutter/test/src/message_widget/components/message_preview_presentation_test.dart @@ -0,0 +1,203 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:stream_chat_flutter/src/message_widget/components/stream_message_sending_status.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_core_flutter/chat.dart' as core; + +import '../../mocks.dart'; + +/// Regression tests for FLU-647: the long-press actions modal re-renders the +/// message on top of a dark scrim, so annotations and sending status must use +/// the on-scrim color instead of their muted / accent in-list colors. +/// +/// The core-owned slots (timestamp, "Edited", username, plain annotations, +/// reply label) are covered in stream_core_flutter. These tests cover the two +/// chat-side widgets that hardcoded their colors and therefore bypassed the +/// theme resolution. +void main() { + final currentUser = OwnUser(id: 'current-user'); + + StreamColorScheme colorSchemeOf(WidgetTester tester) { + return StreamTheme.of(tester.element(find.byType(Scaffold))).colorScheme; + } + + group('DefaultStreamMessageHeader', () { + Future pumpHeader( + WidgetTester tester, { + required Message message, + required core.StreamMessagePresentation presentation, + }) { + final client = MockClient(); + final clientState = MockClientState(); + when(() => client.state).thenReturn(clientState); + when(() => clientState.currentUser).thenReturn(currentUser); + when(() => clientState.currentUserStream).thenAnswer((_) => Stream.value(currentUser)); + + return tester.pumpWidget( + MaterialApp( + home: StreamChat( + client: client, + child: Scaffold( + body: core.StreamMessageLayout( + data: core.StreamMessageLayoutData(presentation: presentation), + child: DefaultStreamMessageHeader( + props: StreamMessageHeaderProps(message: message), + ), + ), + ), + ), + ), + ); + } + + // A reminder without a remindAt renders the "Saved for later" annotation, + // which is accent-colored in the list. + final savedForLater = Message( + id: 'saved-for-later', + text: 'Saved', + createdAt: DateTime(2026), + user: User(id: 'other-user'), + reminder: MessageReminder( + messageId: 'saved-for-later', + channelCid: 'messaging:test', + userId: 'current-user', + createdAt: DateTime(2026), + updatedAt: DateTime(2026), + ), + ); + + // showInChannel renders the annotation with a tappable "View" trailing, + // which uses the link color in the list. + final showInChannel = Message( + id: 'show-in-channel', + text: 'Replied', + createdAt: DateTime(2026), + user: User(id: 'other-user'), + showInChannel: true, + ); + + Color? textColorOf(WidgetTester tester, String text) { + return DefaultTextStyle.of(tester.element(find.text(text))).style.color; + } + + Color? iconColorOf(WidgetTester tester, IconData icon) { + return IconTheme.of(tester.element(find.byIcon(icon))).color; + } + + testWidgets('saved-for-later stays accent-colored in the list', (tester) async { + await pumpHeader( + tester, + message: savedForLater, + presentation: core.StreamMessagePresentation.standard, + ); + + final colorScheme = colorSchemeOf(tester); + expect(textColorOf(tester, 'Saved for later'), colorScheme.accentPrimary); + expect(iconColorOf(tester, StreamIconData.save), colorScheme.accentPrimary); + }); + + testWidgets('saved-for-later turns white in a preview', (tester) async { + await pumpHeader( + tester, + message: savedForLater, + presentation: core.StreamMessagePresentation.preview, + ); + + final colorScheme = colorSchemeOf(tester); + expect(textColorOf(tester, 'Saved for later'), colorScheme.textOnAccent); + expect(iconColorOf(tester, StreamIconData.save), colorScheme.textOnAccent); + }); + + testWidgets('the "View" trailing keeps the link color in the list', (tester) async { + await pumpHeader( + tester, + message: showInChannel, + presentation: core.StreamMessagePresentation.standard, + ); + + expect(textColorOf(tester, 'View'), colorSchemeOf(tester).textLink); + }); + + testWidgets('the "View" trailing turns white in a preview', (tester) async { + await pumpHeader( + tester, + message: showInChannel, + presentation: core.StreamMessagePresentation.preview, + ); + + expect(textColorOf(tester, 'View'), colorSchemeOf(tester).textOnAccent); + }); + }); + + group('StreamMessageSendingStatus', () { + final message = Message( + id: 'own-message', + text: 'Hello', + createdAt: DateTime(2026), + user: currentUser, + state: MessageState.sent, + ); + + // A read by somebody else, after the message was sent. + final reads = [ + Read( + user: User(id: 'other-user'), + lastRead: DateTime(2026, 1, 2), + lastDeliveredAt: DateTime(2026, 1, 2), + ), + ]; + + Future pumpStatus( + WidgetTester tester, { + required core.StreamMessagePresentation presentation, + }) async { + final client = MockClient(); + final clientState = MockClientState(); + final channel = MockChannel(); + final channelState = MockChannelState(); + + when(() => client.state).thenReturn(clientState); + when(() => clientState.currentUser).thenReturn(currentUser); + when(() => clientState.currentUserStream).thenAnswer((_) => Stream.value(currentUser)); + when(() => channel.client).thenReturn(client); + when(() => channel.state).thenReturn(channelState); + when(() => channelState.read).thenReturn(reads); + when(() => channelState.readStream).thenAnswer((_) => Stream.value(reads)); + + await tester.pumpWidget( + MaterialApp( + home: StreamChat( + client: client, + child: StreamChannel( + channel: channel, + child: Scaffold( + body: core.StreamMessageLayout( + data: core.StreamMessageLayoutData(presentation: presentation), + child: StreamMessageSendingStatus(message: message), + ), + ), + ), + ), + ), + ); + + await tester.pumpAndSettle(); + } + + Color? indicatorColor(WidgetTester tester) { + final icon = tester.widget(find.byType(Icon)); + return icon.color; + } + + testWidgets('read receipts stay accent-colored in the list', (tester) async { + await pumpStatus(tester, presentation: core.StreamMessagePresentation.standard); + expect(indicatorColor(tester), colorSchemeOf(tester).accentPrimary); + }); + + testWidgets('read receipts turn white in a preview', (tester) async { + await pumpStatus(tester, presentation: core.StreamMessagePresentation.preview); + expect(indicatorColor(tester), colorSchemeOf(tester).textOnAccent); + }); + }); +} diff --git a/packages/stream_chat_flutter/test/src/message_widget/stream_message_item_preview_test.dart b/packages/stream_chat_flutter/test/src/message_widget/stream_message_item_preview_test.dart new file mode 100644 index 0000000000..300c04f548 --- /dev/null +++ b/packages/stream_chat_flutter/test/src/message_widget/stream_message_item_preview_test.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_core_flutter/chat.dart' as core; + +import '../mocks.dart'; + +/// Guards the wiring for FLU-647: the long-press actions modal must re-render +/// the message under [core.StreamMessagePresentation.preview], which is what +/// flips its metadata and annotations to the on-scrim color. +void main() { + testWidgets( + 'long-pressing a message renders the modal copy as a preview', + (tester) async { + final currentUser = OwnUser(id: 'current-user'); + + final client = MockClient(); + final clientState = MockClientState(); + final channel = MockChannel( + ownCapabilities: const [ + ChannelCapability.sendMessage, + ChannelCapability.sendReply, + ], + ); + final channelState = MockChannelState(); + + when(() => client.state).thenReturn(clientState); + when(() => clientState.currentUser).thenReturn(currentUser); + when(() => clientState.currentUserStream).thenAnswer((_) => Stream.value(currentUser)); + when(() => channel.client).thenReturn(client); + when(() => channel.state).thenReturn(channelState); + + final message = Message( + id: 'test-message', + text: 'Long press me', + createdAt: DateTime(2026), + // Somebody else's message, so no sending status is involved. + user: User(id: 'other-user'), + state: MessageState.sent, + ); + + await tester.pumpWidget( + MaterialApp( + // StreamChat has to sit above the Navigator: the actions modal is + // pushed as a route and re-provides StreamChannel, but relies on + // StreamChat being an ancestor of the navigator, as in a real app. + builder: (context, child) => StreamChat(client: client, child: child), + home: StreamChannel( + channel: channel, + child: Scaffold( + body: StreamMessageItem(message: message), + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // The in-list copy renders with the standard presentation. + expect( + core.StreamMessageLayout.presentationOf( + tester.element(find.text('Long press me')), + ), + core.StreamMessagePresentation.standard, + ); + + // Held past kLongPressTimeout — tester.longPress pumps exactly the + // timeout, which does not reliably cross the recognizer's deadline. + final gesture = await tester.startGesture( + tester.getCenter(find.byType(StreamMessageItem)), + ); + await tester.pump(const Duration(milliseconds: 700)); + await gesture.up(); + await tester.pumpAndSettle(); + + // The modal's copy is keyed 'MessageItem'; it must report a preview so the + // core style defaults resolve to their on-scrim colors. + final modalItem = find.byKey(const Key('MessageItem')); + expect(modalItem, findsOneWidget); + expect( + core.StreamMessageLayout.presentationOf(tester.element(modalItem)), + core.StreamMessagePresentation.preview, + ); + }, + ); +} diff --git a/sample_app/ios/Runner.xcodeproj/project.pbxproj b/sample_app/ios/Runner.xcodeproj/project.pbxproj index 6fa58ae5c8..e1cace4f6a 100644 --- a/sample_app/ios/Runner.xcodeproj/project.pbxproj +++ b/sample_app/ios/Runner.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 8210C58B8A5DAB805ACF46A1 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4899F8CDC11D7148C6179369 /* Pods_Runner.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -51,6 +52,7 @@ 4899F8CDC11D7148C6179369 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 90B43020AC538F68084BBAFD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; @@ -69,6 +71,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, 8210C58B8A5DAB805ACF46A1 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -87,6 +90,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -166,13 +170,15 @@ 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 0BC14C55242B5A7A0028DE94 /* Embed App Extensions */, 7BD3737C65F59B233B7F7FC6 /* [CP] Embed Pods Frameworks */, - 78D972C66518C545847BBB5A /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -202,6 +208,9 @@ Base, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -243,24 +252,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 78D972C66518C545847BBB5A /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging_Privacy.bundle", - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/firebase_messaging_Privacy.bundle", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 7BD3737C65F59B233B7F7FC6 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -268,97 +259,11 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", - "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseCoreExtension/FirebaseCoreExtension.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseCrashlytics/FirebaseCrashlytics.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseSessions/FirebaseSessions.framework", - "${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework", - "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", - "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework", - "${BUILT_PRODUCTS_DIR}/PromisesSwift/Promises.framework", - "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", - "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", - "${BUILT_PRODUCTS_DIR}/audio_session/audio_session.framework", - "${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework", - "${BUILT_PRODUCTS_DIR}/device_info_plus/device_info_plus.framework", - "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", - "${BUILT_PRODUCTS_DIR}/file_selector_ios/file_selector_ios.framework", - "${BUILT_PRODUCTS_DIR}/flutter_app_badger/flutter_app_badger.framework", - "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework", - "${BUILT_PRODUCTS_DIR}/flutter_secure_storage_darwin/flutter_secure_storage_darwin.framework", - "${BUILT_PRODUCTS_DIR}/gal/gal.framework", - "${BUILT_PRODUCTS_DIR}/geolocator_apple/geolocator_apple.framework", - "${BUILT_PRODUCTS_DIR}/get_thumbnail_video/get_thumbnail_video.framework", - "${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework", - "${BUILT_PRODUCTS_DIR}/integration_test/integration_test.framework", - "${BUILT_PRODUCTS_DIR}/just_audio/just_audio.framework", - "${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework", "${BUILT_PRODUCTS_DIR}/media_kit_video/media_kit_video.framework", - "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", - "${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework", - "${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework", - "${BUILT_PRODUCTS_DIR}/record_ios/record_ios.framework", - "${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework", - "${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework", - "${BUILT_PRODUCTS_DIR}/sqflite_darwin/sqflite_darwin.framework", - "${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework", - "${BUILT_PRODUCTS_DIR}/sqlite3_flutter_libs/sqlite3_flutter_libs.framework", - "${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework", - "${BUILT_PRODUCTS_DIR}/video_player_avfoundation/video_player_avfoundation.framework", - "${BUILT_PRODUCTS_DIR}/wakelock_plus/wakelock_plus.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreExtension.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCrashlytics.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseRemoteConfigInterop.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseSessions.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Promises.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/audio_session.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info_plus.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_selector_ios.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_app_badger.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage_darwin.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/gal.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/geolocator_apple.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/get_thumbnail_video.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker_ios.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/integration_test.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/just_audio.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_kit_video.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/record_ios.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite_darwin.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3_flutter_libs.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player_avfoundation.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock_plus.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -718,6 +623,20 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; }