Skip to content

Commit

Permalink
Merge pull request #38 from canopas/fix-use-live-location
Browse files Browse the repository at this point in the history
Fix use live location
  • Loading branch information
kaushiksaliya authored Jul 19, 2024
2 parents 0f8dc74 + aff797d commit 243b61d
Show file tree
Hide file tree
Showing 18 changed files with 335 additions and 42 deletions.
8 changes: 8 additions & 0 deletions app/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<application
android:label="Your space"
Expand Down Expand Up @@ -42,6 +43,13 @@
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}" />

<service
android:enabled="true"
android:exported="true"
android:name="id.flutter.flutter_background_service.BackgroundService"
android:foregroundServiceType="location"
/>

<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
Expand Down
1 change: 1 addition & 0 deletions app/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false
id "com.google.gms.google-services" version "4.3.15" apply false
}

include ":app"
22 changes: 22 additions & 0 deletions app/firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"flutter": {
"platforms": {
"android": {
"default": {
"projectId": "yourspace-regional",
"appId": "1:406838982484:android:009eb33bb8f4ef583afac1",
"fileOutput": "android/app/google-services.json"
}
},
"dart": {
"lib/firebase_options.dart": {
"projectId": "yourspace-regional",
"configurations": {
"android": "1:406838982484:android:009eb33bb8f4ef583afac1",
"ios": "1:406838982484:ios:1f872619a1a0648f3afac1"
}
}
}
}
}
}
95 changes: 93 additions & 2 deletions app/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:data/service/location_manager.dart';
import 'package:data/service/location_service.dart';
import 'package:data/storage/preferences_provider.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:yourspace_flutter/firebase_options.dart';
import 'package:yourspace_flutter/ui/app.dart';


void main() async {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isAndroid) {
Expand All @@ -18,6 +26,11 @@ void main() async {
}

final container = await _initContainer();
final userId = await _getUserIdFromPreferences();
final isLocationPermission = await Permission.location.isGranted;
if (userId != null && isLocationPermission) {
startService(userId);
}

runApp(
UncontrolledProviderScope(container: container, child: const App()),
Expand All @@ -35,4 +48,82 @@ Future<ProviderContainer> _initContainer() async {
],
);
return container;
}
}

Future<String?> _getUserIdFromPreferences() async {
final prefs = await SharedPreferences.getInstance();
final encodedUser = prefs.getString("user_account");
if (encodedUser != null) {
final user = jsonDecode(encodedUser);
return user['id'];
}
return null;
}

void startService(String userId) async {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
onStart: onStart,
autoStart: true,
isForegroundMode: true,
),
iosConfiguration: IosConfiguration(
autoStart: true,
onForeground: onStart,
onBackground: onIosBackground,
),
);
service.startService();
}

Future<void> onStart(ServiceInstance service) async {
WidgetsFlutterBinding.ensureInitialized();

if (service is AndroidServiceInstance) {
service.setForegroundNotificationInfo(
title: "Background Location Service",
content: "Your location is being tracked",
);
service.setAsForegroundService();
}

await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
final locationService = LocationService(FirebaseFirestore.instance);
final userId = await _getUserIdFromPreferences();

if (userId != null) {
_startLocationUpdates(userId, locationService);
}

service.on('stopService').listen((event) {
service.stopSelf();
});
}

void _startLocationUpdates(String userId, LocationService locationService) {
Timer? timer;
Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: LOCATION_UPDATE_DISTANCE,
),
).listen((position) {
final location = LatLng(position.latitude, position.longitude);
timer?.cancel();
timer = Timer(const Duration(milliseconds: 5000), () {
locationService.saveCurrentLocation(
userId,
location.latitude,
location.longitude,
DateTime.now().millisecondsSinceEpoch,
0,
);
});
});
}

