Skip to content

feat(llc): add support for sharing live and static locations #2305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: v10.0.0
Choose a base branch
from

Conversation

xsahil03x
Copy link
Member

@xsahil03x xsahil03x commented Jul 14, 2025

Submit a pull request

Linear: FLU-197

Screenshots / Videos

Screen.Recording.2025-07-11.at.15.50.44.mov

Summary by CodeRabbit

  • New Features

    • Introduced location sharing in chat, allowing users to send static or live locations in messages.
    • Added interactive map views and live location updates within chat messages and threads.
    • Users can stop sharing live locations directly from the chat interface.
    • New dialogs for picking and viewing shared locations, with support for sharing duration selection.
    • Enhanced message rendering to display and interact with location attachments.
  • Bug Fixes

    • Corrected initialization order in channel list page state.
  • Chores

    • Added required location permissions and dependencies for Android, iOS, and macOS platforms.
    • Updated configuration files to support location features and new sample user.
  • Documentation

    • Updated public exports and configuration to reflect new location models and capabilities.

Copy link
Contributor

coderabbitai bot commented Jul 14, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This update introduces comprehensive support for location sharing—including static and live location features—across the core chat client, models, API, and sample application. It adds new models, API endpoints, event types, UI widgets, and supporting logic for managing, displaying, and interacting with shared locations, as well as updates to dependencies and platform-specific configuration for location services.

Changes

File(s) / Group Change Summary
melos.yaml, sample_app/pubspec.yaml Added dependencies for location and map functionality (avatar_glow, flutter_map, flutter_map_animations, geolocator, latlong2, rxdart).
packages/stream_chat/lib/src/client/channel.dart, client.dart, event_resolvers.dart Added support for sending, updating, and expiring static/live locations; event resolvers for location events; state management for active live locations.
packages/stream_chat/lib/src/core/api/user_api.dart, responses.dart, responses.g.dart Added API methods and response models for fetching/updating active live locations.
packages/stream_chat/lib/src/core/models/location.dart, location.g.dart, location_coordinates.dart Introduced new models for location and coordinates, with serialization logic.
packages/stream_chat/lib/src/core/models/message.dart, message.g.dart Added sharedLocation field to messages; updated (de)serialization.
packages/stream_chat/lib/src/core/models/channel_config.dart, channel_config.g.dart Added sharedLocations boolean to channel config and serialization.
packages/stream_chat/lib/src/core/models/channel_model.dart Added shareLocation capability constant.
packages/stream_chat/lib/src/core/models/channel_state.dart, channel_state.g.dart Added activeLiveLocations field to channel state and serialization.
packages/stream_chat/lib/src/event_type.dart Added new event type constants for poll and location events.
packages/stream_chat/lib/stream_chat.dart Exported new location models.
sample_app/lib/pages/channel_list_page.dart Integrated SharedLocationService for managing live location updates.
sample_app/lib/pages/channel_page.dart Added UI and logic for picking, sending, and displaying location attachments in messages.
sample_app/lib/pages/thread_page.dart Enabled rendering of location attachments in thread messages.
sample_app/lib/utils/app_config.dart Added a new user to the defaultUsers map.
sample_app/lib/utils/location_provider.dart Added a singleton for managing device location services and live tracking.
sample_app/lib/utils/shared_location_service.dart Added a service to sync live location updates with the chat client.
sample_app/lib/widgets/location/ (multiple files) Added widgets for picking, displaying, and interacting with location attachments and map views.
sample_app/lib/widgets/simple_map_view.dart Added a widget to render interactive maps with animated markers.
sample_app/lib/widgets/channel_list.dart Changed channel list sorting; added commented-out custom tile builder.
Platform config files (AndroidManifest.xml, Info.plist, entitlements, Xcode project) Added required permissions and configuration for location services on Android, iOS, and macOS.
sample_app/macos/Flutter/Flutter-Debug.xcconfig, Flutter-Release.xcconfig Deleted macOS Flutter build config files.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant App
  participant StreamChatClient
  participant Channel
  participant Server

  User->>App: Opens message input
  User->>App: Picks location (static or live)
  App->>Channel: sendStaticLocation()/startLiveLocationSharing()
  Channel->>Server: Send location message
  Server-->>Channel: locationShared/locationUpdated/locationExpired events
  Channel->>App: Update message list and active live locations
  App->>User: Renders location attachment in message list
  User->>App: Taps location attachment
  App->>App: Shows location detail dialog with map and controls
  User->>App: Stops live location sharing (if owner)
  App->>StreamChatClient: stopLiveLocation()
  StreamChatClient->>Server: Update live location status
  Server-->>Channel: locationExpired event
  Channel->>App: Updates UI to reflect expired location
