stream-chat-swift icon indicating copy to clipboard operation
stream-chat-swift copied to clipboard

Add Static Location and Live Location Support

Open nuno-vieira opened this issue 1 year ago • 5 comments

🔗 Issue Links

Resolves https://linear.app/stream/issue/IOS-578/location-attachment

🎯 Goal

Adds support for static and live location attachments in the Low-Level Client SDK.

The UI has been implemented in the Demo App to demonstrate how to use the new location APIs.

📝 Summary

New APIs:

  • ChatChannelController
    • sendStaticLocation() - Sends a static location message to the channel.
    • startLiveLocationSharing() - Starts a live location-sharing message in the channel.
  • ChatMessageController
    • partialUpdateMessage() - Updates the message partially. (It was missing from the SDK)
    • stopLiveLocationSharing() - Stops sharing the live location attachment if it has one.
  • CurrentChatUserController
    • updateLiveLocation() - Updates the location of all active live location messages for the current user.
    • loadActiveLiveLocationMessages() - Loads all active locations of the current user. Should be called only once.
  • CurrentChatUserControllerDelegate
    • didStartSharingLiveLocation() - Notifies whenever the current user is sharing any live location.
    • didStopSharingLiveLocation() - Notifies whenever the current user stopped/expired all live locations.
    • didChangeActiveLiveLocationMessages() - Notifies whenever the current user's live location messages change.
    • didFailToUpdateLiveLocation() - Called whenever a live location failed to update. Mostly should be used for debugging.
  • Throttler
    • The Throttler was part of the UI SDK somehow, so it was moved to the LLC and made public like the Debouncer.
  • ChatMessage
    • sharedLocation - Returns the location if it has one, either live or static.

🛠 Implementation

The SDK at the moment only handles updating the location attachments. The location tracking should be provided by the App. Something like the LocationProvider in the Demo App should be implemented by the customer.

Creating a location attachment

In order to create a new message with a location attachment, the developer can use the ChannelController.sendStaticLocation() or the ChannelController.startSharingLiveLocation().

Sending location updates (Live Location)

The customer is responsible for sending new location updates to the SDK. This is done through the CurrentChatUserController.updateLiveLocation() method. This method will update all the current user's active location attachments. Internally, it uses a activeLiveLocationMessagesObserver that keeps track of the active location attachments of the current user. These changes are also available to the customer through the CurrentChatUserControllerDelegate to make it easier for the developer to know when it should track location updates and when it can turn them off.

Stopping live location attachment

  • ChatMessageController.stopLiveLocationSharing(): Stops a live location attachment in the given message if it has an active location attachment.

Overall Data Flow

sequenceDiagram
    participant App
    participant LocationProvider
    participant SDK
    participant Backend

    Note over App,Backend: Start New Location Share
    App->>LocationProvider: getCurrentLocation()
    LocationProvider-->>App: Return current location
    App->>SDK: startLiveLocationSharing(location)
    SDK->>Backend: Create location message
    Backend-->>SDK: Confirm creation
    SDK->>App: onStartLiveLocationSharing()
    App->>LocationProvider: startMonitoring()

    Note over App,Backend: Location Updates
    LocationProvider->>LocationProvider: Monitor location changes
    LocationProvider->>SDK: didUpdateLocation(location)
    SDK->>Backend: updateLiveLocation
    Note over SDK: 3s Throttling

    Note over App,Backend: Stop Location Share
    App->>SDK: stopLiveLocationSharing()
    SDK->>Backend: Stop location sharing
    Backend-->>SDK: Confirm stop
    SDK->>App: onStopLiveLocationSharing()
    App->>LocationProvider: stopMonitoring()

🎨 Showcase

Static Live

🧪 Manual Testing Notes

Note: To simulate live location updates in the Simulator, with the Simulator selected, Go to Features > Location > City Bicycle Ride in the top bar of the Mac.

Precondition: Select the Frankfurt C2 environemnt to test the location feature.

Send a static location message ✅
  1. Open a channel with location sharing enabled
  2. Tap on the Attachments Icon
  3. Tap "Send Current Location"
  4. It should render an image snapshot of a map with a Pin
  5. Tapping the attachment should open the map full screen with the Pin
Send a live location message ✅
  1. Open a channel with location sharing enabled
  2. Tap on the Attachments Icon
  3. Tap "Share Live Location"
  4. Set an end time
  5. It should render an image of the map with the avatar of the user in it and a button saying “Stop Sharing”
    • The map is just a static image (Does not update live)
  6. Tapping the attachment should open the map with the user's avatar, and the user's avatar should move when the location updates.
  7. Tapping the "Stop Sharing" button should stop sharing the live location.
  8. It should update the UI, and a label with “Live location ended” appears.
  9. In the full-screen map view, the avatar should not move anymore.