bool onIosBackground(ServiceInstance service) {
onStart(service);
return true;
}
2 changes: 1 addition & 1 deletion app/lib/ui/flow/home/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
return AppPage(
body: ResumeDetector(
onResume: () {
if(state.selectedSpace != null){
if(state.selectedSpace != null) {
notifier.getAllSpace();
notifier.showBatteryOptimizationDialog();
mapNotifier.checkUserPermission();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,16 +178,18 @@ class _SelectedMemberDetailViewState extends State<SelectedMemberDetailView> {
}

void getAddress(ApiLocation? location) async {
if (location != null) {
final latLng = LatLng(location.latitude, location.longitude);
final address = await latLng.getAddressFromLocation();
setState(() {
this.address = address;
});
} else {
setState(() {
address = '';
});
if (mounted) {
if (location != null) {
final latLng = LatLng(location.latitude, location.longitude);
final address = await latLng.getAddressFromLocation();
setState(() {
this.address = address;
});
} else {
setState(() {
address = '';
});
}
}
}
}
2 changes: 1 addition & 1 deletion app/lib/ui/flow/home/map/map_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class _MapScreenState extends ConsumerState<MapScreen> {
onMemberTap: (member) {
notifier.showMemberDetail(member);
},
onRelocateTap: () {},
onRelocateTap: () => notifier.getUserLastLocation(),
onPlacesTap: () {
final space = widget.space;
if (space != null) {
Expand Down
55 changes: 45 additions & 10 deletions app/lib/ui/flow/home/map/map_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:ui' as ui;
import 'package:data/api/auth/auth_models.dart';
import 'package:data/api/place/api_place.dart';
import 'package:data/log/logger.dart';
import 'package:data/service/location_manager.dart';
import 'package:data/service/permission_service.dart';
import 'package:data/service/place_service.dart';
import 'package:data/service/space_service.dart';
Expand All @@ -26,6 +27,7 @@ final mapViewStateProvider =
ref.read(spaceServiceProvider),
ref.read(placeServiceProvider),
ref.read(permissionServiceProvider),
ref.read(locationManagerProvider),
);
});

Expand All @@ -34,12 +36,14 @@ class MapViewNotifier extends StateNotifier<MapViewState> {
final SpaceService spaceService;
final PlaceService placeService;
final PermissionService permissionService;
final LocationManager locationManager;

MapViewNotifier(
this._currentUser,
this.spaceService,
this.placeService,
this.permissionService,
this.locationManager,
) : super(const MapViewState());

void loadData(String? spaceId) {
Expand Down Expand Up @@ -98,7 +102,11 @@ class MapViewNotifier extends StateNotifier<MapViewState> {
final List<UserMarker> markers = [];
for (final info in userInfo) {
if (info.user.id == _currentUser?.id) {
_mapCameraPosition(info);
final latLng = LatLng(
info.location?.latitude ?? 0.0,
info.location?.longitude ?? 0.0,
);
_mapCameraPosition(latLng, defaultCameraZoom);
}

if (info.location != null) {
Expand Down Expand Up @@ -148,15 +156,6 @@ class MapViewNotifier extends StateNotifier<MapViewState> {
return null;
}

void _mapCameraPosition(ApiUserInfo userInfo) {
final position = CameraPosition(
target: LatLng(userInfo.location?.latitude ?? 0.0,
userInfo.location?.longitude ?? 0.0),
zoom: defaultCameraZoom,
);
state = state.copyWith(defaultPosition: position);
}

void onAddMemberTap(String spaceId) async {
try {
state = state.copyWith(fetchingInviteCode: true, spaceInvitationCode: '');
Expand Down Expand Up @@ -235,6 +234,42 @@ class MapViewNotifier extends StateNotifier<MapViewState> {
void showEnableLocationDialog() {
state = state.copyWith(showLocationDialog: DateTime.now());
}

void getUserLastLocation() async {
try {
state = state.copyWith(defaultPosition: null);
final isEnabled = await permissionService.isLocationPermissionGranted();
if (isEnabled) {
final position = await locationManager.getLastLocation();
final latLng = LatLng(position!.latitude, position.longitude);
_mapCameraPosition(latLng, defaultCameraZoom);
} else {
for (final info in state.userInfo) {
if (info.user.id == _currentUser?.id) {
final latLng = LatLng(
info.location?.latitude ?? 0.0,
info.location?.longitude ?? 0.0,
);
_mapCameraPosition(latLng, defaultCameraZoom);
}
}
}
} catch (error, stack) {
logger.e(
'MapViewNotifier: Error while getting last location',
error: error,
stackTrace: stack,
);
}
}

void _mapCameraPosition(LatLng latLng, double zoom) {
final cameraPosition = CameraPosition(
target: LatLng(latLng.latitude, latLng.longitude),
zoom: zoom,
);
state = state.copyWith(defaultPosition: cameraPosition);
}
}

@freezed
Expand Down
25 changes: 17 additions & 8 deletions app/lib/ui/flow/setting/profile/profile_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,38 @@ import 'dart:io';
import 'package:data/api/auth/auth_models.dart';
import 'package:data/log/logger.dart';
import 'package:data/service/auth_service.dart';
import 'package:data/service/location_manager.dart';
import 'package:data/service/space_service.dart';
import 'package:data/storage/app_preferences.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:data/service/space_service.dart';

part 'profile_view_model.freezed.dart';

final editProfileViewStateProvider =
StateNotifierProvider.autoDispose<EditProfileViewNotifier, EditProfileViewState>(
final editProfileViewStateProvider = StateNotifierProvider.autoDispose<
EditProfileViewNotifier, EditProfileViewState>(
(ref) => EditProfileViewNotifier(
ref.read(spaceServiceProvider),
ref.read(authServiceProvider),
ref.read(currentUserPod),
ref.read(locationManagerProvider),
),
);

class EditProfileViewNotifier extends StateNotifier<EditProfileViewState> {
final SpaceService spaceService;
final AuthService authService;
final ApiUser? user;

EditProfileViewNotifier(this.spaceService, this.authService, this.user)
: super(EditProfileViewState(
final LocationManager locationManager;

EditProfileViewNotifier(
this.spaceService,
this.authService,
this.user,
this.locationManager,
) : super(EditProfileViewState(
firstName: TextEditingController(text: user?.first_name),
lastName: TextEditingController(text: user?.last_name),
email: TextEditingController(text: user?.email),
Expand All @@ -43,6 +50,7 @@ class EditProfileViewNotifier extends StateNotifier<EditProfileViewState> {
spaceService.deleteUserSpaces();
authService.deleteUser();
state = state.copyWith(deletingAccount: true, accountDeleted: true);
locationManager.stopService();
} catch (error, stack) {
logger.e(
'EditProfileViewState: error while delete account',
Expand All @@ -69,7 +77,7 @@ class EditProfileViewNotifier extends StateNotifier<EditProfileViewState> {
logger.e(
'EditProfileViewNotifier: error while update user profile',
error: error,
stackTrace: stack
stackTrace: stack,
);
state = state.copyWith(error: error);
}
Expand Down Expand Up @@ -114,7 +122,8 @@ class EditProfileViewNotifier extends StateNotifier<EditProfileViewState> {
error: error,
stackTrace: stack,
);
state = state.copyWith(profileUrl: '', uploadingImage: false, error: error);
state =
state.copyWith(profileUrl: '', uploadingImage: false, error: error);
onChange();
}
}
Expand Down
Loading

0 comments on commit 243b61d

Please sign in to comment.