Loading

Assessment against linked issues

Objective (Issue) Addressed Explanation
Implement LLC (Live Location Sharing) APIs and state (FLU-197)
Add models for location, coordinates, and related serialization (FLU-197)
Integrate event handling and state management for live locations (FLU-197)
Provide UI components/widgets for picking, sending, and displaying locations (FLU-197)

Poem

🗺️
A bunny hopped across the map,
Now chat can show just where you’re at!
With live or static, share your place—
In messages, maps, and UI space.
From code to screen, locations flow,
The warren’s smarter—let’s all go!
🐇✨


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@xsahil03x
Copy link
Member Author

@coderabbitai review

Copy link
Contributor

coderabbitai bot commented Jul 14, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@xsahil03x xsahil03x marked this pull request as draft July 14, 2025 10:52
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

♻️ Duplicate comments (1)
sample_app/macos/Runner/DebugProfile.entitlements (1)

15-16: Same entitlement comment as Release profile

The considerations raised for the Release entitlements apply here as well.

🧹 Nitpick comments (7)
sample_app/macos/Runner/Info.plist (1)

31-32: Usage description present – consider localization

NSLocationUsageDescription string is clear.
For production readiness, provide localized variants to avoid App Store review warnings.

sample_app/lib/widgets/channel_list.dart (1)

254-361: Remove commented-out code.

This large block of commented-out code should be removed to maintain code cleanliness. If this custom channel tile builder is intended for future use, consider:

  • Moving it to a separate file or branch
  • Creating a TODO/issue to track the implementation
  • Removing it entirely if it's no longer needed