Receiving a live location message ✅
  1. Share a live location attachment from another user
  2. The receiving user should see the location message with “Live until XXX” date.
  3. Once the location has reached the end, it should update the message with “Live location ended”
  4. The same behaviour should happen if the user is in the full-screen map view.
  5. In the full-screen map view, the avatar should not move anymore.
Send a live location message when one from the current user is already active ✅
  1. Open a channel with location sharing enabled
  2. Tap on the Attachments Icon
  3. Tap "Share Live Location"
  4. Set an end time
  5. It should render an image of the map with the avatar of the user in it and a button saying “Stop Sharing”
  6. Send another live location
  7. The new live location message should be sent, and the previous one should stop.
Active live location is ended when the last update is after expiration ✅
  1. Share a live location attachment with a 1-minute expiration
  2. The user keeps updating the location
  3. When the last update has already passed the expiration, it should update to “Live location ended”
  4. The same should happen in the full-screen map view.
Active live location is ended after the expiration is reached ✅
  1. Share a live location attachment with a 1-minute expiration
  2. The user is still, so no location updates are being sent to the server
  3. When the 1-minute is reached, the UI should update to “Live Location Ended”
  4. The same should happen in the full-screen map view.
  5. The location monitoring should also be stopped
Active live location from another user ends after the expiration is reached ✅
  1. Share a live location attachment with a 1-minute expiration with User A
  2. User B receive the live location in the message list.
  3. User A is still, so no location updates are being sent to the server
  4. When the 1-minute is reached, the UI from User B should update to “Live Location Ended” ❌
  5. The same should happen in the full-screen map view. ❌

☑️ Contributor Checklist

  • [x] I have signed the Stream CLA (required)
  • [x] This change should be manually QAed
  • [x] Changelog is updated with client-facing changes
  • [ ] Changelog is updated with new localization keys
  • [x] New code is covered by unit tests
  • [x] Comparison screenshots added for visual changes
  • [ ] Affected documentation updated (docusaurus, tutorial, CMS)

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced comprehensive location sharing support, including static and live location sharing in chat messages.
    • Added the ability to send, update, and stop live location sharing within chat channels.
    • Enhanced message and channel models to display and manage shared locations.
    • New UI components for viewing and controlling shared locations, including live status indicators, map previews, user annotations, and a control banner.
    • Added partial message update functionality for selective content and attachment updates.
    • Added delegate callbacks and controller methods for live location lifecycle events.
    • Added a location provider to manage device location services and permissions.
    • Added background worker to track active live location end times and update states accordingly.
  • Improvements

    • Updated privacy settings and permissions to support location access and background location updates.
    • Expanded channel capabilities to indicate and control location sharing permissions.
    • Enhanced message actions to disable editing for location messages.
    • Improved UI handling for location attachments and live location sharing controls.
    • Added throttling to live location updates to optimize network usage.
    • Refined snapshot caching and UI updates for location previews.
    • Reorganized and extended app configuration and plist for location sharing.
  • Bug Fixes

    • Improved handling and filtering of live location messages to ensure accurate state and error reporting.
  • Tests

    • Added extensive test coverage for location sharing, partial message updates, database persistence, API interactions, and error handling.
    • Added tests for live location lifecycle, end time tracking, and message update scenarios.
  • Chores

    • Updated documentation, changelogs, configuration files, and test data to reflect new location sharing features and permissions.

nuno-vieira avatar Dec 13 '24 02:12 nuno-vieira

1 Warning
:warning: Big PR

Generated by :no_entry_sign: Danger

github-actions[bot] avatar Jan 03 '25 22:01 github-actions[bot]

SDK Size

title develop branch diff status
StreamChat 7.55 MB 7.87 MB +327 KB 🟡
StreamChatUI 4.78 MB 4.84 MB +64 KB 🟢

Stream-SDK-Bot avatar Jan 03 '25 22:01 Stream-SDK-Bot

Walkthrough

This change introduces comprehensive location sharing support to the StreamChat iOS SDK and DemoApp. It adds static and live location sharing features, including new models, API endpoints, database entities, and UI components. The update also modifies controllers, repositories, and test suites to support sending, updating, and displaying location messages, as well as managing live location sharing lifecycles.

Changes

