Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into ishita/fix_join_group…
Browse files Browse the repository at this point in the history
…_code_capitilisation

# Conflicts:
#	app/pubspec.lock
  • Loading branch information
cp-ishita-g committed Dec 24, 2024
2 parents ec274f6 + 59a4eb1 commit b268ffc
Show file tree
Hide file tree
Showing 12 changed files with 246 additions and 201 deletions.
2 changes: 1 addition & 1 deletion app/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -461,4 +461,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 9bf7626a50066852dd21123c4db8e9fe30622485

COCOAPODS: 1.15.2
COCOAPODS: 1.16.2
8 changes: 4 additions & 4 deletions app/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
9A5FB9BC2D005B6600F14D83 /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A5FB9BB2D005B5F00F14D83 /* LocationManager.swift */; };
9A95678A2D117BD100F43643 /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A9567892D117BD000F43643 /* LocationManager.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -71,7 +71,7 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9A5FB9BB2D005B5F00F14D83 /* LocationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = "<group>"; };
9A9567892D117BD000F43643 /* LocationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = "<group>"; };
B09B463B48F6F6C17BEDC2CB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -138,7 +138,7 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
9A5FB9BB2D005B5F00F14D83 /* LocationManager.swift */,
9A9567892D117BD000F43643 /* LocationManager.swift */,
63CBD3CD2C5A08DC00283B36 /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
Expand Down Expand Up @@ -431,10 +431,10 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9A5FB9BC2D005B6600F14D83 /* LocationManager.swift in Sources */,
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
6371AA752C7D958A00C5843A /* GeofencePlugin.swift in Sources */,
9A95678A2D117BD100F43643 /* LocationManager.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
51 changes: 30 additions & 21 deletions app/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,19 @@ import Combine
geofencePluginRegistration()
registerLocationChannel()

let locationsHandler = LocationsHandler.shared
if locationsHandler.updatesStarted {
locationsHandler.startLocationUpdates()
let liveLocationUpdates = LocationManager.shared
if liveLocationUpdates.updatesStarted {
liveLocationUpdates.startLocationUpdates()
}

locationsHandler.$lastLocation.sink(receiveValue: { [weak self] location in

let locationData: [String: Any] = [
"latitude": location.coordinate.latitude,
"longitude": location.coordinate.longitude,
"timestamp": location.timestamp.timeIntervalSince1970 * 1000,
]
if liveLocationUpdates.bgActivitySessionStarted {
liveLocationUpdates.bgActivitySessionStarted = true
}

guard let self = self else { return }
if let controller = window?.rootViewController as? FlutterViewController {
let methodChannel = FlutterMethodChannel(name: "com.grouptrack/location", binaryMessenger: controller.binaryMessenger)
methodChannel.invokeMethod("onLocationUpdate", arguments: locationData)
}
liveLocationUpdates.$lastLocation.sink(receiveValue: { [weak self] location in
self?.sendLocationToFlutter(location: location)
}).store(in: &cancellables)

GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
Expand All @@ -67,12 +60,29 @@ import Combine
(call: FlutterMethodCall, result: @escaping FlutterResult) in

if call.method == "getCurrentLocation" {
LocationsHandler.shared.getCurrentLocation(result: result)
LocationManager.shared.getCurrentLocation(result: result)
} else {
result(FlutterMethodNotImplemented)
}
}
}

func sendLocationToFlutter(location: CLLocation) {

let locationData: [String: Any] = [
"latitude": location.coordinate.latitude,
"longitude": location.coordinate.longitude,
"timestamp": location.timestamp.timeIntervalSince1970 * 1000,
]

DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
if let controller = self.window?.rootViewController as? FlutterViewController {
let methodChannel = FlutterMethodChannel(name: "com.grouptrack/location", binaryMessenger: controller.binaryMessenger)
methodChannel.invokeMethod("onLocationUpdate", arguments: locationData)
}
}
}
}

// Geofence methods
Expand All @@ -87,18 +97,17 @@ extension AppDelegate {
(call: FlutterMethodCall, result: @escaping FlutterResult) in
guard self != nil else { return }
if call.method == "startTracking" {
LocationsHandler.shared.startLocationUpdates()
LocationManager.shared.startLocationUpdates()
result(true)
} else if call.method == "stopTracking" {
LocationsHandler.shared.stopLocationUpdates()
LocationManager.shared.stopLocationUpdates()
result(true)
} else {
result(FlutterMethodNotImplemented)
}
}
}



private func geofencePluginRegistration() {
let controller: FlutterViewController =
window?.rootViewController as! FlutterViewController
Expand Down
108 changes: 84 additions & 24 deletions app/ios/Runner/LocationManager.swift
Original file line number Diff line number Diff line change
@@ -1,46 +1,114 @@
//
// LocationManager.swift
// UnifiedLocationManager.swift
// Runner
//
// Created by Radhika S on 04/12/24.
// Created by Radhika S on 17/12/24.
//


import CoreLocation
import Combine

class LocationsHandler: NSObject, ObservableObject, CLLocationManagerDelegate {
static let shared = LocationsHandler()
private let manager: CLLocationManager
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
static let shared = LocationManager()

@Published var lastLocation = CLLocation()
private var manager: CLLocationManager
private var bgActivitySession: Any?

private let distanceThreshold: CLLocationDistance = 10.0

@Published var lastLocation = CLLocation()
@Published
var updatesStarted: Bool = UserDefaults.standard.bool(forKey: "liveLocationUpdatesStarted") {
didSet {
UserDefaults.standard.set(updatesStarted, forKey: "liveLocationUpdatesStarted")
}
}

@Published
var bgActivitySessionStarted: Bool = UserDefaults.standard.bool(forKey: "BGActivitySessionStarted") {
didSet {
if #available(iOS 17.0, *) {
bgActivitySessionStarted ? self.bgActivitySession = CLBackgroundActivitySession(): (self.bgActivitySession as? CLBackgroundActivitySession)?.invalidate()
}
UserDefaults.standard.set(bgActivitySessionStarted, forKey: "BGActivitySessionStarted")
}
}

private override init() {
self.manager = CLLocationManager()
super.init()
manager.delegate = self
manager.distanceFilter = 10
manager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
manager.allowsBackgroundLocationUpdates = true
manager.pausesLocationUpdatesAutomatically = false
if #unavailable(iOS 17.0) {
manager.delegate = self
manager.distanceFilter = 10
manager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
manager.allowsBackgroundLocationUpdates = true
manager.pausesLocationUpdatesAutomatically = false
}
}

func startLocationUpdates() {
if self.manager.authorizationStatus == .notDetermined {
guard updatesStarted else { return }
if manager.authorizationStatus == .notDetermined {
return
}
updatesStarted = true
manager.startUpdatingLocation()
if #available(iOS 17.0, *) {
startLiveLocationUpdates()
} else {
manager.startUpdatingLocation()
}

}

func stopLocationUpdates() {
manager.stopUpdatingLocation()
updatesStarted = false
self.updatesStarted = false
if #available(iOS 17.0, *) {
(bgActivitySession as? CLBackgroundActivitySession)?.invalidate()
bgActivitySessionStarted = false
bgActivitySession = nil
} else {
manager.stopUpdatingLocation()
}
}

@available(iOS 17.0, *)
private func startLiveLocationUpdates() {

Task {
do {
self.bgActivitySession = CLBackgroundActivitySession()

let locationUpdates = CLLocationUpdate.liveUpdates()
.filter { [weak self] update in
guard let self = self else { return false }
let distanceMoved = (update.location?.distance(from: lastLocation) ?? 0.0)
let hasLastLocation = lastLocation.coordinate.latitude != 0 && lastLocation.coordinate.longitude != 0

return distanceMoved >= distanceThreshold || !hasLastLocation
}

for try await update in locationUpdates {
if !self.updatesStarted { break }
if let currentLocation = update.location {
onLocationChanged(location: currentLocation)
if update.isStationary { break }
}

}
} catch {
print("Error with live updates: \(error.localizedDescription)")
}
}
}

private func onLocationChanged(location: CLLocation) {
let lastUpdateTime = lastLocation.timestamp
let hasLastLocation = lastLocation.coordinate.latitude != 0 && lastLocation.coordinate.longitude != 0
let timeInterval = Date().timeIntervalSince(lastUpdateTime)
if (timeInterval >= 10 || !hasLastLocation) && lastLocation != location {
lastLocation = location
}
}

func locationManagerDidChangeAuthorization(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
Expand All @@ -55,15 +123,7 @@ class LocationsHandler: NSObject, ObservableObject, CLLocationManagerDelegate {

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let currentLocation = locations.last else { return }

let lastUpdateTime = lastLocation.timestamp

let timeInterval = Date().timeIntervalSince(lastUpdateTime)
if timeInterval < 10 {
return
}

lastLocation = currentLocation
onLocationChanged(location: currentLocation)
}

func getCurrentLocation(result: @escaping FlutterResult) {
Expand Down
53 changes: 16 additions & 37 deletions app/lib/ui/flow/home/map/map_view_model.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:io';
import 'dart:ui' as ui;

import 'package:data/api/auth/auth_models.dart';
Expand All @@ -17,7 +16,6 @@ import 'package:flutter/services.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:image/image.dart' as img;

Expand Down Expand Up @@ -54,16 +52,16 @@ class MapViewNotifier extends StateNotifier<MapViewState> {
StreamSubscription<List<ApiPlace>>? _placeSubscription;

MapViewNotifier(
this._currentUser,
this.spaceService,
this.placeService,
this.permissionService,
this.locationManager,
this.authService,
this.mapTypeController,
this._currentUser,
this.spaceService,
this.placeService,
this.permissionService,
this.locationManager,
this.authService,
this.mapTypeController,
) : super(MapViewState(mapType: mapTypeController.state)) {
checkUserPermission();
_getCurrentUserLastLocation();
getUserLastLocation();
}

void loadData(String? spaceId) {
Expand All @@ -89,8 +87,9 @@ class MapViewNotifier extends StateNotifier<MapViewState> {
if (state.loading) return;
try {
state = state.copyWith(loading: true, selectedUser: null);
await _userInfoSubscription?.cancel();
_userInfoSubscription = spaceService.getMemberWithLocation(spaceId).listen((userInfo) {
_userInfoSubscription?.cancel();
_userInfoSubscription =
spaceService.getMemberWithLocation(spaceId).listen((userInfo) {
state = state.copyWith(userInfo: userInfo, loading: false);
_userMapPositions(userInfo);
});
Expand All @@ -106,8 +105,9 @@ class MapViewNotifier extends StateNotifier<MapViewState> {

void _listenPlaces(String spaceId) async {
try {
await _placeSubscription?.cancel();
_placeSubscription = placeService.getAllPlacesStream(spaceId).listen((places) {
_placeSubscription?.cancel();
_placeSubscription =
placeService.getAllPlacesStream(spaceId).listen((places) {
state = state.copyWith(places: places);
});
} catch (error, stack) {
Expand Down Expand Up @@ -161,8 +161,8 @@ class MapViewNotifier extends StateNotifier<MapViewState> {
if (image != null) {
final resizedImage = img.copyResize(
image,
width: (markerSize/1.25).toInt(),
height: (markerSize/1.25).toInt(),
width: (markerSize / 1.25).toInt(),
height: (markerSize / 1.25).toInt(),
);
final circularImage = img.copyCropCircle(resizedImage);

Expand Down Expand Up @@ -325,27 +325,6 @@ class MapViewNotifier extends StateNotifier<MapViewState> {
}
}

void _getCurrentUserLastLocation() async {
try {
final location = await _currentUserLocation();
state = state.copyWith(currentUserLocation: LatLng(location.latitude, location.longitude));
} catch (error, stack) {
logger.e('MapViewNotifier: error while get current location',
error: error, stackTrace: stack);
}
}

Future<LatLng> _currentUserLocation() async {
if (Platform.isIOS) {
const platform = MethodChannel('com.grouptrack/current_location');
final locationFromIOS = await platform.invokeMethod('getCurrentLocation');
return LatLng(locationFromIOS['latitude'], locationFromIOS['longitude']);
} else {
var location = await Geolocator.getCurrentPosition();
return LatLng(location.latitude, location.longitude);
}
}

void setMapType(String type) {
mapTypeController.state = type;
state = state.copyWith(mapType: type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class JourneyTimelineViewModel extends StateNotifier<JourneyTimelineState> {
}

void loadMoreJourney() async {
if (state.hasMore && !state.appending) {
if (state.hasMore && !state.appending && !state.isLoading) {
await Future.delayed(const Duration(milliseconds: 200));
_loadJourney(loadMore: true);
}
Expand Down
Loading

0 comments on commit b268ffc

Please sign in to comment.