-  //  BuildContext context,
-  //   List<ItemType> items,
-  //   int index,
-  //   WidgetType defaultWidget,
-  //
-
-  // Widget _customChannelTileBuilder(
-  //   BuildContext context,
-  //   List<Channel> channels,
-  //   int index,
-  //   StreamChannelListTile defaultWidget,
-  // ) {
-  //   final chatTheme = StreamChatTheme.of(context);
-  //   final channel = channels[index];
-  //   final backgroundColor = chatTheme.colorTheme.inputBg;
-  //   final canDeleteChannel = channel.canDeleteChannel;
-  //
-  //   final lastMessage = channel.state?.lastMessage;
-  //
-  //   final channelSubtitle =
-  //
-  //   final channelTile = ColoredBox(
-  //     color: switch (channel.isPinned) {
-  //       true => chatTheme.colorTheme.highlight,
-  //       false => Colors.transparent,
-  //     },
-  //     child: defaultWidget.copyWith(
-  //       subtitle: ChannelListTileSubtitle(
-  //         channel: channel,
-  //         textStyle: channelPreviewTheme.subtitleStyle,
-  //       ),
-  //     ),
-  //   );
-  //
-  //   return Slidable(
-  //     groupTag: 'channels-actions',
-  //     endActionPane: ActionPane(
-  //       extentRatio: canDeleteChannel ? 0.40 : 0.20,
-  //       motion: const BehindMotion(),
-  //       children: [
-  //         CustomSlidableAction(
-  //           backgroundColor: backgroundColor,
-  //           onPressed: (_) {
-  //             showChannelInfoModalBottomSheet(
-  //               context: context,
-  //               channel: channel,
-  //               onViewInfoTap: () {
-  //                 Navigator.pop(context);
-  //                 Navigator.push(
-  //                   context,
-  //                   MaterialPageRoute(
-  //                     builder: (context) {
-  //                       final isOneToOne =
-  //                           channel.memberCount == 2 && channel.isDistinct;
-  //                       return StreamChannel(
-  //                         channel: channel,
-  //                         child: isOneToOne
-  //                             ? ChatInfoScreen(
-  //                                 messageTheme: chatTheme.ownMessageTheme,
-  //                                 user: channel.state!.members
-  //                                     .where((m) =>
-  //                                         m.userId !=
-  //                                         channel.client.state.currentUser!.id)
-  //                                     .first
-  //                                     .user,
-  //                               )
-  //                             : GroupInfoScreen(
-  //                                 messageTheme: chatTheme.ownMessageTheme,
-  //                               ),
-  //                       );
-  //                     },
-  //                   ),
-  //                 );
-  //               },
-  //             );
-  //           },
-  //           child: const Icon(Icons.more_horiz),
-  //         ),
-  //         if (canDeleteChannel)
-  //           CustomSlidableAction(
-  //             backgroundColor: backgroundColor,
-  //             child: StreamSvgIcon(
-  //               icon: StreamSvgIcons.delete,
-  //               color: chatTheme.colorTheme.accentError,
-  //             ),
-  //             onPressed: (_) async {
-  //               final res = await showConfirmationBottomSheet(
-  //                 context,
-  //                 title: 'Delete Conversation',
-  //                 question:
-  //                     'Are you sure you want to delete this conversation?',
-  //                 okText: 'Delete',
-  //                 cancelText: 'Cancel',
-  //                 icon: StreamSvgIcon(
-  //                   icon: StreamSvgIcons.delete,
-  //                   color: chatTheme.colorTheme.accentError,
-  //                 ),
-  //               );
-  //               if (res == true) {
-  //                 await channelListController.deleteChannel(channel);
-  //               }
-  //             },
-  //           ),
-  //       ],
-  //     ),
-  //     child: channelTile,
-  //   );
-  // }
sample_app/lib/utils/shared_location_service.dart (2)

33-33: Consider handling potential errors instead of ignoring them.

The ignore() call suppresses any errors that might occur when fetching active live locations during initialization. Consider adding proper error handling to avoid silent failures.

-    return _client.getActiveLiveLocations().ignore();
+    try {
+      await _client.getActiveLiveLocations();
+    } catch (e) {
+      // Log error or handle appropriately
+      // Don't let initialization fail completely
+    }

40-42: Consider making throttle duration configurable.

The 3-second throttle is hardcoded. Consider making it configurable through the constructor or a constant to improve flexibility for different use cases.

+ static const Duration _defaultThrottleDuration = Duration(seconds: 3);
+ 
  SharedLocationService({
    required StreamChatClient client,
    LocationProvider? locationProvider,
+   Duration throttleDuration = _defaultThrottleDuration,
  })  : _client = client,
-       _locationProvider = locationProvider ?? LocationProvider();
+       _locationProvider = locationProvider ?? LocationProvider(),
+       _throttleDuration = throttleDuration;
  
+ final Duration _throttleDuration;

  // Later in _startTrackingLocation:
-    _positionSubscription = _locationProvider.positionStream
-        .throttleTime(const Duration(seconds: 3))
-        .listen(_onPositionUpdate);
+    _positionSubscription = _locationProvider.positionStream
+        .throttleTime(_throttleDuration)
+        .listen(_onPositionUpdate);
sample_app/lib/utils/location_provider.dart (1)

6-7: Consider making notification configuration configurable.

The notification title and text are hardcoded constants. Consider making them configurable through the constructor or a configuration method to allow customization.

sample_app/lib/widgets/location/location_attachment.dart (1)

206-206: Consider showing date for multi-day live locations.

The current format only shows time (e.g., "Live until 3:30 PM"). For locations shared for multiple days, consider including the date for clarity.

