diff --git a/.fvm/flutter_sdk b/.fvm/flutter_sdk deleted file mode 120000 index c77c100b..00000000 --- a/.fvm/flutter_sdk +++ /dev/null @@ -1 +0,0 @@ -/Users/abhishek/fvm/versions/stable \ No newline at end of file diff --git a/.fvmrc b/.fvmrc deleted file mode 100644 index c300356c..00000000 --- a/.fvmrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "flutter": "stable" -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 43bac5cd..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "java.configuration.updateBuildConfiguration": "automatic", - "dart.flutterSdkPath": ".fvm/versions/stable" -} \ No newline at end of file diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs index fcbe6842..a50efddb 100644 --- a/android/.settings/org.eclipse.buildship.core.prefs +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -1,11 +1,11 @@ arguments=--init-script /var/folders/87/sjnhgg2s1dn1b0l2r0jrgxx80000gn/T/d146c9752a26f79b52047fb6dc6ed385d064e120494f96f08ca63a317c41f94c.gradle --init-script /var/folders/87/sjnhgg2s1dn1b0l2r0jrgxx80000gn/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle -auto.sync=true +auto.sync=false build.scans.enabled=false connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) connection.project.dir= eclipse.preferences.version=1 gradle.user.home= -java.home=/opt/homebrew/Cellar/openjdk/21.0.1/libexec/openjdk.jdk/Contents/Home +java.home=/opt/homebrew/Cellar/openjdk/21.0.2/libexec/openjdk.jdk/Contents/Home jvm.arguments= offline.mode=false override.workspace.settings=true diff --git a/lib/config/environment_config.dart b/lib/Bloc/config/enviornment_config.dart similarity index 100% rename from lib/config/environment_config.dart rename to lib/Bloc/config/enviornment_config.dart diff --git a/lib/services/graphql_config.dart b/lib/Bloc/config/graphql_config.dart similarity index 77% rename from lib/services/graphql_config.dart rename to lib/Bloc/config/graphql_config.dart index 6bae32cb..c9d65108 100644 --- a/lib/services/graphql_config.dart +++ b/lib/Bloc/config/graphql_config.dart @@ -1,6 +1,4 @@ -import 'dart:developer'; - -import 'package:beacon/config/environment_config.dart'; +import 'package:beacon/Bloc/config/enviornment_config.dart'; import 'package:beacon/locator.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; @@ -22,17 +20,17 @@ class GraphQLConfig { )); Future getToken() async { - final _token = userConfig!.currentUser!.authToken; - token = _token; + await localApi.init(); + final user = await localApi.fetchUser(); + if (user != null) { + token = user.authToken; + } return true; } GraphQLClient clientToQuery() { - log(httpLink.toString()); - log(EnvironmentConfig.httpEndpoint!); return GraphQLClient( - cache: GraphQLCache(), - // cache: GraphQLCache(partialDataPolicy: PartialDataCachePolicy.accept), + cache: GraphQLCache(partialDataPolicy: PartialDataCachePolicy.accept), link: httpLink, ); } @@ -49,7 +47,7 @@ class GraphQLConfig { GraphQLClient graphQlClient() { return GraphQLClient( - cache: GraphQLCache(), + cache: GraphQLCache(partialDataPolicy: PartialDataCachePolicy.accept), link: Link.split( (request) => request.isSubscription, websocketLink, diff --git a/lib/Bloc/config/user_config.dart b/lib/Bloc/config/user_config.dart new file mode 100644 index 00000000..c0e88e30 --- /dev/null +++ b/lib/Bloc/config/user_config.dart @@ -0,0 +1,12 @@ +import 'package:beacon/Bloc/data/models/user/user_model.dart'; +import 'package:beacon/locator.dart'; + +class UserModelConfig { + UserModel _userModel = UserModel(authToken: 'null'); + UserModel get userModel => _userModel; + + Future updateUser(UserModel updateUserDetails) async { + _userModel = updateUserDetails; + return localApi.saveUser(updateUserDetails); + } +} diff --git a/lib/Bloc/core/constants/location.dart b/lib/Bloc/core/constants/location.dart new file mode 100644 index 00000000..0e72c7cc --- /dev/null +++ b/lib/Bloc/core/constants/location.dart @@ -0,0 +1,30 @@ +import 'package:geolocator/geolocator.dart'; + +class LocationService { + static Future getCurrentLocation() async { + bool serviceEnabled; + LocationPermission permission; + + serviceEnabled = await Geolocator.isLocationServiceEnabled(); + + if (!serviceEnabled) { + return Future.error('Location service is disabled.'); + } + + permission = await Geolocator.checkPermission(); + + if (permission == LocationPermission.denied) { + permission = await Geolocator.requestPermission(); + if (permission == LocationPermission.denied) { + return Future.error('Location permission is denied'); + } + } + + if (permission == LocationPermission.deniedForever) { + return Future.error('Location permission is permanently denied.'); + } + + return await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.high); + } +} diff --git a/lib/queries/auth.dart b/lib/Bloc/core/queries/auth.dart similarity index 63% rename from lib/queries/auth.dart rename to lib/Bloc/core/queries/auth.dart index 37eca718..1c44b5c3 100644 --- a/lib/queries/auth.dart +++ b/lib/Bloc/core/queries/auth.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - class AuthQueries { String registerUser(String? name, String email, String? password) { return ''' @@ -43,7 +41,6 @@ class AuthQueries { } String fetchUserInfo() { - log('fetching user info'); return ''' query{ me{ @@ -52,38 +49,9 @@ class AuthQueries { name groups{ _id - title - shortcode - leader { - _id - name - } - members { - _id - name - } - beacons{ - _id - } } beacons{ _id - title - shortcode - leader { - _id - name - } - followers{ - _id - name - } - location { - lat - lon - } - startsAt - expiresAt } } } diff --git a/lib/queries/beacon.dart b/lib/Bloc/core/queries/beacon.dart similarity index 100% rename from lib/queries/beacon.dart rename to lib/Bloc/core/queries/beacon.dart diff --git a/lib/queries/group.dart b/lib/Bloc/core/queries/group.dart similarity index 73% rename from lib/queries/group.dart rename to lib/Bloc/core/queries/group.dart index f9b335b5..bc760734 100644 --- a/lib/queries/group.dart +++ b/lib/Bloc/core/queries/group.dart @@ -1,6 +1,29 @@ import 'package:graphql_flutter/graphql_flutter.dart'; class GroupQueries { + String fetchUserGroups(int page, int pageSize) { + return ''' + query { + groups(page: $page, pageSize: $pageSize) { + _id + title + shortcode + leader { + _id + name + } + members { + _id + name + } + beacons { + _id + } + } + } + '''; + } + String createGroup(String? title) { return ''' mutation{ @@ -129,6 +152,36 @@ class GroupQueries { '''; } + String fetchHikes(String groupID, int page, int pageSize) { + return ''' +query{ + beacons(groupId: "$groupID", page: $page, pageSize: $pageSize){ + _id + title + shortcode + leader { + _id + name + } + location{ + lat + lon + } + followers { + _id + name + } + group{ + _id + } + startsAt + expiresAt + + } +} +'''; + } + final groupJoinedSubGql = gql(r''' subscription StreamNewlyJoinedGroups($id: ID!){ groupJoined(id: $id){ diff --git a/lib/Bloc/core/resources/data_state.dart b/lib/Bloc/core/resources/data_state.dart new file mode 100644 index 00000000..a6bdca91 --- /dev/null +++ b/lib/Bloc/core/resources/data_state.dart @@ -0,0 +1,14 @@ +abstract class DataState { + final T? data; + final String? error; + + const DataState({this.data, this.error}); +} + +class DataSuccess extends DataState { + const DataSuccess(T data) : super(data: data); +} + +class DataFailed extends DataState { + const DataFailed(String error) : super(error: error); +} diff --git a/lib/Bloc/core/services/shared_prefrence_service.dart b/lib/Bloc/core/services/shared_prefrence_service.dart new file mode 100644 index 00000000..9e91b816 --- /dev/null +++ b/lib/Bloc/core/services/shared_prefrence_service.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class SharedPreferenceService { + SharedPreferenceService() { + init(); + } + + late SharedPreferences _prefs; + + init() async { + _prefs = await SharedPreferences.getInstance(); + } + + Future saveData(String key, dynamic value) async { + try { + if (value is String) { + await _prefs.setString(key, value); + } else if (value is int) { + await _prefs.setInt(key, value); + } else if (value is bool) { + await _prefs.setBool(key, value); + } else if (value is double) { + await _prefs.setDouble(key, value); + } else if (value is List) { + await _prefs.setStringList(key, value); + } + } catch (e) { + debugPrint(e.toString()); + } + } + + Future loadData(String key) async { + return _prefs.get(key); + } + + Future deleteData(String key) async { + return await _prefs.remove('key'); + } +} diff --git a/lib/Bloc/core/services/size_config.dart b/lib/Bloc/core/services/size_config.dart new file mode 100644 index 00000000..0dd0d64d --- /dev/null +++ b/lib/Bloc/core/services/size_config.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +class SizeConfig { + static late MediaQueryData _mediaQueryData; + static late double screenWidth; + static late double screenHeight; + static double? blockSizeHorizontal; + static double? blockSizeVertical; + static double? paddingTop; + + static late double _safeAreaHorizontal; + static late double _safeAreaVertical; + static double? safeBlockHorizontal; + static double? safeBlockVertical; + + void init(BuildContext context) { + _mediaQueryData = MediaQuery.of(context); + screenWidth = _mediaQueryData.size.width; + screenHeight = _mediaQueryData.size.height; + blockSizeHorizontal = screenWidth / 100; + blockSizeVertical = screenHeight / 100; + + _safeAreaHorizontal = + _mediaQueryData.padding.left + _mediaQueryData.padding.right; + _safeAreaVertical = + _mediaQueryData.padding.top + _mediaQueryData.padding.bottom; + safeBlockHorizontal = (screenWidth - _safeAreaHorizontal) / 100; + safeBlockVertical = (screenHeight - _safeAreaVertical) / 100; + debugPrint("safeBlockHorizontal: $safeBlockHorizontal"); + debugPrint("safeBlockVertical: $safeBlockVertical"); + } +} diff --git a/lib/Bloc/core/usercase/usecase.dart b/lib/Bloc/core/usercase/usecase.dart new file mode 100644 index 00000000..2d8b44d1 --- /dev/null +++ b/lib/Bloc/core/usercase/usecase.dart @@ -0,0 +1,3 @@ +abstract class UseCase { + Future call(Paramas paramas); +} diff --git a/lib/Bloc/core/utils/utils.dart b/lib/Bloc/core/utils/utils.dart new file mode 100644 index 00000000..aa80bd5e --- /dev/null +++ b/lib/Bloc/core/utils/utils.dart @@ -0,0 +1,79 @@ +import 'dart:developer'; +import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:flutter/material.dart'; +import 'package:graphql/client.dart'; + +class Utils { + void showSnackBar(String message, BuildContext context, + {Duration duration = const Duration(seconds: 2)}) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + duration: duration, + content: Text( + message, + style: TextStyle(color: Colors.black), + ), + backgroundColor: kLightBlue.withOpacity(0.8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(10), + ), + ), + behavior: SnackBarBehavior.floating, + elevation: 5, + ), + ); + } + + String filterException(OperationException exception) { + // checking grapqhl exceptions + if (exception.graphqlErrors.isNotEmpty) { + return exception.graphqlErrors.first.message; + } + // checking link exception + else if (exception.linkException != null) { + log('Link Exception: ${exception.linkException!.originalStackTrace}'); + return 'Server exception'; + } else { + return 'Network Error: The request could not be completed.'; + } + } + + Future checkInternetConnectivity() async { + final connectivityResult = await Connectivity().checkConnectivity(); + + if (connectivityResult == ConnectivityResult.mobile || + connectivityResult == ConnectivityResult.wifi || + connectivityResult == ConnectivityResult.ethernet) { + return true; + } + return false; + } + + String? validateEmail(String? value) { + final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); + if (value == null || value.isEmpty) { + return 'Email address is required'; + } else if (!emailRegex.hasMatch(value)) { + return 'Enter a valid email address'; + } + return null; // Return null if the email is valid + } + + String? validatePassword(String? value) { + if (value == null || value.isEmpty) { + return 'Password is required'; + } else if (value.length < 8) { + return '8-digit password is required'; + } + return null; + } + + String? validateName(String? value) { + if (value == null || value.isEmpty) { + return 'Name is required'; + } + return null; + } +} diff --git a/lib/services/validators.dart b/lib/Bloc/core/utils/validators.dart similarity index 64% rename from lib/services/validators.dart rename to lib/Bloc/core/utils/validators.dart index 28a7a21d..febbefc9 100644 --- a/lib/services/validators.dart +++ b/lib/Bloc/core/utils/validators.dart @@ -1,28 +1,28 @@ class Validator { - static String? validateName(String name) { - if (name.isEmpty) { + static String? validateName(String? name) { + if (name != null && name.isEmpty) { return "Name must not be left blank"; } return null; } - static String? validateEmail(String email) { + static String? validateEmail(String? email) { // If email is empty return. - if (email.isEmpty) { + if (email != null && email.isEmpty) { return "Email must not be left blank"; } const String pattern = r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$"; final RegExp regex = RegExp(pattern); - if (!regex.hasMatch(email)) { + if (email != null && !regex.hasMatch(email)) { return 'Please enter a valid Email Address'; } return null; } - static String? validatePassword(String password) { + static String? validatePassword(String? password) { // If password is empty return. - if (password.isEmpty) { + if (password != null && password.isEmpty) { return "Password must not be left blank"; } // const String pattern = r'^(?=.*?[0-9])(?=.*?[!@#\$&*%^~.]).{8,}$'; @@ -32,7 +32,7 @@ class Validator { const String noSpaces = r'^\S+$'; final RegExp noSpaceRegex = RegExp(noSpaces); - if (password.length < 8) { + if (password!.length < 8) { return "Must be of atleast 8 characters"; } // if (!regExp.hasMatch(password)) { @@ -44,33 +44,33 @@ class Validator { return null; } - static String? validateBeaconTitle(String title) { - if (title.isEmpty) { + static String? validateBeaconTitle(String? title) { + if (title != null && title.isEmpty) { return "Title must not be left blank"; } return null; } - static String? validatePasskey(String passkey) { - if (passkey.isEmpty) { + static String? validatePasskey(String? passkey) { + if (passkey != null && passkey.isEmpty) { return "Passkey must not be left blank"; } const String pattern = r'[A-Z]+'; final RegExp regExp = RegExp(pattern); - if (!regExp.hasMatch(passkey) || passkey.length != 6) { + if (!regExp.hasMatch(passkey!) || passkey.length != 6) { return "Invalid passkey"; } return null; } - static String? validateDuration(String duration) { - if (duration.startsWith("0:00:00.")) { + static String? validateDuration(String? duration) { + if (duration != null && duration.startsWith("0:00:00.")) { return "Duration cannot be $duration"; } return null; } - static String? validateStartingTime(String startTime) { + static String? validateStartingTime(String? startTime) { print(startTime); return null; } diff --git a/lib/Bloc/data/datasource/local/local_api.dart b/lib/Bloc/data/datasource/local/local_api.dart new file mode 100644 index 00000000..6b27fce2 --- /dev/null +++ b/lib/Bloc/data/datasource/local/local_api.dart @@ -0,0 +1,182 @@ +import 'dart:async'; +import 'dart:developer'; +import 'dart:io'; +import 'package:beacon/Bloc/data/models/beacon/beacon_model.dart'; +import 'package:beacon/Bloc/data/models/group/group_model.dart'; +import 'package:beacon/Bloc/data/models/landmark/landmark_model.dart'; +import 'package:beacon/Bloc/data/models/location/location_model.dart'; +import 'package:beacon/Bloc/data/models/user/user_model.dart'; +import 'package:hive/hive.dart'; +import 'package:path_provider/path_provider.dart' as path_provider; + +class LocalApi { + String userModelbox = 'userBox'; + String groupModelBox = 'groupBox'; + String beaconModelBox = 'beaconBox'; + String locationModelBox = 'locationBox'; + String landMarkModelBox = 'landMarkBox'; + + late Box userBox; + late Box groupBox; + late Box beaconBox; + late Box locationBox; + late Box landMarkbox; + + UserModel _userModel = UserModel(authToken: null); + UserModel get userModel => _userModel; + + init() async { + Directory directory = + await path_provider.getApplicationDocumentsDirectory(); + + Hive.init(directory.path); + + !Hive.isAdapterRegistered(10) + ? Hive.registerAdapter(UserModelAdapter()) + : null; + !Hive.isAdapterRegistered(20) + ? Hive.registerAdapter(BeaconModelAdapter()) + : null; + !Hive.isAdapterRegistered(30) + ? Hive.registerAdapter(GroupModelAdapter()) + : null; + + !Hive.isAdapterRegistered(40) + ? Hive.registerAdapter(LocationModelAdapter()) + : null; + !Hive.isAdapterRegistered(50) + ? Hive.registerAdapter(LandMarkModelAdapter()) + : null; + + try { + userBox = await Hive.openBox(userModelbox); + groupBox = await Hive.openBox(groupModelBox); + beaconBox = await Hive.openBox(beaconModelBox); + locationBox = await Hive.openBox(locationModelBox); + landMarkbox = await Hive.openBox(landMarkModelBox); + } catch (e) { + log('error: ${e.toString()}'); + } + } + + Future saveUser(UserModel user) async { + try { + _userModel = user; + await userBox.put('currentUser', user); + return true; + } catch (e) { + log(e.toString()); + return false; + } + } + + Future deleteUser() async { + // clearing the info + + try { + _userModel.copyWithModel( + authToken: null, + beacons: null, + email: null, + groups: null, + id: null, + isGuest: null, + location: null, + name: null); + await userBox.clear(); + await groupBox.clear(); + await beaconBox.clear(); + } catch (e) { + log(e.toString()); + } + } + + Future fetchUser() async { + try { + final user = await userBox.get('currentUser'); + return user; + } catch (e) { + log(e.toString()); + return null; + } + } + + Future userloggedIn() async { + try { + UserModel? user = await userBox.get('currentUser'); + + if (user == null) { + return false; + } + _userModel = user; + return true; + } catch (e) { + log(e.toString()); + return false; + } + } + + Future saveGroup(GroupModel group) async { + await deleteGroup(group.id); + try { + await groupBox.put(group.id, group); + return true; + } catch (e) { + log(e.toString()); + return false; + } + } + + Future deleteGroup(String? groupId) async { + try { + bool doesExist = await groupBox.containsKey(groupId); + doesExist ? await groupBox.delete(groupId) : null; + return true; + } catch (e) { + log(e.toString()); + return false; + } + } + + Future getGroup(String? groupId) async { + try { + final group = await groupBox.get(groupId); + return group; + } catch (e) { + log(e.toString()); + return null; + } + } + + Future saveBeacon(BeaconModel beacon) async { + try { + await deleteBeacon(beacon.id); + await beaconBox.put(beacon.id, beacon); + return true; + } catch (e) { + log(e.toString()); + return false; + } + } + + Future deleteBeacon(String? beaconId) async { + try { + bool doesExist = await beaconBox.containsKey(beaconId); + doesExist ? await beaconBox.delete(beaconId) : null; + return true; + } catch (e) { + log(e.toString()); + return false; + } + } + + Future getBeacon(String? beaconId) async { + try { + final beacon = await beaconBox.get(beaconId); + return beacon; + } catch (e) { + log(e.toString()); + return null; + } + } +} diff --git a/lib/Bloc/data/datasource/remote/remote_auth_api.dart b/lib/Bloc/data/datasource/remote/remote_auth_api.dart new file mode 100644 index 00000000..d40bcb3a --- /dev/null +++ b/lib/Bloc/data/datasource/remote/remote_auth_api.dart @@ -0,0 +1,137 @@ +import 'package:beacon/Bloc/core/queries/auth.dart'; +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/data/models/user/user_model.dart'; +import 'package:beacon/locator.dart'; +import 'package:flutter/material.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; + +class RemoteAuthApi { + final ValueNotifier clientNonAuth; + GraphQLClient clientAuth; + + RemoteAuthApi({ + required this.clientNonAuth, + required this.clientAuth, + }); + + AuthQueries _authQueries = AuthQueries(); + + Future> fetchUserInfo() async { + clientAuth = await graphqlConfig.authClient(); + + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) + return DataFailed('Beacon is trying to connect with internet...'); + + // api call + final result = await clientAuth + .mutate(MutationOptions(document: gql(_authQueries.fetchUserInfo()))); + + if (result.data != null && result.isConcrete) { + final json = result.data!['me']; + final user = UserModel.fromJson(json); + + final currentUser = await localApi.fetchUser(); + + // checking if user is login + if (currentUser == null) return DataFailed('Please login first'); + final newUser = user.copyWithModel( + authToken: currentUser.authToken, + isGuest: user.email == '' ? true : false); + + // saving user details locally + await localApi.saveUser(newUser); + + // returning + return DataSuccess(newUser); + } + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + Future> register( + String name, String email, String password) async { + try { + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) + return DataFailed('Beacon is trying to connect with internet...'); + + final result = await clientNonAuth.value.mutate( + MutationOptions( + document: gql(_authQueries.registerUser(name, email, password)), + ), + ); + + if (result.data != null && result.isConcrete) { + // LOGIN API CALL + final dataState = await login(email, password); + return dataState; + } else if (result.hasException) { + final message = encounteredExceptionOrError(result.exception!); + return DataFailed(message); + } + + return DataFailed('An unexpected error occurred during registration.'); + } catch (e) { + return DataFailed(e.toString()); + } + } + + Future> login(String email, String password) async { + try { + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('Beacon is trying to connect with internet...'); + } + + final QueryResult result = await clientNonAuth.value.mutate( + MutationOptions( + document: gql(_authQueries.loginUser(email, password)))); + + if (result.data != null && result.isConcrete) { + final token = "Bearer ${result.data!['login']}"; + + // storing auth token in hive + final user = + UserModel(authToken: token, isGuest: (email == '') ? true : false); + await localApi.saveUser(user); + + // fetching User Info + + final dataState = await fetchUserInfo(); + + if (dataState is DataSuccess) { + final updatedUser = dataState.data! + .copyWithModel(authToken: user.authToken, isGuest: user.isGuest); + + // if(locator.isRegistered( )) + + // saving locally + await localApi.saveUser(updatedUser); + + return dataState; + } + return dataState; + } else if (result.hasException) { + final message = encounteredExceptionOrError(result.exception!); + + return DataFailed(message); + } + + return DataFailed('An unexpected error occured.'); + } catch (e) { + return DataFailed(e.toString()); + } + } + + String encounteredExceptionOrError(OperationException exception) { + if (exception.linkException != null) { + debugPrint(exception.linkException.toString()); + return 'Server not running'; + } else { + return exception.graphqlErrors[0].message.toString(); + } + } +} diff --git a/lib/Bloc/data/datasource/remote/remote_group_api.dart b/lib/Bloc/data/datasource/remote/remote_group_api.dart new file mode 100644 index 00000000..7203aae7 --- /dev/null +++ b/lib/Bloc/data/datasource/remote/remote_group_api.dart @@ -0,0 +1,130 @@ +import 'dart:developer'; + +import 'package:beacon/Bloc/core/queries/beacon.dart'; +import 'package:beacon/Bloc/core/queries/group.dart'; +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/data/models/beacon/beacon_model.dart'; +import 'package:beacon/Bloc/data/models/group/group_model.dart'; +import 'package:beacon/locator.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; + +class RemoteGroupApi { + final GraphQLClient authClient; + + RemoteGroupApi({required this.authClient}); + + final _groupqueries = GroupQueries(); + + final _beaconQueries = BeaconQueries(); + + Future>> fetchHikes( + String groupId, int page, int pageSize) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + GroupModel? group = await localApi.getGroup(groupId); + + if (group != null && group.beacons != null) { + int condition = (page - 1) * pageSize + pageSize; + int beaconLen = group.beacons!.length; + + if (condition > beaconLen) { + condition = beaconLen; + } + + List beacons = []; + + for (int i = (page - 1) * pageSize; i < condition; i++) { + BeaconModel? beaconModel = + await localApi.getBeacon(group.beacons![i]!.id); + + beaconModel != null ? beacons.add(beaconModel) : null; + } + + return DataSuccess(beacons); + } + + return DataFailed('Please check your internet connection!'); + } + + final authClient = await graphqlConfig.authClient(); + final result = await authClient.query(QueryOptions( + document: gql(_groupqueries.fetchHikes(groupId, page, pageSize)))); + + if (result.data != null && result.isConcrete) { + List hikesJson = result.data!['beacons']; + + List hikes = []; + + for (var hikeJson in hikesJson) { + BeaconModel hike = BeaconModel.fromJson(hikeJson); + hikes.add(hike); + + // storing beacon + if (1 == 1) { + log('called'); + await localApi.saveBeacon(hike); + } + } + + return DataSuccess(hikes); + } + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + Future> createHike(String title, int startsAt, + int expiresAt, String lat, String lon, String groupID) async { + final authClient = await graphqlConfig.authClient(); + + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('Please check your internet connection!'); + } + final result = await authClient.mutate(MutationOptions( + document: gql(_beaconQueries.createBeacon( + title, startsAt, expiresAt, lat, lon, groupID)))); + + if (result.data != null && result.isConcrete) { + final hikeJson = result.data!['createBeacon']; + + final beacon = BeaconModel.fromJson(hikeJson); + + // storing beacon + await localApi.saveBeacon(beacon); + return DataSuccess(beacon); + } + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + Future> joinHike(String shortcode) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('Please check your internet connection!'); + } + final authClient = await graphqlConfig.authClient(); + final result = await authClient.mutate( + MutationOptions(document: gql(_beaconQueries.joinBeacon(shortcode)))); + + if (result.data != null && result.isConcrete) { + final hikeJosn = result.data!['joinBeacon']; + + final beacon = BeaconModel.fromJson(hikeJosn); + + // storing beacon + await localApi.saveBeacon(beacon); + + return DataSuccess(beacon); + } + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + String encounteredExceptionOrError(OperationException exception) { + if (exception.linkException != null) { + return 'Server not running'; + } else { + return exception.graphqlErrors[0].message.toString(); + } + } +} diff --git a/lib/Bloc/data/datasource/remote/remote_home_api.dart b/lib/Bloc/data/datasource/remote/remote_home_api.dart new file mode 100644 index 00000000..06fba351 --- /dev/null +++ b/lib/Bloc/data/datasource/remote/remote_home_api.dart @@ -0,0 +1,123 @@ +import 'package:beacon/Bloc/core/queries/group.dart'; +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/data/models/group/group_model.dart'; +import 'package:beacon/Bloc/data/models/user/user_model.dart'; +import 'package:beacon/locator.dart'; +import 'package:flutter/material.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; + +class RemoteHomeApi { + final GraphQLClient _clientAuth; + RemoteHomeApi(this._clientAuth); + + final _groupQueries = GroupQueries(); + + Future>> fetchUserGroups( + int page, int pageSize) async { + final isConnected = await utils.checkInternetConnectivity(); + + print(_clientAuth.toString()); + + if (!isConnected) { + // fetching the previous data stored + // here taking all the ids of group from the user model and then fetching the groups locally from the ids + // returning all groups in one go + UserModel? usermodel = await localApi.fetchUser(); + + if (usermodel != null && usermodel.groups != null) { + // taking user groups + + int condition = (page - 1) * pageSize + pageSize; + int groupLen = usermodel.groups!.length; + + if (condition > groupLen) { + condition = groupLen; + } + + List groups = []; + + for (int i = (page - 1) * pageSize; i < condition; i++) { + GroupModel? groupModel = + await localApi.getGroup(usermodel.groups![i]!.id); + groupModel != null ? groups.add(groupModel) : null; + } + + return DataSuccess(groups); + } + } + + final clientAuth = await graphqlConfig.authClient(); + + final result = await clientAuth.query(QueryOptions( + document: gql(_groupQueries.fetchUserGroups(page, pageSize)))); + + if (result.data != null && result.isConcrete) { + List groups = []; + List groupsData = result.data!['groups']; + for (var groupData in groupsData) { + final group = GroupModel.fromJson(groupData); + + // saving locally + await localApi.saveGroup(group); + + groups.add(group); + } + return DataSuccess(groups); + } + + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + Future> createGroup(String title) async { + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) + return DataFailed('Beacon is trying to connect with internet...'); + final _clientAuth = await graphqlConfig.authClient(); + final result = await _clientAuth.mutate( + MutationOptions(document: gql(_groupQueries.createGroup(title)))); + + if (result.data != null && result.isConcrete) { + GroupModel group = GroupModel.fromJson( + result.data!['createGroup'] as Map); + + // storing group + await localApi.saveGroup(group); + + return DataSuccess(group); + } + + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + Future> joinGroup(String shortCode) async { + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) + return DataFailed('Beacon is trying to connect with internet...'); + final _clientAuth = await graphqlConfig.authClient(); + final result = await _clientAuth.mutate( + MutationOptions(document: gql(_groupQueries.joinGroup(shortCode)))); + + if (result.data != null && result.isConcrete) { + GroupModel group = + GroupModel.fromJson(result.data as Map); + + // storing group + await localApi.saveGroup(group); + + return DataSuccess(group); + } + + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + String encounteredExceptionOrError(OperationException exception) { + if (exception.linkException != null) { + debugPrint(exception.linkException.toString()); + return 'Server not running'; + } else { + return exception.graphqlErrors[0].message.toString(); + } + } +} diff --git a/lib/Bloc/data/models/beacon/beacon_model.dart b/lib/Bloc/data/models/beacon/beacon_model.dart new file mode 100644 index 00000000..24afdb3e --- /dev/null +++ b/lib/Bloc/data/models/beacon/beacon_model.dart @@ -0,0 +1,86 @@ +import 'package:beacon/Bloc/data/models/group/group_model.dart'; +import 'package:beacon/Bloc/data/models/landmark/landmark_model.dart'; +import 'package:beacon/Bloc/data/models/location/location_model.dart'; +import 'package:beacon/Bloc/data/models/user/user_model.dart'; +import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; +import 'package:hive/hive.dart'; +import 'package:json_annotation/json_annotation.dart'; +part 'beacon_model.g.dart'; + +@HiveType(typeId: 20) +@JsonSerializable() +class BeaconModel implements BeaconEntity { + @HiveField(0) + String? id; + @HiveField(1) + String? title; + @HiveField(2) + UserModel? leader; + @HiveField(3) + GroupModel? group; + @HiveField(4) + String? shortcode; + @HiveField(5) + List? followers; + @HiveField(6) + List? landmarks; + @HiveField(7) + LocationModel? location; + @HiveField(8) + List? route; + @HiveField(9) + int? startsAt; + @HiveField(10) + int? expiresAt; + + BeaconModel({ + this.id, + this.title, + this.leader, + this.group, + this.shortcode, + this.followers, + this.landmarks, + this.location, + this.route, + this.startsAt, + this.expiresAt, + }); + + @override + $BeaconEntityCopyWith get copyWith => + throw UnimplementedError(); + + factory BeaconModel.fromJson(Map json) => + _$BeaconModelFromJson(json); + + Map toJson() => _$BeaconModelToJson(this); + + BeaconModel copyWithModel({ + String? id, + String? title, + UserModel? leader, + GroupModel? group, + String? shortcode, + List? followers, + List? landmarks, + LocationModel? location, + List? route, + int? startsAt, + int? expiresAt, + }) { + return BeaconModel( + id: id ?? this.id, + title: title ?? this.title, + leader: leader ?? this.leader, + group: group ?? this.group, + shortcode: shortcode ?? this.shortcode, + followers: followers ?? this.followers, + landmarks: landmarks ?? this.landmarks, + location: location ?? this.location, + route: route ?? this.route, + startsAt: startsAt ?? this.startsAt, + expiresAt: expiresAt ?? this.expiresAt, + ); + } +} diff --git a/lib/Bloc/data/models/beacon/beacon_model.g.dart b/lib/Bloc/data/models/beacon/beacon_model.g.dart new file mode 100644 index 00000000..e94a13e9 --- /dev/null +++ b/lib/Bloc/data/models/beacon/beacon_model.g.dart @@ -0,0 +1,121 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'beacon_model.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class BeaconModelAdapter extends TypeAdapter { + @override + final int typeId = 20; + + @override + BeaconModel read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return BeaconModel( + id: fields[0] as String?, + title: fields[1] as String?, + leader: fields[2] as UserModel?, + group: fields[3] as GroupModel?, + shortcode: fields[4] as String?, + followers: (fields[5] as List?)?.cast(), + landmarks: (fields[6] as List?)?.cast(), + location: fields[7] as LocationModel?, + route: (fields[8] as List?)?.cast(), + startsAt: fields[9] as int?, + expiresAt: fields[10] as int?, + ); + } + + @override + void write(BinaryWriter writer, BeaconModel obj) { + writer + ..writeByte(11) + ..writeByte(0) + ..write(obj.id) + ..writeByte(1) + ..write(obj.title) + ..writeByte(2) + ..write(obj.leader) + ..writeByte(3) + ..write(obj.group) + ..writeByte(4) + ..write(obj.shortcode) + ..writeByte(5) + ..write(obj.followers) + ..writeByte(6) + ..write(obj.landmarks) + ..writeByte(7) + ..write(obj.location) + ..writeByte(8) + ..write(obj.route) + ..writeByte(9) + ..write(obj.startsAt) + ..writeByte(10) + ..write(obj.expiresAt); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is BeaconModelAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +BeaconModel _$BeaconModelFromJson(Map json) => BeaconModel( + id: json['_id'] as String?, + title: json['title'] as String?, + leader: json['leader'] == null + ? null + : UserModel.fromJson(json['leader'] as Map), + group: json['group'] == null + ? null + : GroupModel.fromJson(json['group'] as Map), + shortcode: json['shortcode'] as String?, + followers: (json['followers'] as List?) + ?.map((e) => + e == null ? null : UserModel.fromJson(e as Map)) + .toList(), + landmarks: (json['landmarks'] as List?) + ?.map((e) => e == null + ? null + : LandMarkModel.fromJson(e as Map)) + .toList(), + location: json['location'] == null + ? null + : LocationModel.fromJson(json['location'] as Map), + route: (json['route'] as List?) + ?.map((e) => e == null + ? null + : LocationModel.fromJson(e as Map)) + .toList(), + startsAt: (json['startsAt'] as num?)?.toInt(), + expiresAt: (json['expiresAt'] as num?)?.toInt(), + ); + +Map _$BeaconModelToJson(BeaconModel instance) => + { + '_id': instance.id, + 'title': instance.title, + 'leader': instance.leader, + 'group': instance.group, + 'shortcode': instance.shortcode, + 'followers': instance.followers, + 'landmarks': instance.landmarks, + 'location': instance.location, + 'route': instance.route, + 'startsAt': instance.startsAt, + 'expiresAt': instance.expiresAt, + }; diff --git a/lib/Bloc/data/models/group/group_model.dart b/lib/Bloc/data/models/group/group_model.dart new file mode 100644 index 00000000..faa45dca --- /dev/null +++ b/lib/Bloc/data/models/group/group_model.dart @@ -0,0 +1,58 @@ +import 'package:beacon/Bloc/data/models/beacon/beacon_model.dart'; +import 'package:beacon/Bloc/data/models/user/user_model.dart'; +import 'package:beacon/Bloc/domain/entities/group/group_entity.dart'; +import 'package:hive/hive.dart'; +import 'package:json_annotation/json_annotation.dart'; +part 'group_model.g.dart'; + +@HiveType(typeId: 30) +@JsonSerializable() +class GroupModel implements GroupEntity { + @HiveField(0) + String? id; + @HiveField(1) + String? title; + @HiveField(2) + UserModel? leader; + @HiveField(3) + List? members; + @HiveField(4) + String? shortcode; + @HiveField(5) + List? beacons; + + GroupModel({ + this.id, + this.title, + this.leader, + this.members, + this.shortcode, + this.beacons, + }); + + @override + $GroupEntityCopyWith get copyWith => throw UnimplementedError(); + + factory GroupModel.fromJson(Map json) => + _$GroupModelFromJson(json); + + Map toJson() => _$GroupModelToJson(this); + + GroupModel copyWithModel({ + String? id, + String? title, + UserModel? leader, + List? members, + String? shortcode, + List? beacons, + }) { + return GroupModel( + id: id ?? this.id, + title: title ?? this.title, + leader: leader ?? this.leader, + members: members ?? this.members, + shortcode: shortcode ?? this.shortcode, + beacons: beacons ?? this.beacons, + ); + } +} diff --git a/lib/Bloc/data/models/group/group_model.g.dart b/lib/Bloc/data/models/group/group_model.g.dart new file mode 100644 index 00000000..64d110e5 --- /dev/null +++ b/lib/Bloc/data/models/group/group_model.g.dart @@ -0,0 +1,88 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'group_model.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class GroupModelAdapter extends TypeAdapter { + @override + final int typeId = 30; + + @override + GroupModel read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return GroupModel( + id: fields[0] as String?, + title: fields[1] as String?, + leader: fields[2] as UserModel?, + members: (fields[3] as List?)?.cast(), + shortcode: fields[4] as String?, + beacons: (fields[5] as List?)?.cast(), + ); + } + + @override + void write(BinaryWriter writer, GroupModel obj) { + writer + ..writeByte(6) + ..writeByte(0) + ..write(obj.id) + ..writeByte(1) + ..write(obj.title) + ..writeByte(2) + ..write(obj.leader) + ..writeByte(3) + ..write(obj.members) + ..writeByte(4) + ..write(obj.shortcode) + ..writeByte(5) + ..write(obj.beacons); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is GroupModelAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +GroupModel _$GroupModelFromJson(Map json) => GroupModel( + id: json['_id'] as String?, + title: json['title'] as String?, + leader: json['leader'] == null + ? null + : UserModel.fromJson(json['leader'] as Map), + members: (json['members'] as List?) + ?.map((e) => + e == null ? null : UserModel.fromJson(e as Map)) + .toList(), + shortcode: json['shortcode'] as String?, + beacons: (json['beacons'] as List?) + ?.map((e) => e == null + ? null + : BeaconModel.fromJson(e as Map)) + .toList(), + ); + +Map _$GroupModelToJson(GroupModel instance) => + { + '_id': instance.id, + 'title': instance.title, + 'leader': instance.leader, + 'members': instance.members, + 'shortcode': instance.shortcode, + 'beacons': instance.beacons, + }; diff --git a/lib/Bloc/data/models/landmark/landmark_model.dart b/lib/Bloc/data/models/landmark/landmark_model.dart new file mode 100644 index 00000000..779c3c29 --- /dev/null +++ b/lib/Bloc/data/models/landmark/landmark_model.dart @@ -0,0 +1,36 @@ +import 'package:beacon/Bloc/data/models/location/location_model.dart'; +import 'package:beacon/Bloc/domain/entities/landmark/landmark_entity.dart'; +import 'package:hive/hive.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'landmark_model.g.dart'; + +@HiveType(typeId: 50) +@JsonSerializable() +class LandMarkModel implements LandMarkEntity { + @HiveField(0) + String? title; + @HiveField(1) + LocationModel? location; + + LandMarkModel({this.title, this.location}); + + @override + $LandMarkEntityCopyWith get copyWith => + throw UnimplementedError(); + + factory LandMarkModel.fromJson(Map json) => + _$LandMarkModelFromJson(json); + + Map toJson() => _$LandMarkModelToJson(this); + + LandMarkModel copyWithModel({ + String? title, + LocationModel? location, + }) { + return LandMarkModel( + title: title ?? this.title, + location: location ?? this.location, + ); + } +} diff --git a/lib/Bloc/data/models/landmark/landmark_model.g.dart b/lib/Bloc/data/models/landmark/landmark_model.g.dart new file mode 100644 index 00000000..272a500b --- /dev/null +++ b/lib/Bloc/data/models/landmark/landmark_model.g.dart @@ -0,0 +1,62 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'landmark_model.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class LandMarkModelAdapter extends TypeAdapter { + @override + final int typeId = 50; + + @override + LandMarkModel read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return LandMarkModel( + title: fields[0] as String?, + location: fields[1] as LocationModel?, + ); + } + + @override + void write(BinaryWriter writer, LandMarkModel obj) { + writer + ..writeByte(2) + ..writeByte(0) + ..write(obj.title) + ..writeByte(1) + ..write(obj.location); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is LandMarkModelAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LandMarkModel _$LandMarkModelFromJson(Map json) => + LandMarkModel( + title: json['title'] as String?, + location: json['location'] == null + ? null + : LocationModel.fromJson(json['location'] as Map), + ); + +Map _$LandMarkModelToJson(LandMarkModel instance) => + { + 'title': instance.title, + 'location': instance.location, + }; diff --git a/lib/Bloc/data/models/location/location_model.dart b/lib/Bloc/data/models/location/location_model.dart new file mode 100644 index 00000000..79701b6f --- /dev/null +++ b/lib/Bloc/data/models/location/location_model.dart @@ -0,0 +1,38 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:hive/hive.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:beacon/Bloc/domain/entities/location/location_entity.dart'; +part 'location_model.g.dart'; + +@HiveType(typeId: 40) +@JsonSerializable() +class LocationModel implements LocationEntity { + @HiveField(0) + final String? lat; + @HiveField(1) + final String? lon; + + LocationModel({ + this.lat, + this.lon, + }); + + factory LocationModel.fromJson(Map json) => + _$LocationModelFromJson(json); + + Map toJson() => _$LocationModelToJson(this); + + LocationModel copyWithModel({ + String? lat, + String? long, + }) { + return LocationModel( + lat: lat ?? this.lat, + lon: lon ?? this.lon, + ); + } + + @override + $LocationEntityCopyWith get copyWith => + throw UnimplementedError(); +} diff --git a/lib/Bloc/data/models/location/location_model.g.dart b/lib/Bloc/data/models/location/location_model.g.dart new file mode 100644 index 00000000..174fae3f --- /dev/null +++ b/lib/Bloc/data/models/location/location_model.g.dart @@ -0,0 +1,60 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'location_model.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class LocationModelAdapter extends TypeAdapter { + @override + final int typeId = 40; + + @override + LocationModel read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return LocationModel( + lat: fields[0] as String?, + lon: fields[1] as String?, + ); + } + + @override + void write(BinaryWriter writer, LocationModel obj) { + writer + ..writeByte(2) + ..writeByte(0) + ..write(obj.lat) + ..writeByte(1) + ..write(obj.lon); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is LocationModelAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LocationModel _$LocationModelFromJson(Map json) => + LocationModel( + lat: json['lat'] as String?, + lon: json['lon'] as String?, + ); + +Map _$LocationModelToJson(LocationModel instance) => + { + 'lat': instance.lat, + 'lon': instance.lon, + }; diff --git a/lib/Bloc/data/models/user/user_model.dart b/lib/Bloc/data/models/user/user_model.dart new file mode 100644 index 00000000..41bcd7be --- /dev/null +++ b/lib/Bloc/data/models/user/user_model.dart @@ -0,0 +1,76 @@ +import 'package:beacon/Bloc/data/models/beacon/beacon_model.dart'; +import 'package:beacon/Bloc/data/models/group/group_model.dart'; +import 'package:beacon/Bloc/data/models/location/location_model.dart'; +import 'package:beacon/Bloc/domain/entities/user/user_entity.dart'; +import 'package:hive/hive.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'user_model.g.dart'; + +@HiveType(typeId: 10) +@JsonSerializable() +class UserModel implements UserEntity { + @HiveField(0) + String? id; + + @HiveField(1) + String? name; + + @HiveField(2) + String? email; + + @HiveField(3) + String? authToken; + + @HiveField(4) + bool? isGuest; + + @HiveField(5) + List? groups; + + @HiveField(6) + List? beacons; + + @HiveField(7) + LocationModel? location; + + UserModel( + {this.authToken, + this.beacons, + this.email, + this.groups, + this.id, + this.isGuest, + this.location, + this.name}); + + @override + $UserEntityCopyWith get copyWith => throw UnimplementedError(); + + factory UserModel.fromJson(Map json) => + _$UserModelFromJson(json); + + Map toJson() => _$UserModelToJson(this); + + UserModel copyWithModel({ + String? id, + String? name, + String? authToken, + String? email, + bool? isGuest, + List? groups, + List? beacons, + LocationModel? location, + }) { + return UserModel( + id: id ?? this.id, + name: name ?? this.name, + authToken: authToken ?? this.authToken, + email: email ?? this.email, + isGuest: isGuest ?? this.isGuest, + groups: groups ?? this.groups, + beacons: beacons ?? this.beacons, + location: location ?? this.location, + ); + } +} diff --git a/lib/Bloc/data/models/user/user_model.g.dart b/lib/Bloc/data/models/user/user_model.g.dart new file mode 100644 index 00000000..e52a8909 --- /dev/null +++ b/lib/Bloc/data/models/user/user_model.g.dart @@ -0,0 +1,97 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user_model.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class UserModelAdapter extends TypeAdapter { + @override + final int typeId = 10; + + @override + UserModel read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return UserModel( + authToken: fields[3] as String?, + beacons: (fields[6] as List?)?.cast(), + email: fields[2] as String?, + groups: (fields[5] as List?)?.cast(), + id: fields[0] as String?, + isGuest: fields[4] as bool?, + location: fields[7] as LocationModel?, + name: fields[1] as String?, + ); + } + + @override + void write(BinaryWriter writer, UserModel obj) { + writer + ..writeByte(8) + ..writeByte(0) + ..write(obj.id) + ..writeByte(1) + ..write(obj.name) + ..writeByte(2) + ..write(obj.email) + ..writeByte(3) + ..write(obj.authToken) + ..writeByte(4) + ..write(obj.isGuest) + ..writeByte(5) + ..write(obj.groups) + ..writeByte(6) + ..write(obj.beacons) + ..writeByte(7) + ..write(obj.location); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is UserModelAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +UserModel _$UserModelFromJson(Map json) => UserModel( + authToken: json['authToken'] as String?, + beacons: (json['beacons'] as List?) + ?.map((e) => e == null + ? null + : BeaconModel.fromJson(e as Map)) + .toList(), + email: json['email'] as String?, + groups: (json['groups'] as List?) + ?.map((e) => + e == null ? null : GroupModel.fromJson(e as Map)) + .toList(), + id: json['_id'] as String?, + isGuest: json['isGuest'] as bool?, + location: json['location'] == null + ? null + : LocationModel.fromJson(json['location'] as Map), + name: json['name'] as String?, + ); + +Map _$UserModelToJson(UserModel instance) => { + '_id': instance.id, + 'name': instance.name, + 'email': instance.email, + 'authToken': instance.authToken, + 'isGuest': instance.isGuest, + 'groups': instance.groups, + 'beacons': instance.beacons, + 'location': instance.location, + }; diff --git a/lib/Bloc/data/repositories/auth_repository_implementation.dart b/lib/Bloc/data/repositories/auth_repository_implementation.dart new file mode 100644 index 00000000..3ed41e6e --- /dev/null +++ b/lib/Bloc/data/repositories/auth_repository_implementation.dart @@ -0,0 +1,26 @@ +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/data/datasource/remote/remote_auth_api.dart'; +import 'package:beacon/Bloc/data/models/user/user_model.dart'; +import 'package:beacon/Bloc/domain/repositories/auth_repository.dart'; + +class AuthRepositoryImplementation extends AuthRepository { + final RemoteAuthApi remoteAuthApi; + + AuthRepositoryImplementation({required this.remoteAuthApi}); + + @override + Future> getUser() { + return remoteAuthApi.fetchUserInfo(); + } + + @override + Future> login(String email, String password) { + return remoteAuthApi.login(email, password); + } + + @override + Future> register( + String name, String email, String password) { + return remoteAuthApi.register(name, email, password); + } +} diff --git a/lib/Bloc/data/repositories/group_repository_implementation.dart b/lib/Bloc/data/repositories/group_repository_implementation.dart new file mode 100644 index 00000000..94ada788 --- /dev/null +++ b/lib/Bloc/data/repositories/group_repository_implementation.dart @@ -0,0 +1,26 @@ +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/data/datasource/remote/remote_group_api.dart'; +import 'package:beacon/Bloc/data/models/beacon/beacon_model.dart'; +import 'package:beacon/Bloc/domain/repositories/group_repository.dart'; + +class GroupRepostioryImplementation extends GroupRepository { + final RemoteGroupApi remoteGroupApi; + GroupRepostioryImplementation({required this.remoteGroupApi}); + @override + Future> createHike(String title, int startsAt, + int expiresAt, String lat, String lon, String groupID) async { + return remoteGroupApi.createHike( + title, startsAt, expiresAt, lat, lon, groupID); + } + + @override + Future>> fetchHikes( + String groupID, int page, int pageSize) { + return remoteGroupApi.fetchHikes(groupID, page, pageSize); + } + + @override + Future> joinHike(String shortcode) { + return remoteGroupApi.joinHike(shortcode); + } +} diff --git a/lib/Bloc/data/repositories/home_repository_implementation.dart b/lib/Bloc/data/repositories/home_repository_implementation.dart new file mode 100644 index 00000000..c63b036b --- /dev/null +++ b/lib/Bloc/data/repositories/home_repository_implementation.dart @@ -0,0 +1,25 @@ +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/data/datasource/remote/remote_home_api.dart'; +import 'package:beacon/Bloc/data/models/group/group_model.dart'; +import 'package:beacon/Bloc/domain/repositories/home_repository.dart'; + +class HomeRepostitoryImplementation extends HomeRepository { + final RemoteHomeApi remoteHomeApi; + + HomeRepostitoryImplementation({required this.remoteHomeApi}); + + @override + Future> createGroup(String title) { + return remoteHomeApi.createGroup(title); + } + + @override + Future>> fetchGroups(int page, int pageSize) { + return remoteHomeApi.fetchUserGroups(page, pageSize); + } + + @override + Future> joinGroup(String shortCode) { + return remoteHomeApi.joinGroup(shortCode); + } +} diff --git a/lib/Bloc/domain/entities/beacon/beacon_entity.dart b/lib/Bloc/domain/entities/beacon/beacon_entity.dart new file mode 100644 index 00000000..2f1ce48c --- /dev/null +++ b/lib/Bloc/domain/entities/beacon/beacon_entity.dart @@ -0,0 +1,23 @@ +import 'package:beacon/Bloc/domain/entities/group/group_entity.dart'; +import 'package:beacon/Bloc/domain/entities/landmark/landmark_entity.dart'; +import 'package:beacon/Bloc/domain/entities/location/location_entity.dart'; +import 'package:beacon/Bloc/domain/entities/user/user_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'beacon_entity.freezed.dart'; + +@freezed +class BeaconEntity with _$BeaconEntity { + const factory BeaconEntity( + {String? id, + String? shortcode, + int? startsAt, + int? expiresAt, + String? title, + UserEntity? leader, + List? followers, + List? route, + List? landmarks, + LocationEntity? location, + GroupEntity? group}) = _BeaconEntity; +} diff --git a/lib/Bloc/domain/entities/beacon/beacon_entity.freezed.dart b/lib/Bloc/domain/entities/beacon/beacon_entity.freezed.dart new file mode 100644 index 00000000..a623a54b --- /dev/null +++ b/lib/Bloc/domain/entities/beacon/beacon_entity.freezed.dart @@ -0,0 +1,428 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'beacon_entity.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$BeaconEntity { + String? get id => throw _privateConstructorUsedError; + String? get shortcode => throw _privateConstructorUsedError; + int? get startsAt => throw _privateConstructorUsedError; + int? get expiresAt => throw _privateConstructorUsedError; + String? get title => throw _privateConstructorUsedError; + UserEntity? get leader => throw _privateConstructorUsedError; + List? get followers => throw _privateConstructorUsedError; + List? get route => throw _privateConstructorUsedError; + List? get landmarks => throw _privateConstructorUsedError; + LocationEntity? get location => throw _privateConstructorUsedError; + GroupEntity? get group => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $BeaconEntityCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $BeaconEntityCopyWith<$Res> { + factory $BeaconEntityCopyWith( + BeaconEntity value, $Res Function(BeaconEntity) then) = + _$BeaconEntityCopyWithImpl<$Res, BeaconEntity>; + @useResult + $Res call( + {String? id, + String? shortcode, + int? startsAt, + int? expiresAt, + String? title, + UserEntity? leader, + List? followers, + List? route, + List? landmarks, + LocationEntity? location, + GroupEntity? group}); + + $UserEntityCopyWith<$Res>? get leader; + $LocationEntityCopyWith<$Res>? get location; + $GroupEntityCopyWith<$Res>? get group; +} + +/// @nodoc +class _$BeaconEntityCopyWithImpl<$Res, $Val extends BeaconEntity> + implements $BeaconEntityCopyWith<$Res> { + _$BeaconEntityCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? shortcode = freezed, + Object? startsAt = freezed, + Object? expiresAt = freezed, + Object? title = freezed, + Object? leader = freezed, + Object? followers = freezed, + Object? route = freezed, + Object? landmarks = freezed, + Object? location = freezed, + Object? group = freezed, + }) { + return _then(_value.copyWith( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + shortcode: freezed == shortcode + ? _value.shortcode + : shortcode // ignore: cast_nullable_to_non_nullable + as String?, + startsAt: freezed == startsAt + ? _value.startsAt + : startsAt // ignore: cast_nullable_to_non_nullable + as int?, + expiresAt: freezed == expiresAt + ? _value.expiresAt + : expiresAt // ignore: cast_nullable_to_non_nullable + as int?, + title: freezed == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String?, + leader: freezed == leader + ? _value.leader + : leader // ignore: cast_nullable_to_non_nullable + as UserEntity?, + followers: freezed == followers + ? _value.followers + : followers // ignore: cast_nullable_to_non_nullable + as List?, + route: freezed == route + ? _value.route + : route // ignore: cast_nullable_to_non_nullable + as List?, + landmarks: freezed == landmarks + ? _value.landmarks + : landmarks // ignore: cast_nullable_to_non_nullable + as List?, + location: freezed == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as LocationEntity?, + group: freezed == group + ? _value.group + : group // ignore: cast_nullable_to_non_nullable + as GroupEntity?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $UserEntityCopyWith<$Res>? get leader { + if (_value.leader == null) { + return null; + } + + return $UserEntityCopyWith<$Res>(_value.leader!, (value) { + return _then(_value.copyWith(leader: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $LocationEntityCopyWith<$Res>? get location { + if (_value.location == null) { + return null; + } + + return $LocationEntityCopyWith<$Res>(_value.location!, (value) { + return _then(_value.copyWith(location: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $GroupEntityCopyWith<$Res>? get group { + if (_value.group == null) { + return null; + } + + return $GroupEntityCopyWith<$Res>(_value.group!, (value) { + return _then(_value.copyWith(group: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$BeaconEntityImplCopyWith<$Res> + implements $BeaconEntityCopyWith<$Res> { + factory _$$BeaconEntityImplCopyWith( + _$BeaconEntityImpl value, $Res Function(_$BeaconEntityImpl) then) = + __$$BeaconEntityImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String? id, + String? shortcode, + int? startsAt, + int? expiresAt, + String? title, + UserEntity? leader, + List? followers, + List? route, + List? landmarks, + LocationEntity? location, + GroupEntity? group}); + + @override + $UserEntityCopyWith<$Res>? get leader; + @override + $LocationEntityCopyWith<$Res>? get location; + @override + $GroupEntityCopyWith<$Res>? get group; +} + +/// @nodoc +class __$$BeaconEntityImplCopyWithImpl<$Res> + extends _$BeaconEntityCopyWithImpl<$Res, _$BeaconEntityImpl> + implements _$$BeaconEntityImplCopyWith<$Res> { + __$$BeaconEntityImplCopyWithImpl( + _$BeaconEntityImpl _value, $Res Function(_$BeaconEntityImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? shortcode = freezed, + Object? startsAt = freezed, + Object? expiresAt = freezed, + Object? title = freezed, + Object? leader = freezed, + Object? followers = freezed, + Object? route = freezed, + Object? landmarks = freezed, + Object? location = freezed, + Object? group = freezed, + }) { + return _then(_$BeaconEntityImpl( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + shortcode: freezed == shortcode + ? _value.shortcode + : shortcode // ignore: cast_nullable_to_non_nullable + as String?, + startsAt: freezed == startsAt + ? _value.startsAt + : startsAt // ignore: cast_nullable_to_non_nullable + as int?, + expiresAt: freezed == expiresAt + ? _value.expiresAt + : expiresAt // ignore: cast_nullable_to_non_nullable + as int?, + title: freezed == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String?, + leader: freezed == leader + ? _value.leader + : leader // ignore: cast_nullable_to_non_nullable + as UserEntity?, + followers: freezed == followers + ? _value._followers + : followers // ignore: cast_nullable_to_non_nullable + as List?, + route: freezed == route + ? _value._route + : route // ignore: cast_nullable_to_non_nullable + as List?, + landmarks: freezed == landmarks + ? _value._landmarks + : landmarks // ignore: cast_nullable_to_non_nullable + as List?, + location: freezed == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as LocationEntity?, + group: freezed == group + ? _value.group + : group // ignore: cast_nullable_to_non_nullable + as GroupEntity?, + )); + } +} + +/// @nodoc + +class _$BeaconEntityImpl implements _BeaconEntity { + const _$BeaconEntityImpl( + {this.id, + this.shortcode, + this.startsAt, + this.expiresAt, + this.title, + this.leader, + final List? followers, + final List? route, + final List? landmarks, + this.location, + this.group}) + : _followers = followers, + _route = route, + _landmarks = landmarks; + + @override + final String? id; + @override + final String? shortcode; + @override + final int? startsAt; + @override + final int? expiresAt; + @override + final String? title; + @override + final UserEntity? leader; + final List? _followers; + @override + List? get followers { + final value = _followers; + if (value == null) return null; + if (_followers is EqualUnmodifiableListView) return _followers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + final List? _route; + @override + List? get route { + final value = _route; + if (value == null) return null; + if (_route is EqualUnmodifiableListView) return _route; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + final List? _landmarks; + @override + List? get landmarks { + final value = _landmarks; + if (value == null) return null; + if (_landmarks is EqualUnmodifiableListView) return _landmarks; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + final LocationEntity? location; + @override + final GroupEntity? group; + + @override + String toString() { + return 'BeaconEntity(id: $id, shortcode: $shortcode, startsAt: $startsAt, expiresAt: $expiresAt, title: $title, leader: $leader, followers: $followers, route: $route, landmarks: $landmarks, location: $location, group: $group)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BeaconEntityImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.shortcode, shortcode) || + other.shortcode == shortcode) && + (identical(other.startsAt, startsAt) || + other.startsAt == startsAt) && + (identical(other.expiresAt, expiresAt) || + other.expiresAt == expiresAt) && + (identical(other.title, title) || other.title == title) && + (identical(other.leader, leader) || other.leader == leader) && + const DeepCollectionEquality() + .equals(other._followers, _followers) && + const DeepCollectionEquality().equals(other._route, _route) && + const DeepCollectionEquality() + .equals(other._landmarks, _landmarks) && + (identical(other.location, location) || + other.location == location) && + (identical(other.group, group) || other.group == group)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + id, + shortcode, + startsAt, + expiresAt, + title, + leader, + const DeepCollectionEquality().hash(_followers), + const DeepCollectionEquality().hash(_route), + const DeepCollectionEquality().hash(_landmarks), + location, + group); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$BeaconEntityImplCopyWith<_$BeaconEntityImpl> get copyWith => + __$$BeaconEntityImplCopyWithImpl<_$BeaconEntityImpl>(this, _$identity); +} + +abstract class _BeaconEntity implements BeaconEntity { + const factory _BeaconEntity( + {final String? id, + final String? shortcode, + final int? startsAt, + final int? expiresAt, + final String? title, + final UserEntity? leader, + final List? followers, + final List? route, + final List? landmarks, + final LocationEntity? location, + final GroupEntity? group}) = _$BeaconEntityImpl; + + @override + String? get id; + @override + String? get shortcode; + @override + int? get startsAt; + @override + int? get expiresAt; + @override + String? get title; + @override + UserEntity? get leader; + @override + List? get followers; + @override + List? get route; + @override + List? get landmarks; + @override + LocationEntity? get location; + @override + GroupEntity? get group; + @override + @JsonKey(ignore: true) + _$$BeaconEntityImplCopyWith<_$BeaconEntityImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/Bloc/domain/entities/group/group_entity.dart b/lib/Bloc/domain/entities/group/group_entity.dart new file mode 100644 index 00000000..d036619f --- /dev/null +++ b/lib/Bloc/domain/entities/group/group_entity.dart @@ -0,0 +1,17 @@ +import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/Bloc/domain/entities/user/user_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'group_entity.freezed.dart'; + +@freezed +class GroupEntity with _$GroupEntity { + const factory GroupEntity({ + String? id, + List? beacons, + List? members, + UserEntity? leader, + String? title, + String? shortcode, + }) = _GroupEntity; +} diff --git a/lib/Bloc/domain/entities/group/group_entity.freezed.dart b/lib/Bloc/domain/entities/group/group_entity.freezed.dart new file mode 100644 index 00000000..c601ea0a --- /dev/null +++ b/lib/Bloc/domain/entities/group/group_entity.freezed.dart @@ -0,0 +1,279 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'group_entity.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$GroupEntity { + String? get id => throw _privateConstructorUsedError; + List? get beacons => throw _privateConstructorUsedError; + List? get members => throw _privateConstructorUsedError; + UserEntity? get leader => throw _privateConstructorUsedError; + String? get title => throw _privateConstructorUsedError; + String? get shortcode => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $GroupEntityCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $GroupEntityCopyWith<$Res> { + factory $GroupEntityCopyWith( + GroupEntity value, $Res Function(GroupEntity) then) = + _$GroupEntityCopyWithImpl<$Res, GroupEntity>; + @useResult + $Res call( + {String? id, + List? beacons, + List? members, + UserEntity? leader, + String? title, + String? shortcode}); + + $UserEntityCopyWith<$Res>? get leader; +} + +/// @nodoc +class _$GroupEntityCopyWithImpl<$Res, $Val extends GroupEntity> + implements $GroupEntityCopyWith<$Res> { + _$GroupEntityCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? beacons = freezed, + Object? members = freezed, + Object? leader = freezed, + Object? title = freezed, + Object? shortcode = freezed, + }) { + return _then(_value.copyWith( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + beacons: freezed == beacons + ? _value.beacons + : beacons // ignore: cast_nullable_to_non_nullable + as List?, + members: freezed == members + ? _value.members + : members // ignore: cast_nullable_to_non_nullable + as List?, + leader: freezed == leader + ? _value.leader + : leader // ignore: cast_nullable_to_non_nullable + as UserEntity?, + title: freezed == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String?, + shortcode: freezed == shortcode + ? _value.shortcode + : shortcode // ignore: cast_nullable_to_non_nullable + as String?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $UserEntityCopyWith<$Res>? get leader { + if (_value.leader == null) { + return null; + } + + return $UserEntityCopyWith<$Res>(_value.leader!, (value) { + return _then(_value.copyWith(leader: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$GroupEntityImplCopyWith<$Res> + implements $GroupEntityCopyWith<$Res> { + factory _$$GroupEntityImplCopyWith( + _$GroupEntityImpl value, $Res Function(_$GroupEntityImpl) then) = + __$$GroupEntityImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String? id, + List? beacons, + List? members, + UserEntity? leader, + String? title, + String? shortcode}); + + @override + $UserEntityCopyWith<$Res>? get leader; +} + +/// @nodoc +class __$$GroupEntityImplCopyWithImpl<$Res> + extends _$GroupEntityCopyWithImpl<$Res, _$GroupEntityImpl> + implements _$$GroupEntityImplCopyWith<$Res> { + __$$GroupEntityImplCopyWithImpl( + _$GroupEntityImpl _value, $Res Function(_$GroupEntityImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? beacons = freezed, + Object? members = freezed, + Object? leader = freezed, + Object? title = freezed, + Object? shortcode = freezed, + }) { + return _then(_$GroupEntityImpl( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + beacons: freezed == beacons + ? _value._beacons + : beacons // ignore: cast_nullable_to_non_nullable + as List?, + members: freezed == members + ? _value._members + : members // ignore: cast_nullable_to_non_nullable + as List?, + leader: freezed == leader + ? _value.leader + : leader // ignore: cast_nullable_to_non_nullable + as UserEntity?, + title: freezed == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String?, + shortcode: freezed == shortcode + ? _value.shortcode + : shortcode // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$GroupEntityImpl implements _GroupEntity { + const _$GroupEntityImpl( + {this.id, + final List? beacons, + final List? members, + this.leader, + this.title, + this.shortcode}) + : _beacons = beacons, + _members = members; + + @override + final String? id; + final List? _beacons; + @override + List? get beacons { + final value = _beacons; + if (value == null) return null; + if (_beacons is EqualUnmodifiableListView) return _beacons; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + final List? _members; + @override + List? get members { + final value = _members; + if (value == null) return null; + if (_members is EqualUnmodifiableListView) return _members; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + final UserEntity? leader; + @override + final String? title; + @override + final String? shortcode; + + @override + String toString() { + return 'GroupEntity(id: $id, beacons: $beacons, members: $members, leader: $leader, title: $title, shortcode: $shortcode)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$GroupEntityImpl && + (identical(other.id, id) || other.id == id) && + const DeepCollectionEquality().equals(other._beacons, _beacons) && + const DeepCollectionEquality().equals(other._members, _members) && + (identical(other.leader, leader) || other.leader == leader) && + (identical(other.title, title) || other.title == title) && + (identical(other.shortcode, shortcode) || + other.shortcode == shortcode)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + id, + const DeepCollectionEquality().hash(_beacons), + const DeepCollectionEquality().hash(_members), + leader, + title, + shortcode); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$GroupEntityImplCopyWith<_$GroupEntityImpl> get copyWith => + __$$GroupEntityImplCopyWithImpl<_$GroupEntityImpl>(this, _$identity); +} + +abstract class _GroupEntity implements GroupEntity { + const factory _GroupEntity( + {final String? id, + final List? beacons, + final List? members, + final UserEntity? leader, + final String? title, + final String? shortcode}) = _$GroupEntityImpl; + + @override + String? get id; + @override + List? get beacons; + @override + List? get members; + @override + UserEntity? get leader; + @override + String? get title; + @override + String? get shortcode; + @override + @JsonKey(ignore: true) + _$$GroupEntityImplCopyWith<_$GroupEntityImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/Bloc/domain/entities/landmark/landmark_entity.dart b/lib/Bloc/domain/entities/landmark/landmark_entity.dart new file mode 100644 index 00000000..883699ec --- /dev/null +++ b/lib/Bloc/domain/entities/landmark/landmark_entity.dart @@ -0,0 +1,9 @@ +import 'package:beacon/Bloc/domain/entities/location/location_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'landmark_entity.freezed.dart'; + +@freezed +class LandMarkEntity with _$LandMarkEntity { + const factory LandMarkEntity({String? title, LocationEntity? location}) = + _LandMarkEntity; +} diff --git a/lib/Bloc/domain/entities/landmark/landmark_entity.freezed.dart b/lib/Bloc/domain/entities/landmark/landmark_entity.freezed.dart new file mode 100644 index 00000000..3cbebc00 --- /dev/null +++ b/lib/Bloc/domain/entities/landmark/landmark_entity.freezed.dart @@ -0,0 +1,169 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'landmark_entity.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$LandMarkEntity { + String? get title => throw _privateConstructorUsedError; + LocationEntity? get location => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $LandMarkEntityCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LandMarkEntityCopyWith<$Res> { + factory $LandMarkEntityCopyWith( + LandMarkEntity value, $Res Function(LandMarkEntity) then) = + _$LandMarkEntityCopyWithImpl<$Res, LandMarkEntity>; + @useResult + $Res call({String? title, LocationEntity? location}); + + $LocationEntityCopyWith<$Res>? get location; +} + +/// @nodoc +class _$LandMarkEntityCopyWithImpl<$Res, $Val extends LandMarkEntity> + implements $LandMarkEntityCopyWith<$Res> { + _$LandMarkEntityCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? title = freezed, + Object? location = freezed, + }) { + return _then(_value.copyWith( + title: freezed == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String?, + location: freezed == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as LocationEntity?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $LocationEntityCopyWith<$Res>? get location { + if (_value.location == null) { + return null; + } + + return $LocationEntityCopyWith<$Res>(_value.location!, (value) { + return _then(_value.copyWith(location: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$LandMarkEntityImplCopyWith<$Res> + implements $LandMarkEntityCopyWith<$Res> { + factory _$$LandMarkEntityImplCopyWith(_$LandMarkEntityImpl value, + $Res Function(_$LandMarkEntityImpl) then) = + __$$LandMarkEntityImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String? title, LocationEntity? location}); + + @override + $LocationEntityCopyWith<$Res>? get location; +} + +/// @nodoc +class __$$LandMarkEntityImplCopyWithImpl<$Res> + extends _$LandMarkEntityCopyWithImpl<$Res, _$LandMarkEntityImpl> + implements _$$LandMarkEntityImplCopyWith<$Res> { + __$$LandMarkEntityImplCopyWithImpl( + _$LandMarkEntityImpl _value, $Res Function(_$LandMarkEntityImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? title = freezed, + Object? location = freezed, + }) { + return _then(_$LandMarkEntityImpl( + title: freezed == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String?, + location: freezed == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as LocationEntity?, + )); + } +} + +/// @nodoc + +class _$LandMarkEntityImpl implements _LandMarkEntity { + const _$LandMarkEntityImpl({this.title, this.location}); + + @override + final String? title; + @override + final LocationEntity? location; + + @override + String toString() { + return 'LandMarkEntity(title: $title, location: $location)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LandMarkEntityImpl && + (identical(other.title, title) || other.title == title) && + (identical(other.location, location) || + other.location == location)); + } + + @override + int get hashCode => Object.hash(runtimeType, title, location); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LandMarkEntityImplCopyWith<_$LandMarkEntityImpl> get copyWith => + __$$LandMarkEntityImplCopyWithImpl<_$LandMarkEntityImpl>( + this, _$identity); +} + +abstract class _LandMarkEntity implements LandMarkEntity { + const factory _LandMarkEntity( + {final String? title, + final LocationEntity? location}) = _$LandMarkEntityImpl; + + @override + String? get title; + @override + LocationEntity? get location; + @override + @JsonKey(ignore: true) + _$$LandMarkEntityImplCopyWith<_$LandMarkEntityImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/Bloc/domain/entities/location/location_entity.dart b/lib/Bloc/domain/entities/location/location_entity.dart new file mode 100644 index 00000000..6f7448a9 --- /dev/null +++ b/lib/Bloc/domain/entities/location/location_entity.dart @@ -0,0 +1,7 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'location_entity.freezed.dart'; + +@freezed +class LocationEntity with _$LocationEntity { + factory LocationEntity({String? lat, String? lon}) = _LocationEntity; +} diff --git a/lib/Bloc/domain/entities/location/location_entity.freezed.dart b/lib/Bloc/domain/entities/location/location_entity.freezed.dart new file mode 100644 index 00000000..01117b3a --- /dev/null +++ b/lib/Bloc/domain/entities/location/location_entity.freezed.dart @@ -0,0 +1,150 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'location_entity.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$LocationEntity { + String? get lat => throw _privateConstructorUsedError; + String? get lon => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $LocationEntityCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LocationEntityCopyWith<$Res> { + factory $LocationEntityCopyWith( + LocationEntity value, $Res Function(LocationEntity) then) = + _$LocationEntityCopyWithImpl<$Res, LocationEntity>; + @useResult + $Res call({String? lat, String? lon}); +} + +/// @nodoc +class _$LocationEntityCopyWithImpl<$Res, $Val extends LocationEntity> + implements $LocationEntityCopyWith<$Res> { + _$LocationEntityCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? lat = freezed, + Object? lon = freezed, + }) { + return _then(_value.copyWith( + lat: freezed == lat + ? _value.lat + : lat // ignore: cast_nullable_to_non_nullable + as String?, + lon: freezed == lon + ? _value.lon + : lon // ignore: cast_nullable_to_non_nullable + as String?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$LocationEntityImplCopyWith<$Res> + implements $LocationEntityCopyWith<$Res> { + factory _$$LocationEntityImplCopyWith(_$LocationEntityImpl value, + $Res Function(_$LocationEntityImpl) then) = + __$$LocationEntityImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String? lat, String? lon}); +} + +/// @nodoc +class __$$LocationEntityImplCopyWithImpl<$Res> + extends _$LocationEntityCopyWithImpl<$Res, _$LocationEntityImpl> + implements _$$LocationEntityImplCopyWith<$Res> { + __$$LocationEntityImplCopyWithImpl( + _$LocationEntityImpl _value, $Res Function(_$LocationEntityImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? lat = freezed, + Object? lon = freezed, + }) { + return _then(_$LocationEntityImpl( + lat: freezed == lat + ? _value.lat + : lat // ignore: cast_nullable_to_non_nullable + as String?, + lon: freezed == lon + ? _value.lon + : lon // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$LocationEntityImpl implements _LocationEntity { + _$LocationEntityImpl({this.lat, this.lon}); + + @override + final String? lat; + @override + final String? lon; + + @override + String toString() { + return 'LocationEntity(lat: $lat, lon: $lon)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LocationEntityImpl && + (identical(other.lat, lat) || other.lat == lat) && + (identical(other.lon, lon) || other.lon == lon)); + } + + @override + int get hashCode => Object.hash(runtimeType, lat, lon); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LocationEntityImplCopyWith<_$LocationEntityImpl> get copyWith => + __$$LocationEntityImplCopyWithImpl<_$LocationEntityImpl>( + this, _$identity); +} + +abstract class _LocationEntity implements LocationEntity { + factory _LocationEntity({final String? lat, final String? lon}) = + _$LocationEntityImpl; + + @override + String? get lat; + @override + String? get lon; + @override + @JsonKey(ignore: true) + _$$LocationEntityImplCopyWith<_$LocationEntityImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/Bloc/domain/entities/user/user_entity.dart b/lib/Bloc/domain/entities/user/user_entity.dart new file mode 100644 index 00000000..d82447f4 --- /dev/null +++ b/lib/Bloc/domain/entities/user/user_entity.dart @@ -0,0 +1,19 @@ +import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/Bloc/domain/entities/group/group_entity.dart'; +import 'package:beacon/Bloc/domain/entities/location/location_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'user_entity.freezed.dart'; + +@freezed +class UserEntity with _$UserEntity { + const factory UserEntity( + {String? id, + List? groups, + List? beacons, + String? authToken, + String? email, + bool? isGuest, + String? name, + LocationEntity? location}) = _UserEntity; +} diff --git a/lib/Bloc/domain/entities/user/user_entity.freezed.dart b/lib/Bloc/domain/entities/user/user_entity.freezed.dart new file mode 100644 index 00000000..6fbc3091 --- /dev/null +++ b/lib/Bloc/domain/entities/user/user_entity.freezed.dart @@ -0,0 +1,322 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'user_entity.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$UserEntity { + String? get id => throw _privateConstructorUsedError; + List? get groups => throw _privateConstructorUsedError; + List? get beacons => throw _privateConstructorUsedError; + String? get authToken => throw _privateConstructorUsedError; + String? get email => throw _privateConstructorUsedError; + bool? get isGuest => throw _privateConstructorUsedError; + String? get name => throw _privateConstructorUsedError; + LocationEntity? get location => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $UserEntityCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $UserEntityCopyWith<$Res> { + factory $UserEntityCopyWith( + UserEntity value, $Res Function(UserEntity) then) = + _$UserEntityCopyWithImpl<$Res, UserEntity>; + @useResult + $Res call( + {String? id, + List? groups, + List? beacons, + String? authToken, + String? email, + bool? isGuest, + String? name, + LocationEntity? location}); + + $LocationEntityCopyWith<$Res>? get location; +} + +/// @nodoc +class _$UserEntityCopyWithImpl<$Res, $Val extends UserEntity> + implements $UserEntityCopyWith<$Res> { + _$UserEntityCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? groups = freezed, + Object? beacons = freezed, + Object? authToken = freezed, + Object? email = freezed, + Object? isGuest = freezed, + Object? name = freezed, + Object? location = freezed, + }) { + return _then(_value.copyWith( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + groups: freezed == groups + ? _value.groups + : groups // ignore: cast_nullable_to_non_nullable + as List?, + beacons: freezed == beacons + ? _value.beacons + : beacons // ignore: cast_nullable_to_non_nullable + as List?, + authToken: freezed == authToken + ? _value.authToken + : authToken // ignore: cast_nullable_to_non_nullable + as String?, + email: freezed == email + ? _value.email + : email // ignore: cast_nullable_to_non_nullable + as String?, + isGuest: freezed == isGuest + ? _value.isGuest + : isGuest // ignore: cast_nullable_to_non_nullable + as bool?, + name: freezed == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String?, + location: freezed == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as LocationEntity?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $LocationEntityCopyWith<$Res>? get location { + if (_value.location == null) { + return null; + } + + return $LocationEntityCopyWith<$Res>(_value.location!, (value) { + return _then(_value.copyWith(location: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$UserEntityImplCopyWith<$Res> + implements $UserEntityCopyWith<$Res> { + factory _$$UserEntityImplCopyWith( + _$UserEntityImpl value, $Res Function(_$UserEntityImpl) then) = + __$$UserEntityImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String? id, + List? groups, + List? beacons, + String? authToken, + String? email, + bool? isGuest, + String? name, + LocationEntity? location}); + + @override + $LocationEntityCopyWith<$Res>? get location; +} + +/// @nodoc +class __$$UserEntityImplCopyWithImpl<$Res> + extends _$UserEntityCopyWithImpl<$Res, _$UserEntityImpl> + implements _$$UserEntityImplCopyWith<$Res> { + __$$UserEntityImplCopyWithImpl( + _$UserEntityImpl _value, $Res Function(_$UserEntityImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? groups = freezed, + Object? beacons = freezed, + Object? authToken = freezed, + Object? email = freezed, + Object? isGuest = freezed, + Object? name = freezed, + Object? location = freezed, + }) { + return _then(_$UserEntityImpl( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + groups: freezed == groups + ? _value._groups + : groups // ignore: cast_nullable_to_non_nullable + as List?, + beacons: freezed == beacons + ? _value._beacons + : beacons // ignore: cast_nullable_to_non_nullable + as List?, + authToken: freezed == authToken + ? _value.authToken + : authToken // ignore: cast_nullable_to_non_nullable + as String?, + email: freezed == email + ? _value.email + : email // ignore: cast_nullable_to_non_nullable + as String?, + isGuest: freezed == isGuest + ? _value.isGuest + : isGuest // ignore: cast_nullable_to_non_nullable + as bool?, + name: freezed == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String?, + location: freezed == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as LocationEntity?, + )); + } +} + +/// @nodoc + +class _$UserEntityImpl implements _UserEntity { + const _$UserEntityImpl( + {this.id, + final List? groups, + final List? beacons, + this.authToken, + this.email, + this.isGuest, + this.name, + this.location}) + : _groups = groups, + _beacons = beacons; + + @override + final String? id; + final List? _groups; + @override + List? get groups { + final value = _groups; + if (value == null) return null; + if (_groups is EqualUnmodifiableListView) return _groups; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + final List? _beacons; + @override + List? get beacons { + final value = _beacons; + if (value == null) return null; + if (_beacons is EqualUnmodifiableListView) return _beacons; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + final String? authToken; + @override + final String? email; + @override + final bool? isGuest; + @override + final String? name; + @override + final LocationEntity? location; + + @override + String toString() { + return 'UserEntity(id: $id, groups: $groups, beacons: $beacons, authToken: $authToken, email: $email, isGuest: $isGuest, name: $name, location: $location)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$UserEntityImpl && + (identical(other.id, id) || other.id == id) && + const DeepCollectionEquality().equals(other._groups, _groups) && + const DeepCollectionEquality().equals(other._beacons, _beacons) && + (identical(other.authToken, authToken) || + other.authToken == authToken) && + (identical(other.email, email) || other.email == email) && + (identical(other.isGuest, isGuest) || other.isGuest == isGuest) && + (identical(other.name, name) || other.name == name) && + (identical(other.location, location) || + other.location == location)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + id, + const DeepCollectionEquality().hash(_groups), + const DeepCollectionEquality().hash(_beacons), + authToken, + email, + isGuest, + name, + location); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$UserEntityImplCopyWith<_$UserEntityImpl> get copyWith => + __$$UserEntityImplCopyWithImpl<_$UserEntityImpl>(this, _$identity); +} + +abstract class _UserEntity implements UserEntity { + const factory _UserEntity( + {final String? id, + final List? groups, + final List? beacons, + final String? authToken, + final String? email, + final bool? isGuest, + final String? name, + final LocationEntity? location}) = _$UserEntityImpl; + + @override + String? get id; + @override + List? get groups; + @override + List? get beacons; + @override + String? get authToken; + @override + String? get email; + @override + bool? get isGuest; + @override + String? get name; + @override + LocationEntity? get location; + @override + @JsonKey(ignore: true) + _$$UserEntityImplCopyWith<_$UserEntityImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/Bloc/domain/repositories/auth_repository.dart b/lib/Bloc/domain/repositories/auth_repository.dart new file mode 100644 index 00000000..87e687e3 --- /dev/null +++ b/lib/Bloc/domain/repositories/auth_repository.dart @@ -0,0 +1,14 @@ +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/domain/entities/user/user_entity.dart'; + +abstract class AuthRepository { + // userinfo function + Future> getUser(); + + // Signup function + Future> register( + String name, String email, String password); + + // Login function + Future> login(String email, String password); +} diff --git a/lib/Bloc/domain/repositories/group_repository.dart b/lib/Bloc/domain/repositories/group_repository.dart new file mode 100644 index 00000000..36bb561a --- /dev/null +++ b/lib/Bloc/domain/repositories/group_repository.dart @@ -0,0 +1,12 @@ +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; + +abstract class GroupRepository { + Future> createHike(String title, int startsAt, + int expiresAt, String lat, String lon, String groupID); + + Future> joinHike(String hikeId); + + Future>> fetchHikes( + String groupID, int page, int pageSize); +} diff --git a/lib/Bloc/domain/repositories/home_repository.dart b/lib/Bloc/domain/repositories/home_repository.dart new file mode 100644 index 00000000..23a7dff5 --- /dev/null +++ b/lib/Bloc/domain/repositories/home_repository.dart @@ -0,0 +1,8 @@ +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/domain/entities/group/group_entity.dart'; + +abstract class HomeRepository { + Future>> fetchGroups(int page, int pageSize); + Future> createGroup(String title); + Future> joinGroup(String shortCode); +} diff --git a/lib/Bloc/domain/usecase/auth_usecase.dart b/lib/Bloc/domain/usecase/auth_usecase.dart new file mode 100644 index 00000000..3ce63073 --- /dev/null +++ b/lib/Bloc/domain/usecase/auth_usecase.dart @@ -0,0 +1,23 @@ +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/domain/entities/user/user_entity.dart'; +import 'package:beacon/Bloc/domain/repositories/auth_repository.dart'; + +class AuthUseCase { + final AuthRepository authRepository; + + AuthUseCase({required this.authRepository}); + + Future> registerUseCase( + String name, String email, String password) async { + return await authRepository.register(name, email, password); + } + + Future> loginUserCase( + String email, String password) async { + return await authRepository.login(email, password); + } + + Future> getUserInfoUseCase() async { + return await authRepository.getUser(); + } +} diff --git a/lib/Bloc/domain/usecase/group_usecase.dart b/lib/Bloc/domain/usecase/group_usecase.dart new file mode 100644 index 00000000..6122caee --- /dev/null +++ b/lib/Bloc/domain/usecase/group_usecase.dart @@ -0,0 +1,23 @@ +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/Bloc/domain/repositories/group_repository.dart'; + +class GroupUseCase { + final GroupRepository _groupRepo; + + GroupUseCase(this._groupRepo); + + Future>> fetchHikes( + String groupID, int page, int pageSize) { + return _groupRepo.fetchHikes(groupID, page, pageSize); + } + + Future> joinHike(String shortcode) { + return _groupRepo.joinHike(shortcode); + } + + Future> createHike(String title, int startsAt, + int expiresAt, String lat, String lon, String groupID) { + return _groupRepo.createHike(title, startsAt, expiresAt, lat, lon, groupID); + } +} diff --git a/lib/Bloc/domain/usecase/home_usecase.dart b/lib/Bloc/domain/usecase/home_usecase.dart new file mode 100644 index 00000000..995f7818 --- /dev/null +++ b/lib/Bloc/domain/usecase/home_usecase.dart @@ -0,0 +1,21 @@ +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/domain/entities/group/group_entity.dart'; +import 'package:beacon/Bloc/domain/repositories/home_repository.dart'; + +class HomeUseCase { + final HomeRepository homeRepository; + + HomeUseCase({required this.homeRepository}); + + Future>> groups(int page, int pageSize) { + return homeRepository.fetchGroups(page, pageSize); + } + + Future> createGroup(String title) { + return homeRepository.createGroup(title); + } + + Future> joinGroup(String shortCode) { + return homeRepository.joinGroup(shortCode); + } +} diff --git a/lib/Bloc/presentation/cubit/auth_cubit.dart b/lib/Bloc/presentation/cubit/auth_cubit.dart new file mode 100644 index 00000000..0daf56fb --- /dev/null +++ b/lib/Bloc/presentation/cubit/auth_cubit.dart @@ -0,0 +1,84 @@ +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/domain/entities/user/user_entity.dart'; +import 'package:beacon/Bloc/domain/usecase/auth_usecase.dart'; +import 'package:beacon/locator.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +abstract class AuthState { + final UserEntity? user; + final String? message; + final String? error; + + AuthState({this.error, this.message, this.user}); +} + +class IconToggled extends AuthState { + final bool isIconChecked; + + IconToggled(this.isIconChecked); +} + +class InitialAuthState extends AuthState {} + +class AuthLoadingState extends AuthState {} + +class AuthErrorState extends AuthState { + final String? error; + AuthErrorState({required this.error}); +} + +class SuccessState extends AuthState { + final String? message; + final UserEntity? user; + SuccessState({this.message, this.user}); +} + +class AuthCubit extends Cubit { + final AuthUseCase authUseCase; + AuthCubit({required this.authUseCase}) : super(InitialAuthState()); + + Future register( + String name, + String email, + String password, + ) async { + emit(AuthLoadingState()); + final state = await authUseCase.registerUseCase(name, email, password); + if (state is DataFailed) { + emit(AuthErrorState(error: state.error)); + } else { + emit(SuccessState(user: state.data)); + } + } + + Future login(String email, String password) async { + emit(AuthLoadingState()); + final state = await authUseCase.loginUserCase(email, password); + if (state is DataFailed) { + emit(AuthErrorState(error: state.error)); + } else { + emit(SuccessState(user: state.data)); + } + } + + Future fetchUserInfo() async { + final userInfo = await authUseCase.getUserInfoUseCase(); + + if (userInfo is DataFailed) { + emit(AuthErrorState(error: userInfo.error!)); + } else { + emit(SuccessState(user: userInfo.data)); + } + } + + requestFocus(FocusNode focusNode, BuildContext context) { + FocusScope.of(context).requestFocus(focusNode); + } + + Future isGuest() async { + bool? isguest = await localApi.userModel.isGuest; + + return isguest!; + } +} diff --git a/lib/Bloc/presentation/cubit/group_cubit.dart b/lib/Bloc/presentation/cubit/group_cubit.dart new file mode 100644 index 00000000..34c8a941 --- /dev/null +++ b/lib/Bloc/presentation/cubit/group_cubit.dart @@ -0,0 +1,106 @@ +import 'package:beacon/Bloc/core/constants/location.dart'; +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/Bloc/domain/usecase/group_usecase.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:geolocator/geolocator.dart'; + +abstract class GroupState {} + +class ShrimmerGroupState extends GroupState {} + +class GroupLoadingState extends GroupState {} + +class GroupErrorState extends GroupState { + final String error; + + GroupErrorState({required this.error}); +} + +class GroupReloadState extends GroupState { + List? beacons; + BeaconEntity? beacon; + + GroupReloadState({this.beacon, this.beacons}); +} + +class GroupCubit extends Cubit { + final GroupUseCase _groupUseCase; + GroupCubit(this._groupUseCase) : super(ShrimmerGroupState()); + + int page = 1; + int pageSize = 4; + bool isLoadingMore = false; + bool isCompletelyFetched = false; + List _beacons = []; + List get beacons => _beacons; + Position? position; + + Future createHike(String title, int startsAt, int expiresAt, String lat, + String lon, String groupID) async { + emit(GroupLoadingState()); + final state = await _groupUseCase.createHike( + title, startsAt, expiresAt, lat, lon, groupID); + + if (state is DataFailed) { + emit(GroupErrorState(error: state.error!)); + } else { + BeaconEntity? newHike = state.data; + newHike != null ? _beacons.insert(0, newHike) : null; + emit(GroupReloadState()); + } + } + + Future joinHike(String shortcode) async { + emit(GroupLoadingState()); + final state = await _groupUseCase.joinHike(shortcode); + if (state is DataFailed) { + emit(GroupErrorState(error: state.error!)); + } else { + BeaconEntity? newHike = state.data; + newHike != null ? _beacons.insert(0, newHike) : null; + emit(GroupReloadState()); + } + } + + Future fetchGroupHikes(String groupID) async { + if (isLoadingMore == true) return; + + if (page == 1) { + emit(ShrimmerGroupState()); + } + + isLoadingMore = true; + final state = await _groupUseCase.fetchHikes(groupID, page, pageSize); + + if (state is DataFailed) { + isLoadingMore = false; + emit(GroupErrorState(error: state.error!)); + } else { + final hikes = state.data ?? []; + isLoadingMore = false; + page++; + if (hikes.isEmpty) { + isCompletelyFetched = true; + emit(GroupReloadState()); + return; + } + for (var hike in hikes) { + _beacons.add(hike); + } + emit(GroupReloadState()); + } + } + + Future fetchPosition() async { + position = await LocationService.getCurrentLocation(); + } + + clear() { + page = 1; + pageSize = 4; + _beacons.clear(); + isCompletelyFetched = false; + emit(ShrimmerGroupState()); + } +} diff --git a/lib/Bloc/presentation/cubit/home_cubit.dart b/lib/Bloc/presentation/cubit/home_cubit.dart new file mode 100644 index 00000000..9202258b --- /dev/null +++ b/lib/Bloc/presentation/cubit/home_cubit.dart @@ -0,0 +1,102 @@ +import 'dart:developer'; +import 'package:beacon/Bloc/core/resources/data_state.dart'; +import 'package:beacon/Bloc/domain/entities/group/group_entity.dart'; +import 'package:beacon/Bloc/domain/usecase/home_usecase.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +abstract class HomeState {} + +class InitialHomeState extends HomeState {} + +class ReloadState extends HomeState {} + +class ShrimmerState extends HomeState {} + +class LoadingMoreGroups extends HomeState {} + +class NewGroupLoadingState extends HomeState {} + +class ErrorHomeState extends HomeState { + String error; + ErrorHomeState({required this.error}); +} + +class HomeCubit extends Cubit { + final HomeUseCase homeUseCase; + HomeCubit({required this.homeUseCase}) : super(InitialHomeState()); + + int page = 1; + int pageSize = 4; + bool isLoadingMore = false; + bool isCompletelyFetched = false; + List _totalGroups = []; + List get totalGroups => _totalGroups; + + Future createGroup(String title) async { + emit(NewGroupLoadingState()); + final dataState = await homeUseCase.createGroup(title); + if (dataState is DataFailed) { + emit(ErrorHomeState(error: dataState.error!)); + } else { + GroupEntity? group = dataState.data; + group != null ? _totalGroups.insert(0, group) : null; + emit(ReloadState()); + } + } + + Future joinGroup(String shortCode) async { + emit(NewGroupLoadingState()); + DataState state = await homeUseCase.joinGroup(shortCode); + + if (state is DataFailed) { + emit(ErrorHomeState(error: state.error!)); + } else { + GroupEntity? group = state.data; + group != null ? _totalGroups.insert(0, group) : null; + emit(ReloadState()); + } + } + + Future fetchUserGroups() async { + // if already loading then return + if (isCompletelyFetched == true || isLoadingMore == true) return; + + if (page != 1) log('fetching next set of groups'); + + if (page == 1) { + emit(ShrimmerState()); + } else { + isLoadingMore = true; + emit(LoadingMoreGroups()); + } + + DataState> state = + await homeUseCase.groups(page, pageSize); + + if (state is DataFailed) { + isLoadingMore = false; + emit(ErrorHomeState(error: state.error!)); + } else { + List newGroups = state.data ?? []; + if (newGroups.isEmpty) { + isCompletelyFetched = true; + emit(ReloadState()); + return; + } + for (var newGroup in newGroups) { + _totalGroups.add(newGroup); + } + page++; + isLoadingMore = false; + emit(ReloadState()); + } + } + + clear() { + page = 1; + isLoadingMore = false; + isCompletelyFetched = false; + _totalGroups.clear(); + emit(InitialHomeState()); + } +} diff --git a/lib/Bloc/presentation/screens/auth_screen.dart b/lib/Bloc/presentation/screens/auth_screen.dart new file mode 100644 index 00000000..7a16a165 --- /dev/null +++ b/lib/Bloc/presentation/screens/auth_screen.dart @@ -0,0 +1,447 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/Bloc/presentation/cubit/auth_cubit.dart'; +import 'package:beacon/Bloc/presentation/widgets/text_field.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/old/components/hike_button.dart'; +import 'package:beacon/old/components/loading_screen.dart'; +import 'package:beacon/old/components/shape_painter.dart'; +import 'package:beacon/Bloc/core/utils/validators.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/old/components/utilities/indication_painter.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:sizer/sizer.dart'; + +@RoutePage() +class AuthScreen extends StatefulWidget { + const AuthScreen({super.key}); + + @override + _AuthScreenState createState() => _AuthScreenState(); +} + +class _AuthScreenState extends State + with SingleTickerProviderStateMixin { + Future onPopHome() async { + return showDialog( + context: context, + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + contentPadding: EdgeInsets.all(25.0), + title: Text( + 'Confirm Exit', + style: TextStyle(fontSize: 25, color: kYellow), + ), + content: Text( + 'Do you really want to exit?', + style: TextStyle(fontSize: 18, color: kBlack), + ), + actions: [ + HikeButton( + buttonHeight: 2.5.h, + buttonWidth: 8.w, + onTap: () => AutoRouter.of(context).maybePop(false), + text: 'No', + ), + HikeButton( + buttonHeight: 2.5.h, + buttonWidth: 8.w, + onTap: () => AutoRouter.of(context).maybePop(true), + text: 'Yes', + ), + ], + ), + ); + } + + PageController _pageController = PageController(); + + Color leftColor = Colors.white; + Color rightColor = Colors.black; + + @override + Widget build(BuildContext context) { + Size screensize = MediaQuery.of(context).size; + final authCubit = BlocProvider.of(context); + return + // WillPopScope( + // onWillPop: _onPopHome ?? , + // child: + BlocConsumer( + listener: (context, state) { + if (state is SuccessState) { + AutoRouter.of(context).replaceNamed('/home'); + utils.showSnackBar('Login successful !', context, + duration: Duration(seconds: 2)); + } else if (state is AuthErrorState) { + utils.showSnackBar(state.error!, context, + duration: Duration(seconds: 2)); + } + }, + builder: (context, state) { + return state is AuthLoadingState + ? LoadingScreen() + : Scaffold( + resizeToAvoidBottomInset: true, + body: Container( + width: screensize.width, + height: + screensize.height >= 775.0 ? screensize.height : 775.0, + child: Stack( + children: [ + CustomPaint( + size: Size(screensize.width, screensize.height), + painter: ShapePainter(), + ), + Container( + alignment: Alignment.center, + padding: EdgeInsets.only(top: screensize.height / 3.5), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(top: 20.0), + child: _buildMenuBar(context, _pageController), + ), + Expanded( + flex: 2, + child: PageView( + controller: _pageController, + onPageChanged: (i) { + if (i == 0) { + setState(() { + rightColor = Colors.black; + leftColor = Colors.white; + }); + Future.delayed(Duration(milliseconds: 500), + () { + authCubit.requestFocus( + loginEmailFocus, context); + }); + } else if (i == 1) { + setState(() { + rightColor = Colors.white; + leftColor = Colors.black; + }); + Future.delayed(Duration(milliseconds: 500), + () { + authCubit.requestFocus( + signUpNameFocus, context); + }); + } + }, + children: [ + new ConstrainedBox( + constraints: const BoxConstraints.expand(), + child: _buildSignIn(context), + ), + new ConstrainedBox( + constraints: const BoxConstraints.expand(), + child: _buildSignUp( + context, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ), + ); + }, + ); + } + + Widget _buildMenuBar(BuildContext context, PageController pageController) { + Size screensize = MediaQuery.of(context).size; + return Container( + padding: EdgeInsets.symmetric(horizontal: 13.5.w), + width: screensize.width, + height: screensize.height < 800 ? 7.5.h : 6.h, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(25.0)), + ), + child: CustomPaint( + painter: TabIndicationPainter(pageController: pageController), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: TextButton( + style: ButtonStyle( + overlayColor: MaterialStateProperty.all(Colors.transparent), + ), + //highlightColor: Colors.white, + onPressed: () { + pageController.animateToPage(0, + duration: Duration(milliseconds: 500), + curve: Curves.decelerate); + leftColor = Colors.white; + rightColor = Colors.black; + setState(() {}); + }, + child: Text( + "Existing", + style: TextStyle( + color: leftColor, + fontSize: 18.0, + ), + ), + ), + ), + Expanded( + child: TextButton( + style: ButtonStyle( + overlayColor: MaterialStateProperty.all(Colors.transparent), + ), + onPressed: () { + pageController.animateToPage(1, + duration: Duration(milliseconds: 500), + curve: Curves.decelerate); + rightColor = Colors.white; + leftColor = Colors.black; + setState(() {}); + }, + child: Text( + "New", + style: TextStyle( + color: rightColor, + fontSize: 18.0, + ), + ), + ), + ), + ], + ), + ), + ); + } + + GlobalKey _signInFormKey = GlobalKey(); + GlobalKey _registerFormKey = GlobalKey(); + final loginEmailController = TextEditingController(); + final loginPasswordController = TextEditingController(); + + final signUpNameController = TextEditingController(); + final signUpEmailController = TextEditingController(); + final signUpPasswordController = TextEditingController(); + + final signUpNameFocus = FocusNode(); + final signUpEmailFocus = FocusNode(); + final signUpPasswordFocus = FocusNode(); + + final loginEmailFocus = FocusNode(); + final loginPasswordFocus = FocusNode(); + Widget _buildSignIn(BuildContext context) { + Size screensize = MediaQuery.of(context).size; + + final authCubit = BlocProvider.of(context); + return SingleChildScrollView( + child: Container( + padding: EdgeInsets.only(top: 3.h, left: 8.5.w, right: 8.5.w), + width: screensize.width, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Card( + elevation: 2.0, + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + child: Form( + key: _signInFormKey, + child: Container( + width: screensize.width - 70, + child: Column( + children: [ + Container( + height: 13.h, + padding: EdgeInsets.symmetric( + horizontal: 10, vertical: 10.0), + child: CustomTextField( + iconData: Icons.email, + hintText: 'Email Address', + controller: loginEmailController, + focusNode: loginEmailFocus, + nextFocusNode: loginPasswordFocus, + validator: Validator.validateEmail, + ), + ), + separator(), + Container( + height: 13.h, + padding: EdgeInsets.symmetric( + horizontal: 10, vertical: 10.0), + child: CustomTextField( + iconData: Icons.lock, + hintText: 'Password', + controller: loginPasswordController, + focusNode: loginPasswordFocus, + showTrailing: true, + validator: Validator.validatePassword), + ), + ], + ), + ), + ), + ), + SizedBox( + height: 3.5.h, + ), + BlocBuilder( + builder: (context, state) { + return HikeButton( + onTap: () { + if (_signInFormKey.currentState!.validate()) { + authCubit.login( + loginEmailController.text.trim(), + loginPasswordController.text.trim(), + ); + } else { + utils.showSnackBar( + 'Please complete all the fields', context); + } + }, + text: 'LOGIN', + ); + }, + ), + Padding( + padding: EdgeInsets.only( + left: 15.0, right: 15.0, top: 15.0, bottom: 15.0), + child: Text( + "Or", + style: TextStyle( + color: Colors.black, + fontSize: 16.0, + ), + ), + ), + HikeButton( + onTap: () { + authCubit.login( + loginEmailController.text.trim(), + loginPasswordController.text.trim(), + ); + }, + text: 'LOGIN AS GUEST', + ), + ], + ), + ), + ); + } + + Widget _buildSignUp(BuildContext context) { + final authCubit = BlocProvider.of(context); + Size screensize = MediaQuery.of(context).size; + return SingleChildScrollView( + child: Container( + padding: EdgeInsets.only(top: 3.h, left: 8.5.w, right: 8.5.w), + child: Column( + children: [ + Card( + elevation: 2.0, + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + child: Form( + key: _registerFormKey, + child: Container( + width: screensize.width - 70, + // height: 280.0, + child: Column(children: [ + Container( + height: 13.h, + padding: EdgeInsets.symmetric( + horizontal: 10, vertical: 10.0), + child: CustomTextField( + iconData: Icons.person_2_sharp, + hintText: 'Name', + controller: signUpNameController, + focusNode: signUpNameFocus, + nextFocusNode: signUpEmailFocus, + validator: Validator.validateName, + ), + ), + separator(), + Container( + height: 13.h, + padding: EdgeInsets.symmetric( + horizontal: 10, vertical: 10.0), + child: CustomTextField( + iconData: Icons.mail, + hintText: 'Email Address', + controller: signUpEmailController, + focusNode: signUpEmailFocus, + nextFocusNode: signUpPasswordFocus, + validator: Validator.validateEmail, + ), + ), + separator(), + Container( + height: 13.h, + padding: EdgeInsets.symmetric( + horizontal: 10, vertical: 10.0), + child: CustomTextField( + iconData: Icons.lock, + hintText: 'Password', + controller: signUpPasswordController, + focusNode: signUpPasswordFocus, + showTrailing: true, + validator: Validator.validatePassword), + ), + ])), + ), + ), + SizedBox( + height: 3.5.h, + ), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.0)), + ), + child: BlocBuilder( + builder: (context, state) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.0)), + ), + child: HikeButton( + onTap: () { + if (_registerFormKey.currentState!.validate()) { + authCubit.register( + signUpNameController.text.trim(), + signUpEmailController.text.trim(), + signUpPasswordController.text.trim()); + } else { + utils.showSnackBar( + 'Please complete all the fields', context); + } + }, + text: 'SIGN UP', + ), + ); + }, + )) + ], + ), + ), + ); + } + + Widget separator() { + return Container( + width: 62.w, + height: 0.2.h, + color: Colors.grey[400], + ); + } +} diff --git a/lib/Bloc/presentation/screens/group_screen.dart b/lib/Bloc/presentation/screens/group_screen.dart new file mode 100644 index 00000000..d50053c6 --- /dev/null +++ b/lib/Bloc/presentation/screens/group_screen.dart @@ -0,0 +1,379 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/Bloc/domain/entities/group/group_entity.dart'; +import 'package:beacon/Bloc/presentation/cubit/group_cubit.dart'; +import 'package:beacon/Bloc/presentation/widgets/create_join_dialog.dart'; +import 'package:beacon/old/components/beacon_card.dart'; +import 'package:beacon/old/components/hike_button.dart'; +import 'package:beacon/old/components/loading_screen.dart'; +import 'package:beacon/old/components/shape_painter.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/router.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; +import 'package:sizer/sizer.dart'; + +@RoutePage() +class GroupScreen extends StatefulWidget { + final GroupEntity group; + GroupScreen(this.group) : super(); + + @override + _GroupScreenState createState() => _GroupScreenState(); +} + +class _GroupScreenState extends State + with TickerProviderStateMixin { + late List fetchingUserBeacons; + late List fetchingNearbyBeacons; + + late GroupCubit _groupCubit; + late ScrollController _scrollController; + + @override + void initState() { + _scrollController = ScrollController(); + _scrollController.addListener(_listener); + _groupCubit = context.read(); + _groupCubit.position == null ? _groupCubit.fetchPosition() : null; + _groupCubit.fetchGroupHikes(widget.group.id!); + super.initState(); + } + + _listener() { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + if (_groupCubit.isCompletelyFetched == true) { + return; + } + _groupCubit.fetchGroupHikes(widget.group.id!); + } + } + + @override + void dispose() { + _groupCubit.clear(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + TabController tabController = new TabController(length: 2, vsync: this); + return Scaffold( + resizeToAvoidBottomInset: false, + body: SafeArea( + child: BlocConsumer( + listener: (context, state) { + if (state is GroupErrorState) { + utils.showSnackBar(state.error, context); + } + }, + builder: (context, state) { + return ModalProgressHUD( + progressIndicator: const LoadingScreen(), + inAsyncCall: (state is GroupLoadingState) ? true : false, + child: Stack( + children: [ + CustomPaint( + size: Size(MediaQuery.of(context).size.width, + MediaQuery.of(context).size.height - 200), + painter: ShapePainter(), + ), + Align( + alignment: Alignment(-0.7, -0.95), + child: Container( + width: MediaQuery.of(context).size.width * 0.6, + child: Text( + 'Welcome to Group ' + widget.group.title!, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + color: Colors.white, + ), + ), + ), + ), + Align( + alignment: Alignment(0.9, -0.8), + child: FloatingActionButton( + onPressed: () => showDialog( + context: context, + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + // actionsAlignment: + // MainAxisAlignment.spaceEvenly, + title: Text( + localApi.userModel.isGuest! + ? 'Create Account' + : 'Logout', + style: + TextStyle(fontSize: 25, color: kYellow), + ), + content: Text( + localApi.userModel.isGuest! + ? 'Would you like to create an account?' + : 'Are you sure you wanna logout?', + style: TextStyle(fontSize: 16, color: kBlack), + ), + actions: [ + HikeButton( + buttonHeight: 2.5.h, + buttonWidth: 8.w, + onTap: () => + Navigator.of(context).pop(false), + text: 'No', + textSize: 18.0, + ), + HikeButton( + buttonHeight: 2.5.h, + buttonWidth: 8.w, + onTap: () async { + AutoRouter.of(context).maybePop(); + AutoRouter.of(context).pushAndPopUntil( + AuthScreenRoute(), + predicate: (route) => true, + ); + await localApi.deleteUser(); + }, + text: 'Yes', + textSize: 18.0, + ), + ], + )), + backgroundColor: kYellow, + child: localApi.userModel.isGuest! + ? Icon(Icons.person) + : Icon(Icons.logout), + ), + ), + Padding( + padding: EdgeInsets.fromLTRB(4.w, 25.h, 4.w, 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 45.w, + child: HikeButton( + buttonWidth: homebwidth, + buttonHeight: homebheight - 2, + text: 'Create Hike', + textColor: Colors.white, + borderColor: Colors.white, + buttonColor: kYellow, + onTap: () { + CreateJoinBeaconDialog.createHikeDialog( + context, widget.group.id, _groupCubit); + }, + ), + ), + SizedBox( + width: 1.w, + ), + Container( + width: 45.w, + child: HikeButton( + buttonWidth: homebwidth, + buttonHeight: homebheight - 2, + text: 'Join a Hike', + textColor: kYellow, + borderColor: kYellow, + buttonColor: Colors.white, + onTap: () async { + CreateJoinBeaconDialog.joinBeaconDialog( + context, _groupCubit); + }, + ), + ), + ], + ), + ), + Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + height: MediaQuery.of(context).size.height * 0.565, + margin: EdgeInsets.only(top: 20), + decoration: BoxDecoration( + color: kLightBlue, + borderRadius: BorderRadius.only( + topLeft: const Radius.circular(50.0), + topRight: const Radius.circular(50.0), + ), + ), + child: Column( + children: [ + TabBar( + indicatorSize: TabBarIndicatorSize.tab, + indicatorColor: kBlue, + labelColor: kBlack, + tabs: [ + Tab(text: 'Your Beacons'), + Tab(text: 'Nearby Beacons'), + ], + controller: tabController, + ), + Expanded( + child: TabBarView( + controller: tabController, + children: [ + _groupBeacons(), + _nearByBeacons() + ], + ), + ) + ], + )) + ], + ), + ], + ), + ); + }, + ), + ), + ); + } + + Widget _groupBeacons() { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 2.0), + child: BlocBuilder( + builder: (context, state) { + if (state is ShrimmerGroupState) { + return Center( + child: BeaconCustomWidgets.getPlaceholder(), + ); + } + final beacons = _groupCubit.beacons; + + return Container( + alignment: Alignment.center, + child: beacons.length == 0 + ? SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: Column( + children: [ + Text( + 'You haven\'t joined or created any beacon yet', + textAlign: TextAlign.center, + style: TextStyle(color: kBlack, fontSize: 20), + ), + SizedBox( + height: 2.h, + ), + RichText( + text: TextSpan( + style: TextStyle(color: kBlack, fontSize: 20), + children: [ + TextSpan( + text: 'Join', + style: + TextStyle(fontWeight: FontWeight.bold)), + TextSpan(text: ' a Hike or '), + TextSpan( + text: 'Create', + style: + TextStyle(fontWeight: FontWeight.bold)), + TextSpan(text: ' a new one! '), + ], + ), + ), + ], + ), + ) + : ListView.builder( + controller: _scrollController, + physics: AlwaysScrollableScrollPhysics(), + scrollDirection: Axis.vertical, + itemCount: beacons.length, + padding: EdgeInsets.all(8), + itemBuilder: (context, index) { + if (index == beacons.length) { + return _groupCubit.isLoadingMore + ? Center( + child: LinearProgressIndicator( + color: kBlue, + )) + : SizedBox.shrink(); + } + return BeaconCustomWidgets.getBeaconCard( + context, beacons[index]); + }, + )); + }, + ), + ); + } + + Widget _nearByBeacons() { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 2), + child: BlocBuilder( + builder: (context, state) { + if (state is ShrimmerGroupState) { + return Center( + child: BeaconCustomWidgets.getPlaceholder(), + ); + } + final beacons = _groupCubit.beacons; + + return Container( + alignment: Alignment.center, + child: beacons.length == 0 + ? SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: Column( + children: [ + Text( + 'You haven\'t joined or created any beacon yet', + textAlign: TextAlign.center, + style: TextStyle(color: kBlack, fontSize: 20), + ), + SizedBox( + height: 2.h, + ), + RichText( + text: TextSpan( + // textAlign: + // TextAlign + // .center, + style: TextStyle(color: kBlack, fontSize: 20), + children: [ + TextSpan( + text: 'Join', + style: + TextStyle(fontWeight: FontWeight.bold)), + TextSpan(text: ' a Hike or '), + TextSpan( + text: 'Create', + style: + TextStyle(fontWeight: FontWeight.bold)), + TextSpan(text: ' a new one! '), + ], + ), + ), + ], + ), + ) + : ListView.builder( + physics: AlwaysScrollableScrollPhysics(), + scrollDirection: Axis.vertical, + itemCount: beacons.length, + padding: EdgeInsets.all(8), + itemBuilder: (context, index) { + return BeaconCustomWidgets.getBeaconCard( + context, beacons[index]); + }, + )); + }, + ), + ); + } +} diff --git a/lib/views/hike_screen.dart b/lib/Bloc/presentation/screens/hike_screen.dart similarity index 88% rename from lib/views/hike_screen.dart rename to lib/Bloc/presentation/screens/hike_screen.dart index 24bef382..e622c815 100644 --- a/lib/views/hike_screen.dart +++ b/lib/Bloc/presentation/screens/hike_screen.dart @@ -1,21 +1,23 @@ -import 'package:beacon/components/loading_screen.dart'; +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/old/components/loading_screen.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/view_model/hike_screen_model.dart'; -import 'package:beacon/views/base_view.dart'; +import 'package:beacon/old/components/view_model/hike_screen_model.dart'; +import 'package:beacon/old/components/views/base_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter_animarker/flutter_map_marker_animation.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:intl/intl.dart'; -import 'package:beacon/components/hike_screen_widget.dart'; -import 'package:beacon/models/beacon/beacon.dart'; +import 'package:beacon/old/components/hike_screen_widget.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; -import 'package:beacon/utilities/constants.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; import 'package:sizer/sizer.dart'; import 'package:sliding_up_panel/sliding_up_panel.dart'; +@RoutePage() class HikeScreen extends StatefulWidget { final Beacon? beacon; final bool? isLeader; @@ -160,19 +162,20 @@ class _HikeScreenState extends State { // setPolyline(); }, onTap: (loc) async { - if (model.panelController.isPanelOpen) - model.panelController.close(); - else { - String? title; - HikeScreenWidget - .showCreateLandMarkDialogueDialog( - context, - model.landmarkFormKey, - title, - loc, - model.createLandmark, - ); - } + // if (model.panelController.isPanelOpen) + // model.panelController.close(); + // else { + // String? title; + // HikeScreenWidget + // .showCreateLandMarkDialogueDialog( + // context, + // model.landmarkFormKey, + // title, + // loc, + // model.createLandmark, + + // ); + // } }), ), Align( diff --git a/lib/Bloc/presentation/screens/home_screen.dart b/lib/Bloc/presentation/screens/home_screen.dart new file mode 100644 index 00000000..9e494185 --- /dev/null +++ b/lib/Bloc/presentation/screens/home_screen.dart @@ -0,0 +1,361 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/Bloc/domain/entities/group/group_entity.dart'; +import 'package:beacon/Bloc/presentation/cubit/home_cubit.dart'; +import 'package:beacon/Bloc/presentation/widgets/create_join_dialog.dart'; +import 'package:beacon/old/components/beacon_card.dart'; +import 'package:beacon/old/components/group_card.dart'; +import 'package:beacon/old/components/hike_button.dart'; +import 'package:beacon/old/components/loading_screen.dart'; +import 'package:beacon/old/components/shape_painter.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; +import 'package:sizer/sizer.dart'; + +@RoutePage() +class HomeScreen extends StatefulWidget { + const HomeScreen({super.key}); + + @override + State createState() => _HomeScreenState(); +} + +class _HomeScreenState extends State { + Future _onPopHome(BuildContext context) async { + return showDialog( + context: context, + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + // actionsAlignment: MainAxisAlignment.spaceEvenly, + contentPadding: EdgeInsets.all(25.0), + title: Text( + 'Confirm Exit', + style: TextStyle(fontSize: 25, color: kYellow), + ), + content: Text( + 'Do you really want to exit?', + style: TextStyle(fontSize: 18, color: kBlack), + ), + actions: [ + HikeButton( + buttonHeight: 2.5.h, + buttonWidth: 8.w, + onTap: () => AutoRouter.of(context).maybePop(false), + text: 'No', + ), + HikeButton( + buttonHeight: 2.5.h, + buttonWidth: 8.w, + onTap: () => AutoRouter.of(context).maybePop(true), + text: 'Yes', + ), + ], + ), + ); + } + + late ScrollController _scrollController; + late HomeCubit _homeCubit; + + @override + void initState() { + _scrollController = ScrollController(); + if (localApi.userModel.isGuest == false) { + _homeCubit = BlocProvider.of(context); + _homeCubit.fetchUserGroups(); + _scrollController.addListener(_onScroll); + } + super.initState(); + } + + void _onScroll() { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + if (_homeCubit.isCompletelyFetched) return; + _homeCubit.fetchUserGroups(); + } + } + + @override + void dispose() { + _scrollController.dispose(); + if (localApi.userModel.isGuest == false) { + _homeCubit.clear(); + } + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return PopScope( + onPopInvoked: (didPop) { + _onPopHome(context); + }, + child: BlocConsumer( + listener: (context, state) { + if (state is ErrorHomeState) { + utils.showSnackBar(state.error, context); + } + }, + builder: (context, state) { + return Scaffold( + resizeToAvoidBottomInset: false, + body: SafeArea( + child: ModalProgressHUD( + inAsyncCall: state is NewGroupLoadingState ? true : false, + progressIndicator: LoadingScreen(), + child: Stack( + children: [ + CustomPaint( + size: Size(MediaQuery.of(context).size.width, + MediaQuery.of(context).size.height - 200), + painter: ShapePainter(), + ), + Align( + alignment: Alignment(0.9, -0.8), + child: FloatingActionButton( + onPressed: () => showDialog( + context: context, + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + title: Text( + localApi.userModel.isGuest == true + ? 'Create Account' + : 'Logout', + style: TextStyle( + fontSize: 25, color: kYellow), + ), + content: Text( + localApi.userModel.isGuest == true + ? 'Would you like to create an account?' + : 'Are you sure you wanna logout?', + style: TextStyle( + fontSize: 16, color: kBlack), + ), + actions: [ + HikeButton( + buttonHeight: 2.5.h, + buttonWidth: 8.w, + onTap: () => AutoRouter.of(context) + .maybePop(false), + text: 'No', + textSize: 18.0, + ), + HikeButton( + buttonHeight: 2.5.h, + buttonWidth: 8.w, + onTap: () { + AutoRouter.of(context) + .replaceNamed('/auth'); + localApi.deleteUser(); + }, + text: 'Yes', + textSize: 18.0, + ), + ], + )), + backgroundColor: kYellow, + child: localApi.userModel.isGuest == true + ? Icon(Icons.person) + : Icon(Icons.logout)), + ), + Padding( + padding: EdgeInsets.fromLTRB(4.w, 25.h, 4.w, 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + StatefulBuilder( + builder: (context, setState) { + return Container( + width: 45.w, + child: HikeButton( + buttonWidth: homebwidth - 10, + buttonHeight: homebheight - 2, + text: 'Create Group', + textColor: Colors.white, + borderColor: Colors.white, + buttonColor: kYellow, + onTap: () async { + CreateJoinGroupDialog.createGroupDialog( + context); + }, + ), + ); + }, + ), + SizedBox( + width: 1.w, + ), + Container( + width: 45.w, + child: HikeButton( + buttonWidth: homebwidth, + buttonHeight: homebheight - 2, + text: 'Join a Group', + textColor: kYellow, + borderColor: kYellow, + buttonColor: Colors.white, + onTap: () async { + CreateJoinGroupDialog.joinGroupDialog(context); + }, + ), + ), + ], + ), + ), + Positioned( + bottom: 0, + child: Container( + decoration: BoxDecoration( + color: kLightBlue, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), + topRight: Radius.circular(30))), + height: 56.h, + width: 100.w, + child: Column( + children: [ + Tab(text: 'Your Groups'), + Container( + height: 0.2.h, + color: kBlack, + ), + localApi.userModel.isGuest == true + ? Expanded( + child: Center( + child: SingleChildScrollView( + physics: + AlwaysScrollableScrollPhysics(), + child: Column( + children: [ + Text( + 'You haven\'t joined or created any group yet', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.black, + fontSize: 20), + ), + SizedBox( + height: 20, + ), + RichText( + text: TextSpan( + style: TextStyle( + color: Colors.black, + fontSize: 20), + children: [ + TextSpan( + text: 'Join', + style: TextStyle( + fontWeight: + FontWeight + .bold)), + TextSpan( + text: ' a Group or '), + TextSpan( + text: 'Create', + style: TextStyle( + fontWeight: + FontWeight + .bold)), + TextSpan( + text: ' a new one!'), + ], + ), + ), + ], + ), + )), + ) + : _buildList() + ], + ))) + ], + ), + )), + ); + }, + )); + } + + Widget _buildList() { + return Expanded( + child: BlocBuilder( + builder: (context, state) { + if (state is ShrimmerState) { + return Center( + child: BeaconCustomWidgets.getPlaceholder(), + ); + } + + List groups = _homeCubit.totalGroups; + + if (groups.isEmpty) { + return Center( + child: SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: Column( + children: [ + Text( + 'You haven\'t joined or created any group yet', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.black, fontSize: 20), + ), + SizedBox( + height: 20, + ), + RichText( + text: TextSpan( + style: TextStyle(color: Colors.black, fontSize: 20), + children: [ + TextSpan( + text: 'Join', + style: TextStyle(fontWeight: FontWeight.bold)), + TextSpan(text: ' a Group or '), + TextSpan( + text: 'Create', + style: TextStyle(fontWeight: FontWeight.bold)), + TextSpan(text: ' a new one!'), + ], + ), + ), + ], + ), + )); + } else { + return ListView.builder( + controller: _scrollController, + physics: AlwaysScrollableScrollPhysics(), + scrollDirection: Axis.vertical, + itemCount: groups.length + 1, + padding: EdgeInsets.all(8), + itemBuilder: (context, index) { + if (index == groups.length) { + if (_homeCubit.isLoadingMore && + !_homeCubit.isCompletelyFetched) { + return Center( + child: LinearProgressIndicator( + color: kBlue, + ), + ); + } else { + return SizedBox.shrink(); + } + } + return GroupCustomWidgets.getGroupCard(context, groups[index]); + }, + ); + } + }, + ), + ); + } +} diff --git a/lib/Bloc/presentation/screens/splash_screen.dart b/lib/Bloc/presentation/screens/splash_screen.dart new file mode 100644 index 00000000..0d7764a8 --- /dev/null +++ b/lib/Bloc/presentation/screens/splash_screen.dart @@ -0,0 +1,58 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/Bloc/domain/usecase/auth_usecase.dart'; +import 'package:flutter/material.dart'; +import 'package:beacon/locator.dart'; +import '../../../old/components/loading_screen.dart'; + +@RoutePage() +class SplashScreen extends StatefulWidget { + const SplashScreen({super.key}); + + @override + _SplashScreenState createState() => _SplashScreenState(); +} + +class _SplashScreenState extends State { + bool isCheckingUrl = false; + + @override + void initState() { + _handleNavigation(); + super.initState(); + } + + _handleNavigation() async { + await localApi.init(); + bool? isLoggedIn = await localApi.userloggedIn(); + final authUseCase = locator(); + + if (isLoggedIn == true) { + bool isConnected = await utils.checkInternetConnectivity(); + if (isConnected) { + final userInfo = await authUseCase.getUserInfoUseCase(); + if (userInfo.data != null) { + AutoRouter.of(context).replaceNamed('/home'); + } else { + AutoRouter.of(context).replaceNamed('/auth'); + } + } else { + AutoRouter.of(context).replaceNamed('/home'); + } + } else { + AutoRouter.of(context).replaceNamed('/auth'); + } + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: const Key('SplashScreenScaffold'), + body: LoadingScreen(), + ); + } +} diff --git a/lib/components/create_join_dialog.dart b/lib/Bloc/presentation/widgets/create_join_dialog.dart similarity index 55% rename from lib/components/create_join_dialog.dart rename to lib/Bloc/presentation/widgets/create_join_dialog.dart index 2ba18179..6e317824 100644 --- a/lib/components/create_join_dialog.dart +++ b/lib/Bloc/presentation/widgets/create_join_dialog.dart @@ -1,81 +1,88 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/Bloc/core/utils/validators.dart'; +import 'package:beacon/Bloc/presentation/cubit/group_cubit.dart'; +import 'package:beacon/Bloc/presentation/cubit/home_cubit.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/services/validators.dart'; -import 'package:beacon/components/hike_button.dart'; -import 'package:beacon/utilities/constants.dart'; -import 'package:beacon/view_model/group_screen_view_model.dart'; +import 'package:beacon/old/components/hike_button.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; import 'package:duration_picker/duration_picker.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:intl/intl.dart'; import 'package:sizer/sizer.dart'; -import '../view_model/home_screen_view_model.dart'; - class CreateJoinGroupDialog { - static Future createGroupDialog(BuildContext context, HomeViewModel model) { + static GlobalKey _groupKey = GlobalKey(); + + static final TextEditingController _groupNameController = + TextEditingController(); + + static Future createGroupDialog( + BuildContext context, + ) { bool isSmallSized = MediaQuery.of(context).size.height < 800; return showDialog( context: context, - builder: (context) => GestureDetector( - onTap: () => FocusManager.instance.primaryFocus?.unfocus(), - child: Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - child: SingleChildScrollView( - child: Form( - key: model.formKeyCreate, - child: Container( - height: isSmallSized ? 35.h : 25.h, - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 32, vertical: 16), - child: Column( - children: [ - Container( - height: isSmallSized ? 12.h : 10.h, - child: Padding( - padding: const EdgeInsets.all(4.0), - child: TextFormField( - style: TextStyle(fontSize: 22.0), - validator: (value) => - Validator.validateBeaconTitle(value!), - onChanged: (name) { - model.title = name; - }, - decoration: InputDecoration( - border: InputBorder.none, - hintText: 'Enter Title Here', - labelStyle: TextStyle( - fontSize: labelsize, color: kYellow), - hintStyle: TextStyle( - fontSize: hintsize, color: hintColor), - labelText: 'Title', - alignLabelWithHint: true, - floatingLabelBehavior: - FloatingLabelBehavior.always, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none), - ), + builder: (context) => Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + child: SingleChildScrollView( + child: Form( + key: _groupKey, + child: Container( + height: isSmallSized ? 35.h : 25.h, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 32, vertical: 16), + child: Column( + children: [ + Container( + height: isSmallSized ? 12.h : 10.h, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: TextFormField( + controller: _groupNameController, + style: TextStyle(fontSize: 22.0), + validator: (value) => + Validator.validateBeaconTitle(value!), + onChanged: (name) {}, + decoration: InputDecoration( + border: InputBorder.none, + hintText: 'Enter Title Here', + labelStyle: TextStyle( + fontSize: labelsize, color: kYellow), + hintStyle: TextStyle( + fontSize: hintsize, color: hintColor), + labelText: 'Title', + alignLabelWithHint: true, + floatingLabelBehavior: + FloatingLabelBehavior.always, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none), ), - color: kLightBlue, - ), - SizedBox( - height: 2.h, ), - Flexible( - flex: 2, - child: HikeButton( - text: 'Create Group', - textSize: 18.0, - textColor: Colors.white, - buttonColor: kYellow, - onTap: () { - // FocusManager.instance.primaryFocus?.unfocus(); - // navigationService.pop(); - model.createGroupRoom(); - }), - ), - ], - ), + color: kLightBlue, + ), + SizedBox( + height: 2.h, + ), + Flexible( + flex: 2, + child: HikeButton( + text: 'Create Group', + textSize: 18.0, + textColor: Colors.white, + buttonColor: kYellow, + onTap: () { + if (!_groupKey.currentState!.validate()) return; + AutoRouter.of(context).maybePop(); + BlocProvider.of(context) + .createGroup(_groupNameController.text.trim()); + _groupNameController.clear(); + }), + ), + ], ), ), ), @@ -85,7 +92,12 @@ class CreateJoinGroupDialog { ); } - static Future joinGroupDialog(BuildContext context, HomeViewModel model) { + static GlobalKey _joinGroupKey = GlobalKey(); + + static final TextEditingController _joinGroupController = + TextEditingController(); + + static Future joinGroupDialog(BuildContext context) { bool isSmallSized = MediaQuery.of(context).size.height < 800; return showDialog( context: context, @@ -94,24 +106,25 @@ class CreateJoinGroupDialog { borderRadius: BorderRadius.circular(10.0), ), child: Form( - key: model.formKeyJoin, + key: _joinGroupKey, child: Container( height: isSmallSized ? 35.h : 25.h, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), child: Column( - children: [ + children: [ Container( height: isSmallSized ? 12.h : 10.h, child: Padding( padding: const EdgeInsets.all(4.0), child: TextFormField( + controller: _joinGroupController, keyboardType: TextInputType.text, textCapitalization: TextCapitalization.characters, style: TextStyle(fontSize: 22.0), validator: (value) => Validator.validatePasskey(value!), - onChanged: (key) { - model.enteredGroupCode = key.toUpperCase(); + onChanged: (value) { + _joinGroupController.text = value.toUpperCase(); }, decoration: InputDecoration( alignLabelWithHint: true, @@ -138,8 +151,11 @@ class CreateJoinGroupDialog { textColor: Colors.white, buttonColor: kYellow, onTap: () { - // navigationService.pop(); - model.joinGroupRoom(); + if (!_joinGroupKey.currentState!.validate()) return; + AutoRouter.of(context).maybePop(); + BlocProvider.of(context) + .joinGroup(_joinGroupController.text.trim()); + _joinGroupController.clear(); }, ), ), @@ -154,13 +170,26 @@ class CreateJoinGroupDialog { } class CreateJoinBeaconDialog { - static Future createHikeDialog(BuildContext context, GroupViewModel model, - Function reloadList, String? groupID) { + static late String title; + static DateTime? startDate = DateTime.now(); + static TimeOfDay? startTime = + TimeOfDay(hour: TimeOfDay.now().hour, minute: TimeOfDay.now().minute + 1); + static Duration? duration = Duration(minutes: 5); + + static GlobalKey _createFormKey = GlobalKey(); + + static FocusNode _titleNode = FocusNode(); + static FocusNode _startDateNode = FocusNode(); + static FocusNode _startTimeNode = FocusNode(); + static FocusNode _durationNode = FocusNode(); + + static TextEditingController _dateController = TextEditingController(); + static TextEditingController _startTimeController = TextEditingController(); + static TextEditingController _durationController = TextEditingController(); + + static Future createHikeDialog( + BuildContext context, String? groupID, GroupCubit groupCubit) { bool isSmallSized = MediaQuery.of(context).size.height < 800; - model.resultingDuration = Duration(minutes: 30); - model.durationController = new TextEditingController(); - model.startsAtDate = new TextEditingController(); - model.startsAtTime = new TextEditingController(); return showDialog( context: context, builder: (context) => GestureDetector( @@ -171,14 +200,14 @@ class CreateJoinBeaconDialog { ), child: SingleChildScrollView( child: Form( - key: model.formKeyCreate, + key: _createFormKey, child: Container( height: isSmallSized ? 75.h : 65.h, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), child: Column( - children: [ + children: [ Container( height: isSmallSized ? 14.h : 12.h, child: Padding( @@ -188,7 +217,11 @@ class CreateJoinBeaconDialog { validator: (value) => Validator.validateBeaconTitle(value!), onChanged: (name) { - model.title = name; + title = name; + }, + focusNode: _titleNode, + onEditingComplete: () { + _titleNode.unfocus(); }, decoration: InputDecoration( border: InputBorder.none, @@ -207,44 +240,42 @@ class CreateJoinBeaconDialog { ), color: kLightBlue, ), - SizedBox( - height: 2.h, - ), + SizedBox(height: 2.h), + // Start Date Field Container( height: isSmallSized ? 12.h : 10.h, child: Padding( padding: const EdgeInsets.all(4.0), child: InkWell( onTap: () async { - FocusManager.instance.primaryFocus?.unfocus(); - model.startingdate = await showDatePicker( + startDate = await showDatePicker( context: context, - initialDate: DateTime.now(), + initialDate: startDate!, firstDate: DateTime.now(), lastDate: DateTime(2100), builder: (context, child) => Theme( data: ThemeData().copyWith( textTheme: Theme.of(context).textTheme, colorScheme: ColorScheme.light( - primary: kBlue, - onPrimary: Colors.white, + primary: kLightBlue, + onPrimary: Colors.grey, surface: kBlue, ), ), child: child!), ); - model.startsAtDate.text = model.startingdate - .toString() - .substring(0, 10); + _dateController.text = + DateFormat('yyyy-MM-dd').format(startDate!); + + _startDateNode.unfocus(); + FocusScope.of(context) + .requestFocus(_startTimeNode); }, child: TextFormField( + controller: _dateController, enabled: false, - controller: model.startsAtDate, - onChanged: (value) { - model.startsAtDate.text = model.startingdate - .toString() - .substring(0, 10); - }, + focusNode: _startDateNode, + onEditingComplete: () {}, decoration: InputDecoration( border: InputBorder.none, hintText: 'Choose Start Date', @@ -263,61 +294,27 @@ class CreateJoinBeaconDialog { ), color: kLightBlue, ), - SizedBox( - height: 2.h, - ), + SizedBox(height: 2.h), + // Start Time Field Container( height: isSmallSized ? 12.h : 10.h, child: Padding( padding: const EdgeInsets.all(4.0), child: InkWell( onTap: () async { - FocusManager.instance.primaryFocus?.unfocus(); - model.startingTime = await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - builder: (context, child) { - return Theme( - data: ThemeData( - textTheme: Theme.of(context).textTheme, - timePickerTheme: TimePickerThemeData( - dialHandColor: kBlue, - dayPeriodTextColor: kBlue, - hourMinuteTextColor: kBlue, - helpTextStyle: TextStyle( - fontFamily: 'FuturaBold', - fontSize: 15.0, - fontWeight: FontWeight.w600, - ), - hourMinuteTextStyle: TextStyle( - fontFamily: 'FuturaBold', - fontSize: 40.0, - fontWeight: FontWeight.w600, - ), - dayPeriodTextStyle: TextStyle( - fontFamily: 'FuturaBold', - fontSize: 18.0, - fontWeight: FontWeight.w600, - ), - ), - ), - // This will change to light theme. - child: child!, - ); - }, - ); - model.startsAtTime.text = model.startingTime - .toString() - .substring(10, 15); + startTime = await showTimePicker( + context: context, initialTime: startTime!); + + if (startTime != null) { + _startTimeController.text = + '${startTime!.hour}:${startTime!.minute}'; + } }, child: TextFormField( + controller: _startTimeController, enabled: false, - controller: model.startsAtTime, - onChanged: (value) { - model.startsAtTime.text = model.startingTime - .toString() - .substring(10, 15); - }, + onEditingComplete: () {}, + focusNode: _startTimeNode, decoration: InputDecoration( border: InputBorder.none, alignLabelWithHint: true, @@ -338,40 +335,36 @@ class CreateJoinBeaconDialog { ), color: kLightBlue, ), - SizedBox( - height: 2.h, - ), + SizedBox(height: 2.h), + // Duration Field Container( height: isSmallSized ? 14.h : 12.h, child: Padding( padding: const EdgeInsets.all(4.0), child: InkWell( onTap: () async { - FocusManager.instance.primaryFocus?.unfocus(); - model.resultingDuration = - await showDurationPicker( + duration = await showDurationPicker( context: context, - initialTime: model.resultingDuration != null - ? model.resultingDuration! - : Duration(minutes: 30), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(5.0), - ), + initialTime: duration!, ); - model.durationController.text = model - .resultingDuration - .toString() - .substring(0, 8); + if (duration!.inHours != 0 && + duration!.inMinutes != 0) { + _durationController.text = + '${duration!.inHours.toString()} hour ${(duration!.inMinutes % 60)} minutes'; + } else if (duration!.inMinutes != 0) { + _durationController.text = + '${duration!.inMinutes.toString()} minutes'; + } + if (_durationController.text.isEmpty) { + _durationNode.unfocus(); + } }, child: TextFormField( enabled: false, - controller: model.durationController, - onChanged: (value) { - model.durationController.text = model - .resultingDuration - .toString() - .substring(0, 8); + focusNode: _durationNode, + controller: _durationController, + onEditingComplete: () { + _durationNode.unfocus(); }, validator: (value) => Validator.validateDuration(value.toString()), @@ -394,9 +387,7 @@ class CreateJoinBeaconDialog { ), color: kLightBlue, ), - SizedBox( - height: 2.h, - ), + SizedBox(height: 2.h), Flexible( flex: 2, child: HikeButton( @@ -404,29 +395,50 @@ class CreateJoinBeaconDialog { textSize: 18.0, textColor: Colors.white, buttonColor: kYellow, - onTap: () { - FocusManager.instance.primaryFocus?.unfocus(); - // navigationService.pop(); - if (model.startingdate == null || - model.startingTime == null) { - navigationService! - .showSnackBar("Enter date and time"); - return; - } - model.startsAt = DateTime( - model.startingdate!.year, - model.startingdate!.month, - model.startingdate!.day, - model.startingTime!.hour, - model.startingTime!.minute, - ); - // localNotif.scheduleNotification(); - if (model.startsAt.isBefore(DateTime.now())) { - navigationService!.showSnackBar( - "Enter a valid date and time!!"); - return; + onTap: () async { + if (_createFormKey.currentState!.validate()) { + DateTime startsAt = DateTime( + startDate!.year, + startDate!.month, + startDate!.day, + startTime!.hour, + startTime!.minute); + + final startingTime = + startsAt.millisecondsSinceEpoch; + + int currenTime = + DateTime.now().millisecondsSinceEpoch; + + if (startingTime < currenTime) { + utils.showSnackBar( + 'Please chose a correct time!', context); + return; + } + + final endTime = startsAt + .copyWith( + hour: startsAt.hour + duration!.inHours, + minute: startsAt.minute + + duration!.inMinutes) + .millisecondsSinceEpoch; + + if (groupCubit.position == null) { + utils.showSnackBar( + 'Please give access to location!', + context); + groupCubit.fetchPosition(); + return; + } + AutoRouter.of(context).maybePop(); + groupCubit.createHike( + title, + startingTime, + endTime, + groupCubit.position!.latitude.toString(), + groupCubit.position!.longitude.toString(), + groupID!); } - model.createHikeRoom(groupID, reloadList); }), ), ], @@ -440,8 +452,9 @@ class CreateJoinBeaconDialog { ); } - static Future joinBeaconDialog( - BuildContext context, GroupViewModel model, Function reloadList) { + static GlobalKey _joinBeaconKey = GlobalKey(); + static TextEditingController _joinBeaconController = TextEditingController(); + static Future joinBeaconDialog(BuildContext context, GroupCubit groupCubit) { bool isSmallSized = MediaQuery.of(context).size.height < 800; return showDialog( context: context, @@ -450,7 +463,7 @@ class CreateJoinBeaconDialog { borderRadius: BorderRadius.circular(10.0), ), child: Form( - key: model.formKeyJoin, + key: _joinBeaconKey, child: Container( height: isSmallSized ? 30.h : 25.h, child: Padding( @@ -462,12 +475,13 @@ class CreateJoinBeaconDialog { child: Padding( padding: const EdgeInsets.all(4.0), child: TextFormField( + controller: _joinBeaconController, keyboardType: TextInputType.text, textCapitalization: TextCapitalization.characters, style: TextStyle(fontSize: 22.0), validator: (value) => Validator.validatePasskey(value!), onChanged: (key) { - model.enteredPasskey = key.toUpperCase(); + _joinBeaconController.text = key.toUpperCase(); }, decoration: InputDecoration( alignLabelWithHint: true, @@ -494,8 +508,10 @@ class CreateJoinBeaconDialog { textColor: Colors.white, buttonColor: kYellow, onTap: () { - // navigationService.pop(); - model.joinHikeRoom(reloadList); + if (!_joinBeaconKey.currentState!.validate()) return; + AutoRouter.of(context).maybePop(); + groupCubit.joinHike(_joinBeaconController.text.trim()); + _joinBeaconController.clear(); }, ), ), diff --git a/lib/Bloc/presentation/widgets/text_field.dart b/lib/Bloc/presentation/widgets/text_field.dart new file mode 100644 index 00000000..db87ca98 --- /dev/null +++ b/lib/Bloc/presentation/widgets/text_field.dart @@ -0,0 +1,68 @@ +import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:flutter/material.dart'; + +class CustomTextField extends StatefulWidget { + final IconData iconData; + final String hintText; + final bool showTrailing; + final TextEditingController controller; + final String? Function(String?)? validator; + final FocusNode? focusNode; + final FocusNode? nextFocusNode; + + CustomTextField( + {super.key, + required this.iconData, + required this.hintText, + required this.controller, + this.showTrailing = false, + this.validator, + this.focusNode, + this.nextFocusNode}); + + @override + State createState() => _CustomTextFieldState(); +} + +class _CustomTextFieldState extends State { + bool obscureText = true; + + @override + Widget build(BuildContext context) { + return TextFormField( + validator: widget.validator, + controller: widget.controller, + focusNode: widget.focusNode, + decoration: InputDecoration( + border: InputBorder.none, + icon: Icon( + widget.iconData, + color: Colors.black, + size: 24.0, + ), + hintText: widget.hintText, + hintStyle: TextStyle(fontSize: hintsize - 2, color: hintColor), + suffixIcon: widget.showTrailing == true + ? IconButton( + onPressed: () { + setState(() { + obscureText = !obscureText; + }); + }, + icon: Icon( + obscureText ? Icons.visibility_off : Icons.visibility, + color: Colors.black, + )) + : null), + style: TextStyle(color: Colors.black), + obscureText: widget.showTrailing == false ? false : obscureText, + onEditingComplete: () { + if (widget.nextFocusNode != null) { + FocusScope.of(context).requestFocus(widget.nextFocusNode); + } else { + FocusScope.of(context).unfocus(); + } + }, + ); + } +} diff --git a/lib/Bloc/theme/theme.dart b/lib/Bloc/theme/theme.dart new file mode 100644 index 00000000..a57f4de5 --- /dev/null +++ b/lib/Bloc/theme/theme.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +class CustomTheme { + static const String _fontFamily = + 'FuturaBold'; // Match the name in pubspec.yaml + + // Define your custom colors + Color kYellow = Color(0xFFFDBB2C); + Color kBlue = Color(0xFF222375); + Color lightkBlue = Color(0xFF535393); + Color kLightBlue = Color(0xFFE8F1F8); + Color kBlack = Color(0xFF343434); + Color shimmerSkeletonColor = Color(0xff4e4f91); + Color hintColor = Colors.black54; + + // Define your custom theme data + ThemeData myTheme = ThemeData( + fontFamily: _fontFamily, + // Define primary colors + primaryColor: const Color(0xFF222375), + hintColor: const Color.fromARGB(255, 105, 103, 103), + + // Define text themes + textTheme: const TextTheme( + displayLarge: TextStyle( + fontSize: 19, + fontWeight: FontWeight.bold, + fontFamily: _fontFamily, + color: Colors.white, + ), + displayMedium: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w800, + fontFamily: _fontFamily, + color: Colors.black, + ), + bodyLarge: TextStyle( + fontSize: 16, + fontFamily: _fontFamily, + color: Colors.white, + ), + ), + + // Define other theme properties such as fonts, buttons, etc. + ); +} diff --git a/lib/locator.dart b/lib/locator.dart index 5d5f5d05..127a8df8 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,15 +1,31 @@ +import 'package:beacon/Bloc/core/services/shared_prefrence_service.dart'; +import 'package:beacon/Bloc/core/utils/utils.dart'; +import 'package:beacon/Bloc/data/datasource/local/local_api.dart'; +import 'package:beacon/Bloc/data/datasource/remote/remote_auth_api.dart'; +import 'package:beacon/Bloc/data/datasource/remote/remote_group_api.dart'; +import 'package:beacon/Bloc/data/datasource/remote/remote_home_api.dart'; +import 'package:beacon/Bloc/data/repositories/auth_repository_implementation.dart'; +import 'package:beacon/Bloc/data/repositories/group_repository_implementation.dart'; +import 'package:beacon/Bloc/data/repositories/home_repository_implementation.dart'; +import 'package:beacon/Bloc/domain/repositories/auth_repository.dart'; +import 'package:beacon/Bloc/domain/repositories/group_repository.dart'; +import 'package:beacon/Bloc/domain/repositories/home_repository.dart'; +import 'package:beacon/Bloc/domain/usecase/auth_usecase.dart'; +import 'package:beacon/Bloc/domain/usecase/group_usecase.dart'; +import 'package:beacon/Bloc/domain/usecase/home_usecase.dart'; import 'package:beacon/main.dart'; -import 'package:beacon/services/connection_checker.dart'; -import 'package:beacon/services/database_mutation_functions.dart'; -import 'package:beacon/services/graphql_config.dart'; -import 'package:beacon/services/hive_localdb.dart'; -import 'package:beacon/services/local_notification.dart'; -import 'package:beacon/services/navigation_service.dart'; -import 'package:beacon/services/user_config.dart'; -import 'package:beacon/view_model/auth_screen_model.dart'; -import 'package:beacon/view_model/home_screen_view_model.dart'; -import 'package:beacon/view_model/hike_screen_model.dart'; -import 'package:beacon/view_model/group_screen_view_model.dart'; +import 'package:beacon/old/components/services/connection_checker.dart'; +import 'package:beacon/old/components/services/database_mutation_functions.dart'; +import 'package:beacon/Bloc/config/graphql_config.dart'; +import 'package:beacon/old/components/services/hive_localdb.dart'; +import 'package:beacon/old/components/services/local_notification.dart'; +import 'package:beacon/old/components/services/navigation_service.dart'; +import 'package:beacon/old/components/services/user_config.dart'; +import 'package:beacon/old/components/view_model/auth_screen_model.dart'; +import 'package:beacon/old/components/view_model/home_screen_view_model.dart'; +import 'package:beacon/old/components/view_model/hike_screen_model.dart'; +import 'package:beacon/old/components/view_model/group_screen_view_model.dart'; +import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; GetIt locator = GetIt.instance; @@ -17,18 +33,27 @@ final UserConfig? userConfig = locator(); final NavigationService? navigationService = locator(); final DataBaseMutationFunctions? databaseFunctions = locator(); -final GraphQLConfig? graphqlConfig = locator(); +final GraphQLConfig graphqlConfig = locator(); final LocalNotification? localNotif = locator(); final HiveLocalDb? hiveDb = locator(); final ConnectionChecker? connectionChecker = locator(); +final sharedPrefrenceService = locator(); +final localApi = locator(); +final remoteAuthApi = locator(); +final remoteHomeApi = locator(); +final utils = locator(); + +void setupLocator() async { + // shared prefrence services + locator.registerSingleton(SharedPreferenceService()); -void setupLocator() { //services locator.registerSingleton(NavigationService()); //userConfig locator.registerSingleton(UserConfig()); - locator.registerSingleton(GraphQLConfig()); + + locator.registerSingleton(GraphQLConfig()); //databaseMutationFunction locator.registerSingleton(DataBaseMutationFunctions()); @@ -47,4 +72,46 @@ void setupLocator() { //local Notification locator.registerSingleton(LocalNotification()); + + // hive localDb + locator.registerSingleton(LocalApi()); + + final authClient = await graphqlConfig.authClient(); + + // Remote Api + locator.registerSingleton( + RemoteAuthApi( + clientAuth: authClient, + clientNonAuth: ValueNotifier(graphqlConfig.clientToQuery()), + ), + ); + + locator.registerSingleton( + RemoteHomeApi(authClient), + ); + + locator.registerSingleton( + RemoteGroupApi(authClient: authClient)); + + // registering auth reporitory of domain + locator.registerSingleton( + AuthRepositoryImplementation(remoteAuthApi: locator())); + locator.registerSingleton( + HomeRepostitoryImplementation(remoteHomeApi: locator())); + locator.registerSingleton( + GroupRepostioryImplementation(remoteGroupApi: locator())); + + // use case + locator.registerSingleton( + AuthUseCase(authRepository: locator())); + locator.registerSingleton( + HomeUseCase(homeRepository: locator())); + locator.registerSingleton( + GroupUseCase(locator())); + + // // cubit + // locator.registerFactory(() => HomeCubit(homeUseCase: locator())); + + // registering utils + locator.registerSingleton(Utils()); } diff --git a/lib/main.dart b/lib/main.dart index a2e05ed1..00c807e9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,37 +1,85 @@ -import 'package:beacon/config/environment_config.dart'; +// main.dart +import 'package:beacon/Bloc/config/enviornment_config.dart'; +import 'package:beacon/Bloc/presentation/cubit/auth_cubit.dart'; +import 'package:beacon/Bloc/presentation/cubit/group_cubit.dart'; +import 'package:beacon/Bloc/presentation/cubit/home_cubit.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/router.dart' as router; -import 'package:beacon/view_model/base_view_model.dart'; -import 'package:beacon/views/base_view.dart'; +import 'package:beacon/old/components/view_model/base_view_model.dart'; +import 'package:beacon/old/components/views/base_view.dart'; +import 'package:beacon/router.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:sizer/sizer.dart'; import 'package:overlay_support/overlay_support.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - EnvironmentConfig.loadEnvVariables(); + await EnvironmentConfig.loadEnvVariables(); SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); setupLocator(); + // starting local api for storing data + await localApi.init(); + await localNotif!.initialize(); await hiveDb!.init(); - runApp( - OverlaySupport( + + AppRouter _appRouter = AppRouter(); + + runApp(MyApp(router: _appRouter)); +} + +class MyApp extends StatefulWidget { + final AppRouter router; + + const MyApp({Key? key, required this.router}) : super(key: key); + + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + late AppRouter _appRouter; + + @override + void initState() { + super.initState(); + _appRouter = widget.router; + } + + void restartApp() { + setState(() {}); + } + + @override + Widget build(BuildContext context) { + return OverlaySupport( child: Sizer( - builder: (context, orientation, deviceType) => MaterialApp( - debugShowCheckedModeBanner: false, - title: 'Beacon', - navigatorKey: navigationService!.navigatorKey, - theme: ThemeData(fontFamily: 'FuturaBold'), - initialRoute: '/', - onGenerateRoute: router.generateRoute, + builder: (context, orientation, deviceType) => MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => AuthCubit(authUseCase: locator()), + ), + BlocProvider( + create: (context) => HomeCubit(homeUseCase: locator()), + ), + BlocProvider( + create: (context) => GroupCubit(locator()), + ), + ], + child: MaterialApp.router( + debugShowCheckedModeBanner: false, + title: 'Beacon', + theme: ThemeData(fontFamily: 'FuturaBold'), + routerConfig: _appRouter.config(), + ), ), ), - ), - ); + ); + } } class DemoPageView extends StatelessWidget { diff --git a/lib/components/active_beacon.dart b/lib/old/components/active_beacon.dart similarity index 100% rename from lib/components/active_beacon.dart rename to lib/old/components/active_beacon.dart diff --git a/lib/components/beacon_card.dart b/lib/old/components/beacon_card.dart similarity index 69% rename from lib/components/beacon_card.dart rename to lib/old/components/beacon_card.dart index 3e529faf..cede5b57 100644 --- a/lib/components/beacon_card.dart +++ b/lib/old/components/beacon_card.dart @@ -1,10 +1,15 @@ -import 'package:beacon/components/active_beacon.dart'; -import 'package:beacon/components/timer.dart'; +import 'dart:developer'; +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/old/components/active_beacon.dart'; +import 'package:beacon/old/components/models/location/location.dart'; +import 'package:beacon/old/components/models/user/user_info.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/models/beacon/beacon.dart'; -import 'package:beacon/utilities/constants.dart'; -import 'package:beacon/views/hike_screen.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/router.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:sizer/sizer.dart'; import 'package:skeleton_text/skeleton_text.dart'; import 'package:intl/intl.dart'; @@ -12,7 +17,7 @@ import 'package:intl/intl.dart'; class BeaconCustomWidgets { static final Color textColor = Color(0xFFAFAFAF); - static Widget getBeaconCard(BuildContext context, Beacon beacon) { + static Widget getBeaconCard(BuildContext context, BeaconEntity beacon) { print(beacon.leader!.name); bool hasStarted; bool hasEnded; @@ -25,41 +30,73 @@ class BeaconCustomWidgets { .isBefore(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)); return GestureDetector( onTap: () async { + if (hasEnded) + utils.showSnackBar('Beacon is not active anymore!', context); bool isJoinee = false; for (var i in beacon.followers!) { - if (i.id == userConfig!.currentUser!.id) { + if (i!.id == localApi.userModel.id) { isJoinee = true; } } if (!hasStarted) { - navigationService!.showSnackBar( - 'Beacon has not yet started! \nPlease come back at ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}', - ); + utils.showSnackBar( + 'Beacon has not yet started! \nPlease come back at ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}', + context); return; } if (hasStarted && - (beacon.leader!.id == userConfig!.currentUser!.id || isJoinee)) { - navigationService!.pushScreen('/hikeScreen', - arguments: HikeScreen( - beacon, - isLeader: (beacon.leader!.id == userConfig!.currentUser!.id), - )); - } else { - await databaseFunctions!.init(); - final Beacon? _beacon = - await databaseFunctions!.joinBeacon(beacon.shortcode); - if (!hasStarted) { - navigationService!.showSnackBar( - 'Beacon has not yet started! \nPlease come back at ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}', - ); - return; - } - if (hasStarted && _beacon != null) { - navigationService!.pushScreen('/hikeScreen', - arguments: HikeScreen(beacon, isLeader: false)); - } - //Snackbar is displayed by joinBeacon itself on any error or trying to join expired beacon. + (beacon.leader!.id == localApi.userModel.id || isJoinee)) { + log('here'); + // navigationService!.pushScreen('/hikeScreen', + // arguments: HikeScreen( + // beacon, + // isLeader: (beacon.leader!.id == userConfig!.currentUser!.id), + // )); + + // for(int i=0; i Navigator.of(context).pop(true), - // TODO + // // onTap: () { // navigationService.removeAllAndPush('/groupScreen', '/', // arguments: GroupScreen( diff --git a/lib/enums/view_state.dart b/lib/old/components/enums/view_state.dart similarity index 100% rename from lib/enums/view_state.dart rename to lib/old/components/enums/view_state.dart diff --git a/lib/components/group_card.dart b/lib/old/components/group_card.dart similarity index 76% rename from lib/components/group_card.dart rename to lib/old/components/group_card.dart index db0f62be..304adb07 100644 --- a/lib/components/group_card.dart +++ b/lib/old/components/group_card.dart @@ -1,38 +1,46 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/Bloc/domain/entities/group/group_entity.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/utilities/constants.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/router.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:sizer/sizer.dart'; import 'package:skeleton_text/skeleton_text.dart'; - -import '../models/group/group.dart'; -import '../views/group_screen.dart'; +import 'models/group/group.dart'; class GroupCustomWidgets { static final Color textColor = Color(0xFFAFAFAF); - static Widget getGroupCard(BuildContext context, Group group) { + static Widget getGroupCard(BuildContext context, GroupEntity group) { String noMembers = group.members!.length.toString(); String noBeacons = group.beacons!.length.toString(); return GestureDetector( onTap: () async { bool isMember = false; for (var i in group.members!) { - if (i.id == userConfig!.currentUser!.id) { + if (i!.id == userConfig!.currentUser!.id) { isMember = true; } } - if (group.leader!.id == userConfig!.currentUser!.id || isMember) { - navigationService!.pushScreen('/groupScreen', - arguments: GroupScreen( - group, - )); + if (group.leader!.id == localApi.userModel.id || isMember) { + // navigationService!.pushScreen('/groupScreen', + // arguments: GroupScreen( + // group, + // )); + + // AutoRouter.of(context).pushNamed('/group'); + + AutoRouter.of(context).push(GroupScreenRoute(group: group)); } else { await databaseFunctions!.init(); final Group? _group = await databaseFunctions!.joinGroup(group.shortcode); if (_group != null) { - navigationService! - .pushScreen('/groupScreen', arguments: GroupScreen(group)); + // navigationService! + // .pushScreen('/groupScreen', arguments: GroupScreen(group)); + // AutoRouter.of(context).pushNamed('/group'); + AutoRouter.of(context).push(GroupScreenRoute(group: group)); } //Snackbar is displayed by joinBeacon itself on any error or trying to join expired beacon. } @@ -67,9 +75,24 @@ class GroupCustomWidgets { 'Group has $noBeacons beacons ', style: Style.commonTextStyle, ), - SizedBox(height: 4.0), - Text('Passkey: ${group.shortcode}', - style: Style.commonTextStyle), + // SizedBox(height: 4.0), + Row( + children: [ + Text('Passkey: ${group.shortcode}', + style: Style.commonTextStyle), + IconButton( + onPressed: () { + Clipboard.setData( + ClipboardData(text: group.shortcode.toString())); + utils.showSnackBar('Shortcode copied!', context); + }, + icon: Icon( + Icons.copy, + color: Colors.white, + size: 15, + )) + ], + ) ], ), ], diff --git a/lib/components/hike_button.dart b/lib/old/components/hike_button.dart similarity index 94% rename from lib/components/hike_button.dart rename to lib/old/components/hike_button.dart index 5363ec97..9cebe747 100644 --- a/lib/components/hike_button.dart +++ b/lib/old/components/hike_button.dart @@ -1,4 +1,4 @@ -import 'package:beacon/utilities/constants.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; import 'package:flutter/material.dart'; class HikeButton extends StatelessWidget { diff --git a/lib/components/hike_screen_widget.dart b/lib/old/components/hike_screen_widget.dart similarity index 95% rename from lib/components/hike_screen_widget.dart rename to lib/old/components/hike_screen_widget.dart index b7efefb3..50d7aaa3 100644 --- a/lib/components/hike_screen_widget.dart +++ b/lib/old/components/hike_screen_widget.dart @@ -1,10 +1,10 @@ import 'dart:async'; import 'dart:io'; -import 'package:beacon/components/hike_button.dart'; +import 'package:beacon/old/components/hike_button.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/models/beacon/beacon.dart'; -import 'package:beacon/utilities/constants.dart'; -import 'package:beacon/view_model/hike_screen_model.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/old/components/view_model/hike_screen_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_geocoder_alternative/flutter_geocoder_alternative.dart'; @@ -112,8 +112,8 @@ class HikeScreenWidget extends ChangeNotifier { // sanity check. if (googleMapControllerCompleter.isCompleted == false) return; if (!await connectionChecker!.checkForInternetConnection()) { - navigationService!.showSnackBar( - 'Cannot share the route, please check your internet connection.'); + // navigationService!.showSnackBar( + // 'Cannot share the route, please check your internet connection.'); return; } //show marker description so that image will be more usefull. @@ -239,8 +239,8 @@ class HikeScreenWidget extends ChangeNotifier { ? Fluttertoast.showToast( msg: 'Only beacon holder has access to change the duration') - //TODO: enable this once backend has updated. - //Commented, since we dont have the neccessary mutation atm on backend to change the duration. + // todo enable this once backend has updated. + // Commented, since we dont have the neccessary mutation atm on backend to change the duration. // : DialogBoxes.changeDurationDialog(context); : Container(); }, diff --git a/lib/components/loading_screen.dart b/lib/old/components/loading_screen.dart similarity index 96% rename from lib/components/loading_screen.dart rename to lib/old/components/loading_screen.dart index bfc930dc..a9c9a5c9 100644 --- a/lib/components/loading_screen.dart +++ b/lib/old/components/loading_screen.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; -import '../utilities/constants.dart'; +import 'utilities/constants.dart'; class LoadingScreen extends StatelessWidget { const LoadingScreen({Key? key}) : super(key: key); diff --git a/lib/models/beacon/beacon.dart b/lib/old/components/models/beacon/beacon.dart similarity index 91% rename from lib/models/beacon/beacon.dart rename to lib/old/components/models/beacon/beacon.dart index c177f502..af4f14d9 100644 --- a/lib/models/beacon/beacon.dart +++ b/lib/old/components/models/beacon/beacon.dart @@ -1,6 +1,6 @@ -import 'package:beacon/models/landmarks/landmark.dart'; -import 'package:beacon/models/location/location.dart'; -import 'package:beacon/models/user/user_info.dart'; +import 'package:beacon/old/components/models/landmarks/landmark.dart'; +import 'package:beacon/old/components/models/location/location.dart'; +import 'package:beacon/old/components/models/user/user_info.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; diff --git a/lib/models/beacon/beacon.g.dart b/lib/old/components/models/beacon/beacon.g.dart similarity index 94% rename from lib/models/beacon/beacon.g.dart rename to lib/old/components/models/beacon/beacon.g.dart index f6975e15..73850387 100644 --- a/lib/models/beacon/beacon.g.dart +++ b/lib/old/components/models/beacon/beacon.g.dart @@ -24,8 +24,8 @@ class BeaconAdapter extends TypeAdapter { title: fields[7] as String?, leader: fields[4] as User?, followers: (fields[5] as List?)?.cast(), - route: (fields[6] as List?)?.cast(), - landmarks: (fields[8] as List?)?.cast(), + route: (fields[6] as List?)?.cast(), + landmarks: (fields[8] as List?)?.cast(), location: fields[9] as Location?, group: fields[10] as String?, ); diff --git a/lib/models/group/group.dart b/lib/old/components/models/group/group.dart similarity index 95% rename from lib/models/group/group.dart rename to lib/old/components/models/group/group.dart index 168655af..007e3071 100644 --- a/lib/models/group/group.dart +++ b/lib/old/components/models/group/group.dart @@ -1,4 +1,4 @@ -import 'package:beacon/models/user/user_info.dart'; +import 'package:beacon/old/components/models/user/user_info.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; diff --git a/lib/models/group/group.g.dart b/lib/old/components/models/group/group.g.dart similarity index 100% rename from lib/models/group/group.g.dart rename to lib/old/components/models/group/group.g.dart diff --git a/lib/models/landmarks/landmark.dart b/lib/old/components/models/landmarks/landmark.dart similarity index 89% rename from lib/models/landmarks/landmark.dart rename to lib/old/components/models/landmarks/landmark.dart index 4f01fbde..42cd5ab7 100644 --- a/lib/models/landmarks/landmark.dart +++ b/lib/old/components/models/landmarks/landmark.dart @@ -1,4 +1,4 @@ -import 'package:beacon/models/location/location.dart'; +import 'package:beacon/old/components/models/location/location.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; part 'landmark.g.dart'; diff --git a/lib/models/landmarks/landmark.g.dart b/lib/old/components/models/landmarks/landmark.g.dart similarity index 100% rename from lib/models/landmarks/landmark.g.dart rename to lib/old/components/models/landmarks/landmark.g.dart diff --git a/lib/models/location/location.dart b/lib/old/components/models/location/location.dart similarity index 100% rename from lib/models/location/location.dart rename to lib/old/components/models/location/location.dart diff --git a/lib/models/location/location.g.dart b/lib/old/components/models/location/location.g.dart similarity index 100% rename from lib/models/location/location.g.dart rename to lib/old/components/models/location/location.g.dart diff --git a/lib/models/user/user_info.dart b/lib/old/components/models/user/user_info.dart similarity index 91% rename from lib/models/user/user_info.dart rename to lib/old/components/models/user/user_info.dart index 19af4446..70bd5cdd 100644 --- a/lib/models/user/user_info.dart +++ b/lib/old/components/models/user/user_info.dart @@ -1,6 +1,6 @@ -import 'package:beacon/models/beacon/beacon.dart'; -import 'package:beacon/models/group/group.dart'; -import 'package:beacon/models/location/location.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/old/components/models/group/group.dart'; +import 'package:beacon/old/components/models/location/location.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; part 'user_info.g.dart'; diff --git a/lib/models/user/user_info.g.dart b/lib/old/components/models/user/user_info.g.dart similarity index 100% rename from lib/models/user/user_info.g.dart rename to lib/old/components/models/user/user_info.g.dart diff --git a/lib/services/connection_checker.dart b/lib/old/components/services/connection_checker.dart similarity index 100% rename from lib/services/connection_checker.dart rename to lib/old/components/services/connection_checker.dart diff --git a/lib/services/database_mutation_functions.dart b/lib/old/components/services/database_mutation_functions.dart similarity index 86% rename from lib/services/database_mutation_functions.dart rename to lib/old/components/services/database_mutation_functions.dart index a7baeb7d..2c59f437 100644 --- a/lib/services/database_mutation_functions.dart +++ b/lib/old/components/services/database_mutation_functions.dart @@ -1,18 +1,18 @@ import 'dart:async'; import 'dart:developer'; -import 'package:beacon/models/beacon/beacon.dart'; -import 'package:beacon/models/group/group.dart'; -import 'package:beacon/models/landmarks/landmark.dart'; -import 'package:beacon/models/location/location.dart'; -import 'package:beacon/queries/auth.dart'; -import 'package:beacon/queries/beacon.dart'; -import 'package:beacon/utilities/constants.dart'; +import 'package:beacon/Bloc/core/queries/auth.dart'; +import 'package:beacon/Bloc/core/queries/beacon.dart'; +import 'package:beacon/Bloc/core/queries/group.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/old/components/models/group/group.dart'; +import 'package:beacon/old/components/models/landmarks/landmark.dart'; +import 'package:beacon/old/components/models/location/location.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; -import 'package:beacon/models/user/user_info.dart'; -import '../locator.dart'; -import '../queries/group.dart'; +import 'package:beacon/old/components/models/user/user_info.dart'; +import '../../../locator.dart'; class DataBaseMutationFunctions { late ValueNotifier clientNonAuth; @@ -21,9 +21,9 @@ class DataBaseMutationFunctions { late BeaconQueries _beaconQuery; late GroupQueries _groupQuery; init() async { - clientNonAuth = await ValueNotifier(graphqlConfig!.clientToQuery()); + clientNonAuth = await ValueNotifier(graphqlConfig.clientToQuery()); ValueNotifier(clientNonAuth); - clientAuth = await graphqlConfig!.authClient(); + clientAuth = await graphqlConfig.authClient(); _authQuery = AuthQueries(); _beaconQuery = BeaconQueries(); _groupQuery = GroupQueries(); @@ -53,21 +53,21 @@ class DataBaseMutationFunctions { return true; } else if (exception.graphqlErrors[i].message == userNotFound.message) { if (showSnackBar) { - navigationService! - .showSnackBar("No account registered with this email"); + // navigationService! + // .showSnackBar("No account registered with this email"); } return false; } else if (exception.graphqlErrors[i].message == wrongCredentials.message) { if (showSnackBar) { - navigationService!.showSnackBar("Enter a valid password"); + // navigationService!.showSnackBar("Enter a valid password"); } return false; } else if (exception.graphqlErrors[i].message == emailAccountPresent.message) { if (showSnackBar) { - navigationService! - .showSnackBar("Account with this email already registered"); + // navigationService! + // .showSnackBar("Account with this email already registered"); } return false; } @@ -129,8 +129,8 @@ class DataBaseMutationFunctions { // ); if (result.hasException) { - navigationService! - .showSnackBar("${result.exception!.graphqlErrors.first.message}"); + // navigationService! + // .showSnackBar("${result.exception!.graphqlErrors.first.message}"); debugPrint('${result.exception!.graphqlErrors}'); return exceptionError; } else if (result.data != null && result.isConcrete) { @@ -153,8 +153,8 @@ class DataBaseMutationFunctions { document: gql(_authQuery.loginUser(email, password)))); log(result.exception.toString()); if (result.hasException) { - navigationService! - .showSnackBar("${result.exception!.graphqlErrors.first.message}"); + // navigationService! + // .showSnackBar("${result.exception!.graphqlErrors.first.message}"); print("${result.exception!.graphqlErrors}"); return exceptionError; } else if (result.data != null && result.isConcrete) { @@ -205,6 +205,8 @@ class DataBaseMutationFunctions { Future fetchBeaconInfo(String? id) async { final QueryResult result = await clientAuth .query(QueryOptions(document: gql(_beaconQuery.fetchBeaconDetail(id)))); + + log('fetching beacon info: $result'); if (result.hasException) { final bool exception = encounteredExceptionOrError(result.exception!, showSnackBar: false); @@ -289,16 +291,16 @@ class DataBaseMutationFunctions { try { loc = await AppConstants.getLocation(); } catch (onErr) { - navigationService! - .showSnackBar("$onErr : Allow location access to start beacon"); + // navigationService! + // .showSnackBar("$onErr : Allow location access to start beacon"); return null; } final QueryResult result = await clientAuth.mutate(MutationOptions( document: gql(_beaconQuery.createBeacon(title, startsAt, expiresAt, loc.latitude.toString(), loc.longitude.toString(), groupID)))); if (result.hasException) { - navigationService!.showSnackBar( - "Something went wrong: ${result.exception!.graphqlErrors.first.message}"); + // navigationService!.showSnackBar( + // "Something went wrong: ${result.exception!.graphqlErrors.first.message}"); print("Something went wrong: ${result.exception}"); } else if (result.data != null && result.isConcrete) { final Beacon beacon = Beacon.fromJson( @@ -318,8 +320,8 @@ class DataBaseMutationFunctions { print( "Something went wrong: ${result.exception}", ); - navigationService!.showSnackBar( - "Something went wrong: ${result.exception!.graphqlErrors.first.message}"); + // navigationService!.showSnackBar( + // "Something went wrong: ${result.exception!.graphqlErrors.first.message}"); } else if (result.data != null && result.isConcrete) { final Location location = Location.fromJson( result.data!['updateBeaconLocation']['location'] @@ -335,8 +337,8 @@ class DataBaseMutationFunctions { final QueryResult result = await clientAuth.mutate( MutationOptions(document: gql(_beaconQuery.joinBeacon(shortcode)))); if (result.hasException) { - navigationService!.showSnackBar( - "Something went wrong: ${result.exception!.graphqlErrors.first.message}"); + // navigationService!.showSnackBar( + // "Something went wrong: ${result.exception!.graphqlErrors.first.message}"); print("Something went wrong: ${result.exception}"); navigationService!.removeAllAndPush('/main', '/'); } else if (result.data != null && result.isConcrete) { @@ -345,18 +347,18 @@ class DataBaseMutationFunctions { ); if (DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!) .isBefore(DateTime.now())) { - navigationService!.showSnackBar( - "Looks like the beacon you are trying join has expired", - ); + // navigationService!.showSnackBar( + // "Looks like the beacon you are trying join has expired", + // ); return null; } beacon.route!.add(beacon.leader!.location); hiveDb!.putBeaconInBeaconBox(beacon.id, beacon); return beacon; } else { - navigationService!.showSnackBar( - "Something went wrong while trying to join Beacon", - ); + // navigationService!.showSnackBar( + // "Something went wrong while trying to join Beacon", + // ); } return null; } @@ -369,8 +371,8 @@ class DataBaseMutationFunctions { id, loc.latitude.toString(), loc.longitude.toString(), title)))) .then((value) { if (value.hasException) { - navigationService!.showSnackBar( - "Something went wrong: ${value.exception!.graphqlErrors.first.message}"); + // navigationService!.showSnackBar( + // "Something went wrong: ${value.exception!.graphqlErrors.first.message}"); print("Something went wrong: ${value.exception}"); } else if (value.data != null && value.isConcrete) { final Landmark landmark = Landmark.fromJson( @@ -423,8 +425,8 @@ class DataBaseMutationFunctions { document: gql(_beaconQuery.changeLeader(beaconID, newLeaderID)))) .then((value) { if (value.hasException) { - navigationService!.showSnackBar( - "Something went wrong: ${value.exception!.graphqlErrors.first.message}"); + // navigationService!.showSnackBar( + // "Something went wrong: ${value.exception!.graphqlErrors.first.message}"); print("Something went wrong: ${value.exception}"); } else if (value.data != null && value.isConcrete) { final Beacon changedLeader = Beacon.fromJson( @@ -441,8 +443,8 @@ class DataBaseMutationFunctions { final QueryResult result = await clientAuth .mutate(MutationOptions(document: gql(_groupQuery.createGroup(title)))); if (result.hasException) { - navigationService!.showSnackBar( - "Something went wrong: ${result.exception!.graphqlErrors.first.message}"); + // navigationService!.showSnackBar( + // "Something went wrong: ${result.exception!.graphqlErrors.first.message}"); print("Something went wrong: ${result.exception}"); } else if (result.data != null && result.isConcrete) { final Group group = Group.fromJson( @@ -458,10 +460,11 @@ class DataBaseMutationFunctions { final QueryResult result = await clientAuth.mutate( MutationOptions(document: gql(_groupQuery.joinGroup(shortcode)))); if (result.hasException) { - navigationService!.showSnackBar( - "Something went wrong: ${result.exception!.graphqlErrors.first.message}"); + // navigationService!.showSnackBar( + // "Something went wrong: ${result.exception!.graphqlErrors.first.message}"); print("Something went wrong: ${result.exception}"); - navigationService!.removeAllAndPush('/main', '/'); + // navigationService!.removeAllAndPush('/main', '/'); + // AutoRouter.of(context).pushNamed('/home'); } else if (result.data != null && result.isConcrete) { final Group group = Group.fromJson( result.data!['joinBeacon'] as Map, @@ -469,9 +472,9 @@ class DataBaseMutationFunctions { // hiveDb.putBeaconInBeaconBox(beacon.id, beacon); return group; } else { - navigationService!.showSnackBar( - "Something went wrong while trying to join Group", - ); + // navigationService!.showSnackBar( + // "Something went wrong while trying to join Group", + // ); } return null; } diff --git a/lib/services/hive_localdb.dart b/lib/old/components/services/hive_localdb.dart similarity index 85% rename from lib/services/hive_localdb.dart rename to lib/old/components/services/hive_localdb.dart index d0524a9f..fadda2b0 100644 --- a/lib/services/hive_localdb.dart +++ b/lib/old/components/services/hive_localdb.dart @@ -1,8 +1,8 @@ import 'package:beacon/locator.dart'; -import 'package:beacon/models/beacon/beacon.dart'; -import 'package:beacon/models/landmarks/landmark.dart'; -import 'package:beacon/models/location/location.dart'; -import 'package:beacon/models/user/user_info.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/old/components/models/landmarks/landmark.dart'; +import 'package:beacon/old/components/models/location/location.dart'; +import 'package:beacon/old/components/models/user/user_info.dart'; import 'package:hive/hive.dart'; import 'package:path_provider/path_provider.dart' as path_provider; diff --git a/lib/services/local_notification.dart b/lib/old/components/services/local_notification.dart similarity index 96% rename from lib/services/local_notification.dart rename to lib/old/components/services/local_notification.dart index e0134ffc..d6a30906 100644 --- a/lib/services/local_notification.dart +++ b/lib/old/components/services/local_notification.dart @@ -1,6 +1,6 @@ import 'package:beacon/locator.dart'; -import 'package:beacon/models/beacon/beacon.dart'; -import 'package:beacon/views/hike_screen.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/Bloc/presentation/screens/hike_screen.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:timezone/timezone.dart' as tz; import 'package:timezone/data/latest.dart' as tz; diff --git a/lib/services/navigation_service.dart b/lib/old/components/services/navigation_service.dart similarity index 67% rename from lib/services/navigation_service.dart rename to lib/old/components/services/navigation_service.dart index b7e26d4c..3a21c838 100644 --- a/lib/services/navigation_service.dart +++ b/lib/old/components/services/navigation_service.dart @@ -1,4 +1,3 @@ -import 'package:beacon/utilities/constants.dart'; import 'package:flutter/material.dart'; class NavigationService { @@ -39,26 +38,26 @@ class NavigationService { }); } - void showSnackBar(String message, - {Duration duration = const Duration(seconds: 2)}) { - ScaffoldMessenger.of(navigatorKey.currentContext!).showSnackBar( - SnackBar( - duration: duration, - content: Text( - message, - style: TextStyle(color: Colors.black), - ), - backgroundColor: kLightBlue.withOpacity(0.8), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(10), - ), - ), - behavior: SnackBarBehavior.floating, - elevation: 5, - ), - ); - } + // void showSnackBar(String message, + // {Duration duration = const Duration(seconds: 2)}) { + // ScaffoldMessenger.of(navigatorKey.currentContext!).showSnackBar( + // SnackBar( + // duration: duration, + // content: Text( + // message, + // style: TextStyle(color: Colors.black), + // ), + // backgroundColor: kLightBlue.withOpacity(0.8), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.all( + // Radius.circular(10), + // ), + // ), + // behavior: SnackBarBehavior.floating, + // elevation: 5, + // ), + // ); + // } void pop() { return navigatorKey.currentState!.pop(); diff --git a/lib/services/size_config.dart b/lib/old/components/services/size_config.dart similarity index 100% rename from lib/services/size_config.dart rename to lib/old/components/services/size_config.dart diff --git a/lib/services/user_config.dart b/lib/old/components/services/user_config.dart similarity index 83% rename from lib/services/user_config.dart rename to lib/old/components/services/user_config.dart index 13e83953..01c87735 100644 --- a/lib/services/user_config.dart +++ b/lib/old/components/services/user_config.dart @@ -1,7 +1,7 @@ import 'dart:async'; -import 'package:beacon/models/user/user_info.dart'; +import 'package:beacon/old/components/models/user/user_info.dart'; import 'package:flutter/material.dart'; -import '../locator.dart'; +import '../../../locator.dart'; class UserConfig { User? _currentUser = User(id: 'null', authToken: 'null'); @@ -15,7 +15,7 @@ class UserConfig { return false; } bool userUpdated = true; - await graphqlConfig!.getToken().then((value) async { + await graphqlConfig.getToken().then((value) async { print('${userConfig!._currentUser!.authToken}'); await databaseFunctions!.init(); await databaseFunctions!.fetchCurrentUserInfo().then((value) { @@ -23,7 +23,7 @@ class UserConfig { hiveDb!.saveUserInHive(_currentUser); userUpdated = true; } else { - navigationService!.showSnackBar("Couldn't update User details"); + // navigationService!.showSnackBar("Couldn't update User details"); userUpdated = false; } }); diff --git a/lib/components/shape_painter.dart b/lib/old/components/shape_painter.dart similarity index 96% rename from lib/components/shape_painter.dart rename to lib/old/components/shape_painter.dart index 9b17fe4a..5c31eff5 100644 --- a/lib/components/shape_painter.dart +++ b/lib/old/components/shape_painter.dart @@ -1,5 +1,5 @@ import 'package:flutter/cupertino.dart'; -import '../utilities/constants.dart'; +import 'utilities/constants.dart'; class ShapePainter extends CustomPainter { @override diff --git a/lib/components/timer.dart b/lib/old/components/timer.dart similarity index 92% rename from lib/components/timer.dart rename to lib/old/components/timer.dart index 4cb4f942..45cc84c4 100644 --- a/lib/components/timer.dart +++ b/lib/old/components/timer.dart @@ -1,7 +1,7 @@ import 'package:beacon/locator.dart'; -import 'package:beacon/models/beacon/beacon.dart'; -import 'package:beacon/utilities/constants.dart'; -import 'package:beacon/views/hike_screen.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/Bloc/presentation/screens/hike_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_countdown_timer/index.dart'; diff --git a/lib/utilities/constants.dart b/lib/old/components/utilities/constants.dart similarity index 100% rename from lib/utilities/constants.dart rename to lib/old/components/utilities/constants.dart diff --git a/lib/utilities/indication_painter.dart b/lib/old/components/utilities/indication_painter.dart similarity index 95% rename from lib/utilities/indication_painter.dart rename to lib/old/components/utilities/indication_painter.dart index 17a64e48..953db2cb 100644 --- a/lib/utilities/indication_painter.dart +++ b/lib/old/components/utilities/indication_painter.dart @@ -1,6 +1,6 @@ import 'dart:math'; -import 'package:beacon/utilities/constants.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; import 'package:flutter/material.dart'; class TabIndicationPainter extends CustomPainter { diff --git a/lib/view_model/auth_screen_model.dart b/lib/old/components/view_model/auth_screen_model.dart similarity index 89% rename from lib/view_model/auth_screen_model.dart rename to lib/old/components/view_model/auth_screen_model.dart index b9a67f55..33714b77 100644 --- a/lib/view_model/auth_screen_model.dart +++ b/lib/old/components/view_model/auth_screen_model.dart @@ -1,10 +1,10 @@ import 'dart:developer'; -import 'package:beacon/enums/view_state.dart'; -import 'package:beacon/utilities/constants.dart'; +import 'package:beacon/old/components/enums/view_state.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; import 'package:flutter/material.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/view_model/base_view_model.dart'; +import 'package:beacon/old/components/view_model/base_view_model.dart'; class AuthViewModel extends BaseModel { final formKeySignup = GlobalKey(); @@ -58,11 +58,11 @@ class AuthViewModel extends BaseModel { navigationService!.removeAllAndPush('/auth', '/'); } else { navigationService!.removeAllAndPush('/auth', '/'); - navigationService!.showSnackBar('Something went wrong'); + // navigationService!.showSnackBar('Something went wrong'); } setState(ViewState.idle); } else { - navigationService!.showSnackBar('Enter valid entries'); + // navigationService!.showSnackBar('Enter valid entries'); } } @@ -76,7 +76,7 @@ class AuthViewModel extends BaseModel { navigationService!.removeAllAndPush('/main', '/'); } else { navigationService!.removeAllAndPush('/auth', '/'); - navigationService!.showSnackBar('Something went wrong'); + // navigationService!.showSnackBar('Something went wrong'); } setState(ViewState.idle); } @@ -98,11 +98,11 @@ class AuthViewModel extends BaseModel { navigationService!.removeAllAndPush('/auth', '/'); } else { navigationService!.removeAllAndPush('/auth', '/'); - navigationService!.showSnackBar('Something went wrong'); + // navigationService!.showSnackBar('Something went wrong'); } setState(ViewState.idle); } else { - navigationService!.showSnackBar('Enter valid entries'); + // navigationService!.showSnackBar('Enter valid entries'); } } diff --git a/lib/view_model/base_view_model.dart b/lib/old/components/view_model/base_view_model.dart similarity index 82% rename from lib/view_model/base_view_model.dart rename to lib/old/components/view_model/base_view_model.dart index d0b66cb8..42acc5c9 100644 --- a/lib/view_model/base_view_model.dart +++ b/lib/old/components/view_model/base_view_model.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:beacon/enums/view_state.dart'; +import 'package:beacon/old/components/enums/view_state.dart'; class BaseModel extends ChangeNotifier { ViewState _state = ViewState.idle; diff --git a/lib/view_model/group_screen_view_model.dart b/lib/old/components/view_model/group_screen_view_model.dart similarity index 71% rename from lib/view_model/group_screen_view_model.dart rename to lib/old/components/view_model/group_screen_view_model.dart index 9d4a1504..bdba3895 100644 --- a/lib/view_model/group_screen_view_model.dart +++ b/lib/old/components/view_model/group_screen_view_model.dart @@ -1,10 +1,10 @@ -import 'package:beacon/enums/view_state.dart'; +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/old/components/enums/view_state.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/models/beacon/beacon.dart'; -import 'package:beacon/view_model/base_view_model.dart'; -import 'package:beacon/views/hike_screen.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/old/components/view_model/base_view_model.dart'; +import 'package:beacon/Bloc/presentation/screens/hike_screen.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; class GroupViewModel extends BaseModel { final formKeyCreate = GlobalKey(); @@ -25,11 +25,13 @@ class GroupViewModel extends BaseModel { TextEditingController startsAtTime = new TextEditingController(); String? enteredPasskey; - createHikeRoom(String? groupID, Function reloadList) async { + createHikeRoom( + String? groupID, Function reloadList, BuildContext context) async { FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); validate = AutovalidateMode.always; if (formKeyCreate.currentState!.validate()) { - navigationService!.pop(); + // navigationService!.pop(); + AutoRouter.of(context).maybePop(); setState(ViewState.busy); validate = AutovalidateMode.disabled; databaseFunctions!.init(); @@ -52,9 +54,9 @@ class GroupViewModel extends BaseModel { localNotif!.scheduleNotification(beacon); setState(ViewState.idle); reloadList(); - navigationService!.showSnackBar( - 'Beacon has not yet started! \nPlease come back at ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}', - ); + // navigationService!.showSnackBar( + // 'Beacon has not yet started! \nPlease come back at ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}', + // ); return; } } else { @@ -65,7 +67,7 @@ class GroupViewModel extends BaseModel { } joinHikeRoom(Function reloadList) async { - FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); + // FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); validate = AutovalidateMode.always; if (formKeyJoin.currentState!.validate()) { setState(ViewState.busy); @@ -79,15 +81,15 @@ class GroupViewModel extends BaseModel { .isAfter(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)); if (hasStarted) { - navigationService!.pushScreen('/hikeScreen', - arguments: HikeScreen(beacon, isLeader: false)); + // navigationService!.pushScreen('/hikeScreen', + // arguments: HikeScreen(beacon, isLeader: false)); } else { localNotif!.scheduleNotification(beacon); setState(ViewState.idle); reloadList(); - navigationService!.showSnackBar( - 'Beacon has not yet started! \nPlease come back at ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}', - ); + // navigationService!.showSnackBar( + // 'Beacon has not yet started! \nPlease come back at ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}', + // ); return; } } else { @@ -96,7 +98,7 @@ class GroupViewModel extends BaseModel { } //Snackbar is displayed by joinBeacon itself on any error or trying to join expired beacon. } else { - navigationService!.showSnackBar('Enter Valid Passkey'); + // navigationService!.showSnackBar('Enter Valid Passkey'); } } @@ -106,6 +108,6 @@ class GroupViewModel extends BaseModel { await hiveDb!.beaconsBox.clear(); // setState(ViewState.idle); await localNotif!.deleteNotification(); - navigationService!.removeAllAndPush('/auth', '/'); + // navigationService!.removeAllAndPush('/auth', '/'); } } diff --git a/lib/view_model/hike_screen_model.dart b/lib/old/components/view_model/hike_screen_model.dart similarity index 94% rename from lib/view_model/hike_screen_model.dart rename to lib/old/components/view_model/hike_screen_model.dart index bf9c07f6..0dcd8308 100644 --- a/lib/view_model/hike_screen_model.dart +++ b/lib/old/components/view_model/hike_screen_model.dart @@ -1,22 +1,24 @@ import 'dart:async'; - -import 'package:beacon/components/dialog_boxes.dart'; -import 'package:beacon/config/environment_config.dart'; +import 'dart:developer'; +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/Bloc/core/queries/beacon.dart'; +import 'package:beacon/old/components/dialog_boxes.dart'; +import 'package:beacon/Bloc/config/enviornment_config.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/queries/beacon.dart'; -import 'package:beacon/services/graphql_config.dart'; -import 'package:beacon/utilities/constants.dart'; +import 'package:beacon/Bloc/config/graphql_config.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; import 'package:flutter/material.dart'; import 'package:flutter_animarker/core/ripple_marker.dart'; import 'package:flutter_geocoder_alternative/flutter_geocoder_alternative.dart'; import 'package:flutter_polyline_points/flutter_polyline_points.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:beacon/enums/view_state.dart'; -import 'package:beacon/models/beacon/beacon.dart'; -import 'package:beacon/models/location/location.dart' deferred as locModel; -import 'package:beacon/models/user/user_info.dart'; -import 'package:beacon/view_model/base_view_model.dart'; +import 'package:beacon/old/components/enums/view_state.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/old/components/models/location/location.dart' + deferred as locModel; +import 'package:beacon/old/components/models/user/user_info.dart'; +import 'package:beacon/old/components/view_model/base_view_model.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:overlay_support/overlay_support.dart'; import 'package:share_plus/share_plus.dart'; @@ -227,6 +229,7 @@ class HikeScreenViewModel extends BaseModel { value = hiveDb!.beaconsBox.get(beacon!.id); beacon = value; } + log('value: ${value}'); await updateModel(value!); }); } @@ -375,6 +378,8 @@ class HikeScreenViewModel extends BaseModel { Future initialise(Beacon beaconParsed, bool? widgetIsLeader) async { beacon = hiveDb!.beaconsBox.get(beaconParsed.id); isLeader = widgetIsLeader; + beacon = beaconParsed; + await databaseFunctions!.init(); if (await connectionChecker!.checkForInternetConnection()) { await fetchData(); @@ -425,12 +430,10 @@ class HikeScreenViewModel extends BaseModel { setState(ViewState.idle); } - Future createLandmark( - var title, - var loc, - ) async { + Future createLandmark(var title, var loc, BuildContext context) async { if (landmarkFormKey.currentState!.validate()) { - navigationService!.pop(); + // navigationService!.pop(); + AutoRouter.of(context).maybePop(); await databaseFunctions!.init(); await databaseFunctions! .createLandmark(title, loc, beacon!.id) diff --git a/lib/view_model/home_screen_view_model.dart b/lib/old/components/view_model/home_screen_view_model.dart similarity index 57% rename from lib/view_model/home_screen_view_model.dart rename to lib/old/components/view_model/home_screen_view_model.dart index 8018f112..9aeff65b 100644 --- a/lib/view_model/home_screen_view_model.dart +++ b/lib/old/components/view_model/home_screen_view_model.dart @@ -1,10 +1,11 @@ -import 'package:beacon/enums/view_state.dart'; +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/old/components/enums/view_state.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/view_model/base_view_model.dart'; +import 'package:beacon/old/components/view_model/base_view_model.dart'; +import 'package:beacon/router.dart'; import 'package:flutter/material.dart'; import '../models/group/group.dart'; -import '../views/group_screen.dart'; class HomeViewModel extends BaseModel { final formKeyCreate = GlobalKey(); @@ -14,11 +15,12 @@ class HomeViewModel extends BaseModel { bool isCreatingGroup = false; String? enteredGroupCode; - createGroupRoom() async { + createGroupRoom(BuildContext context) async { FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); validate = AutovalidateMode.always; if (formKeyCreate.currentState!.validate()) { - navigationService!.pop(); + // navigationService!.pop(); + AutoRouter.of(context).maybePop(); setState(ViewState.busy); validate = AutovalidateMode.disabled; databaseFunctions!.init(); @@ -26,19 +28,21 @@ class HomeViewModel extends BaseModel { title, ); if (group != null) { - navigationService!.pushScreen('/groupScreen', - arguments: GroupScreen( - group, - )); + // navigationService!.pushScreen('/groupScreen', + // arguments: GroupScreen( + // group, + // )); + + AutoRouter.of(context).pushNamed('/group'); } } else { - navigationService!.showSnackBar('Something went wrong'); + // navigationService!.showSnackBar('Something went wrong'); setState(ViewState.idle); } } - joinGroupRoom() async { - FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); + joinGroupRoom(BuildContext context) async { + // FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); validate = AutovalidateMode.always; if (formKeyJoin.currentState!.validate()) { setState(ViewState.busy); @@ -47,26 +51,34 @@ class HomeViewModel extends BaseModel { final Group? group = await databaseFunctions!.joinGroup(enteredGroupCode); // setState(ViewState.idle); if (group != null) { - navigationService!.pushScreen('/groupScreen', - arguments: GroupScreen( - group, - )); + // navigationService!.pushScreen('/groupScreen', + // arguments: GroupScreen( + // group, + // )); + + AutoRouter.of(context).pushNamed('/group'); } else { //there was some error, go back to homescreen. setState(ViewState.idle); } //Snackbar is displayed by joinBeacon itself on any error or trying to join expired beacon. } else { - navigationService!.showSnackBar('Enter Valid Group Code'); + // navigationService!.showSnackBar('Enter Valid Group Code'); } } - logout() async { + logout(BuildContext context) async { setState(ViewState.busy); await userConfig!.currentUser!.delete(); await hiveDb!.beaconsBox.clear(); // setState(ViewState.idle); await localNotif!.deleteNotification(); - navigationService!.removeAllAndPush('/auth', '/'); + // navigationService!.removeAllAndPush('/auth', '/'); + AutoRouter.of(context).pushAndPopUntil( + AuthScreenRoute(), + predicate: (route) { + return true; + }, + ); } } diff --git a/lib/views/base_view.dart b/lib/old/components/views/base_view.dart similarity index 100% rename from lib/views/base_view.dart rename to lib/old/components/views/base_view.dart diff --git a/lib/views/workspace.code-workspace b/lib/old/components/views/workspace.code-workspace similarity index 100% rename from lib/views/workspace.code-workspace rename to lib/old/components/views/workspace.code-workspace diff --git a/lib/router.dart b/lib/router.dart index 2d9897ca..601b6171 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -1,10 +1,14 @@ -import 'package:beacon/splash_screen.dart'; -import 'package:beacon/views/home_screen.dart'; +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/Bloc/domain/entities/group/group_entity.dart'; +import 'package:beacon/Bloc/presentation/screens/splash_screen.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/Bloc/presentation/screens/home_screen.dart'; import 'package:flutter/material.dart'; -import 'package:beacon/utilities/constants.dart'; -import 'package:beacon/views/auth_screen.dart'; -import 'package:beacon/views/group_screen.dart'; -import 'package:beacon/views/hike_screen.dart'; +import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/Bloc/presentation/screens/auth_screen.dart'; +import 'package:beacon/Bloc/presentation/screens/group_screen.dart'; +import 'package:beacon/Bloc/presentation/screens/hike_screen.dart'; +part 'router.gr.dart'; Route generateRoute(RouteSettings settings) { switch (settings.name) { @@ -13,7 +17,7 @@ Route generateRoute(RouteSettings settings) { builder: (context) => const AuthScreen(key: Key('auth'))); case Routes.mainScreen: return MaterialPageRoute( - builder: (context) => const MainScreen(key: Key('MainScreen'))); + builder: (context) => HomeScreen(key: Key('MainScreen'))); case Routes.hikeScreen: HikeScreen? arguments = settings.arguments as HikeScreen?; return MaterialPageRoute( @@ -32,3 +36,18 @@ Route generateRoute(RouteSettings settings) { builder: (context) => const SplashScreen(key: Key('SplashScreen'))); } } + +@AutoRouterConfig(replaceInRouteName: 'Route') +class AppRouter extends _$AppRouter { + @override + List get routes => [ + AutoRoute(page: SplashScreenRoute.page, initial: true, path: '/'), + AutoRoute(page: AuthScreenRoute.page, path: '/auth'), + AutoRoute(page: HomeScreenRoute.page, path: '/home'), + AutoRoute( + page: HikeScreenRoute.page, + path: '/hike', + ), + AutoRoute(page: GroupScreenRoute.page, path: '/group'), + ]; +} diff --git a/lib/router.gr.dart b/lib/router.gr.dart new file mode 100644 index 00000000..bac583f4 --- /dev/null +++ b/lib/router.gr.dart @@ -0,0 +1,163 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ************************************************************************** +// AutoRouterGenerator +// ************************************************************************** + +// ignore_for_file: type=lint +// coverage:ignore-file + +part of 'router.dart'; + +abstract class _$AppRouter extends RootStackRouter { + // ignore: unused_element + _$AppRouter({super.navigatorKey}); + + @override + final Map pagesMap = { + AuthScreenRoute.name: (routeData) { + return AutoRoutePage( + routeData: routeData, + child: const AuthScreen(), + ); + }, + GroupScreenRoute.name: (routeData) { + final args = routeData.argsAs(); + return AutoRoutePage( + routeData: routeData, + child: GroupScreen(args.group), + ); + }, + HikeScreenRoute.name: (routeData) { + final args = routeData.argsAs(); + return AutoRoutePage( + routeData: routeData, + child: HikeScreen( + args.beacon, + isLeader: args.isLeader, + ), + ); + }, + HomeScreenRoute.name: (routeData) { + return AutoRoutePage( + routeData: routeData, + child: const HomeScreen(), + ); + }, + SplashScreenRoute.name: (routeData) { + return AutoRoutePage( + routeData: routeData, + child: const SplashScreen(), + ); + }, + }; +} + +/// generated route for +/// [AuthScreen] +class AuthScreenRoute extends PageRouteInfo { + const AuthScreenRoute({List? children}) + : super( + AuthScreenRoute.name, + initialChildren: children, + ); + + static const String name = 'AuthScreenRoute'; + + static const PageInfo page = PageInfo(name); +} + +/// generated route for +/// [GroupScreen] +class GroupScreenRoute extends PageRouteInfo { + GroupScreenRoute({ + required GroupEntity group, + List? children, + }) : super( + GroupScreenRoute.name, + args: GroupScreenRouteArgs(group: group), + initialChildren: children, + ); + + static const String name = 'GroupScreenRoute'; + + static const PageInfo page = + PageInfo(name); +} + +class GroupScreenRouteArgs { + const GroupScreenRouteArgs({required this.group}); + + final GroupEntity group; + + @override + String toString() { + return 'GroupScreenRouteArgs{group: $group}'; + } +} + +/// generated route for +/// [HikeScreen] +class HikeScreenRoute extends PageRouteInfo { + HikeScreenRoute({ + required Beacon? beacon, + bool? isLeader, + List? children, + }) : super( + HikeScreenRoute.name, + args: HikeScreenRouteArgs( + beacon: beacon, + isLeader: isLeader, + ), + initialChildren: children, + ); + + static const String name = 'HikeScreenRoute'; + + static const PageInfo page = + PageInfo(name); +} + +class HikeScreenRouteArgs { + const HikeScreenRouteArgs({ + required this.beacon, + this.isLeader, + }); + + final Beacon? beacon; + + final bool? isLeader; + + @override + String toString() { + return 'HikeScreenRouteArgs{beacon: $beacon, isLeader: $isLeader}'; + } +} + +/// generated route for +/// [HomeScreen] +class HomeScreenRoute extends PageRouteInfo { + const HomeScreenRoute({List? children}) + : super( + HomeScreenRoute.name, + initialChildren: children, + ); + + static const String name = 'HomeScreenRoute'; + + static const PageInfo page = PageInfo(name); +} + +/// generated route for +/// [SplashScreen] +class SplashScreenRoute extends PageRouteInfo { + const SplashScreenRoute({List? children}) + : super( + SplashScreenRoute.name, + initialChildren: children, + ); + + static const String name = 'SplashScreenRoute'; + + static const PageInfo page = PageInfo(name); +} diff --git a/lib/services/shared_preference_service.dart b/lib/services/shared_preference_service.dart deleted file mode 100644 index b6b14443..00000000 --- a/lib/services/shared_preference_service.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:shared_preferences/shared_preferences.dart'; - -class SharedPreferenceService { - late SharedPreferences _prefs; - - Future getSharedPreferencesInstance() async { - try { - _prefs = await SharedPreferences.getInstance(); - return true; - } catch (e) { - print("SharedPreferences error: $e"); - return false; - } - } - - Future setToken(String token) async { - await _prefs.setString('token', token); - } - - Future clearToken() async { - await _prefs.clear(); - } - - Future get token async => _prefs.getString('token'); -} - -SharedPreferenceService sharedPreferenceService = SharedPreferenceService(); diff --git a/lib/splash_screen.dart b/lib/splash_screen.dart deleted file mode 100644 index 6487615a..00000000 --- a/lib/splash_screen.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'dart:async'; - -import 'package:beacon/views/hike_screen.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:beacon/locator.dart'; -import 'package:uni_links/uni_links.dart'; - -import 'components/loading_screen.dart'; - -class SplashScreen extends StatefulWidget { - const SplashScreen({required Key key}) : super(key: key); - - @override - _SplashScreenState createState() => _SplashScreenState(); -} - -class _SplashScreenState extends State { - Uri? _initialUri; - Uri? _latestUri; - late StreamSubscription _sub; - bool isCheckingUrl = false; - - Future _handleInitialUri() async { - _sub = uriLinkStream.listen((Uri? uri) { - if (!mounted) return; - setState(() { - _latestUri = uri; - }); - }, onError: (Object err) { - if (!mounted) return; - setState(() { - _latestUri = null; - }); - }); - try { - final uri = await getInitialUri(); - if (!mounted) return; - setState(() => _initialUri = uri); - } on PlatformException { - if (!mounted) return; - setState(() => _initialUri = null); - } on FormatException catch (err) { - debugPrint(err.toString()); - if (!mounted) return; - setState(() => _initialUri = null); - } - await databaseFunctions!.init(); - await userConfig!.userLoggedIn().then((value) async { - if (_latestUri == null && _initialUri == null) { - if (value || hiveDb!.currentUserBox.containsKey('user')) { - navigationService!.pushReplacementScreen('/main'); - } else { - navigationService!.pushReplacementScreen('/auth'); - } - } else { - if (_initialUri != null) { - var shortcode = _initialUri!.queryParameters['shortcode']; - if (value) { - await databaseFunctions!.joinBeacon(shortcode).then((val) { - if (val != null) { - navigationService!.pushScreen('/hikeScreen', - arguments: HikeScreen(val, isLeader: false)); - } else { - navigationService!.pushReplacementScreen('/main'); - } - }); - } else { - // login in anonymously and join hike - await databaseFunctions!.signup(name: "Anonymous"); - await databaseFunctions!.joinBeacon(shortcode).then((val) async { - navigationService!.pushScreen('/hikeScreen', - arguments: HikeScreen(val, isLeader: false)); - }); - } - } - } - }); - } - - @override - void initState() { - _handleInitialUri(); - super.initState(); - } - - @override - void dispose() { - _sub.cancel(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - key: const Key('SplashScreenScaffold'), - body: LoadingScreen(), - ); - } -} diff --git a/lib/views/auth_screen.dart b/lib/views/auth_screen.dart deleted file mode 100644 index 1cac5694..00000000 --- a/lib/views/auth_screen.dart +++ /dev/null @@ -1,449 +0,0 @@ -import 'package:beacon/components/hike_button.dart'; -import 'package:beacon/components/shape_painter.dart'; -import 'package:beacon/services/validators.dart'; -import 'package:beacon/utilities/constants.dart'; -import 'package:beacon/utilities/indication_painter.dart'; -import 'package:beacon/view_model/auth_screen_model.dart'; -import 'package:beacon/views/base_view.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:sizer/sizer.dart'; - -import '../components/loading_screen.dart'; - -class AuthScreen extends StatefulWidget { - const AuthScreen({Key? key}) : super(key: key); - - @override - _AuthScreenState createState() => _AuthScreenState(); -} - -class _AuthScreenState extends State - with SingleTickerProviderStateMixin { - Future onPopHome() async { - return showDialog( - context: context, - builder: (context) => AlertDialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - // actionsAlignment: MainAxisAlignment.spaceEvenly, - contentPadding: EdgeInsets.all(25.0), - title: Text( - 'Confirm Exit', - style: TextStyle(fontSize: 25, color: kYellow), - ), - content: Text( - 'Do you really want to exit?', - style: TextStyle(fontSize: 18, color: kBlack), - ), - actions: [ - HikeButton( - buttonHeight: 2.5.h, - buttonWidth: 8.w, - onTap: () => Navigator.of(context).pop(false), - text: 'No', - ), - HikeButton( - buttonHeight: 2.5.h, - buttonWidth: 8.w, - onTap: () => - SystemChannels.platform.invokeMethod('SystemNavigator.pop'), - text: 'Yes', - ), - ], - ), - ); - } - - @override - Widget build(BuildContext context) { - Size screensize = MediaQuery.of(context).size; - return - // WillPopScope( - // onWillPop: _onPopHome ?? , - // child: - BaseView( - builder: (context, model, child) { - return (model.isBusy) - ? LoadingScreen() - : new Scaffold( - key: model.scaffoldKey, - resizeToAvoidBottomInset: true, - body: Container( - width: screensize.width, - height: - screensize.height >= 775.0 ? screensize.height : 775.0, - child: Stack( - children: [ - CustomPaint( - size: Size(screensize.width, screensize.height), - painter: ShapePainter(), - ), - Container( - alignment: Alignment.center, - padding: EdgeInsets.only(top: screensize.height / 3.5), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(top: 20.0), - child: _buildMenuBar(context, model), - ), - Expanded( - flex: 2, - child: PageView( - controller: model.pageController, - onPageChanged: (i) { - if (i == 0) { - setState(() { - model.right = Colors.black; - model.left = Colors.white; - }); - Future.delayed(Duration(milliseconds: 500), - () { - model.requestFocusForFocusNode( - model.emailLogin); - }); - } else if (i == 1) { - setState(() { - model.right = Colors.white; - model.left = Colors.black; - }); - Future.delayed(Duration(milliseconds: 500), - () { - model - .requestFocusForFocusNode(model.name); - }); - } - }, - children: [ - new ConstrainedBox( - constraints: const BoxConstraints.expand(), - child: _buildSignIn(context, model), - ), - new ConstrainedBox( - constraints: const BoxConstraints.expand(), - child: _buildSignUp(context, model), - ), - ], - ), - ), - ], - ), - ), - ], - ), - ), - ); - }, - // ), - ); - } - - Widget _buildMenuBar(BuildContext context, AuthViewModel model) { - Size screensize = MediaQuery.of(context).size; - return Container( - padding: EdgeInsets.symmetric(horizontal: 13.5.w), - width: screensize.width, - height: screensize.height < 800 ? 7.5.h : 6.h, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(25.0)), - ), - child: CustomPaint( - painter: TabIndicationPainter(pageController: model.pageController), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Expanded( - child: TextButton( - style: ButtonStyle( - overlayColor: MaterialStateProperty.all(Colors.transparent), - ), - //highlightColor: Colors.white, - onPressed: model.onSignInButtonPress, - child: Text( - "Existing", - style: TextStyle( - color: model.left, - fontSize: 18.0, - ), - ), - ), - ), - Expanded( - child: TextButton( - style: ButtonStyle( - overlayColor: MaterialStateProperty.all(Colors.transparent), - ), - onPressed: model.onSignUpButtonPress, - child: Text( - "New", - style: TextStyle( - color: model.right, - fontSize: 18.0, - ), - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildSignIn(BuildContext context, AuthViewModel model) { - Size screensize = MediaQuery.of(context).size; - return SingleChildScrollView( - child: Container( - padding: EdgeInsets.only(top: 3.h, left: 8.5.w, right: 8.5.w), - width: screensize.width, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Card( - elevation: 2.0, - color: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - child: Form( - key: model.formKeyLogin, - autovalidateMode: model.loginValidate, - child: Container( - width: screensize.width - 70, - child: Column( - children: [ - Container( - height: 13.h, - padding: EdgeInsets.symmetric( - horizontal: 10, vertical: 10.0), - child: TextFormField( - autovalidateMode: model.loginValidate, - focusNode: model.emailLogin, - controller: model.loginEmailController, - validator: (value) => - Validator.validateEmail(value!.trimRight()), - keyboardType: TextInputType.emailAddress, - style: TextStyle(fontSize: 16.0, color: Colors.black), - decoration: InputDecoration( - border: InputBorder.none, - icon: Icon( - Icons.mail_outline, - color: Colors.black, - size: 24.0, - ), - hintText: "Email Address", - hintStyle: TextStyle( - fontSize: hintsize - 2, color: hintColor), - ), - ), - ), - separator(), - Container( - height: 13.h, - padding: EdgeInsets.symmetric( - horizontal: 10, vertical: 10.0), - child: TextFormField( - autovalidateMode: model.loginValidate, - focusNode: model.passwordLogin, - controller: model.loginPasswordController, - obscureText: model.obscureTextLogin, - validator: (value) => - Validator.validatePassword(value!), - style: TextStyle(fontSize: 16.0, color: Colors.black), - decoration: InputDecoration( - border: InputBorder.none, - icon: Icon( - Icons.lock, - size: 24.0, - color: Colors.black, - ), - hintText: "Password", - hintStyle: TextStyle( - fontSize: hintsize - 2, color: hintColor), - suffixIcon: IconButton( - onPressed: () => model.displayPasswordLogin(), - icon: Icon( - model.obscureTextLogin - ? Icons.visibility - : Icons.visibility_off, - size: 20.0, - color: Colors.black, - ), - ), - ), - ), - ), - ], - ), - ), - ), - ), - SizedBox( - height: 3.5.h, - ), - HikeButton( - onTap: model.nextLogin, - text: 'LOGIN', - ), - Padding( - padding: EdgeInsets.only( - left: 15.0, right: 15.0, top: 15.0, bottom: 15.0), - child: Text( - "Or", - style: TextStyle( - color: Colors.black, - fontSize: 16.0, - ), - ), - ), - HikeButton( - onTap: () => model.loginAsGuest(), - text: 'LOGIN AS GUEST', - ), - ], - ), - ), - ); - } - - Widget _buildSignUp(BuildContext context, AuthViewModel model) { - Size screensize = MediaQuery.of(context).size; - return SingleChildScrollView( - child: Container( - padding: EdgeInsets.only(top: 3.h, left: 8.5.w, right: 8.5.w), - child: Column( - children: [ - Card( - elevation: 2.0, - color: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - child: Form( - key: model.formKeySignup, - autovalidateMode: model.signupValidate, - child: Container( - width: screensize.width - 70, - // height: 280.0, - child: Column(children: [ - Container( - height: 13.h, - padding: EdgeInsets.symmetric( - horizontal: 10, vertical: 10.0), - child: TextFormField( - autovalidateMode: model.signupValidate, - validator: (value) => Validator.validateName(value!), - focusNode: model.name, - textInputAction: TextInputAction.next, - controller: model.signupNameController, - keyboardType: TextInputType.text, - textCapitalization: TextCapitalization.words, - style: TextStyle(fontSize: 18.0, color: Colors.black), - decoration: InputDecoration( - border: InputBorder.none, - icon: Icon( - Icons.account_box, - color: Colors.black, - size: 24, - ), - hintText: "Name", - hintStyle: TextStyle( - fontSize: hintsize - 2, color: hintColor), - ), - ), - ), - separator(), - Container( - height: 13.h, - padding: EdgeInsets.symmetric( - horizontal: 10, vertical: 10.0), - child: TextFormField( - autovalidateMode: model.signupValidate, - validator: (value) => Validator.validateEmail(value!), - focusNode: model.email, - textInputAction: TextInputAction.next, - controller: model.signupEmailController, - keyboardType: TextInputType.emailAddress, - style: TextStyle(fontSize: 16.0, color: Colors.black), - decoration: InputDecoration( - border: InputBorder.none, - icon: Icon( - Icons.mail, - color: Colors.black, - size: 24, - ), - hintText: "Email Address", - hintStyle: TextStyle( - fontSize: hintsize - 2, color: hintColor), - ), - ), - ), - separator(), - Container( - height: 13.h, - padding: EdgeInsets.symmetric( - horizontal: 10, vertical: 10.0), - child: TextFormField( - autovalidateMode: model.signupValidate, - focusNode: model.password, - textInputAction: TextInputAction.done, - validator: (value) => - Validator.validatePassword(value!), - controller: model.signupPasswordController, - obscureText: model.obscureTextSignup, - style: TextStyle(fontSize: 16.0, color: Colors.black), - decoration: InputDecoration( - border: InputBorder.none, - icon: Icon( - Icons.lock, - color: Colors.black, - size: 24, - ), - suffixIcon: IconButton( - onPressed: () => model.displayPasswordSignup(), - icon: Icon( - model.obscureTextSignup - ? Icons.visibility - : Icons.visibility_off, - size: 20.0, - color: Colors.black, - ), - ), - hintText: "Password", - hintStyle: TextStyle( - fontSize: hintsize - 2, color: hintColor), - ), - ), - ), - ])), - ), - ), - SizedBox( - height: 3.5.h, - ), - Container( - // margin: EdgeInsets.only(top: 300.0), - decoration: new BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: HikeButton( - onTap: () => model.nextSignup(), - text: 'SIGN UP', - ), - ), - ], - ), - ), - ); - } - - Widget separator() { - return Container( - width: 62.w, - height: 0.2.h, - color: Colors.grey[400], - ); - } -} diff --git a/lib/views/group_screen.dart b/lib/views/group_screen.dart deleted file mode 100644 index fa0d36ec..00000000 --- a/lib/views/group_screen.dart +++ /dev/null @@ -1,417 +0,0 @@ -import 'package:beacon/components/beacon_card.dart'; -import 'package:beacon/components/create_join_dialog.dart'; -import 'package:beacon/components/hike_button.dart'; -import 'package:beacon/components/loading_screen.dart'; -import 'package:beacon/components/shape_painter.dart'; -import 'package:beacon/locator.dart'; -import 'package:beacon/models/beacon/beacon.dart'; -import 'package:beacon/utilities/constants.dart'; -import 'package:beacon/view_model/group_screen_view_model.dart'; -import 'package:beacon/views/base_view.dart'; -import 'package:flutter/material.dart'; -import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; -import 'package:sizer/sizer.dart'; -import '../models/group/group.dart'; - -class GroupScreen extends StatefulWidget { - final Group group; - GroupScreen(this.group); - - @override - _GroupScreenState createState() => _GroupScreenState(); -} - -class _GroupScreenState extends State - with TickerProviderStateMixin { - late List fetchingUserBeacons; - late List fetchingNearbyBeacons; - - @override - void initState() { - super.initState(); - } - - fetchUserBeacons() async { - return await databaseFunctions!.fetchUserBeacons(widget.group.id); - } - - fetchNearByBeacons() async { - return await databaseFunctions!.fetchNearbyBeacon(widget.group.id); - } - - reloadList() async { - fetchingUserBeacons = - await databaseFunctions!.fetchUserBeacons(widget.group.id); - fetchingNearbyBeacons = await databaseFunctions! - .fetchNearbyBeacon(widget.group.id) as List; - setState(() {}); - } - - @override - Widget build(BuildContext context) { - return BaseView(builder: (context, model, child) { - TabController tabController = new TabController(length: 2, vsync: this); - return model.isBusy - ? LoadingScreen() - : Scaffold( - resizeToAvoidBottomInset: false, - body: SafeArea( - child: ModalProgressHUD( - inAsyncCall: model.isCreatingHike, - child: Stack( - children: [ - CustomPaint( - size: Size(MediaQuery.of(context).size.width, - MediaQuery.of(context).size.height - 200), - painter: ShapePainter(), - ), - // Creating a back button - // Align( - // alignment: Alignment(-0.9, -0.8), - // child: FloatingActionButton( - // onPressed: () => navigationService.pop(), - // backgroundColor: kYellow, - // child: Icon(Icons.arrow_back_rounded), - // ), - // ), - Align( - alignment: Alignment(-0.7, -0.95), - child: Container( - width: MediaQuery.of(context).size.width * 0.6, - child: Text( - 'Welcome to Group ' + widget.group.title!, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - color: Colors.white, - ), - ), - ), - ), - Align( - alignment: Alignment(0.9, -0.8), - child: FloatingActionButton( - onPressed: () => showDialog( - context: context, - builder: (context) => AlertDialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - // actionsAlignment: - // MainAxisAlignment.spaceEvenly, - title: Text( - userConfig!.currentUser!.isGuest! - ? 'Create Account' - : 'Logout', - style: TextStyle( - fontSize: 25, color: kYellow), - ), - content: Text( - userConfig!.currentUser!.isGuest! - ? 'Would you like to create an account?' - : 'Are you sure you wanna logout?', - style: TextStyle( - fontSize: 16, color: kBlack), - ), - actions: [ - HikeButton( - buttonHeight: 2.5.h, - buttonWidth: 8.w, - onTap: () => - Navigator.of(context).pop(false), - text: 'No', - textSize: 18.0, - ), - HikeButton( - buttonHeight: 2.5.h, - buttonWidth: 8.w, - onTap: () { - navigationService!.pop(); - model.logout(); - }, - text: 'Yes', - textSize: 18.0, - ), - ], - )), - backgroundColor: kYellow, - child: userConfig!.currentUser!.isGuest! - ? Icon(Icons.person) - : Icon(Icons.logout), - ), - ), - Padding( - padding: EdgeInsets.fromLTRB(4.w, 25.h, 4.w, 5), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 45.w, - child: HikeButton( - buttonWidth: homebwidth, - buttonHeight: homebheight - 2, - text: 'Create Hike', - textColor: Colors.white, - borderColor: Colors.white, - buttonColor: kYellow, - onTap: () { - if (userConfig!.currentUser!.isGuest!) { - navigationService!.showSnackBar( - 'You need to login with credentials to start a hike'); - } else { - CreateJoinBeaconDialog.createHikeDialog( - context, - model, - reloadList, - widget.group.id); - } - }, - ), - ), - SizedBox( - width: 1.w, - ), - Container( - width: 45.w, - child: HikeButton( - buttonWidth: homebwidth, - buttonHeight: homebheight - 2, - text: 'Join a Hike', - textColor: kYellow, - borderColor: kYellow, - buttonColor: Colors.white, - onTap: () async { - CreateJoinBeaconDialog.joinBeaconDialog( - context, model, reloadList); - }, - ), - ), - ], - ), - ), - Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - height: MediaQuery.of(context).size.height * 0.565, - margin: EdgeInsets.only(top: 20), - decoration: BoxDecoration( - color: kLightBlue, - borderRadius: BorderRadius.only( - topLeft: const Radius.circular(50.0), - topRight: const Radius.circular(50.0), - ), - ), - child: Column( - children: [ - TabBar( - indicatorSize: TabBarIndicatorSize.tab, - indicatorColor: kBlue, - labelColor: kBlack, - tabs: [ - Tab(text: 'Your Beacons'), - Tab(text: 'Nearby Beacons'), - ], - controller: tabController, - ), - Expanded( - child: TabBarView( - controller: tabController, - children: [ - Padding( - padding: const EdgeInsets.all(12.0), - child: FutureBuilder( - future: fetchUserBeacons(), - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.done) { - if (snapshot.hasError) { - return Center( - child: Text( - snapshot.error.toString(), - textAlign: TextAlign.center, - textScaler: - TextScaler.linear(1.3), - ), - ); - } - final List posts = - snapshot.data - as List; - return Container( - alignment: Alignment.center, - child: posts.length == 0 - ? SingleChildScrollView( - physics: - AlwaysScrollableScrollPhysics(), - child: Column( - children: [ - Text( - 'You haven\'t joined or created any beacon yet', - textAlign: - TextAlign - .center, - style: TextStyle( - color: - kBlack, - fontSize: - 20), - ), - SizedBox( - height: 2.h, - ), - RichText( - text: TextSpan( - // textAlign: - // TextAlign - // .center, - style: TextStyle( - color: - kBlack, - fontSize: - 20), - children: [ - TextSpan( - text: - 'Join', - style: TextStyle( - fontWeight: - FontWeight.bold)), - TextSpan( - text: - ' a Hike or '), - TextSpan( - text: - 'Create', - style: TextStyle( - fontWeight: - FontWeight.bold)), - TextSpan( - text: - ' a new one! '), - ], - ), - ), - ], - ), - ) - : ListView.builder( - physics: - AlwaysScrollableScrollPhysics(), - scrollDirection: - Axis.vertical, - itemCount: - posts.length, - padding: - EdgeInsets.all(8), - itemBuilder: - (context, index) { - return BeaconCustomWidgets - .getBeaconCard( - context, - posts[ - index]!); - }, - )); - } else { - return Center( - child: BeaconCustomWidgets - .getPlaceholder(), - ); - } - }, - ), - ), - Padding( - padding: const EdgeInsets.all(12.0), - child: Container( - alignment: Alignment.center, - child: FutureBuilder( - future: fetchNearByBeacons(), - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.waiting) - return Center( - child: BeaconCustomWidgets - .getPlaceholder(), - ); - if (snapshot.connectionState == - ConnectionState.done) { - if (snapshot.hasError) { - return Center( - child: Text( - snapshot.error.toString(), - textAlign: - TextAlign.center, - textScaler: - TextScaler.linear( - 1.3), - ), - ); - } - - final posts = snapshot.data - as List; - if (posts.length == 0) { - return SingleChildScrollView( - physics: - AlwaysScrollableScrollPhysics(), - child: Center( - child: Text( - 'No nearby beacons found :(', - style: TextStyle( - color: kBlack, - fontSize: 20), - ), - ), - ); - } - return ListView.builder( - physics: - AlwaysScrollableScrollPhysics(), - scrollDirection: - Axis.vertical, - itemCount: posts.length, - padding: EdgeInsets.all(8), - itemBuilder: - (context, index) { - return BeaconCustomWidgets - .getBeaconCard(context, - posts[index]); - }, - ); - } else { - return SingleChildScrollView( - physics: - AlwaysScrollableScrollPhysics(), - child: Center( - child: Text( - 'No nearby beacons found :(', - style: TextStyle( - color: kBlack, - fontSize: 18))), - ); - } - }, - ), - ), - ), - ], - ), - ), - ], - ), - ), - ], - ), - ], - ), - ), - ), - ); - }); - } -} diff --git a/lib/views/home_screen.dart b/lib/views/home_screen.dart deleted file mode 100644 index cb10fa7b..00000000 --- a/lib/views/home_screen.dart +++ /dev/null @@ -1,340 +0,0 @@ -import 'package:beacon/components/beacon_card.dart'; -import 'package:beacon/components/create_join_dialog.dart'; -import 'package:beacon/components/hike_button.dart'; -import 'package:beacon/components/loading_screen.dart'; -import 'package:beacon/components/shape_painter.dart'; -import 'package:beacon/locator.dart'; -import 'package:beacon/models/group/group.dart'; -import 'package:beacon/utilities/constants.dart'; -import 'package:beacon/views/base_view.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; -// import 'package:modal_progress_hud/modal_progress_hud.dart'; -import 'package:sizer/sizer.dart'; - -import '../components/group_card.dart'; -import '../view_model/home_screen_view_model.dart'; - -class MainScreen extends StatefulWidget { - const MainScreen({Key? key}) : super(key: key); - @override - _MainScreenState createState() => _MainScreenState(); -} - -class _MainScreenState extends State with TickerProviderStateMixin { - var fetchingUserGroups; - Future _onPopHome() async { - return showDialog( - context: context, - builder: (context) => AlertDialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - // actionsAlignment: MainAxisAlignment.spaceEvenly, - contentPadding: EdgeInsets.all(25.0), - title: Text( - 'Confirm Exit', - style: TextStyle(fontSize: 25, color: kYellow), - ), - content: Text( - 'Do you really want to exit?', - style: TextStyle(fontSize: 18, color: kBlack), - ), - actions: [ - HikeButton( - buttonHeight: 2.5.h, - buttonWidth: 8.w, - onTap: () => Navigator.of(context).pop(false), - text: 'No', - ), - HikeButton( - buttonHeight: 2.5.h, - buttonWidth: 8.w, - onTap: () => - SystemChannels.platform.invokeMethod('SystemNavigator.pop'), - text: 'Yes', - ), - ], - ), - ); - } - - @override - void initState() { - fetchingUserGroups = databaseFunctions!.fetchUserGroups(); - super.initState(); - } - - void reloadList() { - setState(() { - fetchingUserGroups = databaseFunctions!.fetchUserGroups(); - }); - } - - @override - Widget build(BuildContext context) { - return PopScope(onPopInvoked: (didPop) { - _onPopHome(); - }, child: BaseView(builder: (context, model, child) { - TabController tabController = new TabController(length: 1, vsync: this); - return model.isBusy - ? LoadingScreen() - : Scaffold( - resizeToAvoidBottomInset: false, - body: SafeArea( - child: ModalProgressHUD( - inAsyncCall: model.isCreatingGroup, - child: Stack( - children: [ - CustomPaint( - size: Size(MediaQuery.of(context).size.width, - MediaQuery.of(context).size.height - 200), - painter: ShapePainter(), - ), - Align( - alignment: Alignment(0.9, -0.8), - child: FloatingActionButton( - onPressed: () => showDialog( - context: context, - builder: (context) => AlertDialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - // actionsAlignment: - // MainAxisAlignment.spaceEvenly, - title: Text( - userConfig!.currentUser!.isGuest! - ? 'Create Account' - : 'Logout', - style: TextStyle( - fontSize: 25, color: kYellow), - ), - content: Text( - userConfig!.currentUser!.isGuest! - ? 'Would you like to create an account?' - : 'Are you sure you wanna logout?', - style: TextStyle( - fontSize: 16, color: kBlack), - ), - actions: [ - HikeButton( - buttonHeight: 2.5.h, - buttonWidth: 8.w, - onTap: () => - Navigator.of(context).pop(false), - text: 'No', - textSize: 18.0, - ), - HikeButton( - buttonHeight: 2.5.h, - buttonWidth: 8.w, - onTap: () { - navigationService!.pop(); - model.logout(); - }, - text: 'Yes', - textSize: 18.0, - ), - ], - )), - backgroundColor: kYellow, - child: userConfig!.currentUser!.isGuest! - ? Icon(Icons.person) - : Icon(Icons.logout), - ), - ), - Padding( - padding: EdgeInsets.fromLTRB(4.w, 25.h, 4.w, 5), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 45.w, - child: HikeButton( - buttonWidth: homebwidth - 10, - buttonHeight: homebheight - 2, - text: 'Create Group', - textColor: Colors.white, - borderColor: Colors.white, - buttonColor: kYellow, - onTap: () { - if (userConfig!.currentUser!.isGuest!) { - navigationService!.showSnackBar( - 'You need to login with credentials to be able to create a group'); - } else { - CreateJoinGroupDialog.createGroupDialog( - context, model); - } - }, - ), - ), - SizedBox( - width: 1.w, - ), - Container( - width: 45.w, - child: HikeButton( - buttonWidth: homebwidth, - buttonHeight: homebheight - 2, - text: 'Join a Group', - textColor: kYellow, - borderColor: kYellow, - buttonColor: Colors.white, - onTap: () async { - CreateJoinGroupDialog.joinGroupDialog( - context, model); - }, - ), - ), - ], - ), - ), - Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - height: MediaQuery.of(context).size.height * 0.565, - margin: EdgeInsets.only(top: 20), - decoration: BoxDecoration( - color: kLightBlue, - borderRadius: BorderRadius.only( - topLeft: const Radius.circular(50.0), - topRight: const Radius.circular(50.0))), - child: Column( - children: [ - TabBar( - indicatorSize: TabBarIndicatorSize.tab, - indicatorColor: kBlue, - labelColor: kBlack, - tabs: [ - Tab(text: 'Your Groups'), - ], - controller: tabController, - ), - Expanded( - child: TabBarView( - controller: tabController, - children: [ - Padding( - padding: const EdgeInsets.all(12.0), - child: FutureBuilder( - future: fetchingUserGroups, - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.done) { - if (snapshot.hasError) { - return Center( - child: Text( - snapshot.error.toString(), - textAlign: TextAlign.center, - textScaler: - TextScaler.linear(1.3), - ), - ); - } - final List posts = - snapshot.data as List; - return Container( - alignment: Alignment.center, - child: posts.length == 0 - ? SingleChildScrollView( - physics: - AlwaysScrollableScrollPhysics(), - child: Column( - children: [ - Text( - 'You haven\'t joined or created any group yet', - textAlign: - TextAlign - .center, - style: TextStyle( - color: - kBlack, - fontSize: - 20), - ), - SizedBox( - height: 2.h, - ), - RichText( - text: TextSpan( - // textAlign: - // TextAlign - // .center, - style: TextStyle( - color: - kBlack, - fontSize: - 20), - children: [ - TextSpan( - text: - 'Join', - style: TextStyle( - fontWeight: - FontWeight.bold)), - TextSpan( - text: - ' a Group or '), - TextSpan( - text: - 'Create', - style: TextStyle( - fontWeight: - FontWeight.bold)), - TextSpan( - text: - ' a new one! '), - ], - ), - ), - ], - ), - ) - : ListView.builder( - physics: - AlwaysScrollableScrollPhysics(), - scrollDirection: - Axis.vertical, - itemCount: - posts.length, - padding: - EdgeInsets.all(8), - itemBuilder: - (context, index) { - return GroupCustomWidgets - .getGroupCard( - context, - posts[ - index]); - }, - )); - } else { - return Center( - child: BeaconCustomWidgets - .getPlaceholder(), - ); - } - }, - ), - ), - ], - ), - ), - ], - ), - ), - ], - ), - ], - ), - ), - ), - ); - })); - } -} diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 02c0949f..7e4f3ece 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -63,10 +63,10 @@ SPEC CHECKSUMS: geolocator_apple: 72a78ae3f3e4ec0db62117bd93e34523f5011d58 location: 7cdb0665bd6577d382b0a343acdadbcb7f964775 modal_progress_hud_nsn: 8099d46c2cf9de7af8fe0a3f8f5d2aa32cf956c3 - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 share_plus: 76dd39142738f7a68dd57b05093b5e8193f220f7 - shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 + shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 4e2a377b..36528b75 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -259,7 +259,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 331C80D4294CF70F00263BE5 = { diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 23349ce4..6099c631 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ =3.2.3 <4.0.0" - flutter: ">=3.16.0" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index a0aac600..9844c928 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: flutter_polyline_points: ^1.0.0 flutter_spinkit: ^5.2.0 fluttertoast: ^8.2.4 - geolocator: ^10.1.0 + geolocator: any get_it: ^7.6.4 google_maps_flutter: ^2.5.3 graphql_flutter: ^5.1.0 @@ -42,13 +42,31 @@ dependencies: sliding_up_panel: ^2.0.0+1 uni_links: ^0.5.1 data_connection_checker_nulls: ^0.0.2 - flutter_geocoder_alternative: + flutter_geocoder_alternative: any + + # for routing + auto_route: ^8.1.1 + + + # for state management + bloc: ^8.1.4 + flutter_bloc: ^8.1.5 + freezed_annotation: ^2.4.1 + json_annotation: ^4.9.0 + dev: ^1.0.0 + json_serializable: ^6.8.0 + + + + + dev_dependencies: build_runner: ^2.1.2 flutter_launcher_icons: ^0.9.3 flutter_test: sdk: flutter + freezed: ^2.5.2 hive_generator: test: ^1.16.5 diff --git a/test/model_tests/beacon_test.dart b/test/model_tests/beacon_test.dart index 52339850..d459740c 100644 --- a/test/model_tests/beacon_test.dart +++ b/test/model_tests/beacon_test.dart @@ -1,4 +1,4 @@ -import 'package:beacon/models/beacon/beacon.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; import 'package:test/test.dart'; void main() { diff --git a/test/model_tests/user_test.dart b/test/model_tests/user_test.dart index 52612090..40fbfa7f 100644 --- a/test/model_tests/user_test.dart +++ b/test/model_tests/user_test.dart @@ -1,5 +1,5 @@ -import 'package:beacon/models/beacon/beacon.dart'; -import 'package:beacon/models/user/user_info.dart'; +import 'package:beacon/old/components/models/beacon/beacon.dart'; +import 'package:beacon/old/components/models/user/user_info.dart'; import 'package:test/test.dart'; void main() {