Ask user to ENABLE Location Services in Flutter even if the user toggles it off from the shutter

Viewed 985

So, in the app that I am working upon I need to enable real-time tracking of the user. The issue that I am facing is whenever the user while using the app switches the location (GPS) service off from the device shutter the Location Bloc doesn't emit any state. The objective is that whenever the user turns off the GPS the app should request user to switch it on. A similar anology to apps like Tinder or Bumble where is the user switches GPS off, they immediately ask the user to turn it on.

Here is my code:

LocationBloc

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../../../data/repositories/send_alert_loc.dart';
import 'package:location/location.dart';

part 'location_bloc_event.dart';
part 'location_bloc_state.dart';

class LocationBloc extends Bloc<LocationEvent, LocationState> {
  bool _serviceEnabled;
  Location location = new Location();
  PermissionStatus _permissionGranted;

  StreamSubscription<LocationData> locationStreamSubscription;

  LocationBloc() : super(LocationInitialState());

  @override
  Stream<LocationState> mapEventToState(
    LocationEvent event,
  ) async* {
    if (event is LocationStartedEvent) {
      yield LocationLoadingState();
      _determinePosition();
    } else if (event is LocationChangedEvent) {
      yield LocationLoadSuccessState(
        locationData: event.locationData,
      );
    }
  }

  void dispose() {
    locationStreamSubscription?.cancel();
  }

  void isLocationServiceEnabled() async {
    _serviceEnabled = await location.serviceEnabled();
    if (!_serviceEnabled) {
      _serviceEnabled = await location.requestService();
      if (!_serviceEnabled) {
        return;
      }
    }
  }

  void _checkForLocationPermission() async {
    _permissionGranted = await location.hasPermission();
    if (_permissionGranted == PermissionStatus.denied) {
      _permissionGranted = await location.requestPermission();
      if (_permissionGranted != PermissionStatus.granted) {
        return;
      }
    }
  }

  _determinePosition() async {
    // Cancel old subscription if any and
    // then start a new location subscription.
    locationStreamSubscription?.cancel();

    // Test if location services are enabled.
    // Location services are not enabled don't continue
    // accessing the position and request users of the
    // App to enable the location services.
    isLocationServiceEnabled();

    // Permissions are denied, next time you could try
    // requesting permissions again (this is also where
    // Android's shouldShowRequestPermissionRationale
    // returned true. According to Android guidelines
    // your App should show an explanatory UI now.
    _checkForLocationPermission();

    // When we reach here, permissions are granted and we can
    // continue accessing the position of the device.
    // i.e. if everything is fine call the LocationChangedEvent.

    locationStreamSubscription =
        location.onLocationChanged.listen((LocationData currentLocation) {
      add(
        LocationChangedEvent(locationData: currentLocation),
      );
    });
  }
}

LocationEvent

part of 'location_bloc.dart';

abstract class LocationEvent {}

class LocationStartedEvent extends LocationEvent {}

class LocationChangedEvent extends LocationEvent {
  final LocationData locationData;

  LocationChangedEvent({
    @required this.locationData,
  });
}

LocationState

part of 'location_bloc.dart';

abstract class LocationState extends Equatable {
  final LocationData locationData;

  const LocationState({
    this.locationData,
  });

  @override
  List<Object> get props => [locationData];
}

class LocationInitialState extends LocationState {}

class LocationLoadingState extends LocationState {}

class LocationLoadSuccessState extends LocationState {
  final LocationData locationData;

  LocationLoadSuccessState({
    @required this.locationData,
  });
}

Implementation above the Material App so that I can access this code from any screen.

 Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [       
        BlocProvider<LocationBloc>(
          create: (context) => LocationBloc()..add(LocationStartedEvent()),
        ),
      ],
      child: Builder(
        builder: (context) {
          return MaterialApp(
            home: Scaffold(
              body: LocationConnectivityWidget(
                child: HomeScreen(),
              ),
            ),
          );
        },
      ),
    );
  }

So, whenever the user toggles the location service the state isn't updated and it doesn't ask for persmission except when the app starts afresh.

LocationConnectivityWidget

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../constant/image_path_constants.dart';
import '../../themes/theme_config.dart';

import '../../logic/blocs/location_bloc/location_bloc.dart';

class LocationConnectivityWidget extends StatelessWidget {
  final Widget child;

  const LocationConnectivityWidget({
    @required this.child,
  }) : assert(child != null);

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<LocationBloc, LocationState>(
      builder: (context, state) {
        if (state is LocationLoadSuccessState) {
          return child;
        }

        return Center(
          child: Container(
            padding: DEFAULT_LARGE_HORIZONTAL_PADDING,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Image.asset(CONNECT_TO_LOCATION_IMAGE),
                SizedBox(
                  height: 16.0,
                ),
                Text(
                  "Please enable Location to continue.",
                  style: TextStyle(
                    color: Theme.of(context).textHeadingColor,
                    fontSize: 16.0,
                    fontWeight: FontWeight.w600,
                  ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

PS: I am new to Bloc pattern so, in case if anyone finds any best practice that I am not following, it would be appreciated if y'all point 'em out as well.

0 Answers
Related