-              'Live until ${liveUntil.jm}',
+              'Live until ${_formatEndTime(sharingEndAt)}',

Add a helper method:

String _formatEndTime(DateTime endTime) {
  final now = DateTime.now();
  final jiffy = Jiffy.parseFromDateTime(endTime.toLocal());
  
  // If it's today, show only time
  if (endTime.day == now.day && endTime.month == now.month && endTime.year == now.year) {
    return jiffy.jm;
  }
  // If it's tomorrow
  if (endTime.difference(now).inDays == 1) {
    return 'tomorrow at ${jiffy.jm}';
  }
  // Otherwise show date and time
  return jiffy.format(pattern: 'MMM d at h:mm a');
}
sample_app/lib/widgets/location/location_picker_dialog.dart (1)

26-27: Improve hashCode implementation for better hash distribution.

The current implementation using XOR can lead to poor hash distribution and potential performance issues in hash-based collections.

-  @override
-  int get hashCode => endSharingAt.hashCode ^ coordinates.hashCode;
+  @override
+  int get hashCode => Object.hash(endSharingAt, coordinates);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74188e3 and b7c8550.

📒 Files selected for processing (41)
  • melos.yaml (3 hunks)
  • packages/stream_chat/lib/src/client/channel.dart (16 hunks)
  • packages/stream_chat/lib/src/client/client.dart (8 hunks)
  • packages/stream_chat/lib/src/client/event_resolvers.dart (3 hunks)
  • packages/stream_chat/lib/src/core/api/responses.dart (2 hunks)
  • packages/stream_chat/lib/src/core/api/responses.g.dart (1 hunks)
  • packages/stream_chat/lib/src/core/api/user_api.dart (2 hunks)
  • packages/stream_chat/lib/src/core/models/channel_config.dart (2 hunks)
  • packages/stream_chat/lib/src/core/models/channel_config.g.dart (2 hunks)
  • packages/stream_chat/lib/src/core/models/channel_model.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/channel_state.dart (5 hunks)
  • packages/stream_chat/lib/src/core/models/channel_state.g.dart (2 hunks)
  • packages/stream_chat/lib/src/core/models/location.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/location.g.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/location_coordinates.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/message.dart (8 hunks)
  • packages/stream_chat/lib/src/core/models/message.g.dart (1 hunks)
  • packages/stream_chat/lib/src/event_type.dart (2 hunks)
  • packages/stream_chat/lib/stream_chat.dart (1 hunks)
  • sample_app/android/app/src/main/AndroidManifest.xml (1 hunks)
  • sample_app/ios/Runner.xcodeproj/project.pbxproj (2 hunks)
  • sample_app/ios/Runner/Info.plist (2 hunks)
  • sample_app/lib/pages/channel_list_page.dart (4 hunks)
  • sample_app/lib/pages/channel_page.dart (7 hunks)
  • sample_app/lib/pages/thread_page.dart (3 hunks)
  • sample_app/lib/utils/app_config.dart (1 hunks)
  • sample_app/lib/utils/location_provider.dart (1 hunks)
  • sample_app/lib/utils/shared_location_service.dart (1 hunks)
  • sample_app/lib/widgets/channel_list.dart (2 hunks)
  • sample_app/lib/widgets/location/location_attachment.dart (1 hunks)
  • sample_app/lib/widgets/location/location_detail_dialog.dart (1 hunks)
  • sample_app/lib/widgets/location/location_picker_dialog.dart (1 hunks)
  • sample_app/lib/widgets/location/location_picker_option.dart (1 hunks)
  • sample_app/lib/widgets/location/location_user_marker.dart (1 hunks)
  • sample_app/lib/widgets/simple_map_view.dart (1 hunks)
  • sample_app/macos/Flutter/Flutter-Debug.xcconfig (0 hunks)
  • sample_app/macos/Flutter/Flutter-Release.xcconfig (0 hunks)
  • sample_app/macos/Runner/DebugProfile.entitlements (1 hunks)
  • sample_app/macos/Runner/Info.plist (1 hunks)
  • sample_app/macos/Runner/Release.entitlements (1 hunks)
  • sample_app/pubspec.yaml (1 hunks)