File(s) / Group Change Summary
CHANGELOG.md Documents new location sharing features and related API additions.
DemoApp/Info.plist Adds location usage descriptions, background location mode, and reorganizes privacy keys.
DemoApp/LocationProvider.swift Adds a singleton for managing location permissions and updates.
DemoApp/Screens/* Enables location attachments by default; integrates live location sharing lifecycle into tab bar controller.
DemoApp/StreamChat/Components/CustomAttachments/LocationAttachment/* Removes old location attachment payloads; refactors and extends UI for live/static location display, adds user annotation and status views, and updates tap handling for new location model.
DemoApp/StreamChat/Components/CustomAttachments/* Updates attachment view logic to use new location model; disables editing for location messages; adds channel list subtitle for location messages.
DemoApp/StreamChat/StreamChatWrapper+DemoApp.swift Removes old location attachment injector registration.
Sources/StreamChat/APIClient/Endpoints/* Adds endpoints and payloads for location sharing; supports partial message updates and live location management.
Sources/StreamChat/Controllers/* Adds methods for sending static/live location, updating, and stopping live location sharing; expands delegate protocols for location events.
Sources/StreamChat/Database/DTOs/*, StreamChatModel.xcdatamodeld Adds new Core Data entities and relationships for shared locations; supports storing, fetching, and converting live location data.
Sources/StreamChat/Models/* Introduces LocationInfo, SharedLocation, and NewLocationInfo structs; extends ChatMessage and ChatChannel for location support.
Sources/StreamChat/Repositories/MessageRepository.swift Adds method to fetch current user's active live location messages.
Sources/StreamChat/Utils/Throttler.swift Makes throttler public for external use.
Sources/StreamChat/Workers/* Adds live location update/stop logic and partial message update support.
TestTools/StreamChatTestTools/* Updates mocks, dummies, and test data to support new location fields and APIs.
Tests/StreamChatTests/* Adds extensive tests for location sharing features, including controller, repository, database, and API endpoint coverage.
StreamChat.xcodeproj/project.pbxproj Removes old location files, adds new ones, and updates project structure for location features.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DemoApp
    participant LocationProvider
    participant ChatChannelController
    participant StreamChat API
    participant Database

    User->>DemoApp: Tap "Send Location"
    DemoApp->>LocationProvider: getCurrentLocation()
    LocationProvider-->>DemoApp: CLLocation
    DemoApp->>ChatChannelController: sendStaticLocation(location, ...)
    ChatChannelController->>StreamChat API: POST /messages with location
    StreamChat API-->>ChatChannelController: Message with location
    ChatChannelController->>Database: Save message with location
    Database-->>DemoApp: Updated message list
    DemoApp-->>User: Show location message in chat
sequenceDiagram
    participant User
    participant DemoApp
    participant LocationProvider
    participant CurrentChatUserController
    participant ChatChannelController
    participant StreamChat API
    participant Database

    User->>DemoApp: Tap "Share Live Location"
    DemoApp->>LocationProvider: getCurrentLocation()
    LocationProvider-->>DemoApp: CLLocation
    DemoApp->>ChatChannelController: startLiveLocationSharing(location, endDate, ...)
    ChatChannelController->>StreamChat API: POST /messages with live location
    StreamChat API-->>ChatChannelController: Message with live location
    ChatChannelController->>Database: Save live location message
    DemoApp->>CurrentChatUserController: loadActiveLiveLocationMessages()
    CurrentChatUserController->>StreamChat API: GET /users/live_locations
    StreamChat API-->>CurrentChatUserController: Active live locations
    CurrentChatUserController->>Database: Save active live locations
    LocationProvider->>CurrentChatUserController: on location update
    CurrentChatUserController->>StreamChat API: PUT /users/live_locations (update)
    StreamChat API-->>CurrentChatUserController: Updated location
    CurrentChatUserController->>Database: Update location message
    DemoApp-->>User: Show live location updates in chat

Assessment against linked issues

Objective Addressed Explanation
Implement location attachment and sharing (IOS-578)
Support static and live location sharing, including sending, updating, and stopping sharing (IOS-578)
Add new models, endpoints, database entities, and UI for location features (IOS-578)
Provide delegate callbacks and error handling for location sharing lifecycle (IOS-578)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
None found

Suggested reviewers

  • martinmitrevski
  • laevandus

Poem

A bunny hopped in with a map in its paw,
Sharing its location, without a flaw!
Now live or static, your whereabouts gleam,
In chat bubbles bright, on every team.
With code so robust, and tests that delight,
This rabbit says: “Location sharing’s out of sight!”
🗺️🐇✨

✨ Finishing Touches
  • [ ] 📝 Generate Docstrings

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.

coderabbitai[bot] avatar Jun 02 '25 14:06 coderabbitai[bot]