💤 Files with no reviewable changes (2)
  • sample_app/macos/Flutter/Flutter-Release.xcconfig
  • sample_app/macos/Flutter/Flutter-Debug.xcconfig
🧰 Additional context used
🪛 Gitleaks (8.26.0)
sample_app/lib/utils/app_config.dart

9-9: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: analyze
  • GitHub Check: test
  • GitHub Check: build (android)
🔇 Additional comments (64)
sample_app/macos/Runner/Release.entitlements (1)

11-12: Location entitlement added – validate runtime flow

Granting com.apple.security.personal-information.location is required for Core Location on macOS and looks correct.
Please make sure the app:

  1. Prompts the user with a matching NSLocationUsageDescription (already present in Info.plist).
  2. Fails gracefully when the user denies permission.
  3. Requests authorization only when the new location-sharing UI is actually used.
packages/stream_chat/lib/stream_chat.dart (1)

45-46: Publicly exporting the new location models LGTM

The new Location and LocationCoordinates models are now available from the top-level import.
No issues spotted; remember to bump the SDK’s public-API version accordingly.

packages/stream_chat/lib/src/core/models/channel_model.dart (1)

370-372: New shareLocation capability constant added

Constant is well-named, alphabetically placed, and follows the existing pattern.
Confirm that backend capability lists and client checks (ChannelCapabilityCheck) are updated in tandem.

melos.yaml (1)

28-28: LGTM! Dependencies properly added for location sharing features.

The new dependencies are well-chosen for the location sharing functionality:

  • avatar_glow for UI effects (likely for live location indicators)
  • flutter_map and flutter_map_animations for map rendering and animations
  • geolocator for location services
  • latlong2 for coordinate handling

All versions appear to be current and the additions are consistent with the PR objectives.

Also applies to: 48-49, 57-57, 67-67

sample_app/pubspec.yaml (1)

23-23: LGTM! Dependencies consistent with melos configuration.

The added dependencies align with the location sharing feature implementation:

  • Location services: geolocator, latlong2
  • Map functionality: flutter_map, flutter_map_animations
  • UI effects: avatar_glow
  • Reactive programming: rxdart (for location stream handling)

All versions are properly specified and follow the project's dependency management approach.

Also applies to: 31-32, 36-36, 38-38, 41-41

sample_app/ios/Runner.xcodeproj/project.pbxproj (1)

289-289: LGTM! iOS framework properly configured for location services.

The geolocator_apple.framework is correctly added to both input and output paths in the [CP] Embed Pods Frameworks build phase. This is necessary for iOS location functionality to work properly.

Also applies to: 334-334

sample_app/lib/utils/app_config.dart (1)

9-12: New user added successfully, but consider JWT token security.

The new leia_organa user is properly added to the default users configuration. However, the static analysis tool correctly identified that JWT tokens are exposed in the codebase. While this may be acceptable for a sample app, consider:

  1. Adding a code comment explaining this is for demo/testing purposes
  2. Ensuring these tokens have limited scope and expiration
  3. Using environment variables or secure configuration for production builds
sample_app/lib/pages/channel_list_page.dart (4)

20-20: LGTM! SharedLocationService import added for location functionality.

The import is correctly added to support the new location sharing features.


109-111: LGTM! SharedLocationService properly configured.

The service is correctly initialized with the StreamChatClient instance and marked as late final for proper lifecycle management.


164-164: LGTM! Proper service initialization in initState.

The location service is correctly initialized after calling super.initState(), following Flutter best practices for stateful widget initialization.

Also applies to: 179-179


185-185: LGTM! Proper service disposal in dispose.

The location service is correctly disposed before calling super.dispose(), ensuring proper cleanup of resources and preventing memory leaks.

packages/stream_chat/lib/src/core/api/responses.g.dart (1)

471-477: LGTM! Generated JSON deserialization follows expected pattern.

The new _$GetActiveLiveLocationsResponseFromJson function correctly deserializes the API response for active live locations. The implementation follows the same pattern as other response deserialization functions in the file.

packages/stream_chat/lib/src/core/models/channel_config.dart (2)

29-29: LGTM! Constructor parameter follows expected pattern.

The sharedLocations parameter is correctly added to the constructor with a sensible default value of false.


95-96: LGTM! Field declaration is well-documented and consistent.

The sharedLocations field follows the same pattern as other boolean configuration properties in the class, with clear documentation indicating its purpose.

sample_app/android/app/src/main/AndroidManifest.xml (1)

11-15: LGTM! Location permissions are correctly configured.

The added permissions are appropriate for the location sharing functionality:

  • FOREGROUND_SERVICE and FOREGROUND_SERVICE_LOCATION enable running background location services for live location updates
  • ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION provide the necessary location access permissions

The grouping and commenting make the purpose clear.

packages/stream_chat/lib/src/core/models/message.g.dart (1)

98-100: LGTM! Shared location deserialization follows expected pattern.

The sharedLocation field is correctly deserialized from the shared_location JSON key to a nullable Location object, following the same pattern as other optional fields in the message model.

packages/stream_chat/lib/src/core/models/channel_config.g.dart (2)

37-37: LGTM! Deserialization logic is correct and consistent.

The sharedLocations field is properly deserialized from the shared_locations JSON key with an appropriate default value of false.


61-61: LGTM! Serialization logic is correct and consistent.

The sharedLocations field is properly serialized to the shared_locations JSON key, maintaining consistency with the API contract.

packages/stream_chat/lib/src/core/api/responses.dart (2)

12-12: LGTM!

The Location model import is correctly added to support the new GetActiveLiveLocationsResponse class.


807-816: LGTM!

The GetActiveLiveLocationsResponse class follows the established patterns in the file:

  • Extends _BaseResponse consistently
  • Has proper JSON serialization with @JsonSerializable annotation
  • Includes clear documentation
  • Follows the naming convention used by other response classes
sample_app/ios/Runner/Info.plist (4)

30-31: LGTM!

The ITSAppUsesNonExemptEncryption key is correctly positioned and set to false, which is appropriate for most apps.


34-38: LGTM!

The NSAppTransportSecurity configuration allowing arbitrary loads is correctly positioned. However, ensure this is necessary for the app's functionality.


43-46: LGTM!

The location permission usage descriptions are well-written and clearly explain why location access is needed. Both NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription are properly configured for the chat location sharing feature.


57-57: LGTM!

The location background mode is correctly added to support live location sharing functionality. This allows the app to continue updating location even when in the background.

sample_app/lib/pages/thread_page.dart (4)

2-3: LGTM!

The location attachment imports are correctly added to support the new location sharing functionality.


48-53: LGTM!

The LocationAttachmentBuilder is well-configured with a proper tap handler that opens the location detail dialog. The implementation follows good separation of concerns.


71-75: LGTM!

The parentMessageBuilder properly integrates the location attachment builder, ensuring parent messages can display location attachments correctly.


77-82: LGTM!

The messageBuilder implementation is well-designed:

  • Properly integrates the location attachment builder
  • Disables edit functionality for location messages (good UX decision)
  • Maintains existing functionality while adding location support
packages/stream_chat/lib/src/core/models/channel_state.dart (4)

5-5: LGTM!

The Location model import is correctly added to support the new activeLiveLocations field.


33-33: LGTM!

The activeLiveLocations parameter is properly added to the constructor, maintaining consistency with the existing parameter list.


63-64: LGTM!

The activeLiveLocations field is well-implemented:

  • Properly typed as nullable List<Location>?
  • Includes clear documentation explaining its purpose
  • Follows the naming convention used by other fields

84-84: LGTM!

The copyWith method is properly updated to include the activeLiveLocations field:

  • Parameter is correctly added with proper nullable type
  • Implementation follows the existing pattern
  • Maintains consistency with other optional fields

Also applies to: 96-96

packages/stream_chat/lib/src/core/models/location_coordinates.dart (1)

1-33: Well-structured immutable data class!

The LocationCoordinates class follows Dart best practices with proper immutability, value equality through Equatable, and a clean API. The implementation is solid and consistent with the codebase patterns.

sample_app/lib/utils/shared_location_service.dart (1)

81-91: Good resource management in dispose method.

The dispose method properly cancels all subscriptions and resets the location provider, preventing memory leaks and ensuring clean shutdown.

packages/stream_chat/lib/src/event_type.dart (2)

125-126: Clean addition of poll event type.

The pollCreated constant follows the established naming conventions and is properly documented.


177-184: Well-structured location event types.

The location-related event constants (locationShared, locationUpdated, locationExpired) are well-named, properly documented, and follow the established patterns in the codebase.

packages/stream_chat/lib/src/core/models/location.g.dart (1)

1-38: Properly generated JSON serialization code.

The generated serialization code correctly handles nullable fields, date parsing, and conditional serialization. The use of modern Dart pattern matching syntax on line 37 is appropriate.

packages/stream_chat/lib/src/core/models/message.dart (3)

7-7: Proper import addition for location functionality.

The import of the Location model is correctly added to support the new shared location feature.


321-326: Well-documented shared location field.

The sharedLocation field is properly documented and correctly annotated with @JsonKey(includeToJson: false) to exclude it from JSON serialization, which is appropriate for this field.


73-73: Consistent integration of shared location field.

The sharedLocation field is consistently integrated across all relevant methods (constructor, copyWith, merge, props) and properly added to the topLevelFields array. The implementation follows the established patterns in the Message class.

Also applies to: 376-376, 439-439, 522-522, 568-568, 634-634

packages/stream_chat/lib/src/core/models/channel_state.g.dart (2)

35-37: JSON deserialization implementation looks correct.

The deserialization logic for activeLiveLocations follows the established pattern used by other list fields in this generated file and properly handles nullable lists.


52-53: JSON serialization implementation looks correct.

The serialization logic correctly maps the activeLiveLocations field to the active_live_locations JSON key and handles nullable lists appropriately.

sample_app/lib/widgets/location/location_user_marker.dart (2)

22-48: Excellent use of pattern matching for conditional rendering.

The logic correctly handles different states of shared locations with appropriate UI representations:

  • Live locations with users get glowing avatars
  • Expired locations get regular avatars without glow
  • Proper fallback to person pin icon for other cases

25-40: Well-structured avatar presentation with consistent theming.

The avatar implementation with border, overlay, and size constraints follows Material Design principles and integrates well with the Stream Chat theme system.

sample_app/lib/utils/location_provider.dart (1)

61-67: Good practice: Preventing duplicate subscriptions.

The subscription cancellation before creating a new one prevents memory leaks and duplicate listeners. The error forwarding ensures proper error handling in the broadcast stream.

sample_app/lib/widgets/location/location_picker_option.dart (2)

34-40: Proper use of permission request lock and async dialog handling.

The implementation correctly uses runInPermissionRequestLock to handle permission requests and properly awaits the dialog result before calling the callback.


5-12: Clean implementation of custom attachment picker types.

The LocationPickerType and LocationPicked classes properly extend the custom attachment picker framework with minimal, focused implementations.

packages/stream_chat/lib/src/core/api/user_api.dart (3)

94-101: Clean implementation of live locations retrieval.

The getActiveLiveLocations() method follows the established pattern for GET requests in this class and properly handles the response parsing.


103-122: Well-structured live location update method.

The updateLiveLocation() method correctly:

  • Uses PUT for updates (appropriate HTTP verb)
  • Conditionally includes optional parameters in the request body
  • Handles DateTime serialization with ISO 8601 format
  • Uses proper JSON encoding for the request data

115-117: Proper use of pattern matching for conditional JSON fields.

The conditional inclusion of latitude/longitude using pattern matching (if (location?.latitude case final latitude)) is clean and follows modern Dart patterns.

sample_app/lib/widgets/simple_map_view.dart (2)

13-40: Well-structured widget with good defaults.

The SimpleMapView widget is properly designed with sensible defaults and theme integration.


151-153: Clean extension method implementation.

The extension properly converts between coordinate types.

packages/stream_chat/lib/src/core/models/location.dart (1)

1-156: Well-designed location model with comprehensive features.

The model properly supports both static and live locations with appropriate JSON serialization and computed properties. Good documentation and proper use of Equatable.

sample_app/lib/pages/channel_page.dart (1)

259-310: Good integration of location attachment features.

The location attachment builder is properly integrated with appropriate tap handling and edit restrictions for location messages.

packages/stream_chat/lib/src/client/event_resolvers.dart (1)

4-129: Well-implemented event resolvers with clear logic.

The new location event resolvers and refactored poll resolvers follow best practices with proper null checks, type validation, and clear documentation. The consistent pattern makes the code easy to understand and maintain.

sample_app/lib/widgets/location/location_attachment.dart (1)

14-51: Clean attachment builder implementation.

The LocationAttachmentBuilder properly extends the base class and uses modern Dart features like pattern matching effectively.

packages/stream_chat/lib/src/client/channel.dart (8)

1251-1251: LGTM!

Making messageText optional for polls is a reasonable API improvement.


2864-2934: Well-structured reaction event handling refactoring

The refactored reaction event handlers provide clearer logic for updating reactions across both channel and thread messages while preserving ownReactions state.


2530-2540: LGTM!

Clean implementation of poll creation event handler with proper validation.


2817-2863: Well-implemented location event handlers

The location event handlers follow consistent patterns with proper null checking and message lookup logic.


3177-3204: LGTM!

Well-implemented location state management with proper deduplication and filtering logic.


3153-3176: Good improvement to pinned message handling

The refactoring properly filters out deleted messages from the pinned messages list, preventing UI inconsistencies.


3951-3955: LGTM!

Properly implemented capability check following the established pattern.


2967-2979: Clean refactoring of message addition logic

The extracted addNewMessage method improves code reusability and properly handles thread-only messages and unread count updates.

@xsahil03x xsahil03x marked this pull request as ready for review July 14, 2025 19:01
Copy link

codecov bot commented Jul 14, 2025

Codecov Report

Attention: Patch coverage is 79.78142% with 74 lines in your changes missing coverage. Please review.

Please upload report for BASE (v10.0.0@74188e3). Learn more about missing BASE report.

Files with missing lines Patch % Lines
packages/stream_chat/lib/src/client/channel.dart 72.30% 54 Missing ⚠️
packages/stream_chat/lib/src/client/client.dart 81.33% 14 Missing ⚠️
...chat/lib/src/core/models/location_coordinates.dart 14.28% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             v10.0.0    #2305   +/-   ##
==========================================
  Coverage           ?   64.22%           
==========================================
  Files              ?      416           
  Lines              ?    25923           
  Branches           ?        0           
==========================================
  Hits               ?    16648           
  Misses             ?     9275           
  Partials           ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@xsahil03x xsahil03x requested a review from renefloor July 14, 2025 22:38
Comment on lines +2240 to +2248
/* Start of location events */

_listenLocationShared();

_listenLocationUpdated();

_listenLocationExpired();

/* End of location events */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use region you can easily collapse these in intellij and android studio. For VS code you might need a plugin

end region doesn't need a name, but can be done to make it more clear.

    //#region Location events

    (...)

    //#endregion Location events
    //#endregion 

@@ -2449,6 +2531,17 @@ class ChannelClientState {
return threadMessage;
}

void _listenPollCreated() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this and the reactions added because we currently have a bug there?

@@ -2174,6 +2234,103 @@ class ClientState {
);
}

void _listenLocationShared() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client and channel files are very large. I wonder if we for example can put all location related code to separates files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants