diff --git a/README.md b/README.md index a0e6a47a..a0896297 100755 --- a/README.md +++ b/README.md @@ -41,31 +41,46 @@ samples, guidance on mobile development, and a full API reference. ## Project Structure -This project follows MVVM architecture with following structure: +This project follows Clean architecture with following structure: ```bash -beacon/lib/ -├── components/ # Shared Components such as dialog boxes, button, and other shared widgets -├── enums/ # enum files -| └── view_state.dart # defines view states i.e Idle, Busy, Error -├── models/ # model classes: group, beacon, location, landmark, user -├── queries/ # includes all graphql query strings -├── services/ # services -| ├── database_mutation_function.dart/ # Graphql Queries implementations -| ├── navigation_service.dart/ # All required navigation services -| └── ... # all config files -├── utilities/ # Utilities that includes constants file -├── views/ # Views/UI layer -| ├── auth_screen.dart -| ├── base_view.dart -| ├── hike_screen.dart -| ├── group_screen.dart -| ├── home.dart -├── viewmodels/ # Viewmodels layer -├── splash_screen.dart # Very first screen displayed whilst data is loading -├── router.dart # All routes to ease navigation -├── locator.dart # dependency injection using get_it -├── main.dart # <3 of the app +beacon/ +├── lib/ +│ ├── config/ # Configuration files +│ ├── core/ # Core application logic +│ ├── data/ +│ │ ├── datasources/ +│ │ │ ├── local/ # Local data sources +│ │ │ └── remote/ # Remote data sources +│ │ ├── models/ # Data models +│ │ └── repositories/ # Data repositories +│ ├── domain/ +│ │ ├── entities/ # Domain entities +│ │ ├── repositories/ # Domain repositories +│ │ └── usecases/ # Domain use cases +│ ├── presentation/ +│ │ ├── auth/ +│ │ │ ├── cubit/ # Authentication Cubit +│ │ │ ├── widget/ # Authentication widgets +│ │ │ └── screen/ # Authentication screens +│ │ ├── home/ +│ │ │ ├── cubit/ # Home Cubit +│ │ │ ├── widget/ # Home widgets +│ │ │ └── screen/ # Home screens +│ │ ├── group/ +│ │ │ ├── cubit/ # Group Cubit +│ │ │ ├── widget/ # Group widgets +│ │ │ └── screen/ # Group screens +│ │ ├── hike/ +│ │ │ ├── cubit/ # Hike Cubit +│ │ │ ├── widget/ # Hike widgets +│ │ │ └── screen/ # Hike screens +│ │ ├── widgets/ # Shared widgets used across all presentation folders +│ │ └── splash_screen.dart # Initial screen displayed while loading +├── main.dart # App entry point +├── theme/ # Theme configurations +├── locator.dart # Dependency injection setup (using get_it) +├── router.dart # App navigation routes ``` ## Screenshots @@ -84,4 +99,4 @@ If you found any bugs, consider opening an [issue](https://github.com/CCExtracto We would love to hear from you! You may join gsoc-beacon channel of CCExtractor community through slack: -[![Slack](https://img.shields.io/badge/chat-on_slack-purple.svg?style=for-the-badge&logo=slack)](https://ccextractor.org/public/general/support/) +[![Slack](https://img.shields.io/badge/chat-on_slack-purple.svg?style=for-the-badge&logo=slack)](https://ccextractor.org/public/general/support/) \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 9572626d..e1d57237 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: project(':flutter_config').projectDir.getPath() + "/dotenv.gradle" android { - compileSdkVersion 33 + compileSdkVersion 34 buildToolsVersion '29.0.0' sourceSets { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4bf22ad4..b12a9c13 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,42 +1,42 @@ + + - + + - - + + + @@ -45,8 +45,7 @@ - + diff --git a/android/app/src/main/kotlin/com/example/beacon/MainActivity.kt b/android/app/src/main/kotlin/com/example/beacon/MainActivity.kt index 7e21f388..8e2e4b9a 100644 --- a/android/app/src/main/kotlin/com/example/beacon/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/beacon/MainActivity.kt @@ -1,6 +1,51 @@ package com.example.beacon +import android.app.PictureInPictureParams +import android.os.Build +import android.util.Rational import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.MethodChannel -class MainActivity: FlutterActivity() { +class MainActivity : FlutterActivity() { + private val CHANNEL = "com.example.beacon/pip" + private var shouldEnterPipMode = false + + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { + super.configureFlutterEngine(flutterEngine) + MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> + when (call.method) { + "switchPIPMode"->{ + shouldEnterPipMode = true + result.success(null) + } + "enablePIPMode" -> { + shouldEnterPipMode = true + result.success(null) + } + "disablePIPMode" -> { + shouldEnterPipMode = false + result.success(null) + } + else -> result.notImplemented() + } + } + } + + override fun onUserLeaveHint() { + super.onUserLeaveHint() + if (shouldEnterPipMode) { + enterPIPMode() + } + } + + private fun enterPIPMode() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val aspectRatio = Rational(16, 9) + val pipParams = PictureInPictureParams.Builder() + .setAspectRatio(aspectRatio) + .build() + enterPictureInPictureMode(pipParams) + } + } } diff --git a/images/filter_icon.png b/images/filter_icon.png new file mode 100644 index 00000000..c0d1b31f Binary files /dev/null and b/images/filter_icon.png differ diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9625e105..7c569640 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/ios/Podfile b/ios/Podfile index 88359b22..279576f3 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '11.0' +# platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f59742c4..d5fe87e7 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -88,22 +88,22 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_config: f48f0d47a284f1791aacce2687eabb3309ba7a41 - flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 + flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086 fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265 geolocator_apple: 9157311f654584b9bb72686c55fc02a97b73f461 - google_maps_flutter_ios: 590249c67f34f422122c232f2a626192adbc78ee + google_maps_flutter_ios: d1318b4ff711612cab16862d7a87e31a7403d458 GoogleMaps: 025272d5876d3b32604e5c080dc25eaf68764693 - location: 3a2eed4dd2fab25e7b7baf2a9efefe82b512d740 + location: d5cf8598915965547c3f36761ae9cc4f4e87d22e modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5 - shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 + shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 uni_links: d97da20c7701486ba192624d99bffaaffcfc298a -PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 +PODFILE CHECKSUM: c4c93c5f6502fe2754f48404d3594bf779584011 -COCOAPODS: 1.14.2 +COCOAPODS: 1.15.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 5edd6cee..b4a0eff2 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -157,7 +157,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -361,7 +361,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -438,7 +438,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -487,7 +487,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index b52b2e69..e67b2808 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ token); - - static WebSocketLink websocketLink = - WebSocketLink(EnvironmentConfig.websocketEndpoint!, - config: SocketClientConfig( - autoReconnect: true, - initialPayload: { - "Authorization": '${userConfig!.currentUser!.authToken}' - }, - )); - - Future getToken() async { - await localApi.init(); - final user = await localApi.fetchUser(); - if (user != null) { - token = user.authToken; - } - return true; - } - - GraphQLClient clientToQuery() { - return GraphQLClient( - cache: GraphQLCache(partialDataPolicy: PartialDataCachePolicy.accept), - link: httpLink, - ); - } - - Future authClient() async { - await getToken(); - final AuthLink authLink = AuthLink(getToken: () async => '$token'); - final Link finalAuthLink = authLink.concat(httpLink); - return GraphQLClient( - cache: GraphQLCache(partialDataPolicy: PartialDataCachePolicy.accept), - link: finalAuthLink, - ); - } - - GraphQLClient graphQlClient() { - return GraphQLClient( - cache: GraphQLCache(partialDataPolicy: PartialDataCachePolicy.accept), - link: Link.split( - (request) => request.isSubscription, - websocketLink, - authLink.concat(httpLink), - ), - ); - } -} diff --git a/lib/Bloc/config/user_config.dart b/lib/Bloc/config/user_config.dart deleted file mode 100644 index c0e88e30..00000000 --- a/lib/Bloc/config/user_config.dart +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 0e72c7cc..00000000 --- a/lib/Bloc/core/constants/location.dart +++ /dev/null @@ -1,30 +0,0 @@ -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/Bloc/core/services/size_config.dart b/lib/Bloc/core/services/size_config.dart deleted file mode 100644 index 0dd0d64d..00000000 --- a/lib/Bloc/core/services/size_config.dart +++ /dev/null @@ -1,32 +0,0 @@ -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 deleted file mode 100644 index 2d8b44d1..00000000 --- a/lib/Bloc/core/usercase/usecase.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class UseCase { - Future call(Paramas paramas); -} diff --git a/lib/Bloc/core/utils/validators.dart b/lib/Bloc/core/utils/validators.dart deleted file mode 100644 index febbefc9..00000000 --- a/lib/Bloc/core/utils/validators.dart +++ /dev/null @@ -1,77 +0,0 @@ -class Validator { - static String? validateName(String? name) { - if (name != null && name.isEmpty) { - return "Name must not be left blank"; - } - return null; - } - - static String? validateEmail(String? email) { - // If email is empty return. - 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 (email != null && !regex.hasMatch(email)) { - return 'Please enter a valid Email Address'; - } - return null; - } - - static String? validatePassword(String? password) { - // If password is empty return. - if (password != null && password.isEmpty) { - return "Password must not be left blank"; - } - // const String pattern = r'^(?=.*?[0-9])(?=.*?[!@#\$&*%^~.]).{8,}$'; - // final RegExp regExp = RegExp(pattern); - - //Regex for no spaces allowed - const String noSpaces = r'^\S+$'; - final RegExp noSpaceRegex = RegExp(noSpaces); - - if (password!.length < 8) { - return "Must be of atleast 8 characters"; - } - // if (!regExp.hasMatch(password)) { - // return "At least 1 number and symbol required"; - // } - if (!noSpaceRegex.hasMatch(password)) { - return "Password must not contain spaces"; - } - return null; - } - - 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 != 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) { - return "Invalid passkey"; - } - return null; - } - - 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) { - print(startTime); - return null; - } -} diff --git a/lib/Bloc/data/datasource/remote/remote_auth_api.dart b/lib/Bloc/data/datasource/remote/remote_auth_api.dart deleted file mode 100644 index d40bcb3a..00000000 --- a/lib/Bloc/data/datasource/remote/remote_auth_api.dart +++ /dev/null @@ -1,137 +0,0 @@ -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 deleted file mode 100644 index 7203aae7..00000000 --- a/lib/Bloc/data/datasource/remote/remote_group_api.dart +++ /dev/null @@ -1,130 +0,0 @@ -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_hike_api.dart b/lib/Bloc/data/datasource/remote/remote_hike_api.dart deleted file mode 100644 index 190346d9..00000000 --- a/lib/Bloc/data/datasource/remote/remote_hike_api.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'dart:developer'; - -import 'package:beacon/Bloc/core/queries/beacon.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/location/location_model.dart'; -import 'package:beacon/locator.dart'; -import 'package:graphql_flutter/graphql_flutter.dart'; - -class RemoteHikeApi { - final GraphQLClient authClient; - - RemoteHikeApi(this.authClient); - - final beaconQueries = BeaconQueries(); - - Future> fetchBeaconDetails(String? beaconId) async { - bool isConnected = await utils.checkInternetConnectivity(); - if (!isConnected) {} - - final result = await authClient.mutate(MutationOptions( - document: gql(beaconQueries.fetchBeaconDetail(beaconId)))); - - if (result.isConcrete && result.data != null) { - final beaconJson = result.data!['beacon']; - - final beacon = BeaconModel.fromJson(beaconJson); - return DataSuccess(beacon); - } - return DataFailed(encounteredExceptionOrError(result.exception!)); - } - - Future> updateBeaconLocation( - String? beaconId, String lat, String lon) async { - bool isConnected = await utils.checkInternetConnectivity(); - if (!isConnected) {} - - final result = await authClient.mutate(MutationOptions( - document: gql(beaconQueries.updateBeaconLocation(beaconId, lat, lon)))); - - log(result.toString()); - - if (result.isConcrete && result.data != null) { - final beaconJson = result.data!['updateBeaconLocation']; - - final location = LocationModel.fromJson(beaconJson); - return DataSuccess(location); - } - return DataFailed(encounteredExceptionOrError(result.exception!)); - } - - Stream> beaconLocationSubscription( - String? beaconId) async* { - bool isConnected = await utils.checkInternetConnectivity(); - if (!isConnected) { - yield DataFailed("No internet connection"); - return; - } - - try { - final subscriptionOptions = SubscriptionOptions( - document: beaconQueries.beaconLocationSubGql, - variables: { - 'id': beaconId, - }, - ); - - final authClient = await graphqlConfig.authClient(); - - final resultStream = authClient.subscribe(subscriptionOptions); - - await for (final result in resultStream) { - log('subscription: ${result.toString()}'); - if (result.isConcrete && - result.data != null && - result.data!['beaconLocation'] != null) { - final locationJson = result.data!['beaconLocation']; - final location = LocationModel.fromJson(locationJson); - yield DataSuccess(location); - } else if (result.hasException) { - yield DataFailed(encounteredExceptionOrError(result.exception!)); - } - } - } catch (e) { - log('subscription error: $e'); - yield DataFailed('subscription error: $e'); - } - } - - 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 deleted file mode 100644 index 06fba351..00000000 --- a/lib/Bloc/data/datasource/remote/remote_home_api.dart +++ /dev/null @@ -1,123 +0,0 @@ -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 deleted file mode 100644 index 24afdb3e..00000000 --- a/lib/Bloc/data/models/beacon/beacon_model.dart +++ /dev/null @@ -1,86 +0,0 @@ -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/landmark/landmark_model.dart b/lib/Bloc/data/models/landmark/landmark_model.dart deleted file mode 100644 index 779c3c29..00000000 --- a/lib/Bloc/data/models/landmark/landmark_model.dart +++ /dev/null @@ -1,36 +0,0 @@ -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/repositories/auth_repository_implementation.dart b/lib/Bloc/data/repositories/auth_repository_implementation.dart deleted file mode 100644 index 3ed41e6e..00000000 --- a/lib/Bloc/data/repositories/auth_repository_implementation.dart +++ /dev/null @@ -1,26 +0,0 @@ -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 deleted file mode 100644 index 94ada788..00000000 --- a/lib/Bloc/data/repositories/group_repository_implementation.dart +++ /dev/null @@ -1,26 +0,0 @@ -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/hike_repository_implementation.dart b/lib/Bloc/data/repositories/hike_repository_implementation.dart deleted file mode 100644 index c649cd11..00000000 --- a/lib/Bloc/data/repositories/hike_repository_implementation.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:beacon/Bloc/core/resources/data_state.dart'; -import 'package:beacon/Bloc/data/datasource/remote/remote_hike_api.dart'; -import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; -import 'package:beacon/Bloc/domain/entities/location/location_entity.dart'; -import 'package:beacon/Bloc/domain/repositories/hike_repository.dart'; -import 'package:geolocator/geolocator.dart'; - -class HikeRepositoryImplementatioin extends HikeRepository { - final RemoteHikeApi remoteHikeApi; - - HikeRepositoryImplementatioin({required this.remoteHikeApi}); - - @override - Stream> beaconLocationSubscription( - String? beaconId) { - return remoteHikeApi.beaconLocationSubscription(beaconId); - } - - @override - Future> fetchBeaconDetails(String? beaconId) { - return remoteHikeApi.fetchBeaconDetails(beaconId); - } - - @override - Future> updateBeaconLocation( - String? beaconId, Position position) { - return remoteHikeApi.updateBeaconLocation( - beaconId, position.latitude.toString(), position.longitude.toString()); - } -} diff --git a/lib/Bloc/data/repositories/home_repository_implementation.dart b/lib/Bloc/data/repositories/home_repository_implementation.dart deleted file mode 100644 index c63b036b..00000000 --- a/lib/Bloc/data/repositories/home_repository_implementation.dart +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index 2f1ce48c..00000000 --- a/lib/Bloc/domain/entities/beacon/beacon_entity.dart +++ /dev/null @@ -1,23 +0,0 @@ -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/group/group_entity.dart b/lib/Bloc/domain/entities/group/group_entity.dart deleted file mode 100644 index d036619f..00000000 --- a/lib/Bloc/domain/entities/group/group_entity.dart +++ /dev/null @@ -1,17 +0,0 @@ -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/landmark/landmark_entity.dart b/lib/Bloc/domain/entities/landmark/landmark_entity.dart deleted file mode 100644 index 883699ec..00000000 --- a/lib/Bloc/domain/entities/landmark/landmark_entity.dart +++ /dev/null @@ -1,9 +0,0 @@ -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/location/location_entity.dart b/lib/Bloc/domain/entities/location/location_entity.dart deleted file mode 100644 index 6f7448a9..00000000 --- a/lib/Bloc/domain/entities/location/location_entity.dart +++ /dev/null @@ -1,7 +0,0 @@ -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/user/user_entity.dart b/lib/Bloc/domain/entities/user/user_entity.dart deleted file mode 100644 index d82447f4..00000000 --- a/lib/Bloc/domain/entities/user/user_entity.dart +++ /dev/null @@ -1,19 +0,0 @@ -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/repositories/group_repository.dart b/lib/Bloc/domain/repositories/group_repository.dart deleted file mode 100644 index 36bb561a..00000000 --- a/lib/Bloc/domain/repositories/group_repository.dart +++ /dev/null @@ -1,12 +0,0 @@ -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/hike_repository.dart b/lib/Bloc/domain/repositories/hike_repository.dart deleted file mode 100644 index 4d8e17aa..00000000 --- a/lib/Bloc/domain/repositories/hike_repository.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:beacon/Bloc/core/resources/data_state.dart'; -import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; -import 'package:beacon/Bloc/domain/entities/location/location_entity.dart'; -import 'package:geolocator/geolocator.dart'; - -abstract class HikeRepository { - Future> updateBeaconLocation( - String? beaconId, Position position); - Future> fetchBeaconDetails(String? beaconId); - Stream> beaconLocationSubscription( - String? beaconId); -} diff --git a/lib/Bloc/domain/repositories/home_repository.dart b/lib/Bloc/domain/repositories/home_repository.dart deleted file mode 100644 index 23a7dff5..00000000 --- a/lib/Bloc/domain/repositories/home_repository.dart +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 3ce63073..00000000 --- a/lib/Bloc/domain/usecase/auth_usecase.dart +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index 6122caee..00000000 --- a/lib/Bloc/domain/usecase/group_usecase.dart +++ /dev/null @@ -1,23 +0,0 @@ -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/hike_usecase.dart b/lib/Bloc/domain/usecase/hike_usecase.dart deleted file mode 100644 index 66e1e3d1..00000000 --- a/lib/Bloc/domain/usecase/hike_usecase.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:beacon/Bloc/core/resources/data_state.dart'; -import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; -import 'package:beacon/Bloc/domain/entities/location/location_entity.dart'; -import 'package:beacon/Bloc/domain/repositories/hike_repository.dart'; -import 'package:geolocator/geolocator.dart'; - -class HikeUseCase { - final HikeRepository hikeRepository; - - HikeUseCase({required this.hikeRepository}); - - Future> updateBeaconLocation( - String beaconId, Position position) { - return hikeRepository.updateBeaconLocation(beaconId, position); - } - - Future> fetchBeaconDetails(String beaconId) { - return hikeRepository.fetchBeaconDetails(beaconId); - } - - Stream> beaconLocationSubscription( - String beaconId) { - return hikeRepository.beaconLocationSubscription(beaconId); - } -} diff --git a/lib/Bloc/domain/usecase/home_usecase.dart b/lib/Bloc/domain/usecase/home_usecase.dart deleted file mode 100644 index 995f7818..00000000 --- a/lib/Bloc/domain/usecase/home_usecase.dart +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 0daf56fb..00000000 --- a/lib/Bloc/presentation/cubit/auth_cubit.dart +++ /dev/null @@ -1,84 +0,0 @@ -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 deleted file mode 100644 index 34c8a941..00000000 --- a/lib/Bloc/presentation/cubit/group_cubit.dart +++ /dev/null @@ -1,106 +0,0 @@ -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/hike_cubit.dart b/lib/Bloc/presentation/cubit/hike_cubit.dart deleted file mode 100644 index 74969b23..00000000 --- a/lib/Bloc/presentation/cubit/hike_cubit.dart +++ /dev/null @@ -1,85 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; -import 'package:beacon/Bloc/core/resources/data_state.dart'; -import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; -import 'package:beacon/Bloc/domain/entities/location/location_entity.dart'; -import 'package:beacon/Bloc/domain/usecase/hike_usecase.dart'; -import 'package:beacon/locator.dart'; -import 'package:bloc/bloc.dart'; -import 'package:flutter/material.dart'; -import 'package:geolocator/geolocator.dart'; - -abstract class HikeState { - final LocationEntity? location; - final String? error; - - HikeState({this.location, this.error}); -} - -class InitialHikeState extends HikeState {} - -class BeaconLocationLoaded extends HikeState { - final LocationEntity location; - BeaconLocationLoaded({required this.location}); -} - -class BeaconLocationError extends HikeState { - final String message; - BeaconLocationError({required this.message}); -} - -class HikeCubit extends Cubit { - final HikeUseCase hikeUsecase; - HikeCubit({required this.hikeUsecase}) : super(InitialHikeState()); - - StreamSubscription>? _locationSubscription; - - Future> fetchBeaconDetails(String beaconId) async { - DataState state = - await hikeUsecase.fetchBeaconDetails(beaconId); - - if (state is DataSuccess) { - return DataSuccess(state.data!); - } - return DataFailed(state.error!); - } - - void beaconLocationSubscription(String beaconId) { - _locationSubscription?.cancel(); - _locationSubscription = - hikeUsecase.beaconLocationSubscription(beaconId).listen((dataState) { - if (dataState is DataSuccess) { - log(dataState.data!.toString()); - emit(BeaconLocationLoaded(location: dataState.data!)); - } else if (dataState is DataFailed) { - log(dataState.error.toString()); - emit(BeaconLocationError(message: dataState.error!)); - } - }); - } - - StreamSubscription? _positionStream; - Position? position; - - updateBeaconLocation(String beaconId, BuildContext context) async { - _positionStream?.cancel(); - _positionStream = await Geolocator.getPositionStream( - locationSettings: LocationSettings( - accuracy: LocationAccuracy.high, - distanceFilter: 10, - )).listen((newPosition) async { - position = newPosition; - utils.showSnackBar( - 'Updating location! ${newPosition.latitude} ${newPosition.longitude}', - context); - await hikeUsecase.updateBeaconLocation(beaconId, newPosition); - }); - } - - @override - Future close() { - _locationSubscription?.cancel(); - _positionStream?.cancel(); - return super.close(); - } -} diff --git a/lib/Bloc/presentation/cubit/home_cubit.dart b/lib/Bloc/presentation/cubit/home_cubit.dart deleted file mode 100644 index 9202258b..00000000 --- a/lib/Bloc/presentation/cubit/home_cubit.dart +++ /dev/null @@ -1,102 +0,0 @@ -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/group_screen.dart b/lib/Bloc/presentation/screens/group_screen.dart deleted file mode 100644 index d50053c6..00000000 --- a/lib/Bloc/presentation/screens/group_screen.dart +++ /dev/null @@ -1,379 +0,0 @@ -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/Bloc/presentation/screens/hike_screen.dart b/lib/Bloc/presentation/screens/hike_screen.dart deleted file mode 100644 index 66f96324..00000000 --- a/lib/Bloc/presentation/screens/hike_screen.dart +++ /dev/null @@ -1,329 +0,0 @@ -import 'dart:developer'; - -import 'package:auto_route/auto_route.dart'; -import 'package:beacon/Bloc/core/constants/location.dart'; -import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; -import 'package:beacon/Bloc/domain/usecase/hike_usecase.dart'; -import 'package:beacon/Bloc/presentation/cubit/hike_cubit.dart'; -import 'package:beacon/old/components/loading_screen.dart'; -import 'package:beacon/locator.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:flutter_bloc/flutter_bloc.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:intl/intl.dart'; - -import 'package:beacon/old/components/hike_screen_widget.dart'; -import 'package:beacon/old/components/models/beacon/beacon.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; -// HikeScreen(this.beacon, {this.isLeader}); -// @override -// _HikeScreenState createState() => _HikeScreenState(); -// } - -// class _HikeScreenState extends State { -// late double screenHeight, screenWidth; -// @override -// Widget build(BuildContext context) { -// screenHeight = MediaQuery.of(context).size.height; -// screenWidth = MediaQuery.of(context).size.width; -// return BaseView( -// onModelReady: (m) { -// m.initialise(widget.beacon!, widget.isLeader); -// }, -// builder: (ctx, model, child) { -// if (!model.modelIsReady) { -// return Scaffold( -// body: Center( -// child: LoadingScreen(), -// ), -// ); -// } -// // ignore: deprecated_member_use -// return WillPopScope( -// onWillPop: () => model.onWillPop(context), -// child: Scaffold( -// body: SafeArea( -// child: ModalProgressHUD( -// inAsyncCall: model.isGeneratingLink || model.isBusy, -// child: SlidingUpPanel( -// maxHeight: 60.h, -// minHeight: 20.h, -// borderRadius: BorderRadius.only( -// topRight: Radius.circular(10), -// topLeft: Radius.circular(10), -// ), -// controller: model.panelController, -// collapsed: Container( -// decoration: BoxDecoration( -// color: kBlue, -// borderRadius: BorderRadius.only( -// topRight: Radius.circular(10), -// topLeft: Radius.circular(10), -// ), -// ), -// child: Column( -// children: [ -// SizedBox( -// height: 1.5.h, -// ), -// Row( -// mainAxisAlignment: MainAxisAlignment.center, -// children: [ -// Container( -// width: 65, -// height: 5, -// decoration: BoxDecoration( -// color: Colors.grey[300], -// borderRadius: BorderRadius.all( -// Radius.circular(12.0), -// ), -// ), -// ), -// ], -// ), -// SizedBox( -// height: 1.5.h, -// ), -// Container( -// width: double.infinity, -// child: Padding( -// padding: const EdgeInsets.symmetric(horizontal: 15), -// child: RichText( -// text: TextSpan( -// style: TextStyle(fontWeight: FontWeight.bold), -// children: [ -// TextSpan( -// text: model.isBeaconExpired -// ? 'Beacon has been expired\n' -// : 'Beacon expiring at ${widget.beacon!.expiresAt == null ? '' : DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(widget.beacon!.expiresAt!)).toString()}\n', -// style: TextStyle(fontSize: 18), -// ), -// TextSpan( -// text: -// 'Beacon holder at: ${model.address}\n', -// style: TextStyle(fontSize: 14), -// ), -// TextSpan( -// text: -// 'Total Followers: ${model.hikers.length - 1} (Swipe up to view the list of followers)\n', -// style: TextStyle(fontSize: 12), -// ), -// TextSpan( -// text: model.isBeaconExpired -// ? '' -// : 'Share this passkey to add user: ${widget.beacon!.shortcode}\n', -// style: TextStyle(fontSize: 12), -// ), -// ], -// ), -// ), -// ), -// height: 15.h, -// ), -// ], -// ), -// ), -// panel: HikeScreenWidget.panel( -// model.scrollController, model, context, widget.isLeader!), -// body: Stack( -// alignment: Alignment.topCenter, -// children: [ -// Animarker( -// rippleColor: Colors.redAccent, -// rippleRadius: 0.01, -// useRotation: true, -// mapId: model.mapController.future.then( -// (value) => value.mapId, -// ), -// markers: model.markers.toSet(), -// // child: Text('hello'), -// child: GoogleMap( -// compassEnabled: true, -// mapType: MapType.terrain, -// polylines: model.polylines, -// initialCameraPosition: CameraPosition( -// target: LatLng( -// double.parse(widget.beacon!.location!.lat!), -// double.parse(widget.beacon!.location!.lon!), -// ), -// zoom: CAMERA_ZOOM, -// tilt: CAMERA_TILT, -// bearing: CAMERA_BEARING), -// onMapCreated: (GoogleMapController controller) { -// setState(() { -// model.mapController.complete(controller); -// }); -// // setPolyline(); -// }, -// onTap: (loc) async { -// // if (model.panelController.isPanelOpen) -// // model.panelController.close(); -// // else { -// // String? title; -// // HikeScreenWidget -// // .showCreateLandMarkDialogueDialog( -// // context, -// // model.landmarkFormKey, -// // title, -// // loc, -// // model.createLandmark, - -// // ); -// // } -// }), -// ), -// Align( -// alignment: Alignment(0.9, -0.98), -// child: model.isBeaconExpired -// ? Container() -// : HikeScreenWidget.shareButton( -// context, widget.beacon!.shortcode)), -// Align( -// alignment: Alignment(-0.9, -0.98), -// child: FloatingActionButton( -// onPressed: () { -// navigationService!.pop(); -// }, -// backgroundColor: kYellow, -// child: Icon( -// Icons.arrow_back, -// size: 35, -// color: Colors.white, -// ), -// ), -// ), -// if (!model.isBeaconExpired) -// //show the routeSharebutton only when beacon is active(?) and mapcontroller is ready. -// Align( -// alignment: screenHeight > 800 -// ? Alignment(0.9, -0.8) -// : Alignment(0.9, -0.77), -// child: AnimatedOpacity( -// duration: Duration(milliseconds: 500), -// opacity: -// model.mapController.isCompleted ? 1.0 : 0.0, -// child: HikeScreenWidget.shareRouteButton(context, -// model.beacon, model.mapController, model.route), -// ), -// ), -// ], -// ), -// ), -// ), -// ), -// ), -// ); -// }, -// ); -// } - -// // void relayBeacon(User newHolder) { -// // Fluttertoast.showToast(msg: 'Beacon handed over to $newHolder'); -// // } -// } - -@RoutePage() -class HikeScreen extends StatefulWidget { - final BeaconEntity beacon; - final bool? isLeader; - const HikeScreen({super.key, required this.beacon, required this.isLeader}); - - @override - State createState() => _HikeScreenState(); -} - -class _HikeScreenState extends State { - late HikeCubit _hikeCubit; - - @override - void initState() { - _hikeCubit = context.read(); - _hikeCubit.updateBeaconLocation(widget.beacon.id!, context); - super.initState(); - } - - @override - Widget build(BuildContext context) { - // return Scaffold( - // body: SafeArea( - // child: SlidingUpPanel( - // panel: Center( - // child: Text("This is the sliding Widget"), - // ), - // collapsed: Container( - // decoration: BoxDecoration( - // color: kBlue, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(10), - // topRight: Radius.circular(10))), - // child: Column( - // children: [ - // SizedBox( - // height: 1.5.h, - // ), - // Container( - // height: 0.7.h, - // width: 20.w, - // decoration: BoxDecoration( - // color: Colors.blueGrey, - // borderRadius: BorderRadius.all(Radius.circular(10))), - // ), - // SizedBox( - // height: 1.5.h, - // ), - // Container( - // width: double.infinity, - // child: Padding( - // padding: const EdgeInsets.symmetric(horizontal: 15), - // child: RichText( - // text: TextSpan( - // style: TextStyle(fontWeight: FontWeight.bold), - // children: [], - // ), - // ), - // ), - // ), - // ], - // ), - // ), - // // body: Center( - // // child: GoogleMap( - // // initialCameraPosition: CameraPosition(target: LatLng(1, 2))), - // // ), - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(10), topRight: Radius.circular(10))), - // ), - // ); - return Scaffold( - appBar: AppBar( - title: IconButton( - onPressed: () async { - // await _hikeCubit.updateBeaconLocation(widget.beacon.id!, context); - - locator().updateBeaconLocation(widget.beacon.id!, - await LocationService.getCurrentLocation()); - }, - icon: Icon(Icons.add))), - body: BlocBuilder( - builder: (context, state) { - return Text( - 'location: ${state.location.toString()}: eroor: ${state.error.toString()}'); - }, - ), - ); - } -} diff --git a/lib/Bloc/presentation/screens/splash_screen.dart b/lib/Bloc/presentation/screens/splash_screen.dart deleted file mode 100644 index 0d7764a8..00000000 --- a/lib/Bloc/presentation/screens/splash_screen.dart +++ /dev/null @@ -1,58 +0,0 @@ -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/Bloc/config/enviornment_config.dart b/lib/config/enviornment_config.dart similarity index 100% rename from lib/Bloc/config/enviornment_config.dart rename to lib/config/enviornment_config.dart diff --git a/lib/config/graphql_config.dart b/lib/config/graphql_config.dart new file mode 100644 index 00000000..924b1087 --- /dev/null +++ b/lib/config/graphql_config.dart @@ -0,0 +1,75 @@ +// import 'dart:async'; +// import 'package:beacon/config/enviornment_config.dart'; +// import 'package:beacon/locator.dart'; +// import 'package:graphql_flutter/graphql_flutter.dart'; + +import 'package:beacon/config/enviornment_config.dart'; +import 'package:beacon/locator.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; + +class GraphQLConfig { + static String? token; + WebSocketLink? _webSocketLink; + static final HttpLink httpLink = HttpLink( + EnvironmentConfig.httpEndpoint!, + ); + + Future _loadAuthLink() async { + // no need to load token, it will get load when _loadWebSocketLink + return AuthLink(getToken: () async => token); + } + + Future _loadWebSocketLink() async { + await _getToken(); + _webSocketLink = WebSocketLink(EnvironmentConfig.websocketEndpoint!, + config: SocketClientConfig( + autoReconnect: true, + initialPayload: {"Authorization": token}, + )); + + return _webSocketLink!; + } + + _getToken() async { + await localApi.init(); + await localApi.userloggedIn(); + token = localApi.userModel.authToken; + return true; + } + +// // for non auth clients + GraphQLClient clientToQuery() { + return GraphQLClient( + cache: GraphQLCache(), + link: httpLink, + ); + } + +// // for auth clients + Future authClient() async { + await _getToken(); + final AuthLink authLink = AuthLink(getToken: () async => '$token'); + final Link finalAuthLink = authLink.concat(httpLink); + return GraphQLClient( + cache: GraphQLCache(partialDataPolicy: PartialDataCachePolicy.accept), + link: finalAuthLink, + ); + } + + // for subscription + Future graphQlClient() async { + final websocketLink = await _loadWebSocketLink(); + final authLink = await _loadAuthLink(); + + return GraphQLClient( + cache: GraphQLCache( + partialDataPolicy: PartialDataCachePolicy.acceptForOptimisticData, + ), + link: Link.split( + (request) => request.isSubscription, + websocketLink, + authLink.concat(httpLink), + ), + ); + } +} diff --git a/lib/old/components/services/local_notification.dart b/lib/config/local_notification.dart similarity index 58% rename from lib/old/components/services/local_notification.dart rename to lib/config/local_notification.dart index 5748c001..99bf4cb3 100644 --- a/lib/old/components/services/local_notification.dart +++ b/lib/config/local_notification.dart @@ -1,6 +1,10 @@ +import 'dart:developer'; + +import 'package:beacon/config/router/router.dart'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/usecase/hike_usecase.dart'; import 'package:beacon/locator.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; @@ -32,24 +36,36 @@ class LocalNotification { ); } - Future onSelectNotification(notificationResponse) async { - if (notificationResponse != null) { - // Beacon beacon = await (databaseFunctions! - // .fetchBeaconInfo(notificationResponse.payload) as Future); - // bool isLeader = beacon.leader!.id == userConfig!.currentUser!.id; - // navigationService!.pushScreen('/hikeScreen', - // arguments: HikeScreen(beacon, isLeader: isLeader)); + Future onSelectNotification( + NotificationResponse notificationResponse) async { + String beaconId = notificationResponse.payload!; + + var hikeUseCase = locator(); + + // Fetch beacon details + final dataState = await hikeUseCase.fetchBeaconDetails(beaconId); + if (dataState is DataSuccess) { + var beacon = dataState.data; + bool isLeader = beacon!.leader!.id == localApi.userModel.id; + appRouter.push(HikeScreenRoute(beacon: beacon, isLeader: isLeader)); } - return; } Future deleteNotification() async { await flutterLocalNotificationsPlugin.cancelAll(); } - Future scheduleNotification(Beacon beacon) async { - var scheduledDate1 = await tz.TZDateTime.from( - DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!), tz.local); + Future scheduleNotification(BeaconEntity beacon) async { + var scheduledDate1 = + tz.TZDateTime.fromMillisecondsSinceEpoch(tz.local, beacon.startsAt!); + + // Check if scheduledDate1 is in the future + if (scheduledDate1.isBefore(tz.TZDateTime.now(tz.local))) { + log('Scheduled date is not in the future.'); + return; + } + + // Schedule the notification for the beacon start time await flutterLocalNotificationsPlugin.zonedSchedule( beacon.id.hashCode, 'Hike ' + beacon.title! + ' has started', @@ -59,7 +75,6 @@ class LocalNotification { android: AndroidNotificationDetails( 'channel id', 'channel name', - // 'this is description', playSound: true, priority: Priority.high, importance: Importance.high, @@ -76,15 +91,11 @@ class LocalNotification { androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, payload: beacon.id, ); - // We have to check if the hike is after 1 hour or not - var scheduledDate2 = await tz.TZDateTime.from( - DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!), - tz.local, - ).subtract(Duration(hours: 1)); + var scheduledDate2 = scheduledDate1.subtract(Duration(hours: 1)); - if (!scheduledDate2.isAfter(tz.TZDateTime.from( - DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!), tz.local))) { + if (scheduledDate2.isBefore(tz.TZDateTime.now(tz.local))) { + log('Reminder date is not in the future.'); return; } @@ -97,7 +108,6 @@ class LocalNotification { android: AndroidNotificationDetails( 'channel id', 'channel name', - // 'this is description', playSound: true, priority: Priority.high, importance: Importance.high, @@ -115,4 +125,34 @@ class LocalNotification { payload: beacon.id, ); } + + Future> getPendingNotifications() async { + final pendingNotifications = + await flutterLocalNotificationsPlugin.pendingNotificationRequests(); + return pendingNotifications; + } + + Future showInstantNotification(String title, String body) async { + await flutterLocalNotificationsPlugin.show( + 0, + title, + body, + NotificationDetails( + android: AndroidNotificationDetails( + 'channel id', + 'channel name', + // 'this is description', + playSound: true, + priority: Priority.high, + importance: Importance.high, + ), + iOS: DarwinNotificationDetails( + presentAlert: true, + presentBadge: true, + presentSound: true, + badgeNumber: 1, + ), + ), + ); + } } diff --git a/lib/config/pip_manager.dart b/lib/config/pip_manager.dart new file mode 100644 index 00000000..573073cc --- /dev/null +++ b/lib/config/pip_manager.dart @@ -0,0 +1,29 @@ +import 'package:flutter/services.dart'; + +class PIPMode { + static const platform = MethodChannel("com.example.beacon/pip"); + + static Future enterPIPMode() async { + try { + await platform.invokeMethod('enablePIPMode'); + } on PlatformException catch (e) { + print("Failed to enter PIP mode: '${e.message}'."); + } + } + + static Future disablePIPMode() async { + try { + await platform.invokeMethod('disablePIPMode'); + } on PlatformException catch (e) { + print("Failed to enter PIP mode: '${e.message}'."); + } + } + + static Future switchPIPMode() async { + try { + await platform.invokeMethod('switchPIPMode'); + } on PlatformException catch (e) { + print("Failed to enter PIP mode: '${e.message}'."); + } + } +} diff --git a/lib/config/router/router.dart b/lib/config/router/router.dart new file mode 100644 index 00000000..7ff17774 --- /dev/null +++ b/lib/config/router/router.dart @@ -0,0 +1,29 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/presentation/auth/verfication_screen.dart'; +import 'package:beacon/presentation/splash/splash_screen.dart'; +import 'package:beacon/presentation/home/home_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:beacon/presentation/auth/auth_screen.dart'; +import 'package:beacon/presentation/group/group_screen.dart'; +import 'package:beacon/presentation/hike/hike_screen.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +part 'router.gr.dart'; + +@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/:hikeDetails', + ), + AutoRoute(page: GroupScreenRoute.page), + AutoRoute( + page: VerificationScreenRoute.page, + ), + ]; +} diff --git a/lib/router.gr.dart b/lib/config/router/router.gr.dart similarity index 88% rename from lib/router.gr.dart rename to lib/config/router/router.gr.dart index 5f285114..994646b0 100644 --- a/lib/router.gr.dart +++ b/lib/config/router/router.gr.dart @@ -51,6 +51,12 @@ abstract class _$AppRouter extends RootStackRouter { child: const SplashScreen(), ); }, + VerificationScreenRoute.name: (routeData) { + return AutoRoutePage( + routeData: routeData, + child: const VerificationScreen(), + ); + }, }; } @@ -167,3 +173,17 @@ class SplashScreenRoute extends PageRouteInfo { static const PageInfo page = PageInfo(name); } + +/// generated route for +/// [VerificationScreen] +class VerificationScreenRoute extends PageRouteInfo { + const VerificationScreenRoute({List? children}) + : super( + VerificationScreenRoute.name, + initialChildren: children, + ); + + static const String name = 'VerificationScreenRoute'; + + static const PageInfo page = PageInfo(name); +} diff --git a/lib/config/service_location.dart b/lib/config/service_location.dart new file mode 100644 index 00000000..fb42c653 --- /dev/null +++ b/lib/config/service_location.dart @@ -0,0 +1,30 @@ +import 'package:location/location.dart'; + +class ServiceLocation { + static LocationData? locationData; + Future getLocation() async { + Location location = new Location(); + + bool _serviceEnabled; + PermissionStatus _permissionGranted; + LocationData _locationData; + + _serviceEnabled = await location.serviceEnabled(); + if (!_serviceEnabled) { + _serviceEnabled = await location.requestService(); + if (!_serviceEnabled) { + return; + } + } + + _permissionGranted = await location.hasPermission(); + if (_permissionGranted == PermissionStatus.denied) { + _permissionGranted = await location.requestPermission(); + if (_permissionGranted != PermissionStatus.granted) { + return; + } + } + + locationData = await location.getLocation(); + } +} diff --git a/lib/Bloc/core/queries/auth.dart b/lib/core/queries/auth.dart similarity index 68% rename from lib/Bloc/core/queries/auth.dart rename to lib/core/queries/auth.dart index 1c44b5c3..5a158970 100644 --- a/lib/Bloc/core/queries/auth.dart +++ b/lib/core/queries/auth.dart @@ -24,6 +24,33 @@ class AuthQueries { '''; } + String sendVerficationCode() { + return ''' + mutation{ + sendVerificationCode + } + '''; + } + + String completeVerificationCode() { + return ''' + mutation{ + completeVerification{ + _id + email + name + groups{ + _id + } + isVerified + beacons{ + _id + } + } + } + '''; + } + String loginUser(String email, String? password) { return ''' mutation{ @@ -47,6 +74,7 @@ class AuthQueries { _id email name + isVerified groups{ _id } diff --git a/lib/Bloc/core/queries/beacon.dart b/lib/core/queries/beacon.dart similarity index 56% rename from lib/Bloc/core/queries/beacon.dart rename to lib/core/queries/beacon.dart index 1811c3c4..909aeb8f 100644 --- a/lib/Bloc/core/queries/beacon.dart +++ b/lib/core/queries/beacon.dart @@ -1,6 +1,59 @@ +import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; class BeaconQueries { + String filterBeacons(String groupId, String type) { + return '''query{ + filterBeacons(id:"$groupId", type: "$type"){ + _id + title + leader{ + _id + name + } + startsAt + expiresAt + shortcode + } + } +'''; + } + + String rescheduleHike(int newExpirestAt, int newStartsAt, String beaconId) { + return '''mutation{ rescheduleHike(newExpiresAt: $newExpirestAt, newStartsAt: $newStartsAt, beaconID: "$beaconId"){ + _id + title + shortcode + leader { + _id + name + } + group{ + _id + title + } + location{ + lat + lon + } + followers { + _id + name + } + startsAt + expiresAt + }}'''; + } + + String deleteBeacon(String? id) { + return ''' + +mutation{ +deleteBeacon(id: "$id") +} +'''; + } + String changeLeader(String? beaconID, String? newLeaderID) { return ''' mutation{ @@ -60,6 +113,10 @@ class BeaconQueries { leader { _id name + email + beacons{ + _id + } } group { _id @@ -87,6 +144,21 @@ class BeaconQueries { '''; } + String createGeofence( + String beaconId, String lat, String lon, double radius) { + return ''' + mutation{ + createGeofence(id: "$beaconId", location: {lat: "$lat", lon:"$lon"}, radius: $radius){ + radius + center{ + lat + lon + } + } + } + '''; + } + String updateBeaconLocation(String? id, String lat, String lon) { return ''' mutation { @@ -100,6 +172,19 @@ class BeaconQueries { '''; } + String changeUserLocation(String? id, String lat, String lon) { + return ''' + mutation { + updateUserLocation(id: "$id", location: {lat: "$lat", lon:"$lon"}){ + location{ + lat + lon + } + } + } + '''; + } + String addLandmark(String title, String lat, String lon, String id) { return ''' mutation{ @@ -159,7 +244,12 @@ class BeaconQueries { _id title leader{ + _id name + location{ + lat + lon + } } group { _id @@ -173,12 +263,24 @@ class BeaconQueries { lon } } + geofence{ + center{ + lat + lon + } + radius + } landmarks{ + _id title location{ lat lon } + createdBy{ + _id + name + } } location{ lat @@ -192,13 +294,30 @@ class BeaconQueries { '''; } - String fetchNearbyBeacons(String lat, String lon) { + String addRoute(String id, LatLng latlng) { + return ''' + mutation{ + addRoute( + id: "$id" + location:{ + lat: "${latlng.latitude}", + lon: "${latlng.longitude}" + } + ) + } + '''; + } + + String fetchNearbyBeacons(String id, String lat, String lon, double radius) { return ''' query { - nearbyBeacons(location:{ + nearbyBeacons( + id: "$id", + location:{ lat: "$lat", lon: "$lon" - }){ + }, + radius: $radius){ _id title shortcode @@ -207,6 +326,7 @@ class BeaconQueries { title } leader { + _id name location { lat @@ -223,13 +343,6 @@ class BeaconQueries { } startsAt expiresAt - landmarks { - title - location { - lat - lon - } - } } } '''; @@ -257,6 +370,49 @@ class BeaconQueries { } '''); + final joinleaveBeaconSubGql = gql(r''' + subscription StreamNewlyJoinedBeacons($id: ID!){ + JoinLeaveBeacon(id: $id){ + newfollower{ + _id + name + email + } + inactiveuser{ + _id + name + email + } + } + } + '''); + + final beaconUpdateSubGql = gql(r''' + subscription StreamBeaconUpdate($id: ID!){ + updateBeacon(id: $id){ + user{ + _id + name + email + location{ + lat + lon + } + } + + landmark{ + _id + title + location{ + lat + lon + } + } + + } + } + '''); + String createLandmark(String? id, String lat, String lon, String? title) { return ''' mutation{ @@ -267,13 +423,78 @@ class BeaconQueries { }, beaconID:"$id") { + _id title location{ lat lon } + createdBy{ + _id + name + } } } '''; } + + String sos(String id) { + return ''' + mutation{ + sos( id:"$id"){ + _id + name + email + location{ + lat + lon + } + } + } + '''; + } + + final locationUpdateGQL = gql(r''' + subscription StreamLocationUpdate($id: ID!){ + beaconLocations(id: $id){ + + route{ + lat + lon + } + + updatedUser{ + _id + name + location{ + lat + lon + } + } + + geofence{ + radius + center{ + lat + lon + } + } + + landmark{ + _id + title + location{ + lat + lon + } + createdBy{ + _id + name + email + } + } + + } + } + '''); } diff --git a/lib/Bloc/core/queries/group.dart b/lib/core/queries/group.dart similarity index 57% rename from lib/Bloc/core/queries/group.dart rename to lib/core/queries/group.dart index bc760734..06cea688 100644 --- a/lib/Bloc/core/queries/group.dart +++ b/lib/core/queries/group.dart @@ -3,25 +3,26 @@ 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 - } + query { + groups(page: $page, pageSize: $pageSize) { + _id + title + beacons{ + _id + } + leader{ + _id + name } + members{ + _id + name + } + shortcode + __typename } - '''; + } + '''; } String createGroup(String? title) { @@ -86,8 +87,7 @@ class GroupQueries { _id name } - beacons - { + beacons{ _id title shortcode @@ -130,22 +130,6 @@ class GroupQueries { beacons { _id - title - shortcode - leader { - _id - name - } - location{ - lat - lon - } - followers { - _id - name - } - startsAt - expiresAt } } } @@ -182,6 +166,129 @@ query{ '''; } + String changeShortCode(String groupId) { + return ''' + mutation{ + changeShortcode(groupId: "$groupId"){ + _id + title + beacons{ + _id + } + leader{ + _id + name + } + members{ + _id + name + } + shortcode + __typename + } + } + +'''; + } + + final groupUpdateSubGql = gql(r''' + subscription groupUpdate($groupIds: [ID!]!) { + groupUpdate(groupIds: $groupIds) { + groupId + + newUser{ + _id + name + email + } + + newBeacon{ + _id + title + leader { + _id + name + email + } + followers { + _id + name + } + group{ + _id + } + location { + lat + lon + } + shortcode + startsAt + expiresAt + } + + deletedBeacon{ + _id + title + leader { + _id + name + email + } + followers { + _id + name + } + group{ + _id + } + location { + lat + lon + } + shortcode + startsAt + expiresAt + } + + updatedBeacon{ + _id + title + leader { + _id + name + email + } + followers { + _id + name + } + group{ + _id + } + location { + lat + lon + } + shortcode + startsAt + expiresAt + } + } + } +'''); + + String removeMember(String groupId, String memberId) { + return ''' + mutation{ + removeMember(groupId: "$groupId", memberId: "$memberId"){ + _id + name + email + } + } + '''; + } + final groupJoinedSubGql = gql(r''' subscription StreamNewlyJoinedGroups($id: ID!){ groupJoined(id: $id){ diff --git a/lib/Bloc/core/resources/data_state.dart b/lib/core/resources/data_state.dart similarity index 100% rename from lib/Bloc/core/resources/data_state.dart rename to lib/core/resources/data_state.dart diff --git a/lib/core/services/location_services.dart b/lib/core/services/location_services.dart new file mode 100644 index 00000000..ca161369 --- /dev/null +++ b/lib/core/services/location_services.dart @@ -0,0 +1,67 @@ +import 'dart:developer'; +import 'package:geolocator/geolocator.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +class LocationService { + static final LocationService _instance = LocationService._internal(); + + LocationService._internal(); + + factory LocationService() { + return _instance; + } + + Position? _currentPosition; + Position? get currentPosition => _currentPosition; + + 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.'); + } + + try { + Position location = await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.high); + + _currentPosition = location; + + + return location; + } catch (e) { + return Future.error('Failed to get location: $e'); + } + } + + Future openSettings() async { + await Geolocator.openAppSettings(); + } + + Future calculateDistance(LatLng first, LatLng second) async { + double distanceInMeters = await Geolocator.distanceBetween( + first.latitude, + first.longitude, + second.latitude, + second.longitude, + ); + + return distanceInMeters; + } +} diff --git a/lib/Bloc/core/services/shared_prefrence_service.dart b/lib/core/services/shared_prefrence_service.dart similarity index 80% rename from lib/Bloc/core/services/shared_prefrence_service.dart rename to lib/core/services/shared_prefrence_service.dart index 9e91b816..af083a85 100644 --- a/lib/Bloc/core/services/shared_prefrence_service.dart +++ b/lib/core/services/shared_prefrence_service.dart @@ -2,8 +2,13 @@ import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class SharedPreferenceService { - SharedPreferenceService() { - init(); + static SharedPreferenceService _instance = + SharedPreferenceService._internal(); + + SharedPreferenceService._internal(); + + factory SharedPreferenceService() { + return _instance; } late SharedPreferences _prefs; @@ -35,6 +40,6 @@ class SharedPreferenceService { } Future deleteData(String key) async { - return await _prefs.remove('key'); + return await _prefs.remove(key); } } diff --git a/lib/old/components/utilities/constants.dart b/lib/core/utils/constants.dart similarity index 67% rename from lib/old/components/utilities/constants.dart rename to lib/core/utils/constants.dart index 8f272eaf..35de8fd7 100644 --- a/lib/old/components/utilities/constants.dart +++ b/lib/core/utils/constants.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:geolocator/geolocator.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:sizer/sizer.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; const Color kYellow = Color(0xFFFDBB2C); const Color kBlue = Color(0xFF222375); @@ -28,31 +26,8 @@ const String otherError = "Other Errors"; const String logSuccess = "Successful Login"; class AppConstants { - static Future getLocation() async { - bool serviceEnabled; - LocationPermission permission; - - serviceEnabled = await Geolocator.isLocationServiceEnabled(); - if (!serviceEnabled) { - return Future.error('Location services are disabled.'); - } - - permission = await Geolocator.checkPermission(); - if (permission == LocationPermission.denied) { - permission = await Geolocator.requestPermission(); - if (permission == LocationPermission.denied) { - return Future.error('Location permissions are denied'); - } - } - - if (permission == LocationPermission.deniedForever) { - return Future.error( - 'Location permissions are permanently denied, we cannot request permissions.'); - } - - Position position = await Geolocator.getCurrentPosition(); - return LatLng(position.latitude, position.longitude); - } + static const _imagePath = 'images'; + static const filterIconPath = '$_imagePath/filter_icon.png'; } //routes diff --git a/lib/Bloc/core/utils/utils.dart b/lib/core/utils/utils.dart similarity index 60% rename from lib/Bloc/core/utils/utils.dart rename to lib/core/utils/utils.dart index aa80bd5e..6b9021c8 100644 --- a/lib/Bloc/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -1,18 +1,33 @@ import 'dart:developer'; -import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/core/utils/constants.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; import 'package:graphql/client.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; class Utils { void showSnackBar(String message, BuildContext context, - {Duration duration = const Duration(seconds: 2)}) { + {Duration duration = const Duration(seconds: 2), + bool icon = false, + bool top = false}) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( duration: duration, - content: Text( - message, - style: TextStyle(color: Colors.black), + content: Row( + children: [ + icon + ? Image.asset( + 'images/male_avatar.png', + height: 35, + ) + : Container(), + icon ? Gap(20) : Container(), + Text( + message, + style: TextStyle(color: Colors.black, fontSize: 12), + ) + ], ), backgroundColor: kLightBlue.withOpacity(0.8), shape: RoundedRectangleBorder( @@ -20,6 +35,9 @@ class Utils { Radius.circular(10), ), ), + margin: top + ? EdgeInsets.only(top: 0, right: 10, left: 10, bottom: 85.h) + : null, behavior: SnackBarBehavior.floating, elevation: 5, ), @@ -50,30 +68,4 @@ class Utils { } 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/core/utils/validators.dart b/lib/core/utils/validators.dart new file mode 100644 index 00000000..4d62cbe7 --- /dev/null +++ b/lib/core/utils/validators.dart @@ -0,0 +1,166 @@ +import 'package:flutter/material.dart'; + +class Validator { + static String? validateName(String? name) { + if (name != null && name.isEmpty) { + return "Name must not be left blank"; + } + return null; + } + + static String? validateRadius(String? radius) { + if (radius == null) { + return 'Radius can\'t be blank'; + } + try { + double.parse(radius); + + return null; + } catch (e) { + return 'Radius should be number'; + } + } + + static String? validateDate(String? date) { + if (date == null || date.isEmpty || date == '') { + return 'Date can\'t be empty'; + } + + DateTime parsedDate = DateTime.parse(date); + DateTime now = DateTime.now(); + + DateTime currentDate = DateTime(now.year, now.month, now.day); + DateTime onlyDate = + DateTime(parsedDate.year, parsedDate.month, parsedDate.day); + + if (onlyDate.isBefore(currentDate)) { + return 'Please enter a valid date'; + } + + return null; + } + + static String? validateStartTime(String? time, String date) { + DateTime parsedDate = DateTime.parse(date); + DateTime selectedDate = + DateTime(parsedDate.year, parsedDate.month, parsedDate.day); + DateTime now = DateTime.now(); + DateTime currentDate = DateTime(now.year, now.month, now.day); + + if (selectedDate.isAfter(currentDate)) { + return null; + } + + if (time == null || time.isEmpty) { + return 'Please chose a start time'; + } + + RegExp timeRegex = RegExp(r'^([0-1]?[0-9]|2[0-3]):[0-5][0-9] (AM|PM)$'); + + if (!timeRegex.hasMatch(time)) { + return 'Invalid time format. Please enter time in hh:mm AM/PM format'; + } + + TimeOfDay enteredTime = _stringToTimeOfDay(time); + + TimeOfDay currentTime = TimeOfDay.now(); + + int isValid = compareTimeOfDay(enteredTime, currentTime); + + if (isValid == -1) { + return 'Please chose a valid time'; + } + + return null; + } + + static int compareTimeOfDay(TimeOfDay time1, TimeOfDay time2) { + if (time1.hour < time2.hour) { + return -1; + } else if (time1.hour > time2.hour) { + return 1; + } else { + // If hours are the same, compare minutes + if (time1.minute < time2.minute) { + return -1; + } else if (time1.minute > time2.minute) { + return 1; + } else { + return 0; + } + } + } + + static TimeOfDay _stringToTimeOfDay(String time) { + final numbers = time.split(' '); + final format = numbers[0].split(":"); + final hour = int.parse(format[0]); + final minute = int.parse(format[1]); + + return TimeOfDay(hour: hour, minute: minute); + } + + static String? validateEmail(String? email) { + // If email is empty return. + 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 (email != null && !regex.hasMatch(email)) { + return 'Please enter a valid Email Address'; + } + return null; + } + + static String? validatePassword(String? password) { + // If password is empty return. + if (password != null && password.isEmpty) { + return "Password must not be left blank"; + } + // const String pattern = r'^(?=.*?[0-9])(?=.*?[!@#\$&*%^~.]).{8,}$'; + // final RegExp regExp = RegExp(pattern); + + //Regex for no spaces allowed + const String noSpaces = r'^\S+$'; + final RegExp noSpaceRegex = RegExp(noSpaces); + + if (password!.length < 8) { + return "Must be of atleast 8 characters"; + } + // if (!regExp.hasMatch(password)) { + // return "At least 1 number and symbol required"; + // } + if (!noSpaceRegex.hasMatch(password)) { + return "Password must not contain spaces"; + } + return null; + } + + 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 != 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) { + return "Invalid passkey"; + } + return null; + } + + static String? validateDuration(String? duration) { + if (duration == null || duration.isEmpty || duration == '') { + return "Please enter duration"; + } + return null; + } +} diff --git a/lib/Bloc/data/datasource/local/local_api.dart b/lib/data/datasource/local/local_api.dart similarity index 85% rename from lib/Bloc/data/datasource/local/local_api.dart rename to lib/data/datasource/local/local_api.dart index 6b27fce2..13ace147 100644 --- a/lib/Bloc/data/datasource/local/local_api.dart +++ b/lib/data/datasource/local/local_api.dart @@ -1,11 +1,11 @@ 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:beacon/data/models/beacon/beacon_model.dart'; +import 'package:beacon/data/models/group/group_model.dart'; +import 'package:beacon/data/models/landmark/landmark_model.dart'; +import 'package:beacon/data/models/location/location_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; import 'package:hive/hive.dart'; import 'package:path_provider/path_provider.dart' as path_provider; @@ -15,10 +15,12 @@ class LocalApi { String beaconModelBox = 'beaconBox'; String locationModelBox = 'locationBox'; String landMarkModelBox = 'landMarkBox'; + String nearbyBeaconModelBox = 'nearbybeaconBox'; late Box userBox; late Box groupBox; late Box beaconBox; + late Box nearbyBeaconBox; late Box locationBox; late Box landMarkbox; @@ -52,6 +54,7 @@ class LocalApi { userBox = await Hive.openBox(userModelbox); groupBox = await Hive.openBox(groupModelBox); beaconBox = await Hive.openBox(beaconModelBox); + nearbyBeaconBox = await Hive.openBox(nearbyBeaconModelBox); locationBox = await Hive.openBox(locationModelBox); landMarkbox = await Hive.openBox(landMarkModelBox); } catch (e) { @@ -159,6 +162,16 @@ class LocalApi { } } + Future savenearbyBeacons(BeaconModel beacon) async { + try { + await deleteBeacon(beacon.id); + await nearbyBeaconBox.put(beacon.id, beacon); + return true; + } catch (e) { + return false; + } + } + Future deleteBeacon(String? beaconId) async { try { bool doesExist = await beaconBox.containsKey(beaconId); diff --git a/lib/data/datasource/remote/remote_auth_api.dart b/lib/data/datasource/remote/remote_auth_api.dart new file mode 100644 index 00000000..30d8cb72 --- /dev/null +++ b/lib/data/datasource/remote/remote_auth_api.dart @@ -0,0 +1,185 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:beacon/core/queries/auth.dart'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/data/datasource/remote/remote_group_api.dart'; +import 'package:beacon/data/datasource/remote/remote_hike_api.dart'; +import 'package:beacon/data/datasource/remote/remote_home_api.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/locator.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; + +class RemoteAuthApi { + GraphQLClient clientNonAuth; + late GraphQLClient _authClient; + + RemoteAuthApi(this._authClient, this.clientNonAuth); + + void loadClient(GraphQLClient newClient) { + _authClient = newClient; + } + + AuthQueries _authQueries = AuthQueries(); + + Future> fetchUserInfo() async { + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) + return DataFailed('Beacon is trying to connect with internet...'); + + var _authClient = await graphqlConfig.authClient(); + // api call + final result = await _authClient + .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.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 { + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('Beacon is trying to connect with internet...'); + } + + final QueryResult result = await clientNonAuth.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: false); + await localApi.saveUser(user); + + // loading clients + final authClient = await graphqlConfig.authClient(); + final subscriptionClient = await graphqlConfig.graphQlClient(); + locator().loadClient(authClient); + locator().loadClient(authClient, subscriptionClient); + locator().loadClient(authClient, subscriptionClient); + locator().loadClient(authClient, subscriptionClient); + + // fetching User Info + + final dataState = await fetchUserInfo(); + + if (dataState is DataSuccess) { + final updatedUser = dataState.data! + .copyWithModel(authToken: user.authToken, isGuest: user.isGuest); + + // saving locally + await localApi.saveUser(updatedUser); + + return DataSuccess(updatedUser); + } + } else if (result.hasException) { + final message = encounteredExceptionOrError(result.exception!); + + return DataFailed(message); + } + + return DataFailed('An unexpected error occured.'); + } + + Future> sendVerificationCode() async { + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('Beacon is trying to connect with internet...'); + } + + final QueryResult result = await _authClient.mutate( + MutationOptions(document: gql(_authQueries.sendVerficationCode()))); + + + if (result.data != null && result.isConcrete) { + return DataSuccess(result.data!['sendVerificationCode'] as String); + } + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + Future> completeVerification() async { + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('Beacon is trying to connect with internet...'); + } + + var authClient = await graphqlConfig.authClient(); + + final QueryResult result = await authClient.mutate(MutationOptions( + document: gql(_authQueries.completeVerificationCode()))); + + + if (result.data != null && result.isConcrete) { + var user = UserModel.fromJson(result.data!['completeVerification']); + var currentUser = await localApi.fetchUser(); + currentUser = currentUser!.copyWithModel(isVerified: user.isVerified); + await localApi.saveUser(currentUser); + return DataSuccess(user); + } + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + String encounteredExceptionOrError(OperationException exception) { + if (exception.linkException != null) { + debugPrint(exception.linkException.toString()); + return 'Something went wrong'; + } else { + return exception.graphqlErrors[0].message.toString(); + } + } +} diff --git a/lib/data/datasource/remote/remote_group_api.dart b/lib/data/datasource/remote/remote_group_api.dart new file mode 100644 index 00000000..181a95a7 --- /dev/null +++ b/lib/data/datasource/remote/remote_group_api.dart @@ -0,0 +1,248 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:beacon/core/queries/beacon.dart'; +import 'package:beacon/core/queries/group.dart'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/data/models/beacon/beacon_model.dart'; +import 'package:beacon/data/models/group/group_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/locator.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; + +class RemoteGroupApi { + late GraphQLClient _authClient; + late GraphQLClient _subscriptionClient; + + RemoteGroupApi(this._authClient, this._subscriptionClient); + + void loadClient(GraphQLClient authClient, GraphQLClient subscriptionClient) { + this._authClient = authClient; + this._subscriptionClient = subscriptionClient; + } + + 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 result = await _authClient.query(QueryOptions( + document: gql(_groupqueries.fetchHikes(groupId, page, pageSize)), + fetchPolicy: FetchPolicy.networkOnly)); + + 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 + 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 { + 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 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!)); + } + + Future>> nearbyBeacons( + String id, String lat, String lon, double radius) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('Please check your internet connection!'); + } + final result = await _authClient.mutate(MutationOptions( + document: + gql(_beaconQueries.fetchNearbyBeacons(id, lat, lon, radius)))); + + if (result.data != null && + result.isConcrete && + result.data!['nearbyBeacons'] != null) { + List nearbyBeaconJson = result.data!['nearbyBeacons']; + + List nearbyBeacons = nearbyBeaconJson + .map((beaconJson) => BeaconModel.fromJson(beaconJson)) + .toList(); + + // storing beacons + for (var beacon in nearbyBeacons) { + await localApi.savenearbyBeacons(beacon); + } + + return DataSuccess(nearbyBeacons); + } + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + Future>> filterBeacons( + String groupId, String type) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('Please check your internet connection!'); + } + final result = await _authClient.mutate(MutationOptions( + document: gql(_beaconQueries.filterBeacons(groupId, type)))); + + if (result.data != null && + result.isConcrete && + result.data!['filterBeacons'] != null) { + List beaconsJson = result.data!['filterBeacons']; + + List beacons = beaconsJson + .map((beaconJson) => BeaconModel.fromJson(beaconJson)) + .toList(); + + return DataSuccess(beacons); + } else { + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + } + + Future> deleteBeacon(String? beaconId) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('Please check your internet connection!'); + } + final result = await _authClient.mutate( + MutationOptions(document: gql(_beaconQueries.deleteBeacon(beaconId)))); + + if (result.data != null && + result.isConcrete && + result.data!['deleteBeacon'] != null) { + bool isDeleted = result.data!['deleteBeacon']; + + return DataSuccess(isDeleted); + } else { + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + } + + Future> rescheduleBeacon( + int newExpiresAt, int newStartsAt, String beaconId) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('Please check your internet connection!'); + } + final result = await _authClient.mutate(MutationOptions( + document: gql(_beaconQueries.rescheduleHike( + newExpiresAt, newStartsAt, beaconId)))); + + if (result.data != null && + result.isConcrete && + result.data!['rescheduleHike'] != null) { + return DataSuccess(BeaconModel.fromJson(result.data!['rescheduleHike'])); + } else { + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + } + + Future> removeMember( + String groupId, String memberId) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('Please check your internet connection!'); + } + final result = await _authClient.mutate(MutationOptions( + document: gql(_groupqueries.removeMember(groupId, memberId)))); + + if (result.data != null && + result.isConcrete && + result.data!['removeMember'] != null) { + return DataSuccess(UserModel.fromJson(result.data!['removeMember'])); + } else { + 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/data/datasource/remote/remote_hike_api.dart b/lib/data/datasource/remote/remote_hike_api.dart new file mode 100644 index 00000000..bc122aa1 --- /dev/null +++ b/lib/data/datasource/remote/remote_hike_api.dart @@ -0,0 +1,366 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:developer'; +import 'package:beacon/core/queries/beacon.dart'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/data/models/beacon/beacon_model.dart'; +import 'package:beacon/data/models/geofence/geofence_model.dart'; +import 'package:beacon/data/models/landmark/landmark_model.dart'; +import 'package:beacon/data/models/location/location_model.dart'; +import 'package:beacon/data/models/subscriptions/beacon_locations_model/beacon_locations_model.dart'; +import 'package:beacon/data/models/subscriptions/join_leave_beacon_model/join_leave_beacon_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/location/location_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/locator.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; +import 'package:http/http.dart' as http; + +class RemoteHikeApi { + late GraphQLClient _authClient; + late GraphQLClient _subscriptionClient; + + RemoteHikeApi(this._authClient, this._subscriptionClient); + + final beaconQueries = BeaconQueries(); + + void loadClient(GraphQLClient authClient, GraphQLClient subscriptionClient) { + this._authClient = authClient; + this._subscriptionClient = subscriptionClient; + } + + Future> fetchBeaconDetails(String beaconId) async { + bool isConnected = await utils.checkInternetConnectivity(); + if (!isConnected) {} + + final result = await _authClient.mutate(MutationOptions( + document: gql(beaconQueries.fetchBeaconDetail(beaconId)))); + + + + if (result.isConcrete && result.data != null) { + final beaconJson = result.data!['beacon']; + + final beacon = BeaconModel.fromJson(beaconJson); + return DataSuccess(beacon); + } + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + Future> updateBeaconLocation( + String? beaconId, String lat, String lon) async { + bool isConnected = await utils.checkInternetConnectivity(); + if (!isConnected) {} + + final result = await _authClient.mutate(MutationOptions( + document: gql(beaconQueries.updateBeaconLocation(beaconId, lat, lon)))); + + if (result.isConcrete && result.data != null) { + final beaconJson = result.data!['updateBeaconLocation']; + + final location = LocationModel.fromJson(beaconJson); + return DataSuccess(location); + } + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + Future> createGeofence( + String beaconId, LatLng latlng, double radius) async { + bool isConnected = await utils.checkInternetConnectivity(); + if (!isConnected) {} + + final result = await _authClient.mutate(MutationOptions( + document: gql(beaconQueries.createGeofence(beaconId, + latlng.latitude.toString(), latlng.longitude.toString(), radius)))); + +; + if (result.isConcrete && result.data != null) { + final beaconJson = result.data!['createGeofence']; + try { + var geofence = GeofenceModel.fromJson(beaconJson); + return DataSuccess(geofence); + } catch (e) { + log(e.toString()); + } + } + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + Stream> beaconLocationSubscription( + String? beaconId) async* { + bool isConnected = await utils.checkInternetConnectivity(); + if (!isConnected) { + yield DataFailed("No internet connection"); + return; + } + + final subscriptionOptions = SubscriptionOptions( + document: beaconQueries.beaconLocationSubGql, + variables: { + 'id': beaconId, + }, + ); + + final authClient = await graphqlConfig.graphQlClient(); + + final resultStream = authClient.subscribe(subscriptionOptions); + + await for (final result in resultStream) { + if (result.isConcrete && + result.data != null && + result.data!['beaconLocation'] != null) { + final locationJson = result.data!['beaconLocation']; + final location = LocationModel.fromJson(locationJson); + yield DataSuccess(location); + } else if (result.hasException) { + yield DataFailed(encounteredExceptionOrError(result.exception!)); + } + } + } + + Stream> beaconJoinedSubscription( + String beaconId) async* { + bool isConnected = await utils.checkInternetConnectivity(); + if (!isConnected) { + yield DataFailed("No internet connection"); + return; + } + + final subscriptionOptions = SubscriptionOptions( + document: beaconQueries.beaconJoinedSubGql, + variables: { + 'id': beaconId, + }, + ); + + final authClient = await graphqlConfig.graphQlClient(); + + final resultStream = await authClient.subscribe(subscriptionOptions); + + await for (var result in resultStream) { + if (result.isConcrete && + result.data != null && + result.data!['beaconJoined'] != null) { + final newMember = UserModel.fromJson(result.data!['beaconJoined']); + yield DataSuccess(newMember); + } + yield DataFailed(encounteredExceptionOrError(result.exception!)); + } + } + + Stream> beaconUpdateSubscription(String beaconId) async* { + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + yield DataFailed('No internet connection'); + return; + } + + final subscriptionOptions = SubscriptionOptions( + document: beaconQueries.beaconUpdateSubGql, + variables: {'id': beaconId}); + + final resultStream = + await _subscriptionClient.subscribe(subscriptionOptions); + + await for (var result in resultStream) { + if (result.isConcrete && + result.data != null && + result.data!['updateBeacon'] != null) { + Map beaconJson = + result.data!['updateBeacon'] as Map; + + if (beaconJson['user'] != null) { + UserModel newUser = UserModel.fromJson(beaconJson['user']); + + yield DataSuccess(newUser); + // return user + } + if (beaconJson['landmark'] != null) { + LandMarkModel newLandmark = + LandMarkModel.fromJson(beaconJson['landmark']); + + yield DataSuccess(newLandmark); + // return landmark + } + } else { + yield DataFailed(encounteredExceptionOrError(result.exception!)); + } + } + } + + Future> changeUserLocation( + String beaconId, LatLng latlng) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('No internet connection'); + } + + final result = await _authClient.mutate(MutationOptions( + document: gql(beaconQueries.changeUserLocation(beaconId, + latlng.latitude.toString(), latlng.longitude.toString())))); + + + + if (result.isConcrete && + result.data != null && + result.data!['updateUserLocation'] != null) { + final user = UserModel.fromJson(result.data!['updateUserLocation']); + return DataSuccess(user); + } else { + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + } + + Future> createLandMark( + String id, String lat, String lon, String title) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('No internet connection'); + } + + final result = await _authClient.mutate(MutationOptions( + document: gql(beaconQueries.createLandmark(id, lat, lon, title)))); + + if (result.isConcrete && + result.data != null && + result.data!['createLandmark'] != null) { + final newLandMark = + LandMarkModel.fromJson(result.data!['createLandmark']); + return DataSuccess(newLandMark); + } else { + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + } + + Stream> locationUpdateSubscription( + String beaconId) async* { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + yield DataFailed('No internet connection'); + } + + final subscriptionOptions = SubscriptionOptions( + document: beaconQueries.locationUpdateGQL, variables: {'id': beaconId}); + + final resultStream = + await _subscriptionClient.subscribe(subscriptionOptions); + + await for (var stream in resultStream) { + if (stream.hasException) { + yield DataFailed('Something went wrong'); + } else { + var locations = + BeaconLocationsModel.fromJson(stream.data!['beaconLocations']); + yield DataSuccess(locations); + } + } + } + + Stream> LeaveJoinBeaconSubscription( + String beaconId) async* { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + yield DataFailed('No internet connection'); + } + + final subscriptionOptions = SubscriptionOptions( + document: beaconQueries.joinleaveBeaconSubGql, + variables: {'id': beaconId}); + + final resultStream = + await _subscriptionClient.subscribe(subscriptionOptions); + + await for (var stream in resultStream) { + if (stream.hasException) { + yield DataFailed('Something went wrong'); + } else { + var locations = + JoinLeaveBeaconModel.fromJson(stream.data!['JoinLeaveBeacon']); + yield DataSuccess(locations); + } + } + } + + Future> addRoute(String id, LatLng latlng) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('No internet connection'); + } + + final result = await _authClient.mutate( + MutationOptions(document: gql(beaconQueries.addRoute(id, latlng)))); + + if (result.isConcrete && + result.data != null && + result.data!['addRoute'] != null) { + return DataSuccess(result.data!['addRoute']); + } else { + return DataSuccess(false); + } + } + + Future> sos(String id) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('No internet connection'); + } + + final result = await _authClient + .mutate(MutationOptions(document: gql(beaconQueries.sos(id)))); + + if (result.isConcrete && + result.data != null && + result.data!['sos'] != null) { + return DataSuccess(UserModel.fromJson(result.data!['sos'])); + } else { + return DataFailed(utils.filterException(result.exception!)); + } + } + + Future>> getRoute(List latlng) async { + bool isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + return DataFailed('No internet connection'); + } + + List> coordinates = []; + + for (var coord in latlng) { + coordinates.add([coord.latitude, coord.longitude]); + } + + final response = await http.post( + Uri.parse( + 'https://api.openrouteservice.org/v2/directions/foot-hiking/gpx'), + headers: { + "Authorization": + "5b3ce3597851110001cf6248873a3b4f20c445c98808378287166ec0", + "Content-Type": "application/json" + }, + body: jsonEncode({"coordinates": coordinates})); + + + if (response.statusCode == 200) { + return DataSuccess([]); + } + return DataSuccess([]); + } + + String encounteredExceptionOrError(OperationException exception) { + if (exception.linkException != null) { + return 'Server not running'; + } else { + return exception.graphqlErrors[0].message.toString(); + } + } +} diff --git a/lib/data/datasource/remote/remote_home_api.dart b/lib/data/datasource/remote/remote_home_api.dart new file mode 100644 index 00000000..16f237cf --- /dev/null +++ b/lib/data/datasource/remote/remote_home_api.dart @@ -0,0 +1,210 @@ +import 'dart:developer'; +import 'package:beacon/core/queries/group.dart'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/data/models/group/group_model.dart'; +import 'package:beacon/data/models/subscriptions/updated_group_model/updated_group_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/locator.dart'; +import 'package:flutter/material.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; + +class RemoteHomeApi { + late GraphQLClient _authClient; + late GraphQLClient _subscriptionClient; + RemoteHomeApi(this._authClient, this._subscriptionClient); + + final _groupQueries = GroupQueries(); + + void loadClient(GraphQLClient authClient, GraphQLClient subscriptionClient) { + this._authClient = authClient; + this._subscriptionClient = subscriptionClient; + } + + Future>> fetchUserGroups( + int page, int pageSize) async { + final isConnected = await utils.checkInternetConnectivity(); + + 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 result = await _authClient.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> fetchGroup(String id) async { + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) + return DataFailed('Beacon is trying to connect with internet...'); + final result = await _authClient + .mutate(MutationOptions(document: gql(_groupQueries.groupDetail(id)))); + + if (result.data != null && result.isConcrete) { + GroupModel group = GroupModel.fromJson(result.data!['group']); + + // storing group + await localApi.saveGroup(group); + + return DataSuccess(group); + } + + 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 result = await _authClient.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 result = await _authClient.mutate( + MutationOptions(document: gql(_groupQueries.joinGroup(shortCode)))); + + + + if (result.data != null && result.isConcrete) { + GroupModel group = GroupModel.fromJson( + result.data!['joinGroup'] as Map); + + // storing group + await localApi.saveGroup(group); + + return DataSuccess(group); + } + + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + + SubscriptionOptions? groupsSubscription; + + Stream> groupUpdateSubscription( + List groupIds) async* { + // Check for internet connectivity + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) { + yield DataFailed('Beacon is trying to connect with internet...'); + return; + } + + // Initialize GraphQL client + final subscriptionOptions = SubscriptionOptions( + document: _groupQueries.groupUpdateSubGql, + variables: {'groupIds': groupIds}, + ); + final resultStream = + await _subscriptionClient.subscribe(subscriptionOptions); + + // Listen to the subscription stream + await for (var result in resultStream) { + if (result.hasException) { + yield DataFailed(result.exception.toString()); + continue; + } + + if (result.data == null || + !result.isConcrete || + result.data!['groupUpdate'] == null) { + continue; + } + + final groupUpdateJson = + result.data!['groupUpdate'] as Map; + + UpdatedGroupModel updatedGroup = + UpdatedGroupModel.fromJson(groupUpdateJson); + + yield DataSuccess(updatedGroup); + } + } + + Future> changeShortCode(String groupId) async { + final isConnected = await utils.checkInternetConnectivity(); + + if (!isConnected) + return DataFailed('Beacon is trying to connect with internet...'); + + final result = await _authClient.mutate( + MutationOptions(document: gql(_groupQueries.changeShortCode(groupId)))); + + if (result.data != null && + result.isConcrete && + result.data!['changeShortcode'] != null) { + return DataSuccess(GroupModel.fromJson(result.data!['changeShortcode'])); + } else { + return DataFailed(encounteredExceptionOrError(result.exception!)); + } + } + + String encounteredExceptionOrError(OperationException exception) { + if (exception.linkException != null) { + debugPrint(exception.linkException.toString()); + return 'Something went wrong'; + } else { + return exception.graphqlErrors[0].message.toString(); + } + } +} diff --git a/lib/data/models/beacon/beacon_model.dart b/lib/data/models/beacon/beacon_model.dart new file mode 100644 index 00000000..75b690aa --- /dev/null +++ b/lib/data/models/beacon/beacon_model.dart @@ -0,0 +1,98 @@ +import 'package:beacon/data/models/geofence/geofence_model.dart'; +import 'package:beacon/data/models/group/group_model.dart'; +import 'package:beacon/data/models/landmark/landmark_model.dart'; +import 'package:beacon/data/models/location/location_model.dart'; +import 'package:beacon/data/models/subscriptions/user_location_model/user_location_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/geofence/geofence_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/user_location_entity/user_location_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 { + @JsonKey(name: '_id') + @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; + @HiveField(11) + GeofenceModel? geofence; + @HiveField(12) + List? membersLocation; + + BeaconModel( + {this.id, + this.title, + this.leader, + this.group, + this.shortcode, + this.followers, + this.landmarks, + this.location, + this.route, + this.startsAt, + this.expiresAt, + this.geofence, + this.membersLocation}); + + @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, + GeofenceModel? geofence, + List? membersLocation}) { + 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, + geofence: geofence ?? this.geofence, + membersLocation: membersLocation ?? this.membersLocation); + } +} diff --git a/lib/Bloc/data/models/beacon/beacon_model.g.dart b/lib/data/models/beacon/beacon_model.g.dart similarity index 83% rename from lib/Bloc/data/models/beacon/beacon_model.g.dart rename to lib/data/models/beacon/beacon_model.g.dart index 2797f1d2..e79bf840 100644 --- a/lib/Bloc/data/models/beacon/beacon_model.g.dart +++ b/lib/data/models/beacon/beacon_model.g.dart @@ -28,13 +28,15 @@ class BeaconModelAdapter extends TypeAdapter { route: (fields[8] as List?)?.cast(), startsAt: fields[9] as int?, expiresAt: fields[10] as int?, + geofence: fields[11] as GeofenceModel?, + membersLocation: (fields[12] as List?)?.cast(), ); } @override void write(BinaryWriter writer, BeaconModel obj) { writer - ..writeByte(11) + ..writeByte(13) ..writeByte(0) ..write(obj.id) ..writeByte(1) @@ -56,7 +58,11 @@ class BeaconModelAdapter extends TypeAdapter { ..writeByte(9) ..write(obj.startsAt) ..writeByte(10) - ..write(obj.expiresAt); + ..write(obj.expiresAt) + ..writeByte(11) + ..write(obj.geofence) + ..writeByte(12) + ..write(obj.membersLocation); } @override @@ -75,7 +81,7 @@ class BeaconModelAdapter extends TypeAdapter { // ************************************************************************** BeaconModel _$BeaconModelFromJson(Map json) => BeaconModel( - id: json['id'] as String?, + id: json['_id'] as String?, title: json['title'] as String?, leader: json['leader'] == null ? null @@ -103,11 +109,19 @@ BeaconModel _$BeaconModelFromJson(Map json) => BeaconModel( .toList(), startsAt: (json['startsAt'] as num?)?.toInt(), expiresAt: (json['expiresAt'] as num?)?.toInt(), + geofence: json['geofence'] == null + ? null + : GeofenceModel.fromJson(json['geofence'] as Map), + membersLocation: (json['membersLocation'] as List?) + ?.map((e) => e == null + ? null + : UserLocationModel.fromJson(e as Map)) + .toList(), ); Map _$BeaconModelToJson(BeaconModel instance) => { - 'id': instance.id, + '_id': instance.id, 'title': instance.title, 'leader': instance.leader, 'group': instance.group, @@ -118,4 +132,6 @@ Map _$BeaconModelToJson(BeaconModel instance) => 'route': instance.route, 'startsAt': instance.startsAt, 'expiresAt': instance.expiresAt, + 'geofence': instance.geofence, + 'membersLocation': instance.membersLocation, }; diff --git a/lib/data/models/geofence/geofence_model.dart b/lib/data/models/geofence/geofence_model.dart new file mode 100644 index 00000000..865edcca --- /dev/null +++ b/lib/data/models/geofence/geofence_model.dart @@ -0,0 +1,25 @@ +import 'package:beacon/data/models/location/location_model.dart'; +import 'package:beacon/domain/entities/geofence/geofence_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:hive/hive.dart'; + +part 'geofence_model.g.dart'; + +@JsonSerializable() +class GeofenceModel implements GeofenceEntity { + @HiveField(0) + final double? radius; + @HiveField(1) + final LocationModel? center; + + const GeofenceModel({this.center, this.radius}); + + factory GeofenceModel.fromJson(Map json) => + _$GeofenceModelFromJson(json); + + Map toJson() => _$GeofenceModelToJson(this); + + @override + $GeofenceEntityCopyWith get copyWith => + throw UnimplementedError(); +} diff --git a/lib/data/models/geofence/geofence_model.g.dart b/lib/data/models/geofence/geofence_model.g.dart new file mode 100644 index 00000000..c6d87c08 --- /dev/null +++ b/lib/data/models/geofence/geofence_model.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'geofence_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +GeofenceModel _$GeofenceModelFromJson(Map json) => + GeofenceModel( + center: json['center'] == null + ? null + : LocationModel.fromJson(json['center'] as Map), + radius: (json['radius'] as num?)?.toDouble(), + ); + +Map _$GeofenceModelToJson(GeofenceModel instance) => + { + 'radius': instance.radius, + 'center': instance.center, + }; diff --git a/lib/Bloc/data/models/group/group_model.dart b/lib/data/models/group/group_model.dart similarity index 79% rename from lib/Bloc/data/models/group/group_model.dart rename to lib/data/models/group/group_model.dart index faa45dca..84e60329 100644 --- a/lib/Bloc/data/models/group/group_model.dart +++ b/lib/data/models/group/group_model.dart @@ -1,6 +1,6 @@ -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:beacon/data/models/beacon/beacon_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; import 'package:hive/hive.dart'; import 'package:json_annotation/json_annotation.dart'; part 'group_model.g.dart'; @@ -8,6 +8,7 @@ part 'group_model.g.dart'; @HiveType(typeId: 30) @JsonSerializable() class GroupModel implements GroupEntity { + @JsonKey(name: '_id') @HiveField(0) String? id; @HiveField(1) @@ -55,4 +56,10 @@ class GroupModel implements GroupEntity { beacons: beacons ?? this.beacons, ); } + + @override + bool get hasBeaconActivity => false; + + @override + bool get hasMemberActivity => false; } diff --git a/lib/Bloc/data/models/group/group_model.g.dart b/lib/data/models/group/group_model.g.dart similarity index 97% rename from lib/Bloc/data/models/group/group_model.g.dart rename to lib/data/models/group/group_model.g.dart index 30507246..64d110e5 100644 --- a/lib/Bloc/data/models/group/group_model.g.dart +++ b/lib/data/models/group/group_model.g.dart @@ -60,7 +60,7 @@ class GroupModelAdapter extends TypeAdapter { // ************************************************************************** GroupModel _$GroupModelFromJson(Map json) => GroupModel( - id: json['id'] as String?, + id: json['_id'] as String?, title: json['title'] as String?, leader: json['leader'] == null ? null @@ -79,7 +79,7 @@ GroupModel _$GroupModelFromJson(Map json) => GroupModel( Map _$GroupModelToJson(GroupModel instance) => { - 'id': instance.id, + '_id': instance.id, 'title': instance.title, 'leader': instance.leader, 'members': instance.members, diff --git a/lib/data/models/landmark/landmark_model.dart b/lib/data/models/landmark/landmark_model.dart new file mode 100644 index 00000000..1a16319f --- /dev/null +++ b/lib/data/models/landmark/landmark_model.dart @@ -0,0 +1,45 @@ +import 'package:beacon/data/models/location/location_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/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; + @JsonKey(name: '_id') + @HiveField(2) + String? id; + @HiveField(3) + UserModel? createdBy; + + LandMarkModel({this.title, this.location, this.id, this.createdBy}); + + @override + $LandMarkEntityCopyWith get copyWith => + throw UnimplementedError(); + + factory LandMarkModel.fromJson(Map json) => + _$LandMarkModelFromJson(json); + + Map toJson() => _$LandMarkModelToJson(this); + + LandMarkModel copyWithModel( + {String? id, + String? title, + LocationModel? location, + UserModel? createdBy}) { + return LandMarkModel( + id: id, + title: title ?? this.title, + location: location ?? this.location, + createdBy: createdBy ?? this.createdBy); + } +} diff --git a/lib/Bloc/data/models/landmark/landmark_model.g.dart b/lib/data/models/landmark/landmark_model.g.dart similarity index 80% rename from lib/Bloc/data/models/landmark/landmark_model.g.dart rename to lib/data/models/landmark/landmark_model.g.dart index 272a500b..96a59958 100644 --- a/lib/Bloc/data/models/landmark/landmark_model.g.dart +++ b/lib/data/models/landmark/landmark_model.g.dart @@ -19,17 +19,23 @@ class LandMarkModelAdapter extends TypeAdapter { return LandMarkModel( title: fields[0] as String?, location: fields[1] as LocationModel?, + id: fields[2] as String?, + createdBy: fields[3] as UserModel?, ); } @override void write(BinaryWriter writer, LandMarkModel obj) { writer - ..writeByte(2) + ..writeByte(4) ..writeByte(0) ..write(obj.title) ..writeByte(1) - ..write(obj.location); + ..write(obj.location) + ..writeByte(2) + ..write(obj.id) + ..writeByte(3) + ..write(obj.createdBy); } @override @@ -53,10 +59,16 @@ LandMarkModel _$LandMarkModelFromJson(Map json) => location: json['location'] == null ? null : LocationModel.fromJson(json['location'] as Map), + id: json['_id'] as String?, + createdBy: json['createdBy'] == null + ? null + : UserModel.fromJson(json['createdBy'] as Map), ); Map _$LandMarkModelToJson(LandMarkModel instance) => { 'title': instance.title, 'location': instance.location, + '_id': instance.id, + 'createdBy': instance.createdBy, }; diff --git a/lib/Bloc/data/models/location/location_model.dart b/lib/data/models/location/location_model.dart similarity index 81% rename from lib/Bloc/data/models/location/location_model.dart rename to lib/data/models/location/location_model.dart index 79701b6f..53ebaf98 100644 --- a/lib/Bloc/data/models/location/location_model.dart +++ b/lib/data/models/location/location_model.dart @@ -1,7 +1,7 @@ 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'; +import 'package:beacon/domain/entities/location/location_entity.dart'; part 'location_model.g.dart'; @HiveType(typeId: 40) @@ -11,8 +11,12 @@ class LocationModel implements LocationEntity { final String? lat; @HiveField(1) final String? lon; + @JsonKey(name: '_id') + @HiveField(2) + final String? id; LocationModel({ + this.id, this.lat, this.lon, }); @@ -23,10 +27,12 @@ class LocationModel implements LocationEntity { Map toJson() => _$LocationModelToJson(this); LocationModel copyWithModel({ + String? id, String? lat, String? long, }) { return LocationModel( + id: id ?? this.id, lat: lat ?? this.lat, lon: lon ?? this.lon, ); diff --git a/lib/Bloc/data/models/location/location_model.g.dart b/lib/data/models/location/location_model.g.dart similarity index 91% rename from lib/Bloc/data/models/location/location_model.g.dart rename to lib/data/models/location/location_model.g.dart index 174fae3f..adec4317 100644 --- a/lib/Bloc/data/models/location/location_model.g.dart +++ b/lib/data/models/location/location_model.g.dart @@ -17,6 +17,7 @@ class LocationModelAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return LocationModel( + id: fields[2] as String?, lat: fields[0] as String?, lon: fields[1] as String?, ); @@ -25,11 +26,13 @@ class LocationModelAdapter extends TypeAdapter { @override void write(BinaryWriter writer, LocationModel obj) { writer - ..writeByte(2) + ..writeByte(3) ..writeByte(0) ..write(obj.lat) ..writeByte(1) - ..write(obj.lon); + ..write(obj.lon) + ..writeByte(2) + ..write(obj.id); } @override @@ -49,6 +52,7 @@ class LocationModelAdapter extends TypeAdapter { LocationModel _$LocationModelFromJson(Map json) => LocationModel( + id: json['_id'] as String?, lat: json['lat'] as String?, lon: json['lon'] as String?, ); @@ -57,4 +61,5 @@ Map _$LocationModelToJson(LocationModel instance) => { 'lat': instance.lat, 'lon': instance.lon, + '_id': instance.id, }; diff --git a/lib/data/models/subscriptions/beacon_locations_model/beacon_locations_model.dart b/lib/data/models/subscriptions/beacon_locations_model/beacon_locations_model.dart new file mode 100644 index 00000000..423270b0 --- /dev/null +++ b/lib/data/models/subscriptions/beacon_locations_model/beacon_locations_model.dart @@ -0,0 +1,29 @@ +import 'package:beacon/data/models/geofence/geofence_model.dart'; +import 'package:beacon/data/models/landmark/landmark_model.dart'; +import 'package:beacon/data/models/location/location_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/subscriptions/beacon_locations_entity/beacon_locations_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'beacon_locations_model.g.dart'; + +@JsonSerializable() +class BeaconLocationsModel implements BeaconLocationsEntity { + UserModel? userSOS; + List? route; + LandMarkModel? landmark; + GeofenceModel? geofence; + @JsonKey(name: 'updatedUser') + UserModel? user; + + BeaconLocationsModel( + {this.userSOS, this.route, this.geofence, this.landmark, this.user}); + + factory BeaconLocationsModel.fromJson(Map json) => + _$BeaconLocationsModelFromJson(json); + + Map toJson() => _$BeaconLocationsModelToJson(this); + + @override + $BeaconLocationsEntityCopyWith get copyWith => + throw UnimplementedError(); +} diff --git a/lib/data/models/subscriptions/beacon_locations_model/beacon_locations_model.g.dart b/lib/data/models/subscriptions/beacon_locations_model/beacon_locations_model.g.dart new file mode 100644 index 00000000..74e366d7 --- /dev/null +++ b/lib/data/models/subscriptions/beacon_locations_model/beacon_locations_model.g.dart @@ -0,0 +1,39 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'beacon_locations_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +BeaconLocationsModel _$BeaconLocationsModelFromJson( + Map json) => + BeaconLocationsModel( + userSOS: json['userSOS'] == null + ? null + : UserModel.fromJson(json['userSOS'] as Map), + route: (json['route'] as List?) + ?.map((e) => e == null + ? null + : LocationModel.fromJson(e as Map)) + .toList(), + geofence: json['geofence'] == null + ? null + : GeofenceModel.fromJson(json['geofence'] as Map), + landmark: json['landmark'] == null + ? null + : LandMarkModel.fromJson(json['landmark'] as Map), + user: json['updatedUser'] == null + ? null + : UserModel.fromJson(json['updatedUser'] as Map), + ); + +Map _$BeaconLocationsModelToJson( + BeaconLocationsModel instance) => + { + 'userSOS': instance.userSOS, + 'route': instance.route, + 'landmark': instance.landmark, + 'geofence': instance.geofence, + 'updatedUser': instance.user, + }; diff --git a/lib/data/models/subscriptions/join_leave_beacon_model/join_leave_beacon_model.dart b/lib/data/models/subscriptions/join_leave_beacon_model/join_leave_beacon_model.dart new file mode 100644 index 00000000..23c1513d --- /dev/null +++ b/lib/data/models/subscriptions/join_leave_beacon_model/join_leave_beacon_model.dart @@ -0,0 +1,21 @@ +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'join_leave_beacon_model.g.dart'; + +@JsonSerializable() +class JoinLeaveBeaconModel implements JoinLeaveBeaconEntity { + UserModel? inactiveuser; + UserModel? newfollower; + + JoinLeaveBeaconModel({this.inactiveuser, this.newfollower}); + + @override + $JoinLeaveBeaconEntityCopyWith get copyWith => + throw UnimplementedError(); + + factory JoinLeaveBeaconModel.fromJson(Map json) => + _$JoinLeaveBeaconModelFromJson(json); + + Map toJson() => _$JoinLeaveBeaconModelToJson(this); +} diff --git a/lib/data/models/subscriptions/join_leave_beacon_model/join_leave_beacon_model.g.dart b/lib/data/models/subscriptions/join_leave_beacon_model/join_leave_beacon_model.g.dart new file mode 100644 index 00000000..43b93503 --- /dev/null +++ b/lib/data/models/subscriptions/join_leave_beacon_model/join_leave_beacon_model.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'join_leave_beacon_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +JoinLeaveBeaconModel _$JoinLeaveBeaconModelFromJson( + Map json) => + JoinLeaveBeaconModel( + inactiveuser: json['inactiveuser'] == null + ? null + : UserModel.fromJson(json['inactiveuser'] as Map), + newfollower: json['newfollower'] == null + ? null + : UserModel.fromJson(json['newfollower'] as Map), + ); + +Map _$JoinLeaveBeaconModelToJson( + JoinLeaveBeaconModel instance) => + { + 'inactiveuser': instance.inactiveuser, + 'newfollower': instance.newfollower, + }; diff --git a/lib/data/models/subscriptions/updated_group_model/updated_group_model.dart b/lib/data/models/subscriptions/updated_group_model/updated_group_model.dart new file mode 100644 index 00000000..2a4315e9 --- /dev/null +++ b/lib/data/models/subscriptions/updated_group_model/updated_group_model.dart @@ -0,0 +1,32 @@ +import 'package:beacon/data/models/beacon/beacon_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/subscriptions/updated_group_entity/updated_group_entity.dart'; +import 'package:json_annotation/json_annotation.dart'; +part 'updated_group_model.g.dart'; + +@JsonSerializable() +class UpdatedGroupModel implements UpdatedGroupEntity { + @JsonKey(name: 'groupId') + String? id; + UserModel? newUser; + BeaconModel? newBeacon; + BeaconModel? updatedBeacon; + BeaconModel? deletedBeacon; + + UpdatedGroupModel({ + this.id, + this.newUser, + this.newBeacon, + this.updatedBeacon, + this.deletedBeacon, + }); + + factory UpdatedGroupModel.fromJson(Map json) => + _$UpdatedGroupModelFromJson(json); + + Map toJson() => _$UpdatedGroupModelToJson(this); + + @override + $UpdatedGroupEntityCopyWith get copyWith => + throw UnimplementedError(); +} diff --git a/lib/data/models/subscriptions/updated_group_model/updated_group_model.g.dart b/lib/data/models/subscriptions/updated_group_model/updated_group_model.g.dart new file mode 100644 index 00000000..aafb3d59 --- /dev/null +++ b/lib/data/models/subscriptions/updated_group_model/updated_group_model.g.dart @@ -0,0 +1,33 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'updated_group_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +UpdatedGroupModel _$UpdatedGroupModelFromJson(Map json) => + UpdatedGroupModel( + id: json['groupId'] as String?, + newUser: json['newUser'] == null + ? null + : UserModel.fromJson(json['newUser'] as Map), + newBeacon: json['newBeacon'] == null + ? null + : BeaconModel.fromJson(json['newBeacon'] as Map), + updatedBeacon: json['updatedBeacon'] == null + ? null + : BeaconModel.fromJson(json['updatedBeacon'] as Map), + deletedBeacon: json['deletedBeacon'] == null + ? null + : BeaconModel.fromJson(json['deletedBeacon'] as Map), + ); + +Map _$UpdatedGroupModelToJson(UpdatedGroupModel instance) => + { + 'groupId': instance.id, + 'newUser': instance.newUser, + 'newBeacon': instance.newBeacon, + 'updatedBeacon': instance.updatedBeacon, + 'deletedBeacon': instance.deletedBeacon, + }; diff --git a/lib/data/models/subscriptions/user_location_model/user_location_model.dart b/lib/data/models/subscriptions/user_location_model/user_location_model.dart new file mode 100644 index 00000000..bab51735 --- /dev/null +++ b/lib/data/models/subscriptions/user_location_model/user_location_model.dart @@ -0,0 +1,24 @@ +import 'package:beacon/data/models/location/location_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/location/location_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/user_location_entity/user_location_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'user_location_model.g.dart'; + +@JsonSerializable() +class UserLocationModel implements UserLocationEntity { + UserModel? user; + LocationModel? location; + + UserLocationModel({this.user, this.location}); + + factory UserLocationModel.fromJson(Map json) => + _$UserLocationModelFromJson(json); + + Map toJson() => _$UserLocationModelToJson(this); + + @override + $UserLocationEntityCopyWith get copyWith => + throw UnimplementedError(); +} diff --git a/lib/data/models/subscriptions/user_location_model/user_location_model.g.dart b/lib/data/models/subscriptions/user_location_model/user_location_model.g.dart new file mode 100644 index 00000000..37565e47 --- /dev/null +++ b/lib/data/models/subscriptions/user_location_model/user_location_model.g.dart @@ -0,0 +1,23 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user_location_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +UserLocationModel _$UserLocationModelFromJson(Map json) => + UserLocationModel( + user: json['user'] == null + ? null + : UserModel.fromJson(json['user'] as Map), + location: json['location'] == null + ? null + : LocationModel.fromJson(json['location'] as Map), + ); + +Map _$UserLocationModelToJson(UserLocationModel instance) => + { + 'user': instance.user, + 'location': instance.location, + }; diff --git a/lib/Bloc/data/models/user/user_model.dart b/lib/data/models/user/user_model.dart similarity index 60% rename from lib/Bloc/data/models/user/user_model.dart rename to lib/data/models/user/user_model.dart index 41bcd7be..1c2b61d6 100644 --- a/lib/Bloc/data/models/user/user_model.dart +++ b/lib/data/models/user/user_model.dart @@ -1,7 +1,7 @@ -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:beacon/data/models/beacon/beacon_model.dart'; +import 'package:beacon/data/models/group/group_model.dart'; +import 'package:beacon/data/models/location/location_model.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; import 'package:hive/hive.dart'; import 'package:json_annotation/json_annotation.dart'; @@ -10,6 +10,7 @@ part 'user_model.g.dart'; @HiveType(typeId: 10) @JsonSerializable() class UserModel implements UserEntity { + @JsonKey(name: '_id') @HiveField(0) String? id; @@ -34,6 +35,9 @@ class UserModel implements UserEntity { @HiveField(7) LocationModel? location; + @HiveField(8) + bool? isVerified; + UserModel( {this.authToken, this.beacons, @@ -42,7 +46,8 @@ class UserModel implements UserEntity { this.id, this.isGuest, this.location, - this.name}); + this.name, + this.isVerified}); @override $UserEntityCopyWith get copyWith => throw UnimplementedError(); @@ -58,19 +63,20 @@ class UserModel implements UserEntity { String? authToken, String? email, bool? isGuest, + bool? isVerified, 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, - ); + 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, + isVerified: isVerified ?? this.isVerified); } } diff --git a/lib/Bloc/data/models/user/user_model.g.dart b/lib/data/models/user/user_model.g.dart similarity index 91% rename from lib/Bloc/data/models/user/user_model.g.dart rename to lib/data/models/user/user_model.g.dart index b1df148f..45bb58a0 100644 --- a/lib/Bloc/data/models/user/user_model.g.dart +++ b/lib/data/models/user/user_model.g.dart @@ -25,13 +25,14 @@ class UserModelAdapter extends TypeAdapter { isGuest: fields[4] as bool?, location: fields[7] as LocationModel?, name: fields[1] as String?, + isVerified: fields[8] as bool?, ); } @override void write(BinaryWriter writer, UserModel obj) { writer - ..writeByte(8) + ..writeByte(9) ..writeByte(0) ..write(obj.id) ..writeByte(1) @@ -47,7 +48,9 @@ class UserModelAdapter extends TypeAdapter { ..writeByte(6) ..write(obj.beacons) ..writeByte(7) - ..write(obj.location); + ..write(obj.location) + ..writeByte(8) + ..write(obj.isVerified); } @override @@ -77,16 +80,17 @@ UserModel _$UserModelFromJson(Map json) => UserModel( ?.map((e) => e == null ? null : GroupModel.fromJson(e as Map)) .toList(), - id: json['id'] as String?, + 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?, + isVerified: json['isVerified'] as bool?, ); Map _$UserModelToJson(UserModel instance) => { - 'id': instance.id, + '_id': instance.id, 'name': instance.name, 'email': instance.email, 'authToken': instance.authToken, @@ -94,4 +98,5 @@ Map _$UserModelToJson(UserModel instance) => { 'groups': instance.groups, 'beacons': instance.beacons, 'location': instance.location, + 'isVerified': instance.isVerified, }; diff --git a/lib/data/repositories/auth_repository_implementation.dart b/lib/data/repositories/auth_repository_implementation.dart new file mode 100644 index 00000000..6e49853d --- /dev/null +++ b/lib/data/repositories/auth_repository_implementation.dart @@ -0,0 +1,36 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/data/datasource/remote/remote_auth_api.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/domain/repositories/auth_repository.dart'; + +class AuthRepositoryImplementation implements 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); + } + + Future> sendVerificationCode() { + return remoteAuthApi.sendVerificationCode(); + } + + @override + Future> completeVerification() { + return remoteAuthApi.completeVerification(); + } +} diff --git a/lib/data/repositories/group_repository_implementation.dart b/lib/data/repositories/group_repository_implementation.dart new file mode 100644 index 00000000..ad4f213e --- /dev/null +++ b/lib/data/repositories/group_repository_implementation.dart @@ -0,0 +1,56 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/data/datasource/remote/remote_group_api.dart'; +import 'package:beacon/data/models/beacon/beacon_model.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/domain/repositories/group_repository.dart'; + +class GroupRepostioryImplementation implements 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); + } + + @override + Future>> nearbyHikes( + String groupId, String lat, String lon, double radius) { + return remoteGroupApi.nearbyBeacons(groupId, lat, lon, radius); + } + + @override + Future>> filterHikes( + String groupId, String type) { + return remoteGroupApi.filterBeacons(groupId, type); + } + + @override + Future> deleteBeacon(String? beaconId) { + return remoteGroupApi.deleteBeacon(beaconId); + } + + @override + Future> rescheduleHike( + int expiresAt, int startsAt, String beaconId) { + return remoteGroupApi.rescheduleBeacon(expiresAt, startsAt, beaconId); + } + + @override + Future> removeMember(String groupId, String memberId) { + return remoteGroupApi.removeMember(groupId, memberId); + } +} diff --git a/lib/data/repositories/hike_repository_implementation.dart b/lib/data/repositories/hike_repository_implementation.dart new file mode 100644 index 00000000..826ec42d --- /dev/null +++ b/lib/data/repositories/hike_repository_implementation.dart @@ -0,0 +1,89 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/data/datasource/remote/remote_hike_api.dart'; +import 'package:beacon/data/models/beacon/beacon_model.dart'; +import 'package:beacon/data/models/landmark/landmark_model.dart'; +import 'package:beacon/data/models/location/location_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/geofence/geofence_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/beacon_locations_entity/beacon_locations_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/domain/repositories/hike_repository.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +class HikeRepositoryImplementatioin implements HikeRepository { + final RemoteHikeApi remoteHikeApi; + + HikeRepositoryImplementatioin({required this.remoteHikeApi}); + + @override + Stream> beaconLocationSubscription(String beaconId) { + return remoteHikeApi.beaconLocationSubscription(beaconId); + } + + @override + Future> fetchBeaconDetails(String beaconId) { + return remoteHikeApi.fetchBeaconDetails(beaconId); + } + + @override + Future> updateBeaconLocation( + String beaconId, LatLng position) { + return remoteHikeApi.updateBeaconLocation( + beaconId, position.latitude.toString(), position.longitude.toString()); + } + + @override + Stream> beaconJoinedSubscription(String beaconId) { + return remoteHikeApi.beaconJoinedSubscription(beaconId); + } + + @override + Stream beaconUpdateSubscription(String beaconId) { + return remoteHikeApi.beaconUpdateSubscription(beaconId); + } + + @override + Future> createLandMark( + String id, String title, String lat, String lon) { + return remoteHikeApi.createLandMark(id, lat, lon, title); + } + + @override + Stream> beaconLocationsSubscription( + String beaconId) { + return remoteHikeApi.locationUpdateSubscription(beaconId); + } + + @override + Stream> joinLeaveBeaconSubscription( + String beaconId) { + return remoteHikeApi.LeaveJoinBeaconSubscription(beaconId); + } + + @override + Future> changeUserLocation(String id, LatLng latLng) { + return remoteHikeApi.changeUserLocation(id, latLng); + } + + @override + Future> createGeofence( + String beaconId, LatLng latlng, double radius) { + return remoteHikeApi.createGeofence(beaconId, latlng, radius); + } + + @override + Future> addRoute(String id, LatLng latlng) { + return remoteHikeApi.addRoute(id, latlng); + } + + @override + Future>> getRoute(List latlng) { + return remoteHikeApi.getRoute(latlng); + } + + @override + Future> sos(String beaconId) { + return remoteHikeApi.sos(beaconId); + } +} diff --git a/lib/data/repositories/home_repository_implementation.dart b/lib/data/repositories/home_repository_implementation.dart new file mode 100644 index 00000000..3804d64e --- /dev/null +++ b/lib/data/repositories/home_repository_implementation.dart @@ -0,0 +1,43 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/data/datasource/remote/remote_home_api.dart'; +import 'package:beacon/data/models/group/group_model.dart'; +import 'package:beacon/data/models/subscriptions/updated_group_model/updated_group_model.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/domain/repositories/home_repository.dart'; + +class HomeRepostitoryImplementation implements 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); + } + + @override + Stream> groupUpdateSubscription( + List groupIds) { + return remoteHomeApi.groupUpdateSubscription(groupIds); + } + + @override + Future> fetchGroup(String groupId) { + return remoteHomeApi.fetchGroup(groupId); + } + + @override + Future> changeShortcode(String groupId) { + return remoteHomeApi.changeShortCode(groupId); + } +} diff --git a/lib/domain/entities/beacon/beacon_entity.dart b/lib/domain/entities/beacon/beacon_entity.dart new file mode 100644 index 00000000..13205286 --- /dev/null +++ b/lib/domain/entities/beacon/beacon_entity.dart @@ -0,0 +1,59 @@ +import 'package:beacon/domain/entities/geofence/geofence_entity.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/domain/entities/landmark/landmark_entity.dart'; +import 'package:beacon/domain/entities/location/location_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/user_location_entity/user_location_entity.dart'; +import 'package:beacon/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, + GeofenceEntity? geofence, + List? membersLocation, + }) = _BeaconEntity; +} + +extension BeaconEntityCopyWithExtension on BeaconEntity { + BeaconEntity copywith( + {String? id, + String? shortcode, + int? startsAt, + int? expiresAt, + String? title, + UserEntity? leader, + List? followers, + List? route, + List? landmarks, + LocationEntity? location, + GroupEntity? group, + GeofenceEntity? geofence, + List? membersLocation}) { + return BeaconEntity( + id: id ?? this.id, + shortcode: shortcode ?? this.shortcode, + startsAt: startsAt ?? this.startsAt, + expiresAt: expiresAt ?? this.expiresAt, + title: title ?? this.title, + leader: leader ?? this.leader, + followers: followers ?? this.followers, + route: route ?? this.route, + landmarks: landmarks ?? this.landmarks, + location: location ?? this.location, + group: group ?? this.group, + geofence: geofence ?? this.geofence, + membersLocation: membersLocation ?? this.membersLocation); + } +} diff --git a/lib/Bloc/domain/entities/beacon/beacon_entity.freezed.dart b/lib/domain/entities/beacon/beacon_entity.freezed.dart similarity index 82% rename from lib/Bloc/domain/entities/beacon/beacon_entity.freezed.dart rename to lib/domain/entities/beacon/beacon_entity.freezed.dart index a623a54b..e5f1c54d 100644 --- a/lib/Bloc/domain/entities/beacon/beacon_entity.freezed.dart +++ b/lib/domain/entities/beacon/beacon_entity.freezed.dart @@ -27,6 +27,9 @@ mixin _$BeaconEntity { List? get landmarks => throw _privateConstructorUsedError; LocationEntity? get location => throw _privateConstructorUsedError; GroupEntity? get group => throw _privateConstructorUsedError; + GeofenceEntity? get geofence => throw _privateConstructorUsedError; + List? get membersLocation => + throw _privateConstructorUsedError; @JsonKey(ignore: true) $BeaconEntityCopyWith get copyWith => @@ -50,11 +53,14 @@ abstract class $BeaconEntityCopyWith<$Res> { List? route, List? landmarks, LocationEntity? location, - GroupEntity? group}); + GroupEntity? group, + GeofenceEntity? geofence, + List? membersLocation}); $UserEntityCopyWith<$Res>? get leader; $LocationEntityCopyWith<$Res>? get location; $GroupEntityCopyWith<$Res>? get group; + $GeofenceEntityCopyWith<$Res>? get geofence; } /// @nodoc @@ -81,6 +87,8 @@ class _$BeaconEntityCopyWithImpl<$Res, $Val extends BeaconEntity> Object? landmarks = freezed, Object? location = freezed, Object? group = freezed, + Object? geofence = freezed, + Object? membersLocation = freezed, }) { return _then(_value.copyWith( id: freezed == id @@ -127,6 +135,14 @@ class _$BeaconEntityCopyWithImpl<$Res, $Val extends BeaconEntity> ? _value.group : group // ignore: cast_nullable_to_non_nullable as GroupEntity?, + geofence: freezed == geofence + ? _value.geofence + : geofence // ignore: cast_nullable_to_non_nullable + as GeofenceEntity?, + membersLocation: freezed == membersLocation + ? _value.membersLocation + : membersLocation // ignore: cast_nullable_to_non_nullable + as List?, ) as $Val); } @@ -165,6 +181,18 @@ class _$BeaconEntityCopyWithImpl<$Res, $Val extends BeaconEntity> return _then(_value.copyWith(group: value) as $Val); }); } + + @override + @pragma('vm:prefer-inline') + $GeofenceEntityCopyWith<$Res>? get geofence { + if (_value.geofence == null) { + return null; + } + + return $GeofenceEntityCopyWith<$Res>(_value.geofence!, (value) { + return _then(_value.copyWith(geofence: value) as $Val); + }); + } } /// @nodoc @@ -186,7 +214,9 @@ abstract class _$$BeaconEntityImplCopyWith<$Res> List? route, List? landmarks, LocationEntity? location, - GroupEntity? group}); + GroupEntity? group, + GeofenceEntity? geofence, + List? membersLocation}); @override $UserEntityCopyWith<$Res>? get leader; @@ -194,6 +224,8 @@ abstract class _$$BeaconEntityImplCopyWith<$Res> $LocationEntityCopyWith<$Res>? get location; @override $GroupEntityCopyWith<$Res>? get group; + @override + $GeofenceEntityCopyWith<$Res>? get geofence; } /// @nodoc @@ -218,6 +250,8 @@ class __$$BeaconEntityImplCopyWithImpl<$Res> Object? landmarks = freezed, Object? location = freezed, Object? group = freezed, + Object? geofence = freezed, + Object? membersLocation = freezed, }) { return _then(_$BeaconEntityImpl( id: freezed == id @@ -264,6 +298,14 @@ class __$$BeaconEntityImplCopyWithImpl<$Res> ? _value.group : group // ignore: cast_nullable_to_non_nullable as GroupEntity?, + geofence: freezed == geofence + ? _value.geofence + : geofence // ignore: cast_nullable_to_non_nullable + as GeofenceEntity?, + membersLocation: freezed == membersLocation + ? _value._membersLocation + : membersLocation // ignore: cast_nullable_to_non_nullable + as List?, )); } } @@ -282,10 +324,13 @@ class _$BeaconEntityImpl implements _BeaconEntity { final List? route, final List? landmarks, this.location, - this.group}) + this.group, + this.geofence, + final List? membersLocation}) : _followers = followers, _route = route, - _landmarks = landmarks; + _landmarks = landmarks, + _membersLocation = membersLocation; @override final String? id; @@ -333,10 +378,21 @@ class _$BeaconEntityImpl implements _BeaconEntity { final LocationEntity? location; @override final GroupEntity? group; + @override + final GeofenceEntity? geofence; + final List? _membersLocation; + @override + List? get membersLocation { + final value = _membersLocation; + if (value == null) return null; + if (_membersLocation is EqualUnmodifiableListView) return _membersLocation; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } @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)'; + return 'BeaconEntity(id: $id, shortcode: $shortcode, startsAt: $startsAt, expiresAt: $expiresAt, title: $title, leader: $leader, followers: $followers, route: $route, landmarks: $landmarks, location: $location, group: $group, geofence: $geofence, membersLocation: $membersLocation)'; } @override @@ -360,7 +416,11 @@ class _$BeaconEntityImpl implements _BeaconEntity { .equals(other._landmarks, _landmarks) && (identical(other.location, location) || other.location == location) && - (identical(other.group, group) || other.group == group)); + (identical(other.group, group) || other.group == group) && + (identical(other.geofence, geofence) || + other.geofence == geofence) && + const DeepCollectionEquality() + .equals(other._membersLocation, _membersLocation)); } @override @@ -376,7 +436,9 @@ class _$BeaconEntityImpl implements _BeaconEntity { const DeepCollectionEquality().hash(_route), const DeepCollectionEquality().hash(_landmarks), location, - group); + group, + geofence, + const DeepCollectionEquality().hash(_membersLocation)); @JsonKey(ignore: true) @override @@ -397,7 +459,9 @@ abstract class _BeaconEntity implements BeaconEntity { final List? route, final List? landmarks, final LocationEntity? location, - final GroupEntity? group}) = _$BeaconEntityImpl; + final GroupEntity? group, + final GeofenceEntity? geofence, + final List? membersLocation}) = _$BeaconEntityImpl; @override String? get id; @@ -422,6 +486,10 @@ abstract class _BeaconEntity implements BeaconEntity { @override GroupEntity? get group; @override + GeofenceEntity? get geofence; + @override + List? get membersLocation; + @override @JsonKey(ignore: true) _$$BeaconEntityImplCopyWith<_$BeaconEntityImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/lib/domain/entities/geofence/geofence_entity.dart b/lib/domain/entities/geofence/geofence_entity.dart new file mode 100644 index 00000000..e20869d8 --- /dev/null +++ b/lib/domain/entities/geofence/geofence_entity.dart @@ -0,0 +1,9 @@ +import 'package:beacon/domain/entities/location/location_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'geofence_entity.freezed.dart'; + +@freezed +class GeofenceEntity with _$GeofenceEntity { + factory GeofenceEntity({LocationEntity? center, double? radius}) = + _GeofenceEntity; +} diff --git a/lib/domain/entities/geofence/geofence_entity.freezed.dart b/lib/domain/entities/geofence/geofence_entity.freezed.dart new file mode 100644 index 00000000..42f7db3d --- /dev/null +++ b/lib/domain/entities/geofence/geofence_entity.freezed.dart @@ -0,0 +1,168 @@ +// 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 'geofence_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 _$GeofenceEntity { + LocationEntity? get center => throw _privateConstructorUsedError; + double? get radius => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $GeofenceEntityCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $GeofenceEntityCopyWith<$Res> { + factory $GeofenceEntityCopyWith( + GeofenceEntity value, $Res Function(GeofenceEntity) then) = + _$GeofenceEntityCopyWithImpl<$Res, GeofenceEntity>; + @useResult + $Res call({LocationEntity? center, double? radius}); + + $LocationEntityCopyWith<$Res>? get center; +} + +/// @nodoc +class _$GeofenceEntityCopyWithImpl<$Res, $Val extends GeofenceEntity> + implements $GeofenceEntityCopyWith<$Res> { + _$GeofenceEntityCopyWithImpl(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? center = freezed, + Object? radius = freezed, + }) { + return _then(_value.copyWith( + center: freezed == center + ? _value.center + : center // ignore: cast_nullable_to_non_nullable + as LocationEntity?, + radius: freezed == radius + ? _value.radius + : radius // ignore: cast_nullable_to_non_nullable + as double?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $LocationEntityCopyWith<$Res>? get center { + if (_value.center == null) { + return null; + } + + return $LocationEntityCopyWith<$Res>(_value.center!, (value) { + return _then(_value.copyWith(center: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$GeofenceEntityImplCopyWith<$Res> + implements $GeofenceEntityCopyWith<$Res> { + factory _$$GeofenceEntityImplCopyWith(_$GeofenceEntityImpl value, + $Res Function(_$GeofenceEntityImpl) then) = + __$$GeofenceEntityImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({LocationEntity? center, double? radius}); + + @override + $LocationEntityCopyWith<$Res>? get center; +} + +/// @nodoc +class __$$GeofenceEntityImplCopyWithImpl<$Res> + extends _$GeofenceEntityCopyWithImpl<$Res, _$GeofenceEntityImpl> + implements _$$GeofenceEntityImplCopyWith<$Res> { + __$$GeofenceEntityImplCopyWithImpl( + _$GeofenceEntityImpl _value, $Res Function(_$GeofenceEntityImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? center = freezed, + Object? radius = freezed, + }) { + return _then(_$GeofenceEntityImpl( + center: freezed == center + ? _value.center + : center // ignore: cast_nullable_to_non_nullable + as LocationEntity?, + radius: freezed == radius + ? _value.radius + : radius // ignore: cast_nullable_to_non_nullable + as double?, + )); + } +} + +/// @nodoc + +class _$GeofenceEntityImpl implements _GeofenceEntity { + _$GeofenceEntityImpl({this.center, this.radius}); + + @override + final LocationEntity? center; + @override + final double? radius; + + @override + String toString() { + return 'GeofenceEntity(center: $center, radius: $radius)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$GeofenceEntityImpl && + (identical(other.center, center) || other.center == center) && + (identical(other.radius, radius) || other.radius == radius)); + } + + @override + int get hashCode => Object.hash(runtimeType, center, radius); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$GeofenceEntityImplCopyWith<_$GeofenceEntityImpl> get copyWith => + __$$GeofenceEntityImplCopyWithImpl<_$GeofenceEntityImpl>( + this, _$identity); +} + +abstract class _GeofenceEntity implements GeofenceEntity { + factory _GeofenceEntity( + {final LocationEntity? center, + final double? radius}) = _$GeofenceEntityImpl; + + @override + LocationEntity? get center; + @override + double? get radius; + @override + @JsonKey(ignore: true) + _$$GeofenceEntityImplCopyWith<_$GeofenceEntityImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/domain/entities/group/group_entity.dart b/lib/domain/entities/group/group_entity.dart new file mode 100644 index 00000000..a4cd0e44 --- /dev/null +++ b/lib/domain/entities/group/group_entity.dart @@ -0,0 +1,39 @@ +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/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, + @Default(false) bool hasBeaconActivity, + @Default(false) bool hasMemberActivity}) = _GroupEntity; +} + +extension GroupEntityCopyWithExtension on GroupEntity { + GroupEntity copywith( + {String? id, + List? beacons, + List? members, + UserEntity? leader, + String? title, + String? shortcode, + bool? hasBeaconActiby, + bool? hasMemberActivity}) { + return GroupEntity( + id: id ?? this.id, + beacons: beacons ?? this.beacons, + members: members ?? this.members, + leader: leader ?? this.leader, + title: title ?? this.title, + shortcode: shortcode ?? this.shortcode, + hasBeaconActivity: hasBeaconActiby ?? this.hasBeaconActivity, + hasMemberActivity: hasMemberActivity ?? this.hasMemberActivity); + } +} diff --git a/lib/Bloc/domain/entities/group/group_entity.freezed.dart b/lib/domain/entities/group/group_entity.freezed.dart similarity index 79% rename from lib/Bloc/domain/entities/group/group_entity.freezed.dart rename to lib/domain/entities/group/group_entity.freezed.dart index c601ea0a..74507d02 100644 --- a/lib/Bloc/domain/entities/group/group_entity.freezed.dart +++ b/lib/domain/entities/group/group_entity.freezed.dart @@ -22,6 +22,8 @@ mixin _$GroupEntity { UserEntity? get leader => throw _privateConstructorUsedError; String? get title => throw _privateConstructorUsedError; String? get shortcode => throw _privateConstructorUsedError; + bool get hasBeaconActivity => throw _privateConstructorUsedError; + bool get hasMemberActivity => throw _privateConstructorUsedError; @JsonKey(ignore: true) $GroupEntityCopyWith get copyWith => @@ -40,7 +42,9 @@ abstract class $GroupEntityCopyWith<$Res> { List? members, UserEntity? leader, String? title, - String? shortcode}); + String? shortcode, + bool hasBeaconActivity, + bool hasMemberActivity}); $UserEntityCopyWith<$Res>? get leader; } @@ -64,6 +68,8 @@ class _$GroupEntityCopyWithImpl<$Res, $Val extends GroupEntity> Object? leader = freezed, Object? title = freezed, Object? shortcode = freezed, + Object? hasBeaconActivity = null, + Object? hasMemberActivity = null, }) { return _then(_value.copyWith( id: freezed == id @@ -90,6 +96,14 @@ class _$GroupEntityCopyWithImpl<$Res, $Val extends GroupEntity> ? _value.shortcode : shortcode // ignore: cast_nullable_to_non_nullable as String?, + hasBeaconActivity: null == hasBeaconActivity + ? _value.hasBeaconActivity + : hasBeaconActivity // ignore: cast_nullable_to_non_nullable + as bool, + hasMemberActivity: null == hasMemberActivity + ? _value.hasMemberActivity + : hasMemberActivity // ignore: cast_nullable_to_non_nullable + as bool, ) as $Val); } @@ -120,7 +134,9 @@ abstract class _$$GroupEntityImplCopyWith<$Res> List? members, UserEntity? leader, String? title, - String? shortcode}); + String? shortcode, + bool hasBeaconActivity, + bool hasMemberActivity}); @override $UserEntityCopyWith<$Res>? get leader; @@ -143,6 +159,8 @@ class __$$GroupEntityImplCopyWithImpl<$Res> Object? leader = freezed, Object? title = freezed, Object? shortcode = freezed, + Object? hasBeaconActivity = null, + Object? hasMemberActivity = null, }) { return _then(_$GroupEntityImpl( id: freezed == id @@ -169,6 +187,14 @@ class __$$GroupEntityImplCopyWithImpl<$Res> ? _value.shortcode : shortcode // ignore: cast_nullable_to_non_nullable as String?, + hasBeaconActivity: null == hasBeaconActivity + ? _value.hasBeaconActivity + : hasBeaconActivity // ignore: cast_nullable_to_non_nullable + as bool, + hasMemberActivity: null == hasMemberActivity + ? _value.hasMemberActivity + : hasMemberActivity // ignore: cast_nullable_to_non_nullable + as bool, )); } } @@ -182,7 +208,9 @@ class _$GroupEntityImpl implements _GroupEntity { final List? members, this.leader, this.title, - this.shortcode}) + this.shortcode, + this.hasBeaconActivity = false, + this.hasMemberActivity = false}) : _beacons = beacons, _members = members; @@ -214,10 +242,16 @@ class _$GroupEntityImpl implements _GroupEntity { final String? title; @override final String? shortcode; + @override + @JsonKey() + final bool hasBeaconActivity; + @override + @JsonKey() + final bool hasMemberActivity; @override String toString() { - return 'GroupEntity(id: $id, beacons: $beacons, members: $members, leader: $leader, title: $title, shortcode: $shortcode)'; + return 'GroupEntity(id: $id, beacons: $beacons, members: $members, leader: $leader, title: $title, shortcode: $shortcode, hasBeaconActivity: $hasBeaconActivity, hasMemberActivity: $hasMemberActivity)'; } @override @@ -231,7 +265,11 @@ class _$GroupEntityImpl implements _GroupEntity { (identical(other.leader, leader) || other.leader == leader) && (identical(other.title, title) || other.title == title) && (identical(other.shortcode, shortcode) || - other.shortcode == shortcode)); + other.shortcode == shortcode) && + (identical(other.hasBeaconActivity, hasBeaconActivity) || + other.hasBeaconActivity == hasBeaconActivity) && + (identical(other.hasMemberActivity, hasMemberActivity) || + other.hasMemberActivity == hasMemberActivity)); } @override @@ -242,7 +280,9 @@ class _$GroupEntityImpl implements _GroupEntity { const DeepCollectionEquality().hash(_members), leader, title, - shortcode); + shortcode, + hasBeaconActivity, + hasMemberActivity); @JsonKey(ignore: true) @override @@ -258,7 +298,9 @@ abstract class _GroupEntity implements GroupEntity { final List? members, final UserEntity? leader, final String? title, - final String? shortcode}) = _$GroupEntityImpl; + final String? shortcode, + final bool hasBeaconActivity, + final bool hasMemberActivity}) = _$GroupEntityImpl; @override String? get id; @@ -273,6 +315,10 @@ abstract class _GroupEntity implements GroupEntity { @override String? get shortcode; @override + bool get hasBeaconActivity; + @override + bool get hasMemberActivity; + @override @JsonKey(ignore: true) _$$GroupEntityImplCopyWith<_$GroupEntityImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/lib/domain/entities/landmark/landmark_entity.dart b/lib/domain/entities/landmark/landmark_entity.dart new file mode 100644 index 00000000..e6d6a130 --- /dev/null +++ b/lib/domain/entities/landmark/landmark_entity.dart @@ -0,0 +1,27 @@ +import 'package:beacon/domain/entities/location/location_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'landmark_entity.freezed.dart'; + +@freezed +class LandMarkEntity with _$LandMarkEntity { + const factory LandMarkEntity( + {String? id, + String? title, + LocationEntity? location, + UserEntity? createdBy}) = _LandMarkEntity; +} + +extension LandMarkEntityCopyWithExtension on LandMarkEntity { + LandMarkEntity copywith( + {String? id, + String? title, + LocationEntity? location, + UserEntity? createdBy}) { + return LandMarkEntity( + id: id ?? this.id, + title: title ?? this.title, + location: location ?? this.location, + createdBy: createdBy ?? this.createdBy); + } +} diff --git a/lib/Bloc/domain/entities/landmark/landmark_entity.freezed.dart b/lib/domain/entities/landmark/landmark_entity.freezed.dart similarity index 69% rename from lib/Bloc/domain/entities/landmark/landmark_entity.freezed.dart rename to lib/domain/entities/landmark/landmark_entity.freezed.dart index 3cbebc00..e0aa6955 100644 --- a/lib/Bloc/domain/entities/landmark/landmark_entity.freezed.dart +++ b/lib/domain/entities/landmark/landmark_entity.freezed.dart @@ -16,8 +16,10 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$LandMarkEntity { + String? get id => throw _privateConstructorUsedError; String? get title => throw _privateConstructorUsedError; LocationEntity? get location => throw _privateConstructorUsedError; + UserEntity? get createdBy => throw _privateConstructorUsedError; @JsonKey(ignore: true) $LandMarkEntityCopyWith get copyWith => @@ -30,9 +32,14 @@ abstract class $LandMarkEntityCopyWith<$Res> { LandMarkEntity value, $Res Function(LandMarkEntity) then) = _$LandMarkEntityCopyWithImpl<$Res, LandMarkEntity>; @useResult - $Res call({String? title, LocationEntity? location}); + $Res call( + {String? id, + String? title, + LocationEntity? location, + UserEntity? createdBy}); $LocationEntityCopyWith<$Res>? get location; + $UserEntityCopyWith<$Res>? get createdBy; } /// @nodoc @@ -48,10 +55,16 @@ class _$LandMarkEntityCopyWithImpl<$Res, $Val extends LandMarkEntity> @pragma('vm:prefer-inline') @override $Res call({ + Object? id = freezed, Object? title = freezed, Object? location = freezed, + Object? createdBy = freezed, }) { return _then(_value.copyWith( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, title: freezed == title ? _value.title : title // ignore: cast_nullable_to_non_nullable @@ -60,6 +73,10 @@ class _$LandMarkEntityCopyWithImpl<$Res, $Val extends LandMarkEntity> ? _value.location : location // ignore: cast_nullable_to_non_nullable as LocationEntity?, + createdBy: freezed == createdBy + ? _value.createdBy + : createdBy // ignore: cast_nullable_to_non_nullable + as UserEntity?, ) as $Val); } @@ -74,6 +91,18 @@ class _$LandMarkEntityCopyWithImpl<$Res, $Val extends LandMarkEntity> return _then(_value.copyWith(location: value) as $Val); }); } + + @override + @pragma('vm:prefer-inline') + $UserEntityCopyWith<$Res>? get createdBy { + if (_value.createdBy == null) { + return null; + } + + return $UserEntityCopyWith<$Res>(_value.createdBy!, (value) { + return _then(_value.copyWith(createdBy: value) as $Val); + }); + } } /// @nodoc @@ -84,10 +113,16 @@ abstract class _$$LandMarkEntityImplCopyWith<$Res> __$$LandMarkEntityImplCopyWithImpl<$Res>; @override @useResult - $Res call({String? title, LocationEntity? location}); + $Res call( + {String? id, + String? title, + LocationEntity? location, + UserEntity? createdBy}); @override $LocationEntityCopyWith<$Res>? get location; + @override + $UserEntityCopyWith<$Res>? get createdBy; } /// @nodoc @@ -101,10 +136,16 @@ class __$$LandMarkEntityImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ + Object? id = freezed, Object? title = freezed, Object? location = freezed, + Object? createdBy = freezed, }) { return _then(_$LandMarkEntityImpl( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, title: freezed == title ? _value.title : title // ignore: cast_nullable_to_non_nullable @@ -113,6 +154,10 @@ class __$$LandMarkEntityImplCopyWithImpl<$Res> ? _value.location : location // ignore: cast_nullable_to_non_nullable as LocationEntity?, + createdBy: freezed == createdBy + ? _value.createdBy + : createdBy // ignore: cast_nullable_to_non_nullable + as UserEntity?, )); } } @@ -120,16 +165,21 @@ class __$$LandMarkEntityImplCopyWithImpl<$Res> /// @nodoc class _$LandMarkEntityImpl implements _LandMarkEntity { - const _$LandMarkEntityImpl({this.title, this.location}); + const _$LandMarkEntityImpl( + {this.id, this.title, this.location, this.createdBy}); + @override + final String? id; @override final String? title; @override final LocationEntity? location; + @override + final UserEntity? createdBy; @override String toString() { - return 'LandMarkEntity(title: $title, location: $location)'; + return 'LandMarkEntity(id: $id, title: $title, location: $location, createdBy: $createdBy)'; } @override @@ -137,13 +187,16 @@ class _$LandMarkEntityImpl implements _LandMarkEntity { return identical(this, other) || (other.runtimeType == runtimeType && other is _$LandMarkEntityImpl && + (identical(other.id, id) || other.id == id) && (identical(other.title, title) || other.title == title) && (identical(other.location, location) || - other.location == location)); + other.location == location) && + (identical(other.createdBy, createdBy) || + other.createdBy == createdBy)); } @override - int get hashCode => Object.hash(runtimeType, title, location); + int get hashCode => Object.hash(runtimeType, id, title, location, createdBy); @JsonKey(ignore: true) @override @@ -155,14 +208,20 @@ class _$LandMarkEntityImpl implements _LandMarkEntity { abstract class _LandMarkEntity implements LandMarkEntity { const factory _LandMarkEntity( - {final String? title, - final LocationEntity? location}) = _$LandMarkEntityImpl; + {final String? id, + final String? title, + final LocationEntity? location, + final UserEntity? createdBy}) = _$LandMarkEntityImpl; + @override + String? get id; @override String? get title; @override LocationEntity? get location; @override + UserEntity? get createdBy; + @override @JsonKey(ignore: true) _$$LandMarkEntityImplCopyWith<_$LandMarkEntityImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/lib/domain/entities/location/location_entity.dart b/lib/domain/entities/location/location_entity.dart new file mode 100644 index 00000000..26c43f87 --- /dev/null +++ b/lib/domain/entities/location/location_entity.dart @@ -0,0 +1,22 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'location_entity.freezed.dart'; + +@freezed +class LocationEntity with _$LocationEntity { + factory LocationEntity({String? id, String? lat, String? lon}) = + _LocationEntity; +} + +extension LocationEntityCopyWithExtension on LocationEntity { + LocationEntity copywith({ + String? id, + String? lat, + String? lon, + }) { + return LocationEntity( + id: id ?? this.id, + lat: lat ?? this.lat, + lon: lon ?? this.lon, + ); + } +} diff --git a/lib/Bloc/domain/entities/location/location_entity.freezed.dart b/lib/domain/entities/location/location_entity.freezed.dart similarity index 82% rename from lib/Bloc/domain/entities/location/location_entity.freezed.dart rename to lib/domain/entities/location/location_entity.freezed.dart index 01117b3a..833de3e0 100644 --- a/lib/Bloc/domain/entities/location/location_entity.freezed.dart +++ b/lib/domain/entities/location/location_entity.freezed.dart @@ -16,6 +16,7 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$LocationEntity { + String? get id => throw _privateConstructorUsedError; String? get lat => throw _privateConstructorUsedError; String? get lon => throw _privateConstructorUsedError; @@ -30,7 +31,7 @@ abstract class $LocationEntityCopyWith<$Res> { LocationEntity value, $Res Function(LocationEntity) then) = _$LocationEntityCopyWithImpl<$Res, LocationEntity>; @useResult - $Res call({String? lat, String? lon}); + $Res call({String? id, String? lat, String? lon}); } /// @nodoc @@ -46,10 +47,15 @@ class _$LocationEntityCopyWithImpl<$Res, $Val extends LocationEntity> @pragma('vm:prefer-inline') @override $Res call({ + Object? id = freezed, Object? lat = freezed, Object? lon = freezed, }) { return _then(_value.copyWith( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, lat: freezed == lat ? _value.lat : lat // ignore: cast_nullable_to_non_nullable @@ -70,7 +76,7 @@ abstract class _$$LocationEntityImplCopyWith<$Res> __$$LocationEntityImplCopyWithImpl<$Res>; @override @useResult - $Res call({String? lat, String? lon}); + $Res call({String? id, String? lat, String? lon}); } /// @nodoc @@ -84,10 +90,15 @@ class __$$LocationEntityImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ + Object? id = freezed, Object? lat = freezed, Object? lon = freezed, }) { return _then(_$LocationEntityImpl( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, lat: freezed == lat ? _value.lat : lat // ignore: cast_nullable_to_non_nullable @@ -103,8 +114,10 @@ class __$$LocationEntityImplCopyWithImpl<$Res> /// @nodoc class _$LocationEntityImpl implements _LocationEntity { - _$LocationEntityImpl({this.lat, this.lon}); + _$LocationEntityImpl({this.id, this.lat, this.lon}); + @override + final String? id; @override final String? lat; @override @@ -112,7 +125,7 @@ class _$LocationEntityImpl implements _LocationEntity { @override String toString() { - return 'LocationEntity(lat: $lat, lon: $lon)'; + return 'LocationEntity(id: $id, lat: $lat, lon: $lon)'; } @override @@ -120,12 +133,13 @@ class _$LocationEntityImpl implements _LocationEntity { return identical(this, other) || (other.runtimeType == runtimeType && other is _$LocationEntityImpl && + (identical(other.id, id) || other.id == id) && (identical(other.lat, lat) || other.lat == lat) && (identical(other.lon, lon) || other.lon == lon)); } @override - int get hashCode => Object.hash(runtimeType, lat, lon); + int get hashCode => Object.hash(runtimeType, id, lat, lon); @JsonKey(ignore: true) @override @@ -136,9 +150,13 @@ class _$LocationEntityImpl implements _LocationEntity { } abstract class _LocationEntity implements LocationEntity { - factory _LocationEntity({final String? lat, final String? lon}) = - _$LocationEntityImpl; + factory _LocationEntity( + {final String? id, + final String? lat, + final String? lon}) = _$LocationEntityImpl; + @override + String? get id; @override String? get lat; @override diff --git a/lib/domain/entities/subscriptions/beacon_locations_entity/beacon_locations_entity.dart b/lib/domain/entities/subscriptions/beacon_locations_entity/beacon_locations_entity.dart new file mode 100644 index 00000000..00fdbd43 --- /dev/null +++ b/lib/domain/entities/subscriptions/beacon_locations_entity/beacon_locations_entity.dart @@ -0,0 +1,18 @@ +import 'package:beacon/domain/entities/geofence/geofence_entity.dart'; +import 'package:beacon/domain/entities/landmark/landmark_entity.dart'; +import 'package:beacon/domain/entities/location/location_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +part 'beacon_locations_entity.freezed.dart'; + +@freezed +class BeaconLocationsEntity with _$BeaconLocationsEntity { + factory BeaconLocationsEntity({ + UserEntity? userSOS, + List? route, + GeofenceEntity? geofence, + LandMarkEntity? landmark, + UserEntity? user, + }) = _BeaconLocationsEntity; +} diff --git a/lib/domain/entities/subscriptions/beacon_locations_entity/beacon_locations_entity.freezed.dart b/lib/domain/entities/subscriptions/beacon_locations_entity/beacon_locations_entity.freezed.dart new file mode 100644 index 00000000..b8757e60 --- /dev/null +++ b/lib/domain/entities/subscriptions/beacon_locations_entity/beacon_locations_entity.freezed.dart @@ -0,0 +1,294 @@ +// 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_locations_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 _$BeaconLocationsEntity { + UserEntity? get userSOS => throw _privateConstructorUsedError; + List? get route => throw _privateConstructorUsedError; + GeofenceEntity? get geofence => throw _privateConstructorUsedError; + LandMarkEntity? get landmark => throw _privateConstructorUsedError; + UserEntity? get user => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $BeaconLocationsEntityCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $BeaconLocationsEntityCopyWith<$Res> { + factory $BeaconLocationsEntityCopyWith(BeaconLocationsEntity value, + $Res Function(BeaconLocationsEntity) then) = + _$BeaconLocationsEntityCopyWithImpl<$Res, BeaconLocationsEntity>; + @useResult + $Res call( + {UserEntity? userSOS, + List? route, + GeofenceEntity? geofence, + LandMarkEntity? landmark, + UserEntity? user}); + + $UserEntityCopyWith<$Res>? get userSOS; + $GeofenceEntityCopyWith<$Res>? get geofence; + $LandMarkEntityCopyWith<$Res>? get landmark; + $UserEntityCopyWith<$Res>? get user; +} + +/// @nodoc +class _$BeaconLocationsEntityCopyWithImpl<$Res, + $Val extends BeaconLocationsEntity> + implements $BeaconLocationsEntityCopyWith<$Res> { + _$BeaconLocationsEntityCopyWithImpl(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? userSOS = freezed, + Object? route = freezed, + Object? geofence = freezed, + Object? landmark = freezed, + Object? user = freezed, + }) { + return _then(_value.copyWith( + userSOS: freezed == userSOS + ? _value.userSOS + : userSOS // ignore: cast_nullable_to_non_nullable + as UserEntity?, + route: freezed == route + ? _value.route + : route // ignore: cast_nullable_to_non_nullable + as List?, + geofence: freezed == geofence + ? _value.geofence + : geofence // ignore: cast_nullable_to_non_nullable + as GeofenceEntity?, + landmark: freezed == landmark + ? _value.landmark + : landmark // ignore: cast_nullable_to_non_nullable + as LandMarkEntity?, + user: freezed == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as UserEntity?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $UserEntityCopyWith<$Res>? get userSOS { + if (_value.userSOS == null) { + return null; + } + + return $UserEntityCopyWith<$Res>(_value.userSOS!, (value) { + return _then(_value.copyWith(userSOS: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $GeofenceEntityCopyWith<$Res>? get geofence { + if (_value.geofence == null) { + return null; + } + + return $GeofenceEntityCopyWith<$Res>(_value.geofence!, (value) { + return _then(_value.copyWith(geofence: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $LandMarkEntityCopyWith<$Res>? get landmark { + if (_value.landmark == null) { + return null; + } + + return $LandMarkEntityCopyWith<$Res>(_value.landmark!, (value) { + return _then(_value.copyWith(landmark: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $UserEntityCopyWith<$Res>? get user { + if (_value.user == null) { + return null; + } + + return $UserEntityCopyWith<$Res>(_value.user!, (value) { + return _then(_value.copyWith(user: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$BeaconLocationsEntityImplCopyWith<$Res> + implements $BeaconLocationsEntityCopyWith<$Res> { + factory _$$BeaconLocationsEntityImplCopyWith( + _$BeaconLocationsEntityImpl value, + $Res Function(_$BeaconLocationsEntityImpl) then) = + __$$BeaconLocationsEntityImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {UserEntity? userSOS, + List? route, + GeofenceEntity? geofence, + LandMarkEntity? landmark, + UserEntity? user}); + + @override + $UserEntityCopyWith<$Res>? get userSOS; + @override + $GeofenceEntityCopyWith<$Res>? get geofence; + @override + $LandMarkEntityCopyWith<$Res>? get landmark; + @override + $UserEntityCopyWith<$Res>? get user; +} + +/// @nodoc +class __$$BeaconLocationsEntityImplCopyWithImpl<$Res> + extends _$BeaconLocationsEntityCopyWithImpl<$Res, + _$BeaconLocationsEntityImpl> + implements _$$BeaconLocationsEntityImplCopyWith<$Res> { + __$$BeaconLocationsEntityImplCopyWithImpl(_$BeaconLocationsEntityImpl _value, + $Res Function(_$BeaconLocationsEntityImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? userSOS = freezed, + Object? route = freezed, + Object? geofence = freezed, + Object? landmark = freezed, + Object? user = freezed, + }) { + return _then(_$BeaconLocationsEntityImpl( + userSOS: freezed == userSOS + ? _value.userSOS + : userSOS // ignore: cast_nullable_to_non_nullable + as UserEntity?, + route: freezed == route + ? _value._route + : route // ignore: cast_nullable_to_non_nullable + as List?, + geofence: freezed == geofence + ? _value.geofence + : geofence // ignore: cast_nullable_to_non_nullable + as GeofenceEntity?, + landmark: freezed == landmark + ? _value.landmark + : landmark // ignore: cast_nullable_to_non_nullable + as LandMarkEntity?, + user: freezed == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as UserEntity?, + )); + } +} + +/// @nodoc + +class _$BeaconLocationsEntityImpl implements _BeaconLocationsEntity { + _$BeaconLocationsEntityImpl( + {this.userSOS, + final List? route, + this.geofence, + this.landmark, + this.user}) + : _route = route; + + @override + final UserEntity? userSOS; + 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); + } + + @override + final GeofenceEntity? geofence; + @override + final LandMarkEntity? landmark; + @override + final UserEntity? user; + + @override + String toString() { + return 'BeaconLocationsEntity(userSOS: $userSOS, route: $route, geofence: $geofence, landmark: $landmark, user: $user)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BeaconLocationsEntityImpl && + (identical(other.userSOS, userSOS) || other.userSOS == userSOS) && + const DeepCollectionEquality().equals(other._route, _route) && + (identical(other.geofence, geofence) || + other.geofence == geofence) && + (identical(other.landmark, landmark) || + other.landmark == landmark) && + (identical(other.user, user) || other.user == user)); + } + + @override + int get hashCode => Object.hash(runtimeType, userSOS, + const DeepCollectionEquality().hash(_route), geofence, landmark, user); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$BeaconLocationsEntityImplCopyWith<_$BeaconLocationsEntityImpl> + get copyWith => __$$BeaconLocationsEntityImplCopyWithImpl< + _$BeaconLocationsEntityImpl>(this, _$identity); +} + +abstract class _BeaconLocationsEntity implements BeaconLocationsEntity { + factory _BeaconLocationsEntity( + {final UserEntity? userSOS, + final List? route, + final GeofenceEntity? geofence, + final LandMarkEntity? landmark, + final UserEntity? user}) = _$BeaconLocationsEntityImpl; + + @override + UserEntity? get userSOS; + @override + List? get route; + @override + GeofenceEntity? get geofence; + @override + LandMarkEntity? get landmark; + @override + UserEntity? get user; + @override + @JsonKey(ignore: true) + _$$BeaconLocationsEntityImplCopyWith<_$BeaconLocationsEntityImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.dart b/lib/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.dart new file mode 100644 index 00000000..2900bed4 --- /dev/null +++ b/lib/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.dart @@ -0,0 +1,10 @@ +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'join_leave_beacon_entity.freezed.dart'; + +@freezed +class JoinLeaveBeaconEntity with _$JoinLeaveBeaconEntity { + factory JoinLeaveBeaconEntity( + {UserEntity? newfollower, + UserEntity? inactiveuser}) = _JoinLeaveBeaconEntity; +} diff --git a/lib/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.freezed.dart b/lib/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.freezed.dart new file mode 100644 index 00000000..51bd776c --- /dev/null +++ b/lib/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.freezed.dart @@ -0,0 +1,188 @@ +// 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 'join_leave_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 _$JoinLeaveBeaconEntity { + UserEntity? get newfollower => throw _privateConstructorUsedError; + UserEntity? get inactiveuser => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $JoinLeaveBeaconEntityCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $JoinLeaveBeaconEntityCopyWith<$Res> { + factory $JoinLeaveBeaconEntityCopyWith(JoinLeaveBeaconEntity value, + $Res Function(JoinLeaveBeaconEntity) then) = + _$JoinLeaveBeaconEntityCopyWithImpl<$Res, JoinLeaveBeaconEntity>; + @useResult + $Res call({UserEntity? newfollower, UserEntity? inactiveuser}); + + $UserEntityCopyWith<$Res>? get newfollower; + $UserEntityCopyWith<$Res>? get inactiveuser; +} + +/// @nodoc +class _$JoinLeaveBeaconEntityCopyWithImpl<$Res, + $Val extends JoinLeaveBeaconEntity> + implements $JoinLeaveBeaconEntityCopyWith<$Res> { + _$JoinLeaveBeaconEntityCopyWithImpl(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? newfollower = freezed, + Object? inactiveuser = freezed, + }) { + return _then(_value.copyWith( + newfollower: freezed == newfollower + ? _value.newfollower + : newfollower // ignore: cast_nullable_to_non_nullable + as UserEntity?, + inactiveuser: freezed == inactiveuser + ? _value.inactiveuser + : inactiveuser // ignore: cast_nullable_to_non_nullable + as UserEntity?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $UserEntityCopyWith<$Res>? get newfollower { + if (_value.newfollower == null) { + return null; + } + + return $UserEntityCopyWith<$Res>(_value.newfollower!, (value) { + return _then(_value.copyWith(newfollower: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $UserEntityCopyWith<$Res>? get inactiveuser { + if (_value.inactiveuser == null) { + return null; + } + + return $UserEntityCopyWith<$Res>(_value.inactiveuser!, (value) { + return _then(_value.copyWith(inactiveuser: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$JoinLeaveBeaconEntityImplCopyWith<$Res> + implements $JoinLeaveBeaconEntityCopyWith<$Res> { + factory _$$JoinLeaveBeaconEntityImplCopyWith( + _$JoinLeaveBeaconEntityImpl value, + $Res Function(_$JoinLeaveBeaconEntityImpl) then) = + __$$JoinLeaveBeaconEntityImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({UserEntity? newfollower, UserEntity? inactiveuser}); + + @override + $UserEntityCopyWith<$Res>? get newfollower; + @override + $UserEntityCopyWith<$Res>? get inactiveuser; +} + +/// @nodoc +class __$$JoinLeaveBeaconEntityImplCopyWithImpl<$Res> + extends _$JoinLeaveBeaconEntityCopyWithImpl<$Res, + _$JoinLeaveBeaconEntityImpl> + implements _$$JoinLeaveBeaconEntityImplCopyWith<$Res> { + __$$JoinLeaveBeaconEntityImplCopyWithImpl(_$JoinLeaveBeaconEntityImpl _value, + $Res Function(_$JoinLeaveBeaconEntityImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? newfollower = freezed, + Object? inactiveuser = freezed, + }) { + return _then(_$JoinLeaveBeaconEntityImpl( + newfollower: freezed == newfollower + ? _value.newfollower + : newfollower // ignore: cast_nullable_to_non_nullable + as UserEntity?, + inactiveuser: freezed == inactiveuser + ? _value.inactiveuser + : inactiveuser // ignore: cast_nullable_to_non_nullable + as UserEntity?, + )); + } +} + +/// @nodoc + +class _$JoinLeaveBeaconEntityImpl implements _JoinLeaveBeaconEntity { + _$JoinLeaveBeaconEntityImpl({this.newfollower, this.inactiveuser}); + + @override + final UserEntity? newfollower; + @override + final UserEntity? inactiveuser; + + @override + String toString() { + return 'JoinLeaveBeaconEntity(newfollower: $newfollower, inactiveuser: $inactiveuser)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$JoinLeaveBeaconEntityImpl && + (identical(other.newfollower, newfollower) || + other.newfollower == newfollower) && + (identical(other.inactiveuser, inactiveuser) || + other.inactiveuser == inactiveuser)); + } + + @override + int get hashCode => Object.hash(runtimeType, newfollower, inactiveuser); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$JoinLeaveBeaconEntityImplCopyWith<_$JoinLeaveBeaconEntityImpl> + get copyWith => __$$JoinLeaveBeaconEntityImplCopyWithImpl< + _$JoinLeaveBeaconEntityImpl>(this, _$identity); +} + +abstract class _JoinLeaveBeaconEntity implements JoinLeaveBeaconEntity { + factory _JoinLeaveBeaconEntity( + {final UserEntity? newfollower, + final UserEntity? inactiveuser}) = _$JoinLeaveBeaconEntityImpl; + + @override + UserEntity? get newfollower; + @override + UserEntity? get inactiveuser; + @override + @JsonKey(ignore: true) + _$$JoinLeaveBeaconEntityImplCopyWith<_$JoinLeaveBeaconEntityImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/domain/entities/subscriptions/updated_group_entity/updated_group_entity.dart b/lib/domain/entities/subscriptions/updated_group_entity/updated_group_entity.dart new file mode 100644 index 00000000..d74dc9e0 --- /dev/null +++ b/lib/domain/entities/subscriptions/updated_group_entity/updated_group_entity.dart @@ -0,0 +1,32 @@ +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'updated_group_entity.freezed.dart'; + +@freezed +class UpdatedGroupEntity with _$UpdatedGroupEntity { + factory UpdatedGroupEntity( + {String? id, + BeaconEntity? deletedBeacon, + BeaconEntity? updatedBeacon, + BeaconEntity? newBeacon, + UserEntity? newUser}) = _UpdatedGroupEntity; +} + +extension UpdatedGroupEntityCopyWithExtension on UpdatedGroupEntity { + UpdatedGroupEntity copywith({ + String? id, + BeaconEntity? deletedBeacon, + BeaconEntity? updatedBeacon, + BeaconEntity? newBeacon, + UserEntity? newUser, + }) { + return UpdatedGroupEntity( + id: id ?? this.id, + deletedBeacon: deletedBeacon ?? this.deletedBeacon, + updatedBeacon: updatedBeacon ?? this.updatedBeacon, + newBeacon: newBeacon ?? this.newBeacon, + newUser: newUser ?? this.newUser, + ); + } +} diff --git a/lib/domain/entities/subscriptions/updated_group_entity/updated_group_entity.freezed.dart b/lib/domain/entities/subscriptions/updated_group_entity/updated_group_entity.freezed.dart new file mode 100644 index 00000000..2e18afd3 --- /dev/null +++ b/lib/domain/entities/subscriptions/updated_group_entity/updated_group_entity.freezed.dart @@ -0,0 +1,283 @@ +// 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 'updated_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 _$UpdatedGroupEntity { + String? get id => throw _privateConstructorUsedError; + BeaconEntity? get deletedBeacon => throw _privateConstructorUsedError; + BeaconEntity? get updatedBeacon => throw _privateConstructorUsedError; + BeaconEntity? get newBeacon => throw _privateConstructorUsedError; + UserEntity? get newUser => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $UpdatedGroupEntityCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $UpdatedGroupEntityCopyWith<$Res> { + factory $UpdatedGroupEntityCopyWith( + UpdatedGroupEntity value, $Res Function(UpdatedGroupEntity) then) = + _$UpdatedGroupEntityCopyWithImpl<$Res, UpdatedGroupEntity>; + @useResult + $Res call( + {String? id, + BeaconEntity? deletedBeacon, + BeaconEntity? updatedBeacon, + BeaconEntity? newBeacon, + UserEntity? newUser}); + + $BeaconEntityCopyWith<$Res>? get deletedBeacon; + $BeaconEntityCopyWith<$Res>? get updatedBeacon; + $BeaconEntityCopyWith<$Res>? get newBeacon; + $UserEntityCopyWith<$Res>? get newUser; +} + +/// @nodoc +class _$UpdatedGroupEntityCopyWithImpl<$Res, $Val extends UpdatedGroupEntity> + implements $UpdatedGroupEntityCopyWith<$Res> { + _$UpdatedGroupEntityCopyWithImpl(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? deletedBeacon = freezed, + Object? updatedBeacon = freezed, + Object? newBeacon = freezed, + Object? newUser = freezed, + }) { + return _then(_value.copyWith( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + deletedBeacon: freezed == deletedBeacon + ? _value.deletedBeacon + : deletedBeacon // ignore: cast_nullable_to_non_nullable + as BeaconEntity?, + updatedBeacon: freezed == updatedBeacon + ? _value.updatedBeacon + : updatedBeacon // ignore: cast_nullable_to_non_nullable + as BeaconEntity?, + newBeacon: freezed == newBeacon + ? _value.newBeacon + : newBeacon // ignore: cast_nullable_to_non_nullable + as BeaconEntity?, + newUser: freezed == newUser + ? _value.newUser + : newUser // ignore: cast_nullable_to_non_nullable + as UserEntity?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $BeaconEntityCopyWith<$Res>? get deletedBeacon { + if (_value.deletedBeacon == null) { + return null; + } + + return $BeaconEntityCopyWith<$Res>(_value.deletedBeacon!, (value) { + return _then(_value.copyWith(deletedBeacon: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $BeaconEntityCopyWith<$Res>? get updatedBeacon { + if (_value.updatedBeacon == null) { + return null; + } + + return $BeaconEntityCopyWith<$Res>(_value.updatedBeacon!, (value) { + return _then(_value.copyWith(updatedBeacon: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $BeaconEntityCopyWith<$Res>? get newBeacon { + if (_value.newBeacon == null) { + return null; + } + + return $BeaconEntityCopyWith<$Res>(_value.newBeacon!, (value) { + return _then(_value.copyWith(newBeacon: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $UserEntityCopyWith<$Res>? get newUser { + if (_value.newUser == null) { + return null; + } + + return $UserEntityCopyWith<$Res>(_value.newUser!, (value) { + return _then(_value.copyWith(newUser: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$UpdatedGroupEntityImplCopyWith<$Res> + implements $UpdatedGroupEntityCopyWith<$Res> { + factory _$$UpdatedGroupEntityImplCopyWith(_$UpdatedGroupEntityImpl value, + $Res Function(_$UpdatedGroupEntityImpl) then) = + __$$UpdatedGroupEntityImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String? id, + BeaconEntity? deletedBeacon, + BeaconEntity? updatedBeacon, + BeaconEntity? newBeacon, + UserEntity? newUser}); + + @override + $BeaconEntityCopyWith<$Res>? get deletedBeacon; + @override + $BeaconEntityCopyWith<$Res>? get updatedBeacon; + @override + $BeaconEntityCopyWith<$Res>? get newBeacon; + @override + $UserEntityCopyWith<$Res>? get newUser; +} + +/// @nodoc +class __$$UpdatedGroupEntityImplCopyWithImpl<$Res> + extends _$UpdatedGroupEntityCopyWithImpl<$Res, _$UpdatedGroupEntityImpl> + implements _$$UpdatedGroupEntityImplCopyWith<$Res> { + __$$UpdatedGroupEntityImplCopyWithImpl(_$UpdatedGroupEntityImpl _value, + $Res Function(_$UpdatedGroupEntityImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? deletedBeacon = freezed, + Object? updatedBeacon = freezed, + Object? newBeacon = freezed, + Object? newUser = freezed, + }) { + return _then(_$UpdatedGroupEntityImpl( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + deletedBeacon: freezed == deletedBeacon + ? _value.deletedBeacon + : deletedBeacon // ignore: cast_nullable_to_non_nullable + as BeaconEntity?, + updatedBeacon: freezed == updatedBeacon + ? _value.updatedBeacon + : updatedBeacon // ignore: cast_nullable_to_non_nullable + as BeaconEntity?, + newBeacon: freezed == newBeacon + ? _value.newBeacon + : newBeacon // ignore: cast_nullable_to_non_nullable + as BeaconEntity?, + newUser: freezed == newUser + ? _value.newUser + : newUser // ignore: cast_nullable_to_non_nullable + as UserEntity?, + )); + } +} + +/// @nodoc + +class _$UpdatedGroupEntityImpl implements _UpdatedGroupEntity { + _$UpdatedGroupEntityImpl( + {this.id, + this.deletedBeacon, + this.updatedBeacon, + this.newBeacon, + this.newUser}); + + @override + final String? id; + @override + final BeaconEntity? deletedBeacon; + @override + final BeaconEntity? updatedBeacon; + @override + final BeaconEntity? newBeacon; + @override + final UserEntity? newUser; + + @override + String toString() { + return 'UpdatedGroupEntity(id: $id, deletedBeacon: $deletedBeacon, updatedBeacon: $updatedBeacon, newBeacon: $newBeacon, newUser: $newUser)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$UpdatedGroupEntityImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.deletedBeacon, deletedBeacon) || + other.deletedBeacon == deletedBeacon) && + (identical(other.updatedBeacon, updatedBeacon) || + other.updatedBeacon == updatedBeacon) && + (identical(other.newBeacon, newBeacon) || + other.newBeacon == newBeacon) && + (identical(other.newUser, newUser) || other.newUser == newUser)); + } + + @override + int get hashCode => Object.hash( + runtimeType, id, deletedBeacon, updatedBeacon, newBeacon, newUser); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$UpdatedGroupEntityImplCopyWith<_$UpdatedGroupEntityImpl> get copyWith => + __$$UpdatedGroupEntityImplCopyWithImpl<_$UpdatedGroupEntityImpl>( + this, _$identity); +} + +abstract class _UpdatedGroupEntity implements UpdatedGroupEntity { + factory _UpdatedGroupEntity( + {final String? id, + final BeaconEntity? deletedBeacon, + final BeaconEntity? updatedBeacon, + final BeaconEntity? newBeacon, + final UserEntity? newUser}) = _$UpdatedGroupEntityImpl; + + @override + String? get id; + @override + BeaconEntity? get deletedBeacon; + @override + BeaconEntity? get updatedBeacon; + @override + BeaconEntity? get newBeacon; + @override + UserEntity? get newUser; + @override + @JsonKey(ignore: true) + _$$UpdatedGroupEntityImplCopyWith<_$UpdatedGroupEntityImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/domain/entities/subscriptions/user_location_entity/user_location_entity.dart b/lib/domain/entities/subscriptions/user_location_entity/user_location_entity.dart new file mode 100644 index 00000000..3476c112 --- /dev/null +++ b/lib/domain/entities/subscriptions/user_location_entity/user_location_entity.dart @@ -0,0 +1,18 @@ +import 'package:beacon/domain/entities/location/location_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +part 'user_location_entity.freezed.dart'; + +@freezed +class UserLocationEntity with _$UserLocationEntity { + factory UserLocationEntity({UserEntity? user, LocationEntity? location}) = + _UserLocationEntity; +} + +extension UserLocationEntityCopyWithExtension on UserLocationEntity { + UserLocationEntity copywith({UserEntity? user, LocationEntity? location}) { + return UserLocationEntity( + location: location ?? this.location, user: user ?? this.user); + } +} diff --git a/lib/domain/entities/subscriptions/user_location_entity/user_location_entity.freezed.dart b/lib/domain/entities/subscriptions/user_location_entity/user_location_entity.freezed.dart new file mode 100644 index 00000000..16b0e6d3 --- /dev/null +++ b/lib/domain/entities/subscriptions/user_location_entity/user_location_entity.freezed.dart @@ -0,0 +1,184 @@ +// 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_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 _$UserLocationEntity { + UserEntity? get user => throw _privateConstructorUsedError; + LocationEntity? get location => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $UserLocationEntityCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $UserLocationEntityCopyWith<$Res> { + factory $UserLocationEntityCopyWith( + UserLocationEntity value, $Res Function(UserLocationEntity) then) = + _$UserLocationEntityCopyWithImpl<$Res, UserLocationEntity>; + @useResult + $Res call({UserEntity? user, LocationEntity? location}); + + $UserEntityCopyWith<$Res>? get user; + $LocationEntityCopyWith<$Res>? get location; +} + +/// @nodoc +class _$UserLocationEntityCopyWithImpl<$Res, $Val extends UserLocationEntity> + implements $UserLocationEntityCopyWith<$Res> { + _$UserLocationEntityCopyWithImpl(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? user = freezed, + Object? location = freezed, + }) { + return _then(_value.copyWith( + user: freezed == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as UserEntity?, + location: freezed == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as LocationEntity?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $UserEntityCopyWith<$Res>? get user { + if (_value.user == null) { + return null; + } + + return $UserEntityCopyWith<$Res>(_value.user!, (value) { + return _then(_value.copyWith(user: 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); + }); + } +} + +/// @nodoc +abstract class _$$UserLocationEntityImplCopyWith<$Res> + implements $UserLocationEntityCopyWith<$Res> { + factory _$$UserLocationEntityImplCopyWith(_$UserLocationEntityImpl value, + $Res Function(_$UserLocationEntityImpl) then) = + __$$UserLocationEntityImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({UserEntity? user, LocationEntity? location}); + + @override + $UserEntityCopyWith<$Res>? get user; + @override + $LocationEntityCopyWith<$Res>? get location; +} + +/// @nodoc +class __$$UserLocationEntityImplCopyWithImpl<$Res> + extends _$UserLocationEntityCopyWithImpl<$Res, _$UserLocationEntityImpl> + implements _$$UserLocationEntityImplCopyWith<$Res> { + __$$UserLocationEntityImplCopyWithImpl(_$UserLocationEntityImpl _value, + $Res Function(_$UserLocationEntityImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? user = freezed, + Object? location = freezed, + }) { + return _then(_$UserLocationEntityImpl( + user: freezed == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as UserEntity?, + location: freezed == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as LocationEntity?, + )); + } +} + +/// @nodoc + +class _$UserLocationEntityImpl implements _UserLocationEntity { + _$UserLocationEntityImpl({this.user, this.location}); + + @override + final UserEntity? user; + @override + final LocationEntity? location; + + @override + String toString() { + return 'UserLocationEntity(user: $user, location: $location)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$UserLocationEntityImpl && + (identical(other.user, user) || other.user == user) && + (identical(other.location, location) || + other.location == location)); + } + + @override + int get hashCode => Object.hash(runtimeType, user, location); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$UserLocationEntityImplCopyWith<_$UserLocationEntityImpl> get copyWith => + __$$UserLocationEntityImplCopyWithImpl<_$UserLocationEntityImpl>( + this, _$identity); +} + +abstract class _UserLocationEntity implements UserLocationEntity { + factory _UserLocationEntity( + {final UserEntity? user, + final LocationEntity? location}) = _$UserLocationEntityImpl; + + @override + UserEntity? get user; + @override + LocationEntity? get location; + @override + @JsonKey(ignore: true) + _$$UserLocationEntityImplCopyWith<_$UserLocationEntityImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/domain/entities/user/user_entity.dart b/lib/domain/entities/user/user_entity.dart new file mode 100644 index 00000000..572c9031 --- /dev/null +++ b/lib/domain/entities/user/user_entity.dart @@ -0,0 +1,45 @@ +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/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, + bool? isVerified, + LocationEntity? location}) = _UserEntity; +} + +extension UserEntityCopyWithExtension on UserEntity { + UserEntity copywith({ + String? id, + List? groups, + List? beacons, + String? authToken, + String? email, + bool? isGuest, + String? name, + bool? isVerified, + LocationEntity? location, + }) { + return UserEntity( + id: id ?? this.id, + groups: groups ?? this.groups, + beacons: beacons ?? this.beacons, + authToken: authToken ?? this.authToken, + email: email ?? this.email, + isGuest: isGuest ?? this.isGuest, + name: name ?? this.name, + location: location ?? this.location, + isVerified: isVerified ?? this.isVerified); + } +} diff --git a/lib/Bloc/domain/entities/user/user_entity.freezed.dart b/lib/domain/entities/user/user_entity.freezed.dart similarity index 92% rename from lib/Bloc/domain/entities/user/user_entity.freezed.dart rename to lib/domain/entities/user/user_entity.freezed.dart index 6fbc3091..ee0b0074 100644 --- a/lib/Bloc/domain/entities/user/user_entity.freezed.dart +++ b/lib/domain/entities/user/user_entity.freezed.dart @@ -23,6 +23,7 @@ mixin _$UserEntity { String? get email => throw _privateConstructorUsedError; bool? get isGuest => throw _privateConstructorUsedError; String? get name => throw _privateConstructorUsedError; + bool? get isVerified => throw _privateConstructorUsedError; LocationEntity? get location => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -44,6 +45,7 @@ abstract class $UserEntityCopyWith<$Res> { String? email, bool? isGuest, String? name, + bool? isVerified, LocationEntity? location}); $LocationEntityCopyWith<$Res>? get location; @@ -69,6 +71,7 @@ class _$UserEntityCopyWithImpl<$Res, $Val extends UserEntity> Object? email = freezed, Object? isGuest = freezed, Object? name = freezed, + Object? isVerified = freezed, Object? location = freezed, }) { return _then(_value.copyWith( @@ -100,6 +103,10 @@ class _$UserEntityCopyWithImpl<$Res, $Val extends UserEntity> ? _value.name : name // ignore: cast_nullable_to_non_nullable as String?, + isVerified: freezed == isVerified + ? _value.isVerified + : isVerified // ignore: cast_nullable_to_non_nullable + as bool?, location: freezed == location ? _value.location : location // ignore: cast_nullable_to_non_nullable @@ -136,6 +143,7 @@ abstract class _$$UserEntityImplCopyWith<$Res> String? email, bool? isGuest, String? name, + bool? isVerified, LocationEntity? location}); @override @@ -160,6 +168,7 @@ class __$$UserEntityImplCopyWithImpl<$Res> Object? email = freezed, Object? isGuest = freezed, Object? name = freezed, + Object? isVerified = freezed, Object? location = freezed, }) { return _then(_$UserEntityImpl( @@ -191,6 +200,10 @@ class __$$UserEntityImplCopyWithImpl<$Res> ? _value.name : name // ignore: cast_nullable_to_non_nullable as String?, + isVerified: freezed == isVerified + ? _value.isVerified + : isVerified // ignore: cast_nullable_to_non_nullable + as bool?, location: freezed == location ? _value.location : location // ignore: cast_nullable_to_non_nullable @@ -210,6 +223,7 @@ class _$UserEntityImpl implements _UserEntity { this.email, this.isGuest, this.name, + this.isVerified, this.location}) : _groups = groups, _beacons = beacons; @@ -245,11 +259,13 @@ class _$UserEntityImpl implements _UserEntity { @override final String? name; @override + final bool? isVerified; + @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)'; + return 'UserEntity(id: $id, groups: $groups, beacons: $beacons, authToken: $authToken, email: $email, isGuest: $isGuest, name: $name, isVerified: $isVerified, location: $location)'; } @override @@ -265,6 +281,8 @@ class _$UserEntityImpl implements _UserEntity { (identical(other.email, email) || other.email == email) && (identical(other.isGuest, isGuest) || other.isGuest == isGuest) && (identical(other.name, name) || other.name == name) && + (identical(other.isVerified, isVerified) || + other.isVerified == isVerified) && (identical(other.location, location) || other.location == location)); } @@ -279,6 +297,7 @@ class _$UserEntityImpl implements _UserEntity { email, isGuest, name, + isVerified, location); @JsonKey(ignore: true) @@ -297,6 +316,7 @@ abstract class _UserEntity implements UserEntity { final String? email, final bool? isGuest, final String? name, + final bool? isVerified, final LocationEntity? location}) = _$UserEntityImpl; @override @@ -314,6 +334,8 @@ abstract class _UserEntity implements UserEntity { @override String? get name; @override + bool? get isVerified; + @override LocationEntity? get location; @override @JsonKey(ignore: true) diff --git a/lib/Bloc/domain/repositories/auth_repository.dart b/lib/domain/repositories/auth_repository.dart similarity index 57% rename from lib/Bloc/domain/repositories/auth_repository.dart rename to lib/domain/repositories/auth_repository.dart index 87e687e3..7a2c9765 100644 --- a/lib/Bloc/domain/repositories/auth_repository.dart +++ b/lib/domain/repositories/auth_repository.dart @@ -1,5 +1,5 @@ -import 'package:beacon/Bloc/core/resources/data_state.dart'; -import 'package:beacon/Bloc/domain/entities/user/user_entity.dart'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; abstract class AuthRepository { // userinfo function @@ -11,4 +11,8 @@ abstract class AuthRepository { // Login function Future> login(String email, String password); + + Future> sendVerificationCode(); + + Future> completeVerification(); } diff --git a/lib/domain/repositories/group_repository.dart b/lib/domain/repositories/group_repository.dart new file mode 100644 index 00000000..5155ef27 --- /dev/null +++ b/lib/domain/repositories/group_repository.dart @@ -0,0 +1,26 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/user/user_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); + + Future>> nearbyHikes( + String groupId, String lat, String lon, double radius); + + Future>> filterHikes( + String groupId, String type); + + Future> deleteBeacon(String? beaconId); + + Future> rescheduleHike( + int expiresAt, int startsAt, String beaconId); + + Future> removeMember(String groupId, String memberId); +} diff --git a/lib/domain/repositories/hike_repository.dart b/lib/domain/repositories/hike_repository.dart new file mode 100644 index 00000000..d86d7205 --- /dev/null +++ b/lib/domain/repositories/hike_repository.dart @@ -0,0 +1,30 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/geofence/geofence_entity.dart'; +import 'package:beacon/domain/entities/landmark/landmark_entity.dart'; +import 'package:beacon/domain/entities/location/location_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/beacon_locations_entity/beacon_locations_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +abstract class HikeRepository { + Future> updateBeaconLocation( + String beaconId, LatLng position); + Future> fetchBeaconDetails(String beaconId); + Future> createLandMark( + String id, String title, String lat, String lon); + Future> changeUserLocation(String id, LatLng latLng); + Future> createGeofence( + String beaconId, LatLng latlng, double radius); + Future> addRoute(String id, LatLng latlng); + Future>> getRoute(List latlng); + Future> sos(String beaconId); + Stream> beaconLocationSubscription(String beaconId); + Stream> beaconJoinedSubscription(String beaconId); + Stream> beaconUpdateSubscription(String beaconId); + Stream> beaconLocationsSubscription( + String beaconId); + Stream> joinLeaveBeaconSubscription( + String beaconId); +} diff --git a/lib/domain/repositories/home_repository.dart b/lib/domain/repositories/home_repository.dart new file mode 100644 index 00000000..237ba5c3 --- /dev/null +++ b/lib/domain/repositories/home_repository.dart @@ -0,0 +1,13 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/updated_group_entity/updated_group_entity.dart'; + +abstract class HomeRepository { + Future>> fetchGroups(int page, int pageSize); + Future> fetchGroup(String groupId); + Future> createGroup(String title); + Future> joinGroup(String shortCode); + Stream> groupUpdateSubscription( + List groupIds); + Future> changeShortcode(String groupId); +} diff --git a/lib/domain/usecase/auth_usecase.dart b/lib/domain/usecase/auth_usecase.dart new file mode 100644 index 00000000..508b7e33 --- /dev/null +++ b/lib/domain/usecase/auth_usecase.dart @@ -0,0 +1,31 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/domain/repositories/auth_repository.dart'; + +class AuthUseCase { + final AuthRepository authRepository; + + AuthUseCase({required this.authRepository}); + + Future> registerUseCase( + String name, String email, String password) async { + return authRepository.register(name, email, password); + } + + Future> loginUserCase( + String email, String password) async { + return authRepository.login(email, password); + } + + Future> getUserInfoUseCase() async { + return authRepository.getUser(); + } + + Future> sendVerificationCode() { + return authRepository.sendVerificationCode(); + } + + Future> completeVerification() { + return authRepository.completeVerification(); + } +} diff --git a/lib/domain/usecase/group_usecase.dart b/lib/domain/usecase/group_usecase.dart new file mode 100644 index 00000000..bed1db5e --- /dev/null +++ b/lib/domain/usecase/group_usecase.dart @@ -0,0 +1,47 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/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); + } + + Future>> nearbyHikes( + String groupId, String lat, String lon, double radius) { + return _groupRepo.nearbyHikes(groupId, lat, lon, radius); + } + + Future>> filterHikes( + String groupId, String type) { + return _groupRepo.filterHikes(groupId, type); + } + + Future> deleteBeacon(String? beaconId) { + return _groupRepo.deleteBeacon(beaconId); + } + + Future> rescheduleHike( + int newExpiresAt, int newStartsAt, String beaconId) { + return _groupRepo.rescheduleHike(newExpiresAt, newStartsAt, beaconId); + } + + Future> removeMember(String groupId, String memberId) { + return _groupRepo.removeMember(groupId, memberId); + } +} diff --git a/lib/domain/usecase/hike_usecase.dart b/lib/domain/usecase/hike_usecase.dart new file mode 100644 index 00000000..84773d39 --- /dev/null +++ b/lib/domain/usecase/hike_usecase.dart @@ -0,0 +1,74 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/geofence/geofence_entity.dart'; +import 'package:beacon/domain/entities/landmark/landmark_entity.dart'; +import 'package:beacon/domain/entities/location/location_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/beacon_locations_entity/beacon_locations_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/domain/repositories/hike_repository.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +class HikeUseCase { + final HikeRepository hikeRepository; + + HikeUseCase({required this.hikeRepository}); + + Future> updateBeaconLocation( + String beaconId, LatLng position) { + return hikeRepository.updateBeaconLocation(beaconId, position); + } + + Future> fetchBeaconDetails(String beaconId) { + return hikeRepository.fetchBeaconDetails(beaconId); + } + + Future> createLandMark( + String id, String title, String lat, String lon) { + return hikeRepository.createLandMark(id, title, lat, lon); + } + + Future> changeUserLocation(String id, LatLng latlng) { + return hikeRepository.changeUserLocation(id, latlng); + } + + Future> createGeofence( + String beaconId, LatLng latlng, double radius) { + return hikeRepository.createGeofence(beaconId, latlng, radius); + } + + Future> addRoute(String id, LatLng latlng) { + return hikeRepository.addRoute(id, latlng); + } + + Stream> beaconLocationSubscription( + String beaconId) { + return hikeRepository.beaconLocationSubscription(beaconId); + } + + Stream> beaconJoinedSubscription(String beaconId) { + return hikeRepository.beaconJoinedSubscription(beaconId); + } + + Stream> beaconUpdateSubscription(String beaconId) { + return hikeRepository.beaconUpdateSubscription(beaconId); + } + + Stream> beaconlocationsSubscription( + String beaconId) { + return hikeRepository.beaconLocationsSubscription(beaconId); + } + + Stream> joinleavebeaconSubscription( + String beaconId) { + return hikeRepository.joinLeaveBeaconSubscription(beaconId); + } + + Future>> getRoutes(List latlng) { + return hikeRepository.getRoute(latlng); + } + + Future> sos(String id) { + return hikeRepository.sos(id); + } +} diff --git a/lib/domain/usecase/home_usecase.dart b/lib/domain/usecase/home_usecase.dart new file mode 100644 index 00000000..359b9728 --- /dev/null +++ b/lib/domain/usecase/home_usecase.dart @@ -0,0 +1,35 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/updated_group_entity/updated_group_entity.dart'; +import 'package:beacon/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> group(String groupId) { + return homeRepository.fetchGroup(groupId); + } + + Future> createGroup(String title) { + return homeRepository.createGroup(title); + } + + Future> joinGroup(String shortCode) { + return homeRepository.joinGroup(shortCode); + } + + Stream> groupUpdateSubscription( + List groupIds) { + return homeRepository.groupUpdateSubscription(groupIds); + } + + Future> changeShortcode(String groupId) { + return homeRepository.changeShortcode(groupId); + } +} diff --git a/lib/locator.dart b/lib/locator.dart index 59833672..dc2af911 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,103 +1,72 @@ -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_hike_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/hike_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/hike_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/hike_usecase.dart'; -import 'package:beacon/Bloc/domain/usecase/home_usecase.dart'; -import 'package:beacon/main.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:beacon/core/services/location_services.dart'; +import 'package:beacon/core/services/shared_prefrence_service.dart'; +import 'package:beacon/core/utils/utils.dart'; +import 'package:beacon/data/datasource/local/local_api.dart'; +import 'package:beacon/data/datasource/remote/remote_auth_api.dart'; +import 'package:beacon/data/datasource/remote/remote_group_api.dart'; +import 'package:beacon/data/datasource/remote/remote_hike_api.dart'; +import 'package:beacon/data/datasource/remote/remote_home_api.dart'; +import 'package:beacon/data/repositories/auth_repository_implementation.dart'; +import 'package:beacon/data/repositories/group_repository_implementation.dart'; +import 'package:beacon/data/repositories/hike_repository_implementation.dart'; +import 'package:beacon/data/repositories/home_repository_implementation.dart'; +import 'package:beacon/domain/repositories/auth_repository.dart'; +import 'package:beacon/domain/repositories/group_repository.dart'; +import 'package:beacon/domain/repositories/hike_repository.dart'; +import 'package:beacon/domain/repositories/home_repository.dart'; +import 'package:beacon/domain/usecase/auth_usecase.dart'; +import 'package:beacon/domain/usecase/group_usecase.dart'; +import 'package:beacon/domain/usecase/hike_usecase.dart'; +import 'package:beacon/domain/usecase/home_usecase.dart'; +import 'package:beacon/presentation/auth/auth_cubit/auth_cubit.dart'; +import 'package:beacon/presentation/auth/verification_cubit/verification_cubit.dart'; +import 'package:beacon/presentation/group/cubit/group_cubit/group_cubit.dart'; +import 'package:beacon/presentation/hike/cubit/hike_cubit/hike_cubit.dart'; +import 'package:beacon/presentation/hike/cubit/location_cubit/location_cubit.dart'; +import 'package:beacon/presentation/hike/cubit/panel_cubit/panel_cubit.dart'; +import 'package:beacon/presentation/home/home_cubit/home_cubit.dart'; +import 'package:beacon/presentation/group/cubit/members_cubit/members_cubit.dart'; +import 'package:beacon/config/graphql_config.dart'; +import 'package:beacon/config/local_notification.dart'; +import 'package:beacon/config/router/router.dart'; import 'package:get_it/get_it.dart'; GetIt locator = GetIt.instance; -final UserConfig? userConfig = locator(); -final NavigationService? navigationService = locator(); -final DataBaseMutationFunctions? databaseFunctions = - locator(); final GraphQLConfig graphqlConfig = locator(); -final LocalNotification? localNotif = locator(); -final HiveLocalDb? hiveDb = locator(); -final ConnectionChecker? connectionChecker = locator(); -final sharedPrefrenceService = locator(); +final LocalNotification localNotif = locator(); final localApi = locator(); -final remoteAuthApi = locator(); -final remoteHomeApi = locator(); final utils = locator(); - -void setupLocator() async { +final locationService = locator(); +final appRouter = locator(); +final sp = locator(); +Future setupLocator() async { // shared prefrence services locator.registerSingleton(SharedPreferenceService()); - //services - locator.registerSingleton(NavigationService()); - - //userConfig - locator.registerSingleton(UserConfig()); + locator.registerLazySingleton(() => LocationService()); + locator.registerSingleton(AppRouter()); locator.registerSingleton(GraphQLConfig()); - //databaseMutationFunction - locator.registerSingleton(DataBaseMutationFunctions()); - - //Hive localdb - locator.registerSingleton(HiveLocalDb()); - - //Connection checker. - locator.registerSingleton(ConnectionChecker()); - - locator.registerFactory(() => DemoViewModel()); - locator.registerFactory(() => AuthViewModel()); - locator.registerFactory(() => HomeViewModel()); - locator.registerFactory(() => HikeScreenViewModel()); - locator.registerFactory(() => GroupViewModel()); - //local Notification locator.registerSingleton(LocalNotification()); // hive localDb locator.registerSingleton(LocalApi()); - final authClient = await graphqlConfig.authClient(); + final clientAuth = await graphqlConfig.authClient(); + final subscriptionClient = await graphqlConfig.graphQlClient(); // Remote Api locator.registerSingleton( - RemoteAuthApi( - clientAuth: authClient, - clientNonAuth: ValueNotifier(graphqlConfig.clientToQuery()), - ), - ); + RemoteAuthApi(clientAuth, graphqlConfig.clientToQuery())); locator.registerSingleton( - RemoteHomeApi(authClient), - ); - + RemoteHomeApi(clientAuth, subscriptionClient)); locator.registerSingleton( - RemoteGroupApi(authClient: authClient)); - - locator.registerSingleton(RemoteHikeApi(authClient)); + RemoteGroupApi(clientAuth, subscriptionClient)); + locator.registerSingleton( + RemoteHikeApi(clientAuth, subscriptionClient)); // registering auth reporitory of domain locator.registerSingleton( @@ -119,9 +88,16 @@ void setupLocator() async { locator.registerSingleton( HikeUseCase(hikeRepository: locator())); - // // cubit - // locator.registerFactory(() => HomeCubit(homeUseCase: locator())); - // registering utils locator.registerSingleton(Utils()); + + // registering cubit class + locator.registerSingleton(AuthCubit(locator())); + locator.registerSingleton(VerificationCubit(locator())); + locator.registerSingleton(HomeCubit(locator())); + locator.registerSingleton(GroupCubit(locator())); + locator.registerSingleton(MembersCubit(locator())); + locator.registerSingleton(HikeCubit(locator())); + locator.registerSingleton(LocationCubit(locator())); + locator.registerSingleton(PanelCubit(locator())); } diff --git a/lib/main.dart b/lib/main.dart index aac0ed9b..f7821c15 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,110 +1,133 @@ -// 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/hike_cubit.dart'; -import 'package:beacon/Bloc/presentation/cubit/home_cubit.dart'; +import 'dart:math' as math; + +import 'package:beacon/config/enviornment_config.dart'; +import 'package:beacon/core/utils/constants.dart'; +import 'package:beacon/presentation/auth/auth_cubit/auth_cubit.dart'; +import 'package:beacon/presentation/auth/verification_cubit/verification_cubit.dart'; +import 'package:beacon/presentation/group/cubit/group_cubit/group_cubit.dart'; +import 'package:beacon/presentation/hike/cubit/hike_cubit/hike_cubit.dart'; +import 'package:beacon/presentation/hike/cubit/location_cubit/location_cubit.dart'; +import 'package:beacon/presentation/hike/cubit/panel_cubit/panel_cubit.dart'; +import 'package:beacon/presentation/home/home_cubit/home_cubit.dart'; +import 'package:beacon/presentation/group/cubit/members_cubit/members_cubit.dart'; import 'package:beacon/locator.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'; +import 'package:responsive_sizer/responsive_sizer.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); + // loading variables await EnvironmentConfig.loadEnvVariables(); + + await setupLocator(); + await localApi.init(); + await localNotif.initialize(); + SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); - setupLocator(); - // starting local api for storing data - await localApi.init(); - await localNotif!.initialize(); - await hiveDb!.init(); - - AppRouter _appRouter = AppRouter(); - - runApp(MyApp(router: _appRouter)); + runApp(MyApp()); } -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(() {}); - } +class MyApp extends StatelessWidget { + MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return OverlaySupport( - child: Sizer( + child: ResponsiveSizer( builder: (context, orientation, deviceType) => MultiBlocProvider( - providers: [ - BlocProvider( - create: (context) => AuthCubit(authUseCase: locator()), - ), - BlocProvider( - create: (context) => HomeCubit(homeUseCase: locator()), - ), - BlocProvider( - create: (context) => GroupCubit(locator()), - ), - BlocProvider( - create: (context) => HikeCubit(hikeUsecase: locator()), - ), - ], + providers: providers, child: MaterialApp.router( debugShowCheckedModeBanner: false, title: 'Beacon', theme: ThemeData(fontFamily: 'FuturaBold'), - routerConfig: _appRouter.config(), + routerConfig: appRouter.config(), ), ), ), ); } + + final List> providers = [ + BlocProvider( + create: (context) => locator(), + ), + BlocProvider( + create: (context) => locator(), + ), + BlocProvider( + create: (context) => locator(), + ), + BlocProvider( + create: (context) => locator(), + ), + BlocProvider( + create: (context) => locator(), + ), + BlocProvider( + create: (context) => locator(), + ), + BlocProvider( + create: (context) => locator(), + ), + BlocProvider( + create: (context) => locator(), + ) + ]; } -class DemoPageView extends StatelessWidget { - const DemoPageView({required Key key}) : super(key: key); +class DrawCircle extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = kBlue + ..style = PaintingStyle.fill; + + canvas.drawCircle(Offset(size.width / 2, 0), size.width / 2, paint); + } @override - Widget build(BuildContext context) { - return BaseView( - builder: (context, model, child) => Scaffold( - appBar: AppBar( - title: const Text('Demo Page'), - ), - body: Container( - child: Text(model.title), - ), - ), - ); + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return false; } } -class DemoViewModel extends BaseModel { - final String _title = "Title from the viewMode GSoC branch"; - String get title => _title; -} +// class DrawCircle extends CustomPainter { +// @override +// void paint(Canvas canvas, Size size) { +// final paint = Paint() +// ..color = kBlue +// ..style = PaintingStyle.fill; + +// final path = Path(); + +// // Convert angles to radians +// final angle1Rad = 60 * (math.pi / 180); +// final angle2Rad = 30 * (math.pi / 180); + +// // Calculate the height of the cut based on the rectangle width and angle +// final cutHeight1 = size.width * math.tan(angle1Rad); +// final cutHeight2 = size.width * math.tan(angle2Rad); + +// // Define the path +// path.moveTo(0, cutHeight1); // Start at the top-left corner with a cut +// path.lineTo(size.width, 0); // Top-right corner +// path.lineTo( +// size.width, size.height - cutHeight2); // Bottom-right corner with a cut +// path.lineTo(0, size.height); // Bottom-left corner +// path.close(); + +// canvas.drawPath(path, paint); +// } + +// @override +// bool shouldRepaint(covariant CustomPainter oldDelegate) { +// return false; +// } +// } diff --git a/lib/old/components/beacon_card.dart b/lib/old/components/beacon_card.dart deleted file mode 100644 index 464cc8f7..00000000 --- a/lib/old/components/beacon_card.dart +++ /dev/null @@ -1,443 +0,0 @@ -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/locator.dart'; -import 'package:beacon/old/components/timer.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'; - -class BeaconCustomWidgets { - static final Color textColor = Color(0xFFAFAFAF); - - static Widget getBeaconCard(BuildContext context, BeaconEntity beacon) { - print(beacon.leader!.name); - bool hasStarted; - bool hasEnded; - bool willStart; - hasStarted = DateTime.now() - .isAfter(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)); - hasEnded = DateTime.now() - .isAfter(DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!)); - willStart = DateTime.now() - .isBefore(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)); - return GestureDetector( - onTap: () async { - AutoRouter.of(context) - .push(HikeScreenRoute(beacon: beacon, isLeader: false)); - // if (hasEnded) - // utils.showSnackBar('Beacon is not active anymore!', context); - // bool isJoinee = false; - // for (var i in beacon.followers!) { - // if (i!.id == localApi.userModel.id) { - // isJoinee = true; - // } - // } - // if (!hasStarted) { - // 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 == localApi.userModel.id || isJoinee)) { - // log('here'); - // // navigationService!.pushScreen('/hikeScreen', - // // arguments: HikeScreen( - // // beacon, - // // isLeader: (beacon.leader!.id == userConfig!.currentUser!.id), - // // )); - - // // for(int i=0; i[ - (hasStarted && !hasEnded) - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - width: 70.w, - child: Text( - '${beacon.title} by ${beacon.leader!.name} ', - style: Style.titleTextStyle, - ), - ), - Align( - alignment: Alignment.topRight, - child: BlinkIcon(), - ), - ], - ), - SizedBox(height: 4.0), - RichText( - text: TextSpan( - text: 'Hike is ', - style: Style.commonTextStyle, - children: const [ - TextSpan( - text: 'Active', - style: TextStyle( - fontSize: 16.0, - color: Colors.white, - fontWeight: FontWeight.bold, - letterSpacing: 1.0), - ), - ], - ), - ), - Row( - children: [ - Text('Passkey: ${beacon.shortcode}', - style: Style.commonTextStyle), - IconButton( - onPressed: () { - Clipboard.setData(ClipboardData( - text: beacon.shortcode.toString())); - utils.showSnackBar( - 'Shortcode copied!', context); - }, - icon: Icon( - Icons.copy, - color: Colors.white, - size: 15, - )) - ], - ), - (beacon.startsAt != null) - ? Text( - 'Started At: ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}', - style: Style.commonTextStyle) - : Container(), - SizedBox(height: 4.0), - (beacon.expiresAt != null) - ? Text( - 'Expires At: ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!)).toString()}', - style: Style.commonTextStyle) - : Container(), - ], - ) - : (willStart) - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - width: 70.w, - child: Text( - '${beacon.title} by ${beacon.leader!.name} ', - style: Style.titleTextStyle, - ), - ), - Align( - alignment: Alignment.topRight, - child: Icon( - Icons.circle, - color: kYellow, - size: 10, - ), - ), - ], - ), - SizedBox(height: 4.0), - Row( - children: [ - RichText( - text: TextSpan( - text: 'Hike ', - style: Style.commonTextStyle, - children: const [ - TextSpan( - text: 'Starts ', - style: TextStyle( - fontSize: 16.0, - color: Colors.white, - fontWeight: FontWeight.bold, - letterSpacing: 1.0), - ), - TextSpan( - text: 'in ', - style: TextStyle( - color: const Color(0xffb6b2df), - fontSize: 14.0, - fontWeight: FontWeight.w400), - ), - ], - ), - ), - SizedBox( - width: 3.0, - ), - CountdownTimerPage( - dateTime: DateTime.fromMillisecondsSinceEpoch( - beacon.startsAt!), - name: beacon.title, - beacon: beacon, - ) - ], - ), - // SizedBox(height: 4.0), - Row( - children: [ - Text('Passkey: ${beacon.shortcode}', - style: Style.commonTextStyle), - IconButton( - onPressed: () { - Clipboard.setData(ClipboardData( - text: beacon.shortcode.toString())); - utils.showSnackBar( - 'Shortcode copied!', context); - }, - icon: Icon( - Icons.copy, - color: Colors.white, - size: 15, - )) - ], - ), - // SizedBox(height: 4.0), - (beacon.startsAt != null) - ? Text( - 'Starts At: ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}', - style: Style.commonTextStyle) - : Container(), - SizedBox(height: 4.0), - (beacon.expiresAt != null) - ? Text( - 'Expires At: ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!)).toString()}', - style: Style.commonTextStyle) - : Container(), - ], - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 70.w, - child: Text( - '${beacon.title} by ${beacon.leader!.name} ', - style: Style.titleTextStyle, - ), - ), - SizedBox(height: 4.0), - RichText( - text: TextSpan( - text: 'Hike has ', - style: Style.commonTextStyle, - children: const [ - TextSpan( - text: 'Ended', - style: TextStyle( - fontSize: 16.0, - color: Colors.white, - fontWeight: FontWeight.bold, - letterSpacing: 1.0), - ), - ], - ), - ), - Row( - children: [ - Text('Passkey: ${beacon.shortcode}', - style: Style.commonTextStyle), - IconButton( - onPressed: () { - Clipboard.setData(ClipboardData( - text: beacon.shortcode.toString())); - utils.showSnackBar( - 'Shortcode copied!', context); - }, - icon: Icon( - Icons.copy, - color: Colors.white, - size: 15, - )) - ], - ), - SizedBox(height: 4.0), - (beacon.startsAt != null) - ? Text( - 'Started At: ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}', - style: Style.commonTextStyle) - : Container(), - SizedBox(height: 4.0), - (beacon.expiresAt != null) - ? Text( - 'Expired At: ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!)).toString()}', - style: Style.commonTextStyle) - : Container(), - ], - ), - ], - ), - decoration: BoxDecoration( - color: willStart - ? Color(0xFF141546) - : hasEnded - ? lightkBlue - : kBlue, - shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(8.0), - boxShadow: [ - BoxShadow( - color: Colors.black26, - blurRadius: 10.0, - offset: Offset(0.0, 10.0), - ), - ], - ), - ), - ); - } - - static ListView getPlaceholder() { - final BorderRadius borderRadius = BorderRadius.circular(10.0); - return ListView.builder( - scrollDirection: Axis.vertical, - physics: BouncingScrollPhysics(), - itemCount: 3, - padding: const EdgeInsets.all(8.0), - itemBuilder: (BuildContext context, int index) { - return Container( - margin: const EdgeInsets.symmetric( - vertical: 10.0, - horizontal: 10.0, - ), - height: 110, - decoration: BoxDecoration( - color: kBlue, - shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(8.0), - boxShadow: [ - BoxShadow( - color: Colors.black26, - blurRadius: 10.0, - offset: Offset(0.0, 10.0), - ), - ], - ), - padding: - EdgeInsets.only(left: 16.0, right: 16.0, bottom: 10, top: 10), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: const EdgeInsets.only( - left: 15.0, bottom: 10.0, right: 15.0), - child: ClipRRect( - borderRadius: borderRadius, - child: SkeletonAnimation( - child: Container( - height: 15.0, - decoration: BoxDecoration(color: shimmerSkeletonColor), - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 30.0, bottom: 10.0), - child: ClipRRect( - borderRadius: borderRadius, - child: SkeletonAnimation( - child: Container( - height: 10.0, - decoration: BoxDecoration(color: shimmerSkeletonColor), - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 45.0, bottom: 10.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10.0), - child: SkeletonAnimation( - child: Container( - height: 10.0, - decoration: BoxDecoration(color: shimmerSkeletonColor), - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 15.0, right: 60.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10.0), - child: SkeletonAnimation( - child: Container( - height: 10.0, - decoration: BoxDecoration(color: shimmerSkeletonColor), - ), - ), - ), - ), - ], - ), - ); - }); - } -} diff --git a/lib/old/components/dialog_boxes.dart b/lib/old/components/dialog_boxes.dart deleted file mode 100644 index afd4d771..00000000 --- a/lib/old/components/dialog_boxes.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:beacon/old/components/hike_button.dart'; -import 'package:beacon/old/components/utilities/constants.dart'; -import 'package:flutter/material.dart'; -import 'package:sizer/sizer.dart'; - -class DialogBoxes { - static AlertDialog showExitDialog( - BuildContext context, bool? isLeader, int X, bool isBeaconExpired) { - return AlertDialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - title: Text( - 'This will terminate the hike, Confirm?', - style: TextStyle(fontSize: 25, color: kYellow), - ), - content: Text( - isBeaconExpired - ? 'Are you sure you want to exit?' - : isLeader! && (X - 1 > 0) - ? 'There are ${X - 1} followers and you are carrying the beacon. Do you want to terminate the hike?' - : 'Are you sure you want to terminate the hike?', - style: TextStyle(fontSize: 16, color: kBlack), - ), - // actionsAlignment: MainAxisAlignment.spaceEvenly, - 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: () => Navigator.of(context).pop(true), - // - // onTap: () { - // navigationService.removeAllAndPush('/groupScreen', '/', - // arguments: GroupScreen( - // group, - // ));} - text: 'Yes', - textSize: 18.0, - ), - ], - ); - } - - static Future changeDurationDialog(BuildContext context) { - return showDialog( - context: context, - builder: (context) => Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - child: Container( - height: 500, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), - child: Column( - children: [ - Flexible( - child: Container( - color: kLightBlue, - child: Column( - children: [ - Text( - 'Change Beacon Duration', - style: TextStyle(color: kYellow, fontSize: 14.0), - ), - ], - ), - ), - ), - SizedBox( - height: 3.h, - ), - Flexible( - child: HikeButton( - buttonWidth: optbwidth, - text: 'Done', - textSize: 18.0, - textColor: Colors.white, - buttonColor: kYellow, - onTap: () { - // DateTime newTime = - // DateTime.now().add(newDuration); - // update time - Navigator.pop(context); - }), - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/lib/old/components/enums/view_state.dart b/lib/old/components/enums/view_state.dart deleted file mode 100644 index 4c02c01b..00000000 --- a/lib/old/components/enums/view_state.dart +++ /dev/null @@ -1,5 +0,0 @@ -/// Represents the state of the view -enum ViewState { - idle, - busy, -} diff --git a/lib/old/components/group_card.dart b/lib/old/components/group_card.dart deleted file mode 100644 index 2dd9ef7a..00000000 --- a/lib/old/components/group_card.dart +++ /dev/null @@ -1,203 +0,0 @@ -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/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'; - -class GroupCustomWidgets { - static final Color textColor = Color(0xFFAFAFAF); - - 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 == localApi.userModel.id) { - isMember = true; - } - } - if (group.leader!.id == localApi.userModel.id || isMember) { - // navigationService!.pushScreen('/groupScreen', - // arguments: GroupScreen( - // 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)); - // 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. - } - }, - child: Container( - margin: const EdgeInsets.symmetric( - vertical: 10.0, - horizontal: 10.0, - ), - padding: EdgeInsets.only(left: 16.0, right: 16.0, bottom: 8, top: 8), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 70.w, - child: Text( - '${group.title} by ${group.leader!.name} ', - style: Style.titleTextStyle, - ), - ), - SizedBox(height: 4.0), - Text( - 'Group has $noMembers members ', - style: Style.commonTextStyle, - ), - SizedBox(height: 4.0), - Text( - 'Group has $noBeacons beacons ', - 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, - )) - ], - ) - ], - ), - ], - ), - decoration: BoxDecoration( - color: kBlue, - shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(8.0), - boxShadow: [ - BoxShadow( - color: Colors.black26, - blurRadius: 10.0, - offset: Offset(0.0, 10.0), - ), - ], - ), - ), - ); - } - - static ListView getPlaceholder() { - final BorderRadius borderRadius = BorderRadius.circular(10.0); - return ListView.builder( - scrollDirection: Axis.vertical, - physics: BouncingScrollPhysics(), - itemCount: 3, - padding: const EdgeInsets.all(8.0), - itemBuilder: (BuildContext context, int index) { - return Container( - margin: const EdgeInsets.symmetric( - vertical: 10.0, - horizontal: 10.0, - ), - height: 110, - decoration: BoxDecoration( - color: kBlue, - shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(8.0), - boxShadow: [ - BoxShadow( - color: Colors.black26, - blurRadius: 10.0, - offset: Offset(0.0, 10.0), - ), - ], - ), - padding: - EdgeInsets.only(left: 16.0, right: 16.0, bottom: 10, top: 10), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: const EdgeInsets.only( - left: 15.0, bottom: 10.0, right: 15.0), - child: ClipRRect( - borderRadius: borderRadius, - child: SkeletonAnimation( - child: Container( - height: 15.0, - decoration: BoxDecoration(color: shimmerSkeletonColor), - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 30.0, bottom: 10.0), - child: ClipRRect( - borderRadius: borderRadius, - child: SkeletonAnimation( - child: Container( - height: 10.0, - decoration: BoxDecoration(color: shimmerSkeletonColor), - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 45.0, bottom: 10.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10.0), - child: SkeletonAnimation( - child: Container( - height: 10.0, - decoration: BoxDecoration(color: shimmerSkeletonColor), - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 15.0, right: 60.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10.0), - child: SkeletonAnimation( - child: Container( - height: 10.0, - decoration: BoxDecoration(color: shimmerSkeletonColor), - ), - ), - ), - ), - ], - ), - ); - }); - } -} diff --git a/lib/old/components/hike_screen_widget.dart b/lib/old/components/hike_screen_widget.dart deleted file mode 100644 index 50d7aaa3..00000000 --- a/lib/old/components/hike_screen_widget.dart +++ /dev/null @@ -1,337 +0,0 @@ -import 'dart:async'; -import 'dart:io'; -import 'package:beacon/old/components/hike_button.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/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'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:share_plus/share_plus.dart'; - -import 'package:sizer/sizer.dart'; - -class HikeScreenWidget extends ChangeNotifier { - static copyPasskey(String? passkey) { - Clipboard.setData(ClipboardData(text: passkey!)); - Fluttertoast.showToast(msg: 'PASSKEY: $passkey COPIED'); - } - - static Geocoder geocoder = Geocoder(); - - static generateUrl(String? shortcode) async { - Uri url = Uri.parse('https://beacon.aadibajpai.com/?shortcode=$shortcode'); - Share.share('To join beacon follow this link: $url'); - } - - static Widget shareButton(BuildContext context, String? passkey) { - return FloatingActionButton( - heroTag: - 'shareRouteTag', //had to pass this tag else we would get error since there will be two FAB in the same subtree with the same tag. - onPressed: () { - showDialog( - context: context, - builder: (context) => Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - child: Container( - height: 30.h, - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 32, vertical: 16), - child: Column( - children: [ - Container( - child: Padding( - padding: const EdgeInsets.all(4.0), - child: Text( - 'Invite Friends', - style: TextStyle(fontSize: 24), - ), - ), - ), - SizedBox( - height: 3.5.h, - ), - Flexible( - child: HikeButton( - buttonHeight: optbheight - 4, - textSize: 16, - text: 'Generate URL', - textColor: Colors.white, - buttonColor: kYellow, - onTap: () async { - generateUrl(passkey); - navigationService!.pop(); - }), - ), - SizedBox( - height: 2.h, - ), - Flexible( - child: HikeButton( - buttonHeight: optbheight - 4, - textSize: 16, - text: 'Copy Passkey', - textColor: Colors.white, - buttonColor: kYellow, - onTap: () { - copyPasskey(passkey); - navigationService!.pop(); - }, - ), - ) - ], - ), - ), - ), - ), - ); - }, - backgroundColor: kYellow, - child: Icon(Icons.person_add), - ); - } - - static Widget shareRouteButton( - BuildContext context, - Beacon? beacon, - Completer googleMapControllerCompleter, - List beaconRoute, - ) { - return FloatingActionButton( - heroTag: - 'shareRouteTag1', //had to pass this tag else we would get error since there will be two FAB in the same subtree with the same tag. - onPressed: () async { - final mapController = await googleMapControllerCompleter.future; - // sanity check. - if (googleMapControllerCompleter.isCompleted == false) return; - if (!await connectionChecker!.checkForInternetConnection()) { - // navigationService!.showSnackBar( - // 'Cannot share the route, please check your internet connection.'); - return; - } - //show marker description so that image will be more usefull. - await mapController.showMarkerInfoWindow(MarkerId("1")); - //getting the image (ss) of map. - final image = await (mapController.takeSnapshot()); - // getting the app directory - final appDir = await getApplicationDocumentsDirectory(); - // Creating a file for the image. - File imageFile = await File('${appDir.path}/shareImage.png').create(); - //writing the image to the file we just created so that it can be shared. - imageFile.writeAsBytesSync(image!); - // initial coordinates - // Coordinates coordinates = Coordinates( - // beaconRoute.first.latitude, - // beaconRoute.first.longitude, - // ); - - // initial address - //current coordinates - // coordinates = Coordinates( - // beaconRoute.last.latitude, - // beaconRoute.last.longitude, - // ); - //current address - // All the neccessary info should be here. - //Will be used as subject if shared via email, else isnt used. - // await Share.shareXFiles([XFile(imageFile.path)], - // text: textToShare, subject: subjectToShare); - //hide after sharing. - await mapController.hideMarkerInfoWindow(MarkerId("1")); - return; - }, - backgroundColor: kYellow, - child: Icon( - Icons.share, - ), - ); - } - - static Column panel(ScrollController sc, HikeScreenViewModel model, - BuildContext context, bool isLeader) { - return Column( - children: [ - SizedBox( - height: 15.0, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 60, - height: 5, - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.all(Radius.circular(12.0))), - ), - ], - ), - SizedBox( - height: 12, - ), - Container( - height: MediaQuery.of(context).size.height * 0.6 - 32, - child: ListView( - controller: sc, - physics: AlwaysScrollableScrollPhysics(), - children: [ - isLeader - ? Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: RichText( - text: TextSpan( - style: TextStyle( - fontWeight: FontWeight.bold, color: kBlack), - children: [ - TextSpan( - text: - 'Long Press on any hiker to hand over the beacon\n', - style: TextStyle(fontSize: 16)), - ], - ), - ), - ) - : Container(), - SizedBox( - height: 6, - ), - Material( - child: ListView.builder( - shrinkWrap: true, - clipBehavior: Clip.antiAlias, - scrollDirection: Axis.vertical, - physics: const NeverScrollableScrollPhysics(), - itemCount: model.hikers.length, - itemBuilder: (BuildContext context, int index) { - return ListTile( - onLongPress: () async { - model.relayBeacon( - model.hikers[index]!.name, model.hikers[index]!.id); - }, - leading: CircleAvatar( - backgroundColor: - model.isBeaconExpired ? Colors.grey : kYellow, - radius: 18, - child: ClipRRect( - borderRadius: BorderRadius.circular(50), - child: Icon( - Icons.person_outline, - color: Colors.white, - ), - ), - ), - title: Text( - model.hikers[index]!.name!, - style: TextStyle(color: Colors.black, fontSize: 18), - ), - trailing: - model.hikers[index]!.id == model.beacon!.leader!.id - ? GestureDetector( - onDoubleTap: () { - isLeader - ? 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. - // : DialogBoxes.changeDurationDialog(context); - : Container(); - }, - child: Icon( - Icons.room, - color: model.isBeaconExpired - ? Colors.grey - : kYellow, - size: 40, - ), - ) - : Container(width: 10), - ); - }, - ), - ), - ], - ), - ), - ], - ); - } - - static void showCreateLandMarkDialogueDialog( - BuildContext context, - var landmarkFormKey, - var title, - var loc, - Future createLandmark(var landmarkTitle, var location), - ) { - showDialog( - context: context, - builder: (context) => Dialog( - child: Container( - height: MediaQuery.of(context).size.height < 800 ? 30.h : 25.h, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), - child: Form( - key: landmarkFormKey, - child: Column( - children: [ - Container( - height: - MediaQuery.of(context).size.height < 800 ? 14.h : 12.h, - child: Padding( - padding: const EdgeInsets.all(4.0), - child: TextFormField( - style: TextStyle(fontSize: 20.0), - onChanged: (key) { - title = key; - }, - validator: (value) { - if (value == null || value.isEmpty) { - return "Please enter title for landmark"; - } else { - return null; - } - }, - decoration: InputDecoration( - border: InputBorder.none, - alignLabelWithHint: true, - floatingLabelBehavior: FloatingLabelBehavior.always, - hintText: 'Add title for the landmark', - hintStyle: - TextStyle(fontSize: hintsize, color: hintColor), - labelText: 'Title', - labelStyle: - TextStyle(fontSize: labelsize, color: kYellow), - ), - ), - ), - color: kLightBlue, - ), - SizedBox( - height: 2.h, - ), - Flexible( - child: HikeButton( - text: 'Create Landmark', - textSize: 17.0, - textColor: Colors.white, - buttonColor: kYellow, - onTap: () => createLandmark(title, loc), - ), - ), - ], - ), - ), - ), - ), - ), - ); - } -} diff --git a/lib/old/components/models/beacon/beacon.dart b/lib/old/components/models/beacon/beacon.dart deleted file mode 100644 index af4f14d9..00000000 --- a/lib/old/components/models/beacon/beacon.dart +++ /dev/null @@ -1,88 +0,0 @@ -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'; - -part 'beacon.g.dart'; - -@HiveType(typeId: 3) -class Beacon extends HiveObject { - Beacon( - {this.id, - this.shortcode, - this.startsAt, - this.expiresAt, - this.title, - this.leader, - this.followers, - this.route, - this.landmarks, - this.location, - this.group}); - - factory Beacon.fromJson(Map json) { - return Beacon( - id: json['_id'] as String?, - shortcode: json['shortcode'] as String?, - title: json['title'] != null ? json['title'] as String? : null, - startsAt: json['startsAt'] as int?, - expiresAt: json['expiresAt'] as int?, - leader: json['leader'] != null - ? User.fromJson(json['leader'] as Map) - : null, - location: json['location'] != null - ? Location.fromJson(json['location'] as Map) - : null, - followers: json['followers'] != null - ? (json['followers'] as List) - .map((e) => User.fromJson(e as Map)) - .toList() - : [], - route: json['route'] != null - ? (json['route'] as List) - .map((e) => Location.fromJson(e as Map)) - .toList() - : [], - landmarks: json['landmarks'] != null - ? (json['landmarks'] as List) - .map((e) => Landmark.fromJson(e as Map)) - .toList() - : [], - // group: json['group'] != null - // ? Group.fromJson(json['group'] as Map) - // : null, - group: json['group'] != null ? json['group']['_id'] : null, - ); - } - - @HiveField(0) - String? id; - @HiveField(1) - String? shortcode; - @HiveField(2) - int? startsAt; - @HiveField(3) - int? expiresAt; - @HiveField(4) - User? leader; - @HiveField(5) - List? followers = []; - @HiveField(6) - List? route = []; - @HiveField(7) - String? title; - @HiveField(8) - List? landmarks = []; - @HiveField(9) - Location? location; - @HiveField(10) - String? group; - - print() { - debugPrint('shortCode: ${this.shortcode}'); - debugPrint('_id: ${this.id}'); - debugPrint('startsAt: ${this.startsAt}'); - debugPrint('expiresAt: ${this.expiresAt}'); - } -} diff --git a/lib/old/components/models/beacon/beacon.g.dart b/lib/old/components/models/beacon/beacon.g.dart deleted file mode 100644 index 73850387..00000000 --- a/lib/old/components/models/beacon/beacon.g.dart +++ /dev/null @@ -1,71 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'beacon.dart'; - -// ************************************************************************** -// TypeAdapterGenerator -// ************************************************************************** - -class BeaconAdapter extends TypeAdapter { - @override - final int typeId = 3; - - @override - Beacon read(BinaryReader reader) { - final numOfFields = reader.readByte(); - final fields = { - for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), - }; - return Beacon( - id: fields[0] as String?, - shortcode: fields[1] as String?, - startsAt: fields[2] as int?, - expiresAt: fields[3] as int?, - 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(), - location: fields[9] as Location?, - group: fields[10] as String?, - ); - } - - @override - void write(BinaryWriter writer, Beacon obj) { - writer - ..writeByte(11) - ..writeByte(0) - ..write(obj.id) - ..writeByte(1) - ..write(obj.shortcode) - ..writeByte(2) - ..write(obj.startsAt) - ..writeByte(3) - ..write(obj.expiresAt) - ..writeByte(4) - ..write(obj.leader) - ..writeByte(5) - ..write(obj.followers) - ..writeByte(6) - ..write(obj.route) - ..writeByte(7) - ..write(obj.title) - ..writeByte(8) - ..write(obj.landmarks) - ..writeByte(9) - ..write(obj.location) - ..writeByte(10) - ..write(obj.group); - } - - @override - int get hashCode => typeId.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is BeaconAdapter && - runtimeType == other.runtimeType && - typeId == other.typeId; -} diff --git a/lib/old/components/models/group/group.dart b/lib/old/components/models/group/group.dart deleted file mode 100644 index 007e3071..00000000 --- a/lib/old/components/models/group/group.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:beacon/old/components/models/user/user_info.dart'; -import 'package:flutter/material.dart'; -import 'package:hive/hive.dart'; - -import '../beacon/beacon.dart'; - -part 'group.g.dart'; - -@HiveType(typeId: 5) -class Group extends HiveObject { - Group({ - this.id, - this.shortcode, - this.title, - this.leader, - this.members, - this.beacons, - }); - - factory Group.fromJson(Map json) { - return Group( - id: json['_id'] as String?, - title: json['title'] != null ? json['title'] as String? : null, - shortcode: json['shortcode'] as String?, - leader: json['leader'] != null - ? User.fromJson(json['leader'] as Map) - : null, - members: json['members'] != null - ? (json['members'] as List) - .map((e) => User.fromJson(e as Map)) - .toList() - : [], - beacons: json['beacons'] != null - ? (json['beacons'] as List) - .map((e) => Beacon.fromJson(e as Map)) - .toList() - : [], - ); - } - - @HiveField(0) - String? id; - @HiveField(1) - String? title; - @HiveField(2) - String? shortcode; - @HiveField(3) - User? leader; - @HiveField(4) - List? members = []; - @HiveField(5) - List? beacons = []; - - print() { - debugPrint('shortCode: ${this.shortcode}'); - debugPrint('_id: ${this.id}'); - debugPrint('groupLeader: ${this.leader}'); - } -} diff --git a/lib/old/components/models/group/group.g.dart b/lib/old/components/models/group/group.g.dart deleted file mode 100644 index d9123740..00000000 --- a/lib/old/components/models/group/group.g.dart +++ /dev/null @@ -1,56 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'group.dart'; - -// ************************************************************************** -// TypeAdapterGenerator -// ************************************************************************** - -class GroupAdapter extends TypeAdapter { - @override - final int typeId = 5; - - @override - Group read(BinaryReader reader) { - final numOfFields = reader.readByte(); - final fields = { - for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), - }; - return Group( - id: fields[0] as String?, - shortcode: fields[2] as String?, - title: fields[1] as String?, - leader: fields[3] as User?, - members: (fields[4] as List?)?.cast(), - beacons: (fields[5] as List?)?.cast(), - ); - } - - @override - void write(BinaryWriter writer, Group obj) { - writer - ..writeByte(6) - ..writeByte(0) - ..write(obj.id) - ..writeByte(1) - ..write(obj.title) - ..writeByte(2) - ..write(obj.shortcode) - ..writeByte(3) - ..write(obj.leader) - ..writeByte(4) - ..write(obj.members) - ..writeByte(5) - ..write(obj.beacons); - } - - @override - int get hashCode => typeId.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is GroupAdapter && - runtimeType == other.runtimeType && - typeId == other.typeId; -} diff --git a/lib/old/components/models/landmarks/landmark.dart b/lib/old/components/models/landmarks/landmark.dart deleted file mode 100644 index 42cd5ab7..00000000 --- a/lib/old/components/models/landmarks/landmark.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:beacon/old/components/models/location/location.dart'; -import 'package:flutter/material.dart'; -import 'package:hive/hive.dart'; -part 'landmark.g.dart'; - -@HiveType(typeId: 4) -class Landmark extends HiveObject { - Landmark({this.title, this.location}); - - factory Landmark.fromJson(Map json) { - return Landmark( - title: json['title'] != null ? json['title'] as String? : null, - location: json['location'] != null - ? Location.fromJson(json['location'] as Map) - : null, - ); - } - - @HiveField(0) - String? title; - @HiveField(1) - Location? location; - - print() { - debugPrint('title: ${this.title}'); - } -} diff --git a/lib/old/components/models/landmarks/landmark.g.dart b/lib/old/components/models/landmarks/landmark.g.dart deleted file mode 100644 index 5495c481..00000000 --- a/lib/old/components/models/landmarks/landmark.g.dart +++ /dev/null @@ -1,44 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'landmark.dart'; - -// ************************************************************************** -// TypeAdapterGenerator -// ************************************************************************** - -class LandmarkAdapter extends TypeAdapter { - @override - final int typeId = 4; - - @override - Landmark read(BinaryReader reader) { - final numOfFields = reader.readByte(); - final fields = { - for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), - }; - return Landmark( - title: fields[0] as String?, - location: fields[1] as Location?, - ); - } - - @override - void write(BinaryWriter writer, Landmark 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 LandmarkAdapter && - runtimeType == other.runtimeType && - typeId == other.typeId; -} diff --git a/lib/old/components/models/location/location.dart b/lib/old/components/models/location/location.dart deleted file mode 100644 index 953885d6..00000000 --- a/lib/old/components/models/location/location.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hive/hive.dart'; -part 'location.g.dart'; - -@HiveType(typeId: 2) -class Location extends HiveObject { - Location({this.lat, this.lon}); - - factory Location.fromJson(Map json) { - return Location( - lat: json['lat'] != null ? json['lat'] as String? : null, - lon: json['lon'] != null ? json['lon'] as String? : null, - ); - } - - @HiveField(0) - String? lat; - @HiveField(1) - String? lon; - - print() { - debugPrint('lat: ${this.lat}'); - debugPrint('long: ${this.lon}'); - } -} diff --git a/lib/old/components/models/location/location.g.dart b/lib/old/components/models/location/location.g.dart deleted file mode 100644 index e171a2cb..00000000 --- a/lib/old/components/models/location/location.g.dart +++ /dev/null @@ -1,44 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'location.dart'; - -// ************************************************************************** -// TypeAdapterGenerator -// ************************************************************************** - -class LocationAdapter extends TypeAdapter { - @override - final int typeId = 2; - - @override - Location read(BinaryReader reader) { - final numOfFields = reader.readByte(); - final fields = { - for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), - }; - return Location( - lat: fields[0] as String?, - lon: fields[1] as String?, - ); - } - - @override - void write(BinaryWriter writer, Location 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 LocationAdapter && - runtimeType == other.runtimeType && - typeId == other.typeId; -} diff --git a/lib/old/components/models/user/user_info.dart b/lib/old/components/models/user/user_info.dart deleted file mode 100644 index 70bd5cdd..00000000 --- a/lib/old/components/models/user/user_info.dart +++ /dev/null @@ -1,82 +0,0 @@ -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'; - -@HiveType(typeId: 1) -class User extends HiveObject { - User( - {this.authToken, - this.email, - this.name, - this.location, - this.beacon, - this.groups, - this.id, - this.isGuest}); - - factory User.fromJson(Map json) { - return User( - id: json['_id'] as String?, - name: json['name'] != null ? json['name'] as String? : 'Anonymous', - email: json['email'] != null ? json['email'] as String? : '', - location: json['location'] != null - ? Location.fromJson(json['location'] as Map) - : null, - beacon: json['beacons'] != null - ? (json['beacons'] as List) - .map((e) => Beacon.fromJson(e as Map)) - .toList() - : [], - groups: json['groups'] != null - ? (json['groups'] as List) - .map((e) => Group.fromJson(e as Map)) - .toList() - : [], - isGuest: json['isGuest'] != null ? json['isGuest'] as bool? : false, - ); - } - - @HiveField(0) - String? id; - @HiveField(1) - String? authToken; - @HiveField(2) - String? name; - @HiveField(3) - String? email; - @HiveField(4) - List? beacon = []; - @HiveField(5) - List? groups = []; - @HiveField(6) - Location? location; - @HiveField(7) - bool? isGuest = false; - - print() { - debugPrint('authToken: ${this.authToken}'); - debugPrint('_id: ${this.id}'); - debugPrint('firstName: ${this.name}'); - debugPrint('email: ${this.email}'); - debugPrint('location: ${this.location}'); - debugPrint('beacons: ${this.beacon}'); - debugPrint('groups: ${this.groups}'); - } - - // updateBeacon(List beaconList) { - // this.beacon = beaconList; - // } - - update(User details) { - this.authToken = details.authToken; - this.name = details.name; - this.email = details.email; - this.location = details.location; - this.beacon = details.beacon; - this.isGuest = details.isGuest; - this.groups = details.groups; - } -} diff --git a/lib/old/components/models/user/user_info.g.dart b/lib/old/components/models/user/user_info.g.dart deleted file mode 100644 index e5839179..00000000 --- a/lib/old/components/models/user/user_info.g.dart +++ /dev/null @@ -1,62 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'user_info.dart'; - -// ************************************************************************** -// TypeAdapterGenerator -// ************************************************************************** - -class UserAdapter extends TypeAdapter { - @override - final int typeId = 1; - - @override - User read(BinaryReader reader) { - final numOfFields = reader.readByte(); - final fields = { - for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), - }; - return User( - authToken: fields[1] as String?, - email: fields[3] as String?, - name: fields[2] as String?, - location: fields[6] as Location?, - beacon: (fields[4] as List?)?.cast(), - groups: (fields[5] as List?)?.cast(), - id: fields[0] as String?, - isGuest: fields[7] as bool?, - ); - } - - @override - void write(BinaryWriter writer, User obj) { - writer - ..writeByte(8) - ..writeByte(0) - ..write(obj.id) - ..writeByte(1) - ..write(obj.authToken) - ..writeByte(2) - ..write(obj.name) - ..writeByte(3) - ..write(obj.email) - ..writeByte(4) - ..write(obj.beacon) - ..writeByte(5) - ..write(obj.groups) - ..writeByte(6) - ..write(obj.location) - ..writeByte(7) - ..write(obj.isGuest); - } - - @override - int get hashCode => typeId.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is UserAdapter && - runtimeType == other.runtimeType && - typeId == other.typeId; -} diff --git a/lib/old/components/services/connection_checker.dart b/lib/old/components/services/connection_checker.dart deleted file mode 100644 index 481331d0..00000000 --- a/lib/old/components/services/connection_checker.dart +++ /dev/null @@ -1,9 +0,0 @@ -// import 'package:data_connection_checker/data_connection_checker.dart'; - -import 'package:data_connection_checker_nulls/data_connection_checker_nulls.dart'; - -class ConnectionChecker { - Future checkForInternetConnection() async { - return await DataConnectionChecker().hasConnection; - } -} diff --git a/lib/old/components/services/database_mutation_functions.dart b/lib/old/components/services/database_mutation_functions.dart deleted file mode 100644 index cbf74669..00000000 --- a/lib/old/components/services/database_mutation_functions.dart +++ /dev/null @@ -1,534 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; -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/old/components/models/user/user_info.dart'; -import '../../../locator.dart'; - -class DataBaseMutationFunctions { - late ValueNotifier clientNonAuth; - late GraphQLClient clientAuth; - late AuthQueries _authQuery; - late BeaconQueries _beaconQuery; - late GroupQueries _groupQuery; - init() async { - clientNonAuth = await ValueNotifier(graphqlConfig.clientToQuery()); - ValueNotifier(clientNonAuth); - clientAuth = await graphqlConfig.authClient(); - _authQuery = AuthQueries(); - _beaconQuery = BeaconQueries(); - _groupQuery = GroupQueries(); - } - - GraphQLError userNotFound = const GraphQLError(message: 'User not found'); - GraphQLError userNotAuthenticated = const GraphQLError( - message: 'Authentication required to perform this action.'); - GraphQLError emailAccountPresent = - const GraphQLError(message: 'Email address already exists'); - GraphQLError wrongCredentials = - const GraphQLError(message: 'Invalid credentials'); - - bool encounteredExceptionOrError(OperationException exception, - {bool showSnackBar = true}) { - if (exception.linkException != null) { - debugPrint(exception.linkException.toString()); - if (showSnackBar) { - debugPrint("Server not running/wrong url"); - } - return false; - } else { - debugPrint(exception.graphqlErrors.toString()); - for (int i = 0; i < exception.graphqlErrors.length; i++) { - if (exception.graphqlErrors[i].message == - userNotAuthenticated.message) { - return true; - } else if (exception.graphqlErrors[i].message == userNotFound.message) { - if (showSnackBar) { - // 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"); - } - return false; - } else if (exception.graphqlErrors[i].message == - emailAccountPresent.message) { - if (showSnackBar) { - // navigationService! - // .showSnackBar("Account with this email already registered"); - } - return false; - } - } - print("Something went wrong"); - return false; - } - } - - Future?> gqlquery(String query) async { - final QueryOptions options = QueryOptions( - document: gql(query), - variables: {}, - ); - - final QueryResult result = await clientAuth.query(options); - if (result.hasException) { - final bool exception = - encounteredExceptionOrError(result.exception!, showSnackBar: false); - if (exception) debugPrint("Exception Occured"); - } else if (result.data != null && result.isConcrete) { - return result.data; - } - - return result.data; - } - - //Auth - Future signup({String? name, String? email, String? password}) async { - final QueryResult result = email != null - ? await clientNonAuth.value.mutate(MutationOptions( - document: gql(_authQuery.registerUser(name, email, password)), - variables: { - 'name': name, - 'email': email, - 'password': password, - }, - )) - : await clientNonAuth.value.mutate(MutationOptions( - document: gql(_authQuery.loginAsGuest(name)), - )); - // final HttpLink httpLink = HttpLink('http://10.0.2.2:4000/graphql'); - // final ValueNotifier client = ValueNotifier( - // GraphQLClient( - // link: httpLink, - // cache: GraphQLCache(), - // ), - // ); - - // final QueryResult result = await client.value.mutate( - // MutationOptions( - // document: gql(_authQuery.registerUser(name, email!, password)), - // variables: { - // 'name': name, - // 'email': email, - // 'password': password, - // }, - // ), - // ); - - if (result.hasException) { - // navigationService! - // .showSnackBar("${result.exception!.graphqlErrors.first.message}"); - debugPrint('${result.exception!.graphqlErrors}'); - return exceptionError; - } else if (result.data != null && result.isConcrete) { - final User signedInUser = - User.fromJson(result.data!['register'] as Map); - final String logIn = email != null - ? await databaseFunctions! - .login(email: email, password: password, user: signedInUser) - : await databaseFunctions!.login(user: signedInUser); - return logIn; - } - return otherError; - } - - Future login({String? email, String? password, User? user}) async { - final QueryResult result = (email == null) - ? await clientNonAuth.value.mutate( - MutationOptions(document: gql(_authQuery.loginUsingID(user!.id)))) - : await clientNonAuth.value.mutate(MutationOptions( - document: gql(_authQuery.loginUser(email, password)))); - log(result.exception.toString()); - if (result.hasException) { - // navigationService! - // .showSnackBar("${result.exception!.graphqlErrors.first.message}"); - print("${result.exception!.graphqlErrors}"); - return exceptionError; - } else if (result.data != null && result.isConcrete) { - bool userSaved = false; - if (email == null) { - user!.isGuest = true; - user.authToken = "Bearer ${result.data!['login']}"; - userSaved = await userConfig!.updateUser(user); - } else { - User loggedInUser = - User(authToken: "Bearer ${result.data!['login']}", isGuest: false); - userSaved = await userConfig!.updateUser(loggedInUser); - } - final bool fetchInfo = await databaseFunctions!.fetchCurrentUserInfo(); - if (userSaved && fetchInfo) - return logSuccess; - else - return otherError; - } - return otherError; - } - - // User Info - Future fetchCurrentUserInfo() async { - await databaseFunctions!.init(); - final QueryResult result = await clientAuth - .query(QueryOptions(document: gql(_authQuery.fetchUserInfo()))); - if (result.hasException) { - final bool exception = - encounteredExceptionOrError(result.exception!, showSnackBar: false); - if (exception) { - await userConfig!.currentUser!.delete(); - navigationService!.pushReplacementScreen('/auth'); - } - } else if (result.data != null && result.isConcrete) { - User userInfo = User.fromJson( - result.data!['me'] as Map, - ); - userInfo.authToken = userConfig!.currentUser!.authToken; - userInfo.isGuest = userConfig!.currentUser!.isGuest; - await userConfig!.updateUser(userInfo); - return true; - } - return false; - } - - // Beacon Info - 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); - if (exception) { - print('Exception: ${result.exception}'); - } - } else if (result.data != null && result.isConcrete) { - final Beacon beacon = Beacon.fromJson( - result.data!['beacon'] as Map, - ); - return beacon; - } - return null; - } - - Future> fetchUserBeacons(String? groupid) async { - List beacons = []; - List _userBeacons = []; - Set beaconIds = {}; - List expiredBeacons = []; - if (!await connectionChecker!.checkForInternetConnection()) { - final userBeacons = hiveDb!.getAllUserBeacons(); - for (Beacon? i in userBeacons) { - if (i!.group == groupid) { - if (DateTime.fromMillisecondsSinceEpoch(i.expiresAt!) - .isBefore(DateTime.now())) - expiredBeacons.add(i); - else - beacons.add(i); - } - } - beacons.addAll(expiredBeacons); - return beacons; - } - - //if connected to internet take from internet. - final QueryResult result = await clientAuth - .query(QueryOptions(document: gql(_groupQuery.groupDetail(groupid)))); - if (result.hasException) { - final bool exception = - encounteredExceptionOrError(result.exception!, showSnackBar: false); - if (exception) { - print('$exception'); - } - } else if (result.data != null && result.isConcrete) { - // print(result.toString() + 'aadeeshmc'); - _userBeacons = (result.data!['group']['beacons'] as List) - .map((e) => Beacon.fromJson(e as Map)) - .toList(); - - // userInfo.print(); - for (var i in _userBeacons) { - if (!beaconIds.contains(i.id)) { - if (!hiveDb!.beaconsBox.containsKey(i.id)) { - //This only happens if a someone else adds user to their beacon (which currently is not possible). - //beacons are put in box when creating or joining. - await hiveDb!.putBeaconInBeaconBox(i.id, i); - } - beaconIds.add(i.id); - if (DateTime.fromMillisecondsSinceEpoch(i.expiresAt!) - .isBefore(DateTime.now())) { - expiredBeacons.insert(0, i); - expiredBeacons - .sort((a, b) => a!.expiresAt!.compareTo(b!.expiresAt!)); - expiredBeacons = expiredBeacons.reversed.toList(); - } else { - beacons.add(i); - beacons.sort((a, b) => a!.startsAt!.compareTo(b!.startsAt!)); - } - } - } - } - beacons.addAll(expiredBeacons); - - return beacons; - } - - Future createBeacon( - String? title, int startsAt, int expiresAt, String? groupID) async { - log(startsAt.toString()); - LatLng loc; - try { - loc = await AppConstants.getLocation(); - } catch (onErr) { - // 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}"); - print("Something went wrong: ${result.exception}"); - } else if (result.data != null && result.isConcrete) { - final Beacon beacon = Beacon.fromJson( - result.data!['createBeacon'] as Map, - ); - hiveDb!.putBeaconInBeaconBox(beacon.id, beacon); - return beacon; - } - return null; - } - - Future updateLeaderLoc(String? id, LatLng latLng) async { - final QueryResult result = await clientAuth.mutate(MutationOptions( - document: gql(_beaconQuery.updateBeaconLocation( - id, latLng.latitude.toString(), latLng.longitude.toString())))); - if (result.hasException) { - print( - "Something went wrong: ${result.exception}", - ); - // 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'] - as Map, - ); - print('location update successful'); - return location; - } - return null; - } - - Future joinBeacon(String? shortcode) async { - 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}"); - print("Something went wrong: ${result.exception}"); - navigationService!.removeAllAndPush('/main', '/'); - } else if (result.data != null && result.isConcrete) { - final Beacon beacon = Beacon.fromJson( - result.data!['joinBeacon'] as Map, - ); - if (DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!) - .isBefore(DateTime.now())) { - // 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", - // ); - } - return null; - } - - Future createLandmark( - String? title, LatLng loc, String? id) async { - await clientAuth - .mutate(MutationOptions( - document: gql(_beaconQuery.createLandmark( - id, loc.latitude.toString(), loc.longitude.toString(), title)))) - .then((value) { - if (value.hasException) { - // 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( - value.data!['createLandmark'] as Map, - ); - return landmark; - } - return null; - } as Future Function(QueryResult)); - return null; - } - - Future?> fetchNearbyBeacon(String? groupID) async { - await databaseFunctions!.init(); - List _nearbyBeacons = []; - List _nearbyBeaconsinGroup = []; - LatLng loc; - try { - loc = await AppConstants.getLocation(); - } catch (onErr) { - return null; - } - print(loc.latitude.toString()); - print(loc.longitude.toString()); - final QueryResult result = await clientAuth.query(QueryOptions( - document: gql(_beaconQuery.fetchNearbyBeacons( - loc.latitude.toString(), loc.longitude.toString())))); - if (result.hasException) { - final bool exception = - encounteredExceptionOrError(result.exception!, showSnackBar: false); - if (exception) { - print('${result.exception}'); - return null; - } - } else if (result.data != null && result.isConcrete) { - _nearbyBeacons = (result.data!['nearbyBeacons'] as List) - .map((e) => Beacon.fromJson(e as Map)) - .toList(); - for (Beacon i in _nearbyBeacons) - if (i.group == groupID) _nearbyBeaconsinGroup.add(i); - _nearbyBeaconsinGroup.sort((a, b) => a.startsAt!.compareTo(b.startsAt!)); - return _nearbyBeaconsinGroup; - } - return _nearbyBeacons; - } - - Future changeLeader(String? beaconID, String? newLeaderID) async { - await clientAuth - .mutate(MutationOptions( - document: gql(_beaconQuery.changeLeader(beaconID, newLeaderID)))) - .then((value) { - if (value.hasException) { - // 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( - value.data!['changeLeader'] as Map); - return changedLeader; - } - return null; - } as Future Function(QueryResult)); - return null; - } - - // Group Info - Future createGroup(String? title) async { - 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}"); - print("Something went wrong: ${result.exception}"); - } else if (result.data != null && result.isConcrete) { - final Group group = Group.fromJson( - result.data!['createGroup'] as Map, - ); - // hiveDb.putBeaconInBeaconBox(group.id, group); - return group; - } - return null; - } - - Future joinGroup(String? shortcode) async { - 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}"); - print("Something went wrong: ${result.exception}"); - // 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, - ); - // hiveDb.putBeaconInBeaconBox(beacon.id, beacon); - return group; - } else { - // navigationService!.showSnackBar( - // "Something went wrong while trying to join Group", - // ); - } - return null; - } - - Future> fetchUserGroups() async { - List groups = []; - Set groupIds = {}; - - // if (!await connectionChecker.checkForInternetConnection()) { - // final userBeacons = hiveDb.getAllUserBeacons(); - // if (userBeacons == null) { - // //snackbar has already been shown in getAllUserBeacons; - // return beacons; - // } - // for (Beacon i in userBeacons) { - // if (i.id == groupid) { - // if (DateTime.fromMillisecondsSinceEpoch(i.expiresAt) - // .isBefore(DateTime.now())) - // expiredBeacons.add(i); - // else - // beacons.add(i); - // } - // } - // beacons.addAll(expiredBeacons); - // return beacons; - // } - - //if connected to internet take from internet. - final QueryResult result = await clientAuth - .query(QueryOptions(document: gql(_authQuery.fetchUserInfo()))); - if (result.hasException) { - final bool exception = - encounteredExceptionOrError(result.exception!, showSnackBar: false); - if (exception) { - print('$exception'); - } - } else if (result.data != null && result.isConcrete) { - final User userInfo = User.fromJson( - result.data!['me'] as Map, - ); - // userInfo.print(); - for (var i in userInfo.groups!) { - // print(i.beacons.length.toString() + "hello"); - if (!groupIds.contains(i.id)) { - // if (!hiveDb.beaconsBox.containsKey(i.id)) { - // //This only happens if a someone else adds user to their beacon (which currently is not possible). - // //beacons are put in box when creating or joining. - // await hiveDb.putBeaconInBeaconBox(i.id, i); - // } - groupIds.add(i.id); - groups.add(i); - } - } - } - return groups; - } -} diff --git a/lib/old/components/services/hive_localdb.dart b/lib/old/components/services/hive_localdb.dart deleted file mode 100644 index fadda2b0..00000000 --- a/lib/old/components/services/hive_localdb.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:beacon/locator.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; - -import '../models/group/group.dart'; - -class HiveLocalDb { - late Box currentUserBox; - late Box beaconsBox; - Box? groupsBox; - - Future init() async { - final appDocumentDirectory = - await path_provider.getApplicationDocumentsDirectory(); - Hive - ..init(appDocumentDirectory.path) - ..registerAdapter(UserAdapter()) - ..registerAdapter(BeaconAdapter()) - ..registerAdapter(LocationAdapter()) - ..registerAdapter(LandmarkAdapter()) - ..registerAdapter(GroupAdapter()); - currentUserBox = await Hive.openBox('currentUser'); - beaconsBox = await Hive.openBox('beacons'); - groupsBox = await Hive.openBox('groups'); - } - - Future saveUserInHive(User? currentUser) async { - final box = currentUserBox; - if (currentUserBox.containsKey('user')) { - currentUserBox.delete('user'); - } - return await box.put('user', currentUser); - } - - Future putBeaconInBeaconBox(String? id, Beacon? beacon, - {bool fetchFromNetwork = false}) async { - if (beaconsBox.containsKey(id)) { - await beaconsBox.delete(id); - } - if (fetchFromNetwork) { - databaseFunctions!.init(); - beacon = await databaseFunctions!.fetchBeaconInfo(id); - } - await beaconsBox.put(id, beacon); - } - - List getAllUserBeacons() { - final user = currentUserBox.get('user')!; - print("asd" + user.id!); - final userBeacons = beaconsBox.values.toList(); - return userBeacons; - } -} diff --git a/lib/old/components/services/navigation_service.dart b/lib/old/components/services/navigation_service.dart deleted file mode 100644 index 3a21c838..00000000 --- a/lib/old/components/services/navigation_service.dart +++ /dev/null @@ -1,65 +0,0 @@ -import 'package:flutter/material.dart'; - -class NavigationService { - GlobalKey navigatorKey = GlobalKey(); - - Future pushScreen(String routeName, {dynamic arguments}) { - return navigatorKey.currentState! - .pushNamed(routeName, arguments: arguments); - } - - Future pushReplacementScreen(String routeName, {dynamic arguments}) { - return navigatorKey.currentState! - .pushReplacementNamed(routeName, arguments: arguments); - } - - void fromInviteLink(List routeNames, List arguments) { - int i = 0; - removeAllAndPush('/${routeNames[i]}', '/', arguments: arguments[i]); - for (i = 1; i < routeNames.length; i++) { - pushScreen('/${routeNames[i]}', arguments: arguments[i]); - } - } - - Future removeAllAndPush(String routeName, String tillRoute, - {dynamic arguments}) { - return navigatorKey.currentState!.pushNamedAndRemoveUntil( - routeName, ModalRoute.withName(tillRoute), - arguments: arguments); - } - - void pushDialog(Widget dialog) { - showDialog( - context: navigatorKey.currentContext!, - barrierColor: Colors.transparent, - barrierDismissible: false, - builder: (BuildContext context) { - return dialog; - }); - } - - // 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/old/components/services/size_config.dart b/lib/old/components/services/size_config.dart deleted file mode 100644 index 2be69044..00000000 --- a/lib/old/components/services/size_config.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter/widgets.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/old/components/services/user_config.dart b/lib/old/components/services/user_config.dart deleted file mode 100644 index 01c87735..00000000 --- a/lib/old/components/services/user_config.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:async'; -import 'package:beacon/old/components/models/user/user_info.dart'; -import 'package:flutter/material.dart'; -import '../../../locator.dart'; - -class UserConfig { - User? _currentUser = User(id: 'null', authToken: 'null'); - User? get currentUser => _currentUser; - - Future userLoggedIn() async { - final boxUser = hiveDb!.currentUserBox; - _currentUser = boxUser.get('user'); - if (_currentUser == null) { - _currentUser = User(id: 'null', authToken: 'null'); - return false; - } - bool userUpdated = true; - await graphqlConfig.getToken().then((value) async { - print('${userConfig!._currentUser!.authToken}'); - await databaseFunctions!.init(); - await databaseFunctions!.fetchCurrentUserInfo().then((value) { - if (value) { - hiveDb!.saveUserInHive(_currentUser); - userUpdated = true; - } else { - // navigationService!.showSnackBar("Couldn't update User details"); - userUpdated = false; - } - }); - }); - print('user updated: $userUpdated'); - return userUpdated; - } - - Future updateUser(User updatedUserDetails) async { - try { - _currentUser = updatedUserDetails; - print("User is guest or not: ${updatedUserDetails.isGuest}"); - hiveDb!.saveUserInHive(_currentUser); - return true; - } on Exception catch (e) { - debugPrint(e.toString()); - return false; - } - } -} diff --git a/lib/old/components/view_model/auth_screen_model.dart b/lib/old/components/view_model/auth_screen_model.dart deleted file mode 100644 index 33714b77..00000000 --- a/lib/old/components/view_model/auth_screen_model.dart +++ /dev/null @@ -1,143 +0,0 @@ -import 'dart:developer'; - -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/old/components/view_model/base_view_model.dart'; - -class AuthViewModel extends BaseModel { - final formKeySignup = GlobalKey(); - final formKeyLogin = GlobalKey(); - - AutovalidateMode loginValidate = AutovalidateMode.disabled; - AutovalidateMode signupValidate = AutovalidateMode.disabled; - final GlobalKey scaffoldKey = new GlobalKey(); - - final FocusNode emailLogin = FocusNode(); - final FocusNode passwordLogin = FocusNode(); - - final FocusNode password = FocusNode(); - final FocusNode email = FocusNode(); - final FocusNode name = FocusNode(); - - TextEditingController loginEmailController = new TextEditingController(); - TextEditingController loginPasswordController = new TextEditingController(); - - bool obscureTextLogin = true; - bool obscureTextSignup = true; - - TextEditingController signupEmailController = new TextEditingController(); - TextEditingController signupNameController = new TextEditingController(); - TextEditingController signupPasswordController = new TextEditingController(); - - PageController pageController = PageController(); - - Color left = Colors.white; - Color right = Colors.black; - - Color leftBg = kLightBlue; - Color rightBg = kBlue; - - nextSignup() async { - log('clicked'); - FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); - signupValidate = AutovalidateMode.always; - if (formKeySignup.currentState!.validate()) { - setState(ViewState.busy); - signupValidate = AutovalidateMode.disabled; - databaseFunctions!.init(); - final String signUpSuccess = await databaseFunctions!.signup( - name: signupNameController.text, - email: signupEmailController.text, - password: signupPasswordController.text); - if (signUpSuccess == logSuccess) { - userConfig!.currentUser!.print(); - navigationService!.removeAllAndPush('/main', '/'); - } else if (signUpSuccess == exceptionError) { - navigationService!.removeAllAndPush('/auth', '/'); - } else { - navigationService!.removeAllAndPush('/auth', '/'); - // navigationService!.showSnackBar('Something went wrong'); - } - setState(ViewState.idle); - } else { - // navigationService!.showSnackBar('Enter valid entries'); - } - } - - loginAsGuest() async { - setState(ViewState.busy); - await databaseFunctions!.init(); - final String signUpSuccess = - await databaseFunctions!.signup(name: "Anonymous"); - if (signUpSuccess == logSuccess) { - userConfig!.currentUser!.print(); - navigationService!.removeAllAndPush('/main', '/'); - } else { - navigationService!.removeAllAndPush('/auth', '/'); - // navigationService!.showSnackBar('Something went wrong'); - } - setState(ViewState.idle); - } - - nextLogin() async { - FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); - loginValidate = AutovalidateMode.always; - if (formKeyLogin.currentState!.validate()) { - setState(ViewState.busy); - loginValidate = AutovalidateMode.disabled; - await databaseFunctions!.init(); - final String loginSuccess = await databaseFunctions!.login( - email: loginEmailController.text.trimRight(), - password: loginPasswordController.text); - if (loginSuccess == logSuccess) { - userConfig!.currentUser!.print(); - navigationService!.removeAllAndPush('/main', '/'); - } else if (loginSuccess == exceptionError) { - navigationService!.removeAllAndPush('/auth', '/'); - } else { - navigationService!.removeAllAndPush('/auth', '/'); - // navigationService!.showSnackBar('Something went wrong'); - } - setState(ViewState.idle); - } else { - // navigationService!.showSnackBar('Enter valid entries'); - } - } - - void requestFocusForFocusNode(FocusNode focusNode) { - FocusScope.of(navigationService!.navigatorKey.currentContext!) - .requestFocus(focusNode); - } - - void onSignInButtonPress() { - pageController - .animateToPage(0, - duration: Duration(milliseconds: 500), curve: Curves.decelerate) - .then((value) { - requestFocusForFocusNode(emailLogin); - }); - } - - void onSignUpButtonPress() { - pageController - .animateToPage(1, - duration: Duration(milliseconds: 500), curve: Curves.decelerate) - .then((value) { - requestFocusForFocusNode(name); - }); - } - - displayPasswordLogin() { - setState(ViewState.busy); - obscureTextLogin = !obscureTextLogin; - setState(ViewState.idle); - } - - displayPasswordSignup() { - setState(ViewState.busy); - obscureTextSignup = !obscureTextSignup; - setState(ViewState.idle); - } -} diff --git a/lib/old/components/view_model/base_view_model.dart b/lib/old/components/view_model/base_view_model.dart deleted file mode 100644 index 42acc5c9..00000000 --- a/lib/old/components/view_model/base_view_model.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:beacon/old/components/enums/view_state.dart'; - -class BaseModel extends ChangeNotifier { - ViewState _state = ViewState.idle; - - ViewState get state => _state; - bool get isBusy => _state == ViewState.busy; - - void setState(ViewState viewState) { - _state = viewState; - notifyListeners(); - } -} diff --git a/lib/old/components/view_model/group_screen_view_model.dart b/lib/old/components/view_model/group_screen_view_model.dart deleted file mode 100644 index 0e72334a..00000000 --- a/lib/old/components/view_model/group_screen_view_model.dart +++ /dev/null @@ -1,113 +0,0 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:beacon/old/components/enums/view_state.dart'; -import 'package:beacon/locator.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'; - -class GroupViewModel extends BaseModel { - final formKeyCreate = GlobalKey(); - final formKeyJoin = GlobalKey(); - Duration? resultingDuration = Duration(minutes: 30); - AutovalidateMode validate = AutovalidateMode.onUserInteraction; - late DateTime startsAt; - DateTime? startingdate; - TimeOfDay? startingTime; - bool isCreatingHike = false; - String? title; - late bool hasStarted; - String? groupID; - //commenting out since its value isnt used anywhere. - //TextEditingController _titleController = new TextEditingController(); - TextEditingController durationController = new TextEditingController(); - TextEditingController startsAtDate = new TextEditingController(); - TextEditingController startsAtTime = new TextEditingController(); - String? enteredPasskey; - - createHikeRoom( - String? groupID, Function reloadList, BuildContext context) async { - FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); - validate = AutovalidateMode.always; - if (formKeyCreate.currentState!.validate()) { - // navigationService!.pop(); - AutoRouter.of(context).maybePop(); - setState(ViewState.busy); - validate = AutovalidateMode.disabled; - databaseFunctions!.init(); - final Beacon? beacon = await databaseFunctions!.createBeacon( - title, - startsAt.millisecondsSinceEpoch.toInt(), - startsAt.add(resultingDuration!).millisecondsSinceEpoch.toInt(), - groupID); - // setState(ViewState.idle); - if (beacon != null) { - hasStarted = DateTime.now() - .isAfter(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)); - if (hasStarted) { - // navigationService!.pushScreen('/hikeScreen', - // arguments: HikeScreen( - // beacon, - // isLeader: true, - // )); - } 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()}', - // ); - return; - } - } else { - // navigationService.showSnackBar('Something went wrong'); - setState(ViewState.idle); - } - } - } - - joinHikeRoom(Function reloadList) async { - // FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); - validate = AutovalidateMode.always; - if (formKeyJoin.currentState!.validate()) { - setState(ViewState.busy); - validate = AutovalidateMode.disabled; - databaseFunctions!.init(); - final Beacon? beacon = - await databaseFunctions!.joinBeacon(enteredPasskey); - // setState(ViewState.idle); - if (beacon != null) { - hasStarted = DateTime.now() - .isAfter(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)); - - if (hasStarted) { - // 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()}', - // ); - return; - } - } 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 Passkey'); - } - } - - logout() async { - setState(ViewState.busy); - await userConfig!.currentUser!.delete(); - await hiveDb!.beaconsBox.clear(); - // setState(ViewState.idle); - await localNotif!.deleteNotification(); - // navigationService!.removeAllAndPush('/auth', '/'); - } -} diff --git a/lib/old/components/view_model/hike_screen_model.dart b/lib/old/components/view_model/hike_screen_model.dart deleted file mode 100644 index 0dcd8308..00000000 --- a/lib/old/components/view_model/hike_screen_model.dart +++ /dev/null @@ -1,457 +0,0 @@ -import 'dart:async'; -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/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/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'; -import 'package:sliding_up_panel/sliding_up_panel.dart'; -import 'package:location/location.dart'; -import 'package:rxdart/rxdart.dart'; - -class HikeScreenViewModel extends BaseModel { - bool modelIsReady = false; - Beacon? beacon; - Set followerId = {}; - bool isGeneratingLink = false, isBeaconExpired = false; - List hikers = []; - List route = []; - Duration newDuration = Duration(seconds: 0); - Completer mapController = Completer(); - String? address, prevAddress; - bool isBusy = false; - Set markers = {}; - Set polylines = Set(); - StreamSubscription? _leaderLocation; - Stream? beaconLocationStream, beaconJoinedStream, mergedStream; - List polylineCoordinates = []; - PolylinePoints polylinePoints = PolylinePoints(); - final GlobalKey landmarkFormKey = GlobalKey(); - ScrollController scrollController = ScrollController(); - Location loc = new Location(); - late GraphQLClient graphQlClient; - PanelController panelController = PanelController(); - final List mergedStreamSubscriptions = []; - bool? isLeader = false; - - Geocoder geocoder = Geocoder(); - - void relayBeacon(String? newLeaderName, String? newLeaderID) async { - print(newLeaderID); - if (newLeaderID == userConfig!.currentUser!.id) - Fluttertoast.showToast(msg: 'Yeah, that\'s you'); - else { - if (beacon!.leader!.id == userConfig!.currentUser!.id) { - await databaseFunctions!.init(); - beacon!.leader!.id = newLeaderID; - Fluttertoast.showToast(msg: 'Beacon handed over to $newLeaderName'); - notifyListeners(); - } else { - Fluttertoast.showToast(msg: 'You dont have beacon to relay'); - } - } - } - - Future onWillPop(context) async { - return (await (showDialog( - context: context, - builder: (context) => DialogBoxes.showExitDialog( - context, isLeader, hikers.length, isBeaconExpired), - ) as FutureOr?)) ?? - false; - } - - LatLngBounds calculateMapBoundsFromListOfLatLng(List pointsList, - {double padding = 0.0005}) { - double southWestLatitude = 90; - double southWestLongitude = 90; - double northEastLatitude = -180; - double northEastLongitude = -180; - pointsList.forEach((point) { - if (point.latitude < southWestLatitude) { - southWestLatitude = point.latitude; - } - if (point.longitude < southWestLongitude) { - southWestLongitude = point.longitude; - } - if (point.latitude > northEastLatitude) { - northEastLatitude = point.latitude; - } - if (point.longitude > northEastLongitude) { - northEastLongitude = point.longitude; - } - }); - southWestLatitude = southWestLatitude - padding; - southWestLongitude = southWestLongitude - padding; - northEastLatitude = northEastLatitude + padding; - northEastLongitude = northEastLongitude + padding; - LatLngBounds bound = LatLngBounds( - southwest: LatLng(southWestLatitude, southWestLongitude), - northeast: LatLng(northEastLatitude, northEastLongitude)); - return bound; - } - - Future setPolyline() async { - PolylineResult? result = await polylinePoints.getRouteBetweenCoordinates( - EnvironmentConfig.googleMapApi!, // Google Maps API Key - PointLatLng(route.first.latitude, route.first.longitude), - PointLatLng(route.last.latitude, route.last.longitude), - ); - if (result.points.isNotEmpty) { - result.points.forEach((PointLatLng point) { - polylineCoordinates.add(LatLng(point.latitude, point.longitude)); - }); - } - - Polyline polyline = Polyline( - polylineId: PolylineId('poly'), - color: Colors.red, - points: polylineCoordinates, - width: 3, - ); - polylines.add(polyline); - } - - Future updatePinOnMap(LatLng loc) async { - CameraPosition cPosition = CameraPosition( - zoom: CAMERA_ZOOM, - tilt: CAMERA_TILT, - bearing: CAMERA_BEARING, - target: loc, - ); - final GoogleMapController controller = await mapController.future; - controller - .animateCamera(CameraUpdate.newCameraPosition(cPosition)) - .then((v) async { - CameraUpdate cameraUpdate = CameraUpdate.newLatLngBounds( - calculateMapBoundsFromListOfLatLng(route), 50); - controller.animateCamera(cameraUpdate); - }); - - var pinPosition = loc; - markers.removeWhere((m) => m.markerId.value == "1"); - markers.add(RippleMarker( - ripple: true, - markerId: MarkerId("1"), - position: pinPosition, // updated position - infoWindow: InfoWindow( - title: 'Current Location', - ), - )); - } - - Future updateModel(Beacon value) async { - // Coordinates coordinates = Coordinates(double.parse(beacon!.location!.lat!), - // double.parse(beacon!.location!.lon!)); - // var addresses = - // await Geocoder.local.findAddressesFromCoordinates(coordinates); - - var addresses = await geocoder.getAddressFromLonLat( - double.parse(beacon!.location!.lat!), - double.parse(beacon!.location!.lon!)); - isBeaconExpired = DateTime.fromMillisecondsSinceEpoch(beacon!.expiresAt!) - .isBefore(DateTime.now()); - hikers.add(value.leader); - for (var i in value.followers!) { - if (!followerId.contains(i.id)) { - hikers.add(i); - followerId.add(i.id); - } - } - var lat = double.parse(value.location!.lat!); - var lon = double.parse(value.location!.lon!); - route.add(LatLng(lat, lon)); - address = addresses; - markers.add(Marker( - markerId: MarkerId("0"), - position: route.first, - infoWindow: InfoWindow( - title: 'Initial Location', - ), - )); - markers.add(RippleMarker( - ripple: true, - markerId: MarkerId("1"), - position: route.last, - infoWindow: InfoWindow( - title: 'Current Location', - ), - )); - for (var i in value.landmarks!) { - markers.add(Marker( - markerId: MarkerId((markers.length + 1).toString()), - position: LatLng( - double.parse(i!.location!.lat!), double.parse(i.location!.lon!)), - infoWindow: InfoWindow( - title: '${i.title}', - ), - icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue), - )); - } - // for (var i in value.followers) { - // markers.add(Marker( - // markerId: MarkerId((markers.length + 1).toString()), - // position: LatLng( - // double.parse(i.location.lat), double.parse(i.location.lon)), - // infoWindow: InfoWindow( - // title: '${i.name}', - // ), - // icon: BitmapDescriptor.defaultMarkerWithHue( - // BitmapDescriptor.hueYellow), - // )); - // } - //notifyListeners(); - } - - Future fetchData() async { - await databaseFunctions!.fetchBeaconInfo(beacon!.id).then((value) async { - if (value != null) { - beacon = value; - await hiveDb!.putBeaconInBeaconBox(beacon!.id, beacon); - } else { - value = hiveDb!.beaconsBox.get(beacon!.id); - beacon = value; - } - log('value: ${value}'); - await updateModel(value!); - }); - } - - Future setupSubscriptions(bool isExpired) async { - if (isBeaconExpired || isExpired) return; - if (isLeader!) { - // distanceFilter (in m) can be changed to reduce the backend calls - await loc.changeSettings(interval: 3000, distanceFilter: 0.0); - _leaderLocation = loc.onLocationChanged.listen( - (LocationData currentLocation) async { - if (DateTime.fromMillisecondsSinceEpoch(beacon!.expiresAt!) - .isBefore(DateTime.now())) _leaderLocation!.cancel(); - // Coordinates coordinates = Coordinates( - // currentLocation.latitude!, currentLocation.longitude!); - // var addresses = - // await Geocoder.local.findAddressesFromCoordinates(coordinates); - - var addresses = await geocoder.getAddressFromLonLat( - currentLocation.latitude!, currentLocation.longitude!); - - String? _address = addresses; - if (address != _address) { - databaseFunctions!.init(); - await databaseFunctions!.updateLeaderLoc(beacon!.id, - LatLng(currentLocation.latitude!, currentLocation.longitude!)); - address = _address; - route.add( - LatLng(currentLocation.latitude!, currentLocation.longitude!)); - updatePinOnMap( - LatLng(currentLocation.latitude!, currentLocation.longitude!)); - setPolyline(); - notifyListeners(); - } - }, - ); - } else { - beaconLocationStream = graphQlClient.subscribe( - SubscriptionOptions( - document: BeaconQueries().beaconLocationSubGql, - variables: { - 'id': beacon!.id, - }, - ), - ); - } - - beaconJoinedStream = graphQlClient.subscribe( - SubscriptionOptions( - document: BeaconQueries().beaconJoinedSubGql, - variables: { - 'id': beacon!.id, - }, - ), - ); - if (!isLeader!) { - mergedStream = MergeStream([beaconLocationStream!, beaconJoinedStream!]); - } else { - mergedStream = beaconJoinedStream; - } - late StreamSubscription mergeStreamSubscription; - mergeStreamSubscription = mergedStream!.listen((event) async { - if (DateTime.fromMillisecondsSinceEpoch(beacon!.expiresAt!) - .isBefore(DateTime.now())) { - mergeStreamSubscription.cancel(); - isBeaconExpired = true; - notifyListeners(); - return; - } - if (event.data != null) { - print('${event.data}'); - if (event.data.containsKey('beaconJoined')) { - User newJoinee = User.fromJson(event.data['beaconJoined']); - - showOverlayNotification((context) { - return Card( - color: kLightBlue, - margin: const EdgeInsets.symmetric(horizontal: 4), - child: SafeArea( - child: ListTile( - leading: SizedBox.fromSize( - size: const Size(40, 40), - child: ClipOval( - child: Container( - child: - Image(image: AssetImage('images/male_avatar.png')), - ))), - title: Text('${newJoinee.name} joined the hike!'), - trailing: IconButton( - icon: Icon(Icons.close), - onPressed: () { - OverlaySupportEntry.of(context)!.dismiss(); - }), - ), - ), - ); - }, duration: Duration(milliseconds: 4000)); - - if (!followerId.contains(newJoinee.id)) { - hikers.add(newJoinee); - followerId.add(newJoinee.id); - beacon!.followers!.add(newJoinee); - await hiveDb!.putBeaconInBeaconBox(beacon!.id, beacon); - } - // markers.add(Marker( - // markerId: MarkerId((markers.length + 1).toString()), - // position: LatLng(double.parse(newJoinee.location.lat), - // double.parse(newJoinee.location.lon)), - // infoWindow: InfoWindow( - // title: '${newJoinee.name}', - // ), - // icon: BitmapDescriptor.defaultMarkerWithHue( - // BitmapDescriptor.hueYellow), - // )); - notifyListeners(); - } - if (event.data.containsKey('beaconLocation')) { - LatLng coord = LatLng( - double.parse(event.data['beaconLocation']['lat']), - double.parse(event.data['beaconLocation']['lon'])); - // var addresses = await Geocoder.local.findAddressesFromCoordinates( - // Coordinates(coord.latitude, coord.longitude)); - - var addresses = await geocoder.getAddressFromLonLat( - coord.latitude, coord.longitude); - beacon!.route!.add( - locModel.Location( - lat: coord.latitude.toString(), - lon: coord.longitude.toString(), - ), - ); - await hiveDb!.putBeaconInBeaconBox(beacon!.id, beacon); - String? _address = addresses; - route.add(coord); - updatePinOnMap(coord); - address = _address; - // setPolyline(); - notifyListeners(); - } - } - }); - - mergedStreamSubscriptions.add(mergeStreamSubscription); - } - - 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(); - graphQlClient = GraphQLConfig().graphQlClient(); - await setupSubscriptions( - DateTime.fromMillisecondsSinceEpoch(beacon!.expiresAt!) - .isBefore(DateTime.now())); - } else { - await updateModel(beacon!); - } - modelIsReady = true; - notifyListeners(); - // print("REBUITL" + modelIsReady.toString()); - } - - void beaconExpired() { - Fluttertoast.showToast(msg: 'Beacon Expired'); - } - - // startCountdown() { - // Future.delayed( - // DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt) - // .difference(DateTime.now()), () { - // beaconExpired(); - // }); - // } - - void dispose() { - if (_leaderLocation != null) { - _leaderLocation!.cancel(); - } - for (var streamSub in mergedStreamSubscriptions) { - streamSub.cancel(); - } - connectionChecker!.checkForInternetConnection().then( - (value) async { - await hiveDb! - .putBeaconInBeaconBox(beacon!.id, beacon, fetchFromNetwork: value); - }, - ); - super.dispose(); - } - - generateUrl(String shortcode) async { - setState(ViewState.busy); - Uri url = Uri.parse('https://beacon.aadibajpai.com/?shortcode=$shortcode'); - Share.share('To join beacon follow this link: $url'); - setState(ViewState.idle); - } - - Future createLandmark(var title, var loc, BuildContext context) async { - if (landmarkFormKey.currentState!.validate()) { - // navigationService!.pop(); - AutoRouter.of(context).maybePop(); - await databaseFunctions!.init(); - await databaseFunctions! - .createLandmark(title, loc, beacon!.id) - .then((value) async { - markers.add(Marker( - markerId: MarkerId((markers.length + 1).toString()), - position: loc, - infoWindow: InfoWindow( - title: '$title', - ), - icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue), - )); - beacon!.landmarks!.add(value); - await hiveDb!.putBeaconInBeaconBox(beacon!.id, beacon); - print(hiveDb!.beaconsBox.get(beacon!.id)!.landmarks!.length.toString() + - 'asdasdasd'); - notifyListeners(); - }); - } - } -} diff --git a/lib/old/components/view_model/home_screen_view_model.dart b/lib/old/components/view_model/home_screen_view_model.dart deleted file mode 100644 index 9aeff65b..00000000 --- a/lib/old/components/view_model/home_screen_view_model.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:beacon/old/components/enums/view_state.dart'; -import 'package:beacon/locator.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'; - -class HomeViewModel extends BaseModel { - final formKeyCreate = GlobalKey(); - final formKeyJoin = GlobalKey(); - AutovalidateMode validate = AutovalidateMode.onUserInteraction; - String? title; - bool isCreatingGroup = false; - String? enteredGroupCode; - - createGroupRoom(BuildContext context) async { - FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); - validate = AutovalidateMode.always; - if (formKeyCreate.currentState!.validate()) { - // navigationService!.pop(); - AutoRouter.of(context).maybePop(); - setState(ViewState.busy); - validate = AutovalidateMode.disabled; - databaseFunctions!.init(); - final Group? group = await databaseFunctions!.createGroup( - title, - ); - if (group != null) { - // navigationService!.pushScreen('/groupScreen', - // arguments: GroupScreen( - // group, - // )); - - AutoRouter.of(context).pushNamed('/group'); - } - } else { - // navigationService!.showSnackBar('Something went wrong'); - setState(ViewState.idle); - } - } - - joinGroupRoom(BuildContext context) async { - // FocusScope.of(navigationService!.navigatorKey.currentContext!).unfocus(); - validate = AutovalidateMode.always; - if (formKeyJoin.currentState!.validate()) { - setState(ViewState.busy); - validate = AutovalidateMode.disabled; - databaseFunctions!.init(); - final Group? group = await databaseFunctions!.joinGroup(enteredGroupCode); - // setState(ViewState.idle); - if (group != null) { - // 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'); - } - } - - logout(BuildContext context) async { - setState(ViewState.busy); - await userConfig!.currentUser!.delete(); - await hiveDb!.beaconsBox.clear(); - // setState(ViewState.idle); - await localNotif!.deleteNotification(); - // navigationService!.removeAllAndPush('/auth', '/'); - AutoRouter.of(context).pushAndPopUntil( - AuthScreenRoute(), - predicate: (route) { - return true; - }, - ); - } -} diff --git a/lib/old/components/views/base_view.dart b/lib/old/components/views/base_view.dart deleted file mode 100644 index 1b810559..00000000 --- a/lib/old/components/views/base_view.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:beacon/locator.dart'; - -class BaseView extends StatefulWidget { - const BaseView({ - required this.builder, - this.onModelReady, - }); - final Function(T)? onModelReady; - final Widget Function(BuildContext, T, Widget?) builder; - - @override - _BaseViewState createState() => _BaseViewState(); -} - -class _BaseViewState extends State> { - late T - model; // Note: Using `late` to indicate that it will be initialized in initState - - @override - void initState() { - super.initState(); - model = locator(); - - if (widget.onModelReady != null) { - widget.onModelReady!(model); - } - } - - @override - Widget build(BuildContext context) { - return ChangeNotifierProvider( - create: (context) => model, - child: Consumer( - builder: widget.builder, - ), - ); - } -} diff --git a/lib/old/components/views/workspace.code-workspace b/lib/old/components/views/workspace.code-workspace deleted file mode 100644 index 9596538c..00000000 --- a/lib/old/components/views/workspace.code-workspace +++ /dev/null @@ -1,13 +0,0 @@ -{ - "folders": [ - { - "path": "../.." - }, - { - "path": "../../../../EnHike/images" - } - ], -"settings": { - "java.configuration.updateBuildConfiguration": "interactive" -} -} \ No newline at end of file diff --git a/lib/presentation/auth/auth_cubit/auth_cubit.dart b/lib/presentation/auth/auth_cubit/auth_cubit.dart new file mode 100644 index 00000000..8f54240a --- /dev/null +++ b/lib/presentation/auth/auth_cubit/auth_cubit.dart @@ -0,0 +1,71 @@ +import 'dart:developer'; + +import 'package:beacon/config/router/router.dart'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/usecase/auth_usecase.dart'; +import 'package:beacon/presentation/auth/auth_cubit/auth_state.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/presentation/auth/verification_cubit/verification_cubit.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class AuthCubit extends Cubit { + static AuthCubit? _instance; + final AuthUseCase authUseCase; + AuthCubit._internal({required this.authUseCase}) : super(InitialAuthState()); + + factory AuthCubit(AuthUseCase authUseCase) { + return _instance ?? AuthCubit._internal(authUseCase: authUseCase); + } + + Future register( + String name, + String email, + String password, + ) async { + emit(AuthLoadingState()); + final dataState = await authUseCase.registerUseCase(name, email, password); + if (dataState is DataSuccess && dataState.data != null) { + if (dataState.data!.isVerified == false) { + // show verification screen + emit(AuthVerificationState()); + } else { + emit(SuccessState(message: "Welcome")); + } + } else { + emit(AuthErrorState(error: dataState.error!)); + } + } + + Future navigate() async { + await sp.deleteData('time'); + await sp.deleteData('otp'); + await locator().sendEmailVerification(); + appRouter.replace(VerificationScreenRoute()); + } + + Future login(String email, String password) async { + emit(AuthLoadingState()); + final dataState = await authUseCase.loginUserCase(email, password); + + if (dataState is DataSuccess && dataState.data != null) { + if (dataState.data!.isVerified == false) { + // show verification screen + emit(AuthVerificationState()); + } else { + emit(SuccessState()); + } + } else { + emit(AuthErrorState(error: dataState.error!)); + } + } + + void 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/presentation/auth/auth_cubit/auth_state.dart b/lib/presentation/auth/auth_cubit/auth_state.dart new file mode 100644 index 00000000..87391f55 --- /dev/null +++ b/lib/presentation/auth/auth_cubit/auth_state.dart @@ -0,0 +1,17 @@ +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'auth_state.freezed.dart'; + +@freezed +abstract class AuthState with _$AuthState { + const factory AuthState.initial() = InitialAuthState; + + const factory AuthState.loading() = AuthLoadingState; + + const factory AuthState.error({String? error}) = AuthErrorState; + + const factory AuthState.success({String? message}) = SuccessState; + + const factory AuthState.verify() = AuthVerificationState; +} diff --git a/lib/presentation/auth/auth_cubit/auth_state.freezed.dart b/lib/presentation/auth/auth_cubit/auth_state.freezed.dart new file mode 100644 index 00000000..8bda4037 --- /dev/null +++ b/lib/presentation/auth/auth_cubit/auth_state.freezed.dart @@ -0,0 +1,757 @@ +// 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 'auth_state.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 _$AuthState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(String? error) error, + required TResult Function(String? message) success, + required TResult Function() verify, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(String? error)? error, + TResult? Function(String? message)? success, + TResult? Function()? verify, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(String? error)? error, + TResult Function(String? message)? success, + TResult Function()? verify, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(InitialAuthState value) initial, + required TResult Function(AuthLoadingState value) loading, + required TResult Function(AuthErrorState value) error, + required TResult Function(SuccessState value) success, + required TResult Function(AuthVerificationState value) verify, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialAuthState value)? initial, + TResult? Function(AuthLoadingState value)? loading, + TResult? Function(AuthErrorState value)? error, + TResult? Function(SuccessState value)? success, + TResult? Function(AuthVerificationState value)? verify, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialAuthState value)? initial, + TResult Function(AuthLoadingState value)? loading, + TResult Function(AuthErrorState value)? error, + TResult Function(SuccessState value)? success, + TResult Function(AuthVerificationState value)? verify, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthStateCopyWith<$Res> { + factory $AuthStateCopyWith(AuthState value, $Res Function(AuthState) then) = + _$AuthStateCopyWithImpl<$Res, AuthState>; +} + +/// @nodoc +class _$AuthStateCopyWithImpl<$Res, $Val extends AuthState> + implements $AuthStateCopyWith<$Res> { + _$AuthStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$InitialAuthStateImplCopyWith<$Res> { + factory _$$InitialAuthStateImplCopyWith(_$InitialAuthStateImpl value, + $Res Function(_$InitialAuthStateImpl) then) = + __$$InitialAuthStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$InitialAuthStateImplCopyWithImpl<$Res> + extends _$AuthStateCopyWithImpl<$Res, _$InitialAuthStateImpl> + implements _$$InitialAuthStateImplCopyWith<$Res> { + __$$InitialAuthStateImplCopyWithImpl(_$InitialAuthStateImpl _value, + $Res Function(_$InitialAuthStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$InitialAuthStateImpl implements InitialAuthState { + const _$InitialAuthStateImpl(); + + @override + String toString() { + return 'AuthState.initial()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$InitialAuthStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(String? error) error, + required TResult Function(String? message) success, + required TResult Function() verify, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(String? error)? error, + TResult? Function(String? message)? success, + TResult? Function()? verify, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(String? error)? error, + TResult Function(String? message)? success, + TResult Function()? verify, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialAuthState value) initial, + required TResult Function(AuthLoadingState value) loading, + required TResult Function(AuthErrorState value) error, + required TResult Function(SuccessState value) success, + required TResult Function(AuthVerificationState value) verify, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialAuthState value)? initial, + TResult? Function(AuthLoadingState value)? loading, + TResult? Function(AuthErrorState value)? error, + TResult? Function(SuccessState value)? success, + TResult? Function(AuthVerificationState value)? verify, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialAuthState value)? initial, + TResult Function(AuthLoadingState value)? loading, + TResult Function(AuthErrorState value)? error, + TResult Function(SuccessState value)? success, + TResult Function(AuthVerificationState value)? verify, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class InitialAuthState implements AuthState { + const factory InitialAuthState() = _$InitialAuthStateImpl; +} + +/// @nodoc +abstract class _$$AuthLoadingStateImplCopyWith<$Res> { + factory _$$AuthLoadingStateImplCopyWith(_$AuthLoadingStateImpl value, + $Res Function(_$AuthLoadingStateImpl) then) = + __$$AuthLoadingStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$AuthLoadingStateImplCopyWithImpl<$Res> + extends _$AuthStateCopyWithImpl<$Res, _$AuthLoadingStateImpl> + implements _$$AuthLoadingStateImplCopyWith<$Res> { + __$$AuthLoadingStateImplCopyWithImpl(_$AuthLoadingStateImpl _value, + $Res Function(_$AuthLoadingStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$AuthLoadingStateImpl implements AuthLoadingState { + const _$AuthLoadingStateImpl(); + + @override + String toString() { + return 'AuthState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$AuthLoadingStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(String? error) error, + required TResult Function(String? message) success, + required TResult Function() verify, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(String? error)? error, + TResult? Function(String? message)? success, + TResult? Function()? verify, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(String? error)? error, + TResult Function(String? message)? success, + TResult Function()? verify, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialAuthState value) initial, + required TResult Function(AuthLoadingState value) loading, + required TResult Function(AuthErrorState value) error, + required TResult Function(SuccessState value) success, + required TResult Function(AuthVerificationState value) verify, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialAuthState value)? initial, + TResult? Function(AuthLoadingState value)? loading, + TResult? Function(AuthErrorState value)? error, + TResult? Function(SuccessState value)? success, + TResult? Function(AuthVerificationState value)? verify, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialAuthState value)? initial, + TResult Function(AuthLoadingState value)? loading, + TResult Function(AuthErrorState value)? error, + TResult Function(SuccessState value)? success, + TResult Function(AuthVerificationState value)? verify, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class AuthLoadingState implements AuthState { + const factory AuthLoadingState() = _$AuthLoadingStateImpl; +} + +/// @nodoc +abstract class _$$AuthErrorStateImplCopyWith<$Res> { + factory _$$AuthErrorStateImplCopyWith(_$AuthErrorStateImpl value, + $Res Function(_$AuthErrorStateImpl) then) = + __$$AuthErrorStateImplCopyWithImpl<$Res>; + @useResult + $Res call({String? error}); +} + +/// @nodoc +class __$$AuthErrorStateImplCopyWithImpl<$Res> + extends _$AuthStateCopyWithImpl<$Res, _$AuthErrorStateImpl> + implements _$$AuthErrorStateImplCopyWith<$Res> { + __$$AuthErrorStateImplCopyWithImpl( + _$AuthErrorStateImpl _value, $Res Function(_$AuthErrorStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? error = freezed, + }) { + return _then(_$AuthErrorStateImpl( + error: freezed == error + ? _value.error + : error // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$AuthErrorStateImpl implements AuthErrorState { + const _$AuthErrorStateImpl({this.error}); + + @override + final String? error; + + @override + String toString() { + return 'AuthState.error(error: $error)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuthErrorStateImpl && + (identical(other.error, error) || other.error == error)); + } + + @override + int get hashCode => Object.hash(runtimeType, error); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$AuthErrorStateImplCopyWith<_$AuthErrorStateImpl> get copyWith => + __$$AuthErrorStateImplCopyWithImpl<_$AuthErrorStateImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(String? error) error, + required TResult Function(String? message) success, + required TResult Function() verify, + }) { + return error(this.error); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(String? error)? error, + TResult? Function(String? message)? success, + TResult? Function()? verify, + }) { + return error?.call(this.error); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(String? error)? error, + TResult Function(String? message)? success, + TResult Function()? verify, + required TResult orElse(), + }) { + if (error != null) { + return error(this.error); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialAuthState value) initial, + required TResult Function(AuthLoadingState value) loading, + required TResult Function(AuthErrorState value) error, + required TResult Function(SuccessState value) success, + required TResult Function(AuthVerificationState value) verify, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialAuthState value)? initial, + TResult? Function(AuthLoadingState value)? loading, + TResult? Function(AuthErrorState value)? error, + TResult? Function(SuccessState value)? success, + TResult? Function(AuthVerificationState value)? verify, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialAuthState value)? initial, + TResult Function(AuthLoadingState value)? loading, + TResult Function(AuthErrorState value)? error, + TResult Function(SuccessState value)? success, + TResult Function(AuthVerificationState value)? verify, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class AuthErrorState implements AuthState { + const factory AuthErrorState({final String? error}) = _$AuthErrorStateImpl; + + String? get error; + @JsonKey(ignore: true) + _$$AuthErrorStateImplCopyWith<_$AuthErrorStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$SuccessStateImplCopyWith<$Res> { + factory _$$SuccessStateImplCopyWith( + _$SuccessStateImpl value, $Res Function(_$SuccessStateImpl) then) = + __$$SuccessStateImplCopyWithImpl<$Res>; + @useResult + $Res call({String? message}); +} + +/// @nodoc +class __$$SuccessStateImplCopyWithImpl<$Res> + extends _$AuthStateCopyWithImpl<$Res, _$SuccessStateImpl> + implements _$$SuccessStateImplCopyWith<$Res> { + __$$SuccessStateImplCopyWithImpl( + _$SuccessStateImpl _value, $Res Function(_$SuccessStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? message = freezed, + }) { + return _then(_$SuccessStateImpl( + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$SuccessStateImpl implements SuccessState { + const _$SuccessStateImpl({this.message}); + + @override + final String? message; + + @override + String toString() { + return 'AuthState.success(message: $message)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SuccessStateImpl && + (identical(other.message, message) || other.message == message)); + } + + @override + int get hashCode => Object.hash(runtimeType, message); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SuccessStateImplCopyWith<_$SuccessStateImpl> get copyWith => + __$$SuccessStateImplCopyWithImpl<_$SuccessStateImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(String? error) error, + required TResult Function(String? message) success, + required TResult Function() verify, + }) { + return success(message); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(String? error)? error, + TResult? Function(String? message)? success, + TResult? Function()? verify, + }) { + return success?.call(message); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(String? error)? error, + TResult Function(String? message)? success, + TResult Function()? verify, + required TResult orElse(), + }) { + if (success != null) { + return success(message); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialAuthState value) initial, + required TResult Function(AuthLoadingState value) loading, + required TResult Function(AuthErrorState value) error, + required TResult Function(SuccessState value) success, + required TResult Function(AuthVerificationState value) verify, + }) { + return success(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialAuthState value)? initial, + TResult? Function(AuthLoadingState value)? loading, + TResult? Function(AuthErrorState value)? error, + TResult? Function(SuccessState value)? success, + TResult? Function(AuthVerificationState value)? verify, + }) { + return success?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialAuthState value)? initial, + TResult Function(AuthLoadingState value)? loading, + TResult Function(AuthErrorState value)? error, + TResult Function(SuccessState value)? success, + TResult Function(AuthVerificationState value)? verify, + required TResult orElse(), + }) { + if (success != null) { + return success(this); + } + return orElse(); + } +} + +abstract class SuccessState implements AuthState { + const factory SuccessState({final String? message}) = _$SuccessStateImpl; + + String? get message; + @JsonKey(ignore: true) + _$$SuccessStateImplCopyWith<_$SuccessStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$AuthVerificationStateImplCopyWith<$Res> { + factory _$$AuthVerificationStateImplCopyWith( + _$AuthVerificationStateImpl value, + $Res Function(_$AuthVerificationStateImpl) then) = + __$$AuthVerificationStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$AuthVerificationStateImplCopyWithImpl<$Res> + extends _$AuthStateCopyWithImpl<$Res, _$AuthVerificationStateImpl> + implements _$$AuthVerificationStateImplCopyWith<$Res> { + __$$AuthVerificationStateImplCopyWithImpl(_$AuthVerificationStateImpl _value, + $Res Function(_$AuthVerificationStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$AuthVerificationStateImpl implements AuthVerificationState { + const _$AuthVerificationStateImpl(); + + @override + String toString() { + return 'AuthState.verify()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuthVerificationStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(String? error) error, + required TResult Function(String? message) success, + required TResult Function() verify, + }) { + return verify(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(String? error)? error, + TResult? Function(String? message)? success, + TResult? Function()? verify, + }) { + return verify?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(String? error)? error, + TResult Function(String? message)? success, + TResult Function()? verify, + required TResult orElse(), + }) { + if (verify != null) { + return verify(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialAuthState value) initial, + required TResult Function(AuthLoadingState value) loading, + required TResult Function(AuthErrorState value) error, + required TResult Function(SuccessState value) success, + required TResult Function(AuthVerificationState value) verify, + }) { + return verify(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialAuthState value)? initial, + TResult? Function(AuthLoadingState value)? loading, + TResult? Function(AuthErrorState value)? error, + TResult? Function(SuccessState value)? success, + TResult? Function(AuthVerificationState value)? verify, + }) { + return verify?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialAuthState value)? initial, + TResult Function(AuthLoadingState value)? loading, + TResult Function(AuthErrorState value)? error, + TResult Function(SuccessState value)? success, + TResult Function(AuthVerificationState value)? verify, + required TResult orElse(), + }) { + if (verify != null) { + return verify(this); + } + return orElse(); + } +} + +abstract class AuthVerificationState implements AuthState { + const factory AuthVerificationState() = _$AuthVerificationStateImpl; +} diff --git a/lib/Bloc/presentation/screens/auth_screen.dart b/lib/presentation/auth/auth_screen.dart similarity index 94% rename from lib/Bloc/presentation/screens/auth_screen.dart rename to lib/presentation/auth/auth_screen.dart index 7a16a165..98110de0 100644 --- a/lib/Bloc/presentation/screens/auth_screen.dart +++ b/lib/presentation/auth/auth_screen.dart @@ -1,16 +1,19 @@ 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/config/router/router.dart'; +import 'package:beacon/presentation/auth/auth_cubit/auth_cubit.dart'; +import 'package:beacon/presentation/auth/auth_cubit/auth_state.dart'; +import 'package:beacon/presentation/auth/verification_cubit/verification_cubit.dart'; +import 'package:beacon/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:beacon/presentation/widgets/hike_button.dart'; +import 'package:beacon/presentation/widgets/loading_screen.dart'; +import 'package:beacon/presentation/widgets/shape_painter.dart'; +import 'package:beacon/core/utils/validators.dart'; +import 'package:beacon/core/utils/constants.dart'; +import 'package:beacon/presentation/widgets/indication_painter.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:sizer/sizer.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; @RoutePage() class AuthScreen extends StatefulWidget { @@ -72,9 +75,10 @@ class _AuthScreenState extends State BlocConsumer( listener: (context, state) { if (state is SuccessState) { - AutoRouter.of(context).replaceNamed('/home'); - utils.showSnackBar('Login successful !', context, - duration: Duration(seconds: 2)); + appRouter.replaceNamed('/home'); + utils.showSnackBar(state.message!, context); + } else if (state is AuthVerificationState) { + context.read().navigate(); } else if (state is AuthErrorState) { utils.showSnackBar(state.error!, context, duration: Duration(seconds: 2)); diff --git a/lib/presentation/auth/verfication_screen.dart b/lib/presentation/auth/verfication_screen.dart new file mode 100644 index 00000000..782bce56 --- /dev/null +++ b/lib/presentation/auth/verfication_screen.dart @@ -0,0 +1,104 @@ +import 'dart:developer'; + +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/config/router/router.dart'; +import 'package:beacon/core/utils/constants.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/presentation/auth/verification_cubit/verification_cubit.dart'; +import 'package:beacon/presentation/auth/verification_cubit/verification_state.dart'; +import 'package:beacon/presentation/widgets/hike_button.dart'; +import 'package:beacon/presentation/widgets/shape_painter.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:gap/gap.dart'; +import 'package:pinput/pinput.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; + +@RoutePage() +class VerificationScreen extends StatefulWidget { + const VerificationScreen({super.key}); + + @override + State createState() => _VerificationScreenState(); +} + +class _VerificationScreenState extends State { + @override + void initState() { + super.initState(); + } + + TextEditingController _controller = TextEditingController(); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( + width: 100.w, + height: 100.h >= 775.0 ? 100.h : 775.0, + child: Stack( + children: [ + CustomPaint( + size: Size(100.w, 100.h), + painter: ShapePainter(), + ), + Align( + alignment: Alignment(-0.9, -0.9), + child: FloatingActionButton( + backgroundColor: kYellow, + onPressed: () async { + await sp.deleteData('time'); + await sp.deleteData('otp'); + appRouter.replace(AuthScreenRoute()); + }, + child: Icon(CupertinoIcons.back)), + ), + Container( + width: 100.w, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + 'A verification code is sent to your email', + style: TextStyle(color: kBlack, fontSize: 16), + ), + Gap(10), + Pinput( + controller: _controller, + onCompleted: (pin) => print(pin), + ), + Gap(20), + BlocBuilder( + builder: (context, state) { + return HikeButton( + onTap: state is OTPSentState + ? () async { + if (_controller.text == state.otp) { + await locator() + .completeVerification(); + if (state is OTPVerifiedState) { + appRouter.push(VerificationScreenRoute()); + } + } else { + utils.showSnackBar( + 'Please enter valid otp', context); + } + } + : null, + buttonColor: + state is OTPSendingState ? kBlack : kYellow, + text: ' Verify ', + ); + }, + ), + ], + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/presentation/auth/verification_cubit/verification_cubit.dart b/lib/presentation/auth/verification_cubit/verification_cubit.dart new file mode 100644 index 00000000..82ffbc27 --- /dev/null +++ b/lib/presentation/auth/verification_cubit/verification_cubit.dart @@ -0,0 +1,46 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/usecase/auth_usecase.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/presentation/auth/verification_cubit/verification_state.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +class VerificationCubit extends Cubit { + AuthUseCase _authUseCase; + VerificationCubit(this._authUseCase) : super(InitialOTPState()); + + emitVerificationSentstate(String otp) { + emit(OTPSentState(otp: otp)); + } + + _clear() async { + await sp.deleteData('time'); + await sp.deleteData('otp'); + } + + Future sendEmailVerification() async { + emit(OTPSendingState()); + final dataState = await _authUseCase.sendVerificationCode(); + + if (dataState is DataSuccess && dataState.data != null) { + await sp.init(); + await sp.saveData('time', DateTime.now().toIso8601String()); + await sp.saveData('otp', dataState.data!); + emit(OTPSentState(otp: dataState.data)); + } else { + emit(OTPFailureState()); + } + } + + Future completeVerification() async { + emit(OTPVerifyingState()); + + final dataState = await _authUseCase.completeVerification(); + + if (dataState is DataSuccess && dataState.data != null) { + _clear(); + appRouter.replaceNamed('/home'); + } else if (dataState is DataFailed) { + emit(OTPFailureState()); + } + } +} diff --git a/lib/presentation/auth/verification_cubit/verification_state.dart b/lib/presentation/auth/verification_cubit/verification_state.dart new file mode 100644 index 00000000..18c1ef98 --- /dev/null +++ b/lib/presentation/auth/verification_cubit/verification_state.dart @@ -0,0 +1,13 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'verification_state.freezed.dart'; + +@freezed +class OTPVerificationState with _$OTPVerificationState { + factory OTPVerificationState.initial() = InitialOTPState; + factory OTPVerificationState.otpSending() = OTPSendingState; + factory OTPVerificationState.otpSent({String? otp}) = OTPSentState; + factory OTPVerificationState.otpVerifying() = OTPVerifyingState; + factory OTPVerificationState.otpVerified() = OTPVerifiedState; + factory OTPVerificationState.failure() = OTPFailureState; +} diff --git a/lib/presentation/auth/verification_cubit/verification_state.freezed.dart b/lib/presentation/auth/verification_cubit/verification_state.freezed.dart new file mode 100644 index 00000000..688d823a --- /dev/null +++ b/lib/presentation/auth/verification_cubit/verification_state.freezed.dart @@ -0,0 +1,887 @@ +// 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 'verification_state.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 _$OTPVerificationState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() otpSending, + required TResult Function(String? otp) otpSent, + required TResult Function() otpVerifying, + required TResult Function() otpVerified, + required TResult Function() failure, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? otpSending, + TResult? Function(String? otp)? otpSent, + TResult? Function()? otpVerifying, + TResult? Function()? otpVerified, + TResult? Function()? failure, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? otpSending, + TResult Function(String? otp)? otpSent, + TResult Function()? otpVerifying, + TResult Function()? otpVerified, + TResult Function()? failure, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(InitialOTPState value) initial, + required TResult Function(OTPSendingState value) otpSending, + required TResult Function(OTPSentState value) otpSent, + required TResult Function(OTPVerifyingState value) otpVerifying, + required TResult Function(OTPVerifiedState value) otpVerified, + required TResult Function(OTPFailureState value) failure, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialOTPState value)? initial, + TResult? Function(OTPSendingState value)? otpSending, + TResult? Function(OTPSentState value)? otpSent, + TResult? Function(OTPVerifyingState value)? otpVerifying, + TResult? Function(OTPVerifiedState value)? otpVerified, + TResult? Function(OTPFailureState value)? failure, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialOTPState value)? initial, + TResult Function(OTPSendingState value)? otpSending, + TResult Function(OTPSentState value)? otpSent, + TResult Function(OTPVerifyingState value)? otpVerifying, + TResult Function(OTPVerifiedState value)? otpVerified, + TResult Function(OTPFailureState value)? failure, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $OTPVerificationStateCopyWith<$Res> { + factory $OTPVerificationStateCopyWith(OTPVerificationState value, + $Res Function(OTPVerificationState) then) = + _$OTPVerificationStateCopyWithImpl<$Res, OTPVerificationState>; +} + +/// @nodoc +class _$OTPVerificationStateCopyWithImpl<$Res, + $Val extends OTPVerificationState> + implements $OTPVerificationStateCopyWith<$Res> { + _$OTPVerificationStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$InitialOTPStateImplCopyWith<$Res> { + factory _$$InitialOTPStateImplCopyWith(_$InitialOTPStateImpl value, + $Res Function(_$InitialOTPStateImpl) then) = + __$$InitialOTPStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$InitialOTPStateImplCopyWithImpl<$Res> + extends _$OTPVerificationStateCopyWithImpl<$Res, _$InitialOTPStateImpl> + implements _$$InitialOTPStateImplCopyWith<$Res> { + __$$InitialOTPStateImplCopyWithImpl( + _$InitialOTPStateImpl _value, $Res Function(_$InitialOTPStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$InitialOTPStateImpl implements InitialOTPState { + _$InitialOTPStateImpl(); + + @override + String toString() { + return 'OTPVerificationState.initial()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$InitialOTPStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() otpSending, + required TResult Function(String? otp) otpSent, + required TResult Function() otpVerifying, + required TResult Function() otpVerified, + required TResult Function() failure, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? otpSending, + TResult? Function(String? otp)? otpSent, + TResult? Function()? otpVerifying, + TResult? Function()? otpVerified, + TResult? Function()? failure, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? otpSending, + TResult Function(String? otp)? otpSent, + TResult Function()? otpVerifying, + TResult Function()? otpVerified, + TResult Function()? failure, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialOTPState value) initial, + required TResult Function(OTPSendingState value) otpSending, + required TResult Function(OTPSentState value) otpSent, + required TResult Function(OTPVerifyingState value) otpVerifying, + required TResult Function(OTPVerifiedState value) otpVerified, + required TResult Function(OTPFailureState value) failure, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialOTPState value)? initial, + TResult? Function(OTPSendingState value)? otpSending, + TResult? Function(OTPSentState value)? otpSent, + TResult? Function(OTPVerifyingState value)? otpVerifying, + TResult? Function(OTPVerifiedState value)? otpVerified, + TResult? Function(OTPFailureState value)? failure, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialOTPState value)? initial, + TResult Function(OTPSendingState value)? otpSending, + TResult Function(OTPSentState value)? otpSent, + TResult Function(OTPVerifyingState value)? otpVerifying, + TResult Function(OTPVerifiedState value)? otpVerified, + TResult Function(OTPFailureState value)? failure, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class InitialOTPState implements OTPVerificationState { + factory InitialOTPState() = _$InitialOTPStateImpl; +} + +/// @nodoc +abstract class _$$OTPSendingStateImplCopyWith<$Res> { + factory _$$OTPSendingStateImplCopyWith(_$OTPSendingStateImpl value, + $Res Function(_$OTPSendingStateImpl) then) = + __$$OTPSendingStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$OTPSendingStateImplCopyWithImpl<$Res> + extends _$OTPVerificationStateCopyWithImpl<$Res, _$OTPSendingStateImpl> + implements _$$OTPSendingStateImplCopyWith<$Res> { + __$$OTPSendingStateImplCopyWithImpl( + _$OTPSendingStateImpl _value, $Res Function(_$OTPSendingStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$OTPSendingStateImpl implements OTPSendingState { + _$OTPSendingStateImpl(); + + @override + String toString() { + return 'OTPVerificationState.otpSending()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$OTPSendingStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() otpSending, + required TResult Function(String? otp) otpSent, + required TResult Function() otpVerifying, + required TResult Function() otpVerified, + required TResult Function() failure, + }) { + return otpSending(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? otpSending, + TResult? Function(String? otp)? otpSent, + TResult? Function()? otpVerifying, + TResult? Function()? otpVerified, + TResult? Function()? failure, + }) { + return otpSending?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? otpSending, + TResult Function(String? otp)? otpSent, + TResult Function()? otpVerifying, + TResult Function()? otpVerified, + TResult Function()? failure, + required TResult orElse(), + }) { + if (otpSending != null) { + return otpSending(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialOTPState value) initial, + required TResult Function(OTPSendingState value) otpSending, + required TResult Function(OTPSentState value) otpSent, + required TResult Function(OTPVerifyingState value) otpVerifying, + required TResult Function(OTPVerifiedState value) otpVerified, + required TResult Function(OTPFailureState value) failure, + }) { + return otpSending(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialOTPState value)? initial, + TResult? Function(OTPSendingState value)? otpSending, + TResult? Function(OTPSentState value)? otpSent, + TResult? Function(OTPVerifyingState value)? otpVerifying, + TResult? Function(OTPVerifiedState value)? otpVerified, + TResult? Function(OTPFailureState value)? failure, + }) { + return otpSending?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialOTPState value)? initial, + TResult Function(OTPSendingState value)? otpSending, + TResult Function(OTPSentState value)? otpSent, + TResult Function(OTPVerifyingState value)? otpVerifying, + TResult Function(OTPVerifiedState value)? otpVerified, + TResult Function(OTPFailureState value)? failure, + required TResult orElse(), + }) { + if (otpSending != null) { + return otpSending(this); + } + return orElse(); + } +} + +abstract class OTPSendingState implements OTPVerificationState { + factory OTPSendingState() = _$OTPSendingStateImpl; +} + +/// @nodoc +abstract class _$$OTPSentStateImplCopyWith<$Res> { + factory _$$OTPSentStateImplCopyWith( + _$OTPSentStateImpl value, $Res Function(_$OTPSentStateImpl) then) = + __$$OTPSentStateImplCopyWithImpl<$Res>; + @useResult + $Res call({String? otp}); +} + +/// @nodoc +class __$$OTPSentStateImplCopyWithImpl<$Res> + extends _$OTPVerificationStateCopyWithImpl<$Res, _$OTPSentStateImpl> + implements _$$OTPSentStateImplCopyWith<$Res> { + __$$OTPSentStateImplCopyWithImpl( + _$OTPSentStateImpl _value, $Res Function(_$OTPSentStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? otp = freezed, + }) { + return _then(_$OTPSentStateImpl( + otp: freezed == otp + ? _value.otp + : otp // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$OTPSentStateImpl implements OTPSentState { + _$OTPSentStateImpl({this.otp}); + + @override + final String? otp; + + @override + String toString() { + return 'OTPVerificationState.otpSent(otp: $otp)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$OTPSentStateImpl && + (identical(other.otp, otp) || other.otp == otp)); + } + + @override + int get hashCode => Object.hash(runtimeType, otp); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$OTPSentStateImplCopyWith<_$OTPSentStateImpl> get copyWith => + __$$OTPSentStateImplCopyWithImpl<_$OTPSentStateImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() otpSending, + required TResult Function(String? otp) otpSent, + required TResult Function() otpVerifying, + required TResult Function() otpVerified, + required TResult Function() failure, + }) { + return otpSent(otp); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? otpSending, + TResult? Function(String? otp)? otpSent, + TResult? Function()? otpVerifying, + TResult? Function()? otpVerified, + TResult? Function()? failure, + }) { + return otpSent?.call(otp); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? otpSending, + TResult Function(String? otp)? otpSent, + TResult Function()? otpVerifying, + TResult Function()? otpVerified, + TResult Function()? failure, + required TResult orElse(), + }) { + if (otpSent != null) { + return otpSent(otp); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialOTPState value) initial, + required TResult Function(OTPSendingState value) otpSending, + required TResult Function(OTPSentState value) otpSent, + required TResult Function(OTPVerifyingState value) otpVerifying, + required TResult Function(OTPVerifiedState value) otpVerified, + required TResult Function(OTPFailureState value) failure, + }) { + return otpSent(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialOTPState value)? initial, + TResult? Function(OTPSendingState value)? otpSending, + TResult? Function(OTPSentState value)? otpSent, + TResult? Function(OTPVerifyingState value)? otpVerifying, + TResult? Function(OTPVerifiedState value)? otpVerified, + TResult? Function(OTPFailureState value)? failure, + }) { + return otpSent?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialOTPState value)? initial, + TResult Function(OTPSendingState value)? otpSending, + TResult Function(OTPSentState value)? otpSent, + TResult Function(OTPVerifyingState value)? otpVerifying, + TResult Function(OTPVerifiedState value)? otpVerified, + TResult Function(OTPFailureState value)? failure, + required TResult orElse(), + }) { + if (otpSent != null) { + return otpSent(this); + } + return orElse(); + } +} + +abstract class OTPSentState implements OTPVerificationState { + factory OTPSentState({final String? otp}) = _$OTPSentStateImpl; + + String? get otp; + @JsonKey(ignore: true) + _$$OTPSentStateImplCopyWith<_$OTPSentStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$OTPVerifyingStateImplCopyWith<$Res> { + factory _$$OTPVerifyingStateImplCopyWith(_$OTPVerifyingStateImpl value, + $Res Function(_$OTPVerifyingStateImpl) then) = + __$$OTPVerifyingStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$OTPVerifyingStateImplCopyWithImpl<$Res> + extends _$OTPVerificationStateCopyWithImpl<$Res, _$OTPVerifyingStateImpl> + implements _$$OTPVerifyingStateImplCopyWith<$Res> { + __$$OTPVerifyingStateImplCopyWithImpl(_$OTPVerifyingStateImpl _value, + $Res Function(_$OTPVerifyingStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$OTPVerifyingStateImpl implements OTPVerifyingState { + _$OTPVerifyingStateImpl(); + + @override + String toString() { + return 'OTPVerificationState.otpVerifying()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$OTPVerifyingStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() otpSending, + required TResult Function(String? otp) otpSent, + required TResult Function() otpVerifying, + required TResult Function() otpVerified, + required TResult Function() failure, + }) { + return otpVerifying(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? otpSending, + TResult? Function(String? otp)? otpSent, + TResult? Function()? otpVerifying, + TResult? Function()? otpVerified, + TResult? Function()? failure, + }) { + return otpVerifying?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? otpSending, + TResult Function(String? otp)? otpSent, + TResult Function()? otpVerifying, + TResult Function()? otpVerified, + TResult Function()? failure, + required TResult orElse(), + }) { + if (otpVerifying != null) { + return otpVerifying(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialOTPState value) initial, + required TResult Function(OTPSendingState value) otpSending, + required TResult Function(OTPSentState value) otpSent, + required TResult Function(OTPVerifyingState value) otpVerifying, + required TResult Function(OTPVerifiedState value) otpVerified, + required TResult Function(OTPFailureState value) failure, + }) { + return otpVerifying(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialOTPState value)? initial, + TResult? Function(OTPSendingState value)? otpSending, + TResult? Function(OTPSentState value)? otpSent, + TResult? Function(OTPVerifyingState value)? otpVerifying, + TResult? Function(OTPVerifiedState value)? otpVerified, + TResult? Function(OTPFailureState value)? failure, + }) { + return otpVerifying?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialOTPState value)? initial, + TResult Function(OTPSendingState value)? otpSending, + TResult Function(OTPSentState value)? otpSent, + TResult Function(OTPVerifyingState value)? otpVerifying, + TResult Function(OTPVerifiedState value)? otpVerified, + TResult Function(OTPFailureState value)? failure, + required TResult orElse(), + }) { + if (otpVerifying != null) { + return otpVerifying(this); + } + return orElse(); + } +} + +abstract class OTPVerifyingState implements OTPVerificationState { + factory OTPVerifyingState() = _$OTPVerifyingStateImpl; +} + +/// @nodoc +abstract class _$$OTPVerifiedStateImplCopyWith<$Res> { + factory _$$OTPVerifiedStateImplCopyWith(_$OTPVerifiedStateImpl value, + $Res Function(_$OTPVerifiedStateImpl) then) = + __$$OTPVerifiedStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$OTPVerifiedStateImplCopyWithImpl<$Res> + extends _$OTPVerificationStateCopyWithImpl<$Res, _$OTPVerifiedStateImpl> + implements _$$OTPVerifiedStateImplCopyWith<$Res> { + __$$OTPVerifiedStateImplCopyWithImpl(_$OTPVerifiedStateImpl _value, + $Res Function(_$OTPVerifiedStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$OTPVerifiedStateImpl implements OTPVerifiedState { + _$OTPVerifiedStateImpl(); + + @override + String toString() { + return 'OTPVerificationState.otpVerified()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$OTPVerifiedStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() otpSending, + required TResult Function(String? otp) otpSent, + required TResult Function() otpVerifying, + required TResult Function() otpVerified, + required TResult Function() failure, + }) { + return otpVerified(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? otpSending, + TResult? Function(String? otp)? otpSent, + TResult? Function()? otpVerifying, + TResult? Function()? otpVerified, + TResult? Function()? failure, + }) { + return otpVerified?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? otpSending, + TResult Function(String? otp)? otpSent, + TResult Function()? otpVerifying, + TResult Function()? otpVerified, + TResult Function()? failure, + required TResult orElse(), + }) { + if (otpVerified != null) { + return otpVerified(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialOTPState value) initial, + required TResult Function(OTPSendingState value) otpSending, + required TResult Function(OTPSentState value) otpSent, + required TResult Function(OTPVerifyingState value) otpVerifying, + required TResult Function(OTPVerifiedState value) otpVerified, + required TResult Function(OTPFailureState value) failure, + }) { + return otpVerified(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialOTPState value)? initial, + TResult? Function(OTPSendingState value)? otpSending, + TResult? Function(OTPSentState value)? otpSent, + TResult? Function(OTPVerifyingState value)? otpVerifying, + TResult? Function(OTPVerifiedState value)? otpVerified, + TResult? Function(OTPFailureState value)? failure, + }) { + return otpVerified?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialOTPState value)? initial, + TResult Function(OTPSendingState value)? otpSending, + TResult Function(OTPSentState value)? otpSent, + TResult Function(OTPVerifyingState value)? otpVerifying, + TResult Function(OTPVerifiedState value)? otpVerified, + TResult Function(OTPFailureState value)? failure, + required TResult orElse(), + }) { + if (otpVerified != null) { + return otpVerified(this); + } + return orElse(); + } +} + +abstract class OTPVerifiedState implements OTPVerificationState { + factory OTPVerifiedState() = _$OTPVerifiedStateImpl; +} + +/// @nodoc +abstract class _$$OTPFailureStateImplCopyWith<$Res> { + factory _$$OTPFailureStateImplCopyWith(_$OTPFailureStateImpl value, + $Res Function(_$OTPFailureStateImpl) then) = + __$$OTPFailureStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$OTPFailureStateImplCopyWithImpl<$Res> + extends _$OTPVerificationStateCopyWithImpl<$Res, _$OTPFailureStateImpl> + implements _$$OTPFailureStateImplCopyWith<$Res> { + __$$OTPFailureStateImplCopyWithImpl( + _$OTPFailureStateImpl _value, $Res Function(_$OTPFailureStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$OTPFailureStateImpl implements OTPFailureState { + _$OTPFailureStateImpl(); + + @override + String toString() { + return 'OTPVerificationState.failure()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$OTPFailureStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() otpSending, + required TResult Function(String? otp) otpSent, + required TResult Function() otpVerifying, + required TResult Function() otpVerified, + required TResult Function() failure, + }) { + return failure(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? otpSending, + TResult? Function(String? otp)? otpSent, + TResult? Function()? otpVerifying, + TResult? Function()? otpVerified, + TResult? Function()? failure, + }) { + return failure?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? otpSending, + TResult Function(String? otp)? otpSent, + TResult Function()? otpVerifying, + TResult Function()? otpVerified, + TResult Function()? failure, + required TResult orElse(), + }) { + if (failure != null) { + return failure(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialOTPState value) initial, + required TResult Function(OTPSendingState value) otpSending, + required TResult Function(OTPSentState value) otpSent, + required TResult Function(OTPVerifyingState value) otpVerifying, + required TResult Function(OTPVerifiedState value) otpVerified, + required TResult Function(OTPFailureState value) failure, + }) { + return failure(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialOTPState value)? initial, + TResult? Function(OTPSendingState value)? otpSending, + TResult? Function(OTPSentState value)? otpSent, + TResult? Function(OTPVerifyingState value)? otpVerifying, + TResult? Function(OTPVerifiedState value)? otpVerified, + TResult? Function(OTPFailureState value)? failure, + }) { + return failure?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialOTPState value)? initial, + TResult Function(OTPSendingState value)? otpSending, + TResult Function(OTPSentState value)? otpSent, + TResult Function(OTPVerifyingState value)? otpVerifying, + TResult Function(OTPVerifiedState value)? otpVerified, + TResult Function(OTPFailureState value)? failure, + required TResult orElse(), + }) { + if (failure != null) { + return failure(this); + } + return orElse(); + } +} + +abstract class OTPFailureState implements OTPVerificationState { + factory OTPFailureState() = _$OTPFailureStateImpl; +} diff --git a/lib/presentation/group/cubit/group_cubit/group_cubit.dart b/lib/presentation/group/cubit/group_cubit/group_cubit.dart new file mode 100644 index 00000000..149b1915 --- /dev/null +++ b/lib/presentation/group/cubit/group_cubit/group_cubit.dart @@ -0,0 +1,681 @@ +import 'dart:async'; +import 'dart:developer'; +import 'package:beacon/config/local_notification.dart'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/domain/usecase/group_usecase.dart'; +import 'package:beacon/domain/usecase/hike_usecase.dart'; +import 'package:beacon/presentation/group/cubit/group_cubit/group_state.dart'; +import 'package:beacon/presentation/home/home_cubit/home_cubit.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/config/router/router.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:intl/intl.dart'; + +class GroupCubit extends Cubit { + final GroupUseCase _groupUseCase; + + GroupCubit._internal(this._groupUseCase) : super(InitialGroupState()) { + _initializeStates(); + } + + static GroupCubit? _instance; + + factory GroupCubit(GroupUseCase groupUseCase) { + return _instance ?? GroupCubit._internal(groupUseCase); + } + + int _page = 1; + int _pageSize = 4; + List _beacons = []; + List _nearbyBeacons = []; + List _statusBeacons = []; + + double _radius = 1000.0; + Position? _currentPosition; + String? _groupId; + + // for all beacon state + bool _isCompletelyFetched = false; + bool _isLoadingMore = false; + + // for status beacon state + + filters _currentFilter = filters.ALL; + + late AllBeaconGroupState _allBeaconGroupState; + late NearbyBeaconGroupState _nearbyBeaconGroupState; + late StatusFilterBeaconGroupState _statusFilterBeaconGroupState; + late ShrimmerGroupState _shrimmerGroupState; + late LoadingGroupState _loadingGroupState; + + init(GroupEntity group) { + _groupId = group.id!; + _currentPosition = locationService.currentPosition; + } + + _initializeStates() { + _shrimmerGroupState = ShrimmerGroupState(); + _allBeaconGroupState = AllBeaconGroupState(beacons: []); + + _nearbyBeaconGroupState = + NearbyBeaconGroupState(beacons: _nearbyBeacons, radius: _radius); + + _statusFilterBeaconGroupState = + StatusFilterBeaconGroupState(beacons: [], type: _currentFilter); + + _loadingGroupState = LoadingGroupState(); + } + + clear() { + _page = 1; + _beacons.clear(); + _nearbyBeacons.clear(); + _statusBeacons.clear(); + _isLoadingMore = false; + _isCompletelyFetched = false; + _currentFilter = filters.ALL; + _groupId = null; + emit(InitialGroupState()); + } + + Future createHike(String title, int startsAt, int expiresAt, + String groupID, bool isInstant) async { + emit(_loadingGroupState); + + bool isLocationEnabled = await fetchPosition(); + if (!isLocationEnabled) { + emit(ErrorGroupState( + message: 'To create a hike please enable your location!', + )); + return; + } + + final dataState = await _groupUseCase.createHike( + title, + startsAt, + expiresAt, + _currentPosition!.latitude.toString(), + _currentPosition!.longitude.toString(), + groupID); + + // checking the current state of the screen to add the beacon in the same list of state + + if (dataState is DataSuccess && dataState.data != null) { + BeaconEntity beacon = dataState.data!; + + // for adding beacons in group card + locator().addBeaconInGroup(beacon, _groupId!); + + locator().scheduleNotification(beacon); + + _beacons.add(beacon); + _beacons = sortHikes(_beacons); + if (_currentFilter == filters.ALL) { + if (isInstant) { + appRouter.popAndPush(HikeScreenRoute(beacon: beacon, isLeader: true)); + return; + } + emit(_allBeaconGroupState.copyWith( + beacons: _beacons, message: 'New Hike created')); + } + if (_currentFilter == filters.NEARBY) { + if (isInstant) { + appRouter.popAndPush(HikeScreenRoute(beacon: beacon, isLeader: true)); + return; + } + _nearbyBeacons.add(beacon); + _nearbyBeacons = sortHikes(_nearbyBeacons); + emit(_nearbyBeaconGroupState.copyWith(beacons: _nearbyBeacons)); + } else if (_currentFilter == filters.UPCOMING) { + if (isInstant) { + appRouter.popAndPush(HikeScreenRoute(beacon: beacon, isLeader: true)); + return; + } + _statusBeacons.add(beacon); + _statusBeacons = sortHikes(_statusBeacons); + emit(_statusFilterBeaconGroupState.copyWith( + beacons: _statusBeacons, type: _currentFilter)); + } + } else { + _emitErrorState(dataState.error); + } + } + + _emitErrorState(String? message) { + if (_currentFilter == filters.ALL) { + emit(_allBeaconGroupState.copyWith( + beacons: _beacons, + message: message, + )); + } else if (_currentFilter == filters.NEARBY) { + emit(_nearbyBeaconGroupState.copyWith( + beacons: _nearbyBeacons, + message: message, + )); + } else { + emit(_statusFilterBeaconGroupState.copyWith( + beacons: _statusBeacons, message: message, type: _currentFilter)); + } + } + + // ALL HIKES + Future allHikes(String groupId) async { + print('calling hikes'); + + if (_isCompletelyFetched || _isLoadingMore) return; + + if (_page == 1) { + emit((ShrimmerGroupState())); + } else { + _isLoadingMore = true; + emit(AllBeaconGroupState( + beacons: _beacons, + isLoadingMore: _isLoadingMore, + isCompletelyFetched: _isCompletelyFetched)); + } + + final dataState = await _groupUseCase.fetchHikes(groupId, _page, _pageSize); + + if (dataState is DataSuccess && dataState.data != null) { + print(dataState.data!.length.toString()); + + addBeaconList(dataState.data!); + _beacons = sortHikes(_beacons); + int length = dataState.data!.length; + if (length < 4) { + _isCompletelyFetched = true; + } + _page++; + _isLoadingMore = false; + emit(_allBeaconGroupState.copyWith( + beacons: _beacons, + isLoadingMore: _isLoadingMore, + isCompletelyFetched: _isCompletelyFetched)); + } else { + _isLoadingMore = false; + emit(_allBeaconGroupState.copyWith( + beacons: _beacons, + isLoadingMore: _isLoadingMore, + message: dataState.error, + isCompletelyFetched: _isCompletelyFetched)); + } + } + + void addBeaconList(List newBeacons) { + late bool isBeaconPresent; + var beacons = newBeacons; + for (int i = 0; i < beacons.length; i++) { + var beacon = beacons[i]; + isBeaconPresent = false; + for (int j = 0; j < _beacons.length; j++) { + if (beacon.id! == _beacons[j].id!) { + isBeaconPresent = true; + _beacons.removeAt(j); + _beacons.add(beacon); + } + } + if (isBeaconPresent == false) { + _beacons.add(beacon); + } + } + } + + Future fetchPosition() async { + _currentPosition = locationService.currentPosition; + if (_currentPosition == null) { + try { + _currentPosition = await locationService.getCurrentLocation(); + return true; + } catch (e) { + print('error: $e'); + return false; + } + } + return true; + } + + // NEARBY HIKES + Future nearbyHikes(String groupId, {double radius = 1000.0}) async { + _currentFilter = filters.NEARBY; + + emit(_shrimmerGroupState); + bool isLocationEnabled = await fetchPosition(); + if (!isLocationEnabled) { + emit(ErrorGroupState( + message: 'To see nearby hikes Please give access to your location!', + )); + return; + } + _radius = radius; + + final dataState = await _groupUseCase.nearbyHikes( + groupId, + _currentPosition!.latitude.toString(), + _currentPosition!.longitude.toString(), + radius); + + if (dataState is DataSuccess && dataState.data != null) { + _nearbyBeacons.clear(); + dataState.data!.forEach((beacon) { + _nearbyBeacons.add(beacon); + }); + _nearbyBeacons = sortHikes(_nearbyBeacons); + emit(_nearbyBeaconGroupState.copyWith( + beacons: _nearbyBeacons, + radius: _radius, + message: 'Beacons under $radius km..')); + } else { + emit(_nearbyBeaconGroupState.copyWith( + beacons: _nearbyBeacons, radius: _radius, message: dataState.error)); + } + } + + // ACTIVE UPCOMING INACTIVE HIKES + Future _filterHikes(String groupId, filters type) async { + print('calling filter hikes'); + print(_currentFilter.toString()); + emit(ShrimmerGroupState()); + final dataState = await _groupUseCase.filterHikes(groupId, type.name); + + if (dataState is DataSuccess && dataState.data != null) { + for (var beacon in dataState.data!) { + _statusBeacons.add(beacon); + } + _statusBeacons = sortHikes(_statusBeacons); + + print('calling function inside: ${_statusBeacons.length.toString()}'); + + emit(_statusFilterBeaconGroupState.copyWith( + beacons: _statusBeacons, type: type)); + } else { + emit(_statusFilterBeaconGroupState.copyWith( + beacons: _statusBeacons, type: type, message: dataState.error)); + } + } + + // DELETE BEACON + Future deleteBeacon(BeaconEntity beacon) async { + if (beacon.leader!.id != localApi.userModel.id) { + // for showing the snackbar + reloadState(message: 'You are not the leader of beacon!'); + return false; + } + var dataState = await _groupUseCase.deleteBeacon(beacon.id); + if (dataState is DataSuccess && dataState.data != null) { + // for removing beacons from group card + locator().deleteBeaconFromGroup(beacon, _groupId!); + + _beacons.removeWhere((currentBeacon) => currentBeacon.id! == beacon.id!); + _nearbyBeacons + .removeWhere((currentBeacon) => currentBeacon.id! == beacon.id!); + _statusBeacons + .removeWhere((currentBeacon) => currentBeacon.id! == beacon.id!); + + return true; + } else { + return false; + } + } + + List sortHikes(List _beacons) { + List inactive = []; + var now = DateTime.now(); + + _beacons.sort((a, b) => a.startsAt!.compareTo(b.startsAt!)); + + _beacons.removeWhere((beacon) { + var expiresAt = DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!); + if (expiresAt.isBefore(now)) { + inactive.add(beacon); + return true; + } + return false; + }); + + _beacons.addAll(inactive); + return _beacons; + } + + void changeFilter(filters filter) { + // emitting all loading state + print(filter.toString()); + if (filter == filters.ALL) { + _currentFilter = filters.ALL; + emit(ShrimmerGroupState()); + Future.delayed(Duration(milliseconds: 500), () { + emit(_allBeaconGroupState.copyWith(beacons: _beacons)); + }); + } + // emitting active upcoming and active on the basis of filter chosen + else if (filter == filters.ACTIVE || + filter == filters.INACTIVE || + filter == filters.UPCOMING) { + _loadfilterBeacons(filter, _groupId!); + } + } + + void _loadfilterBeacons(filters type, String groupId) { + if (type == _currentFilter) { + emit(ShrimmerGroupState()); + Future.delayed(Duration(milliseconds: 500), () { + emit(_statusFilterBeaconGroupState.copyWith( + beacons: _statusBeacons, type: type)); + }); + } else { + _currentFilter = type; + _statusBeacons.clear(); + _filterHikes(groupId, type); + } + } + + void reloadState({String? message}) { + emit(_loadingGroupState); + String? _message = message; + if (_currentFilter == filters.ALL) { + emit(_allBeaconGroupState.copyWith(beacons: _beacons, message: _message)); + } else if (_currentFilter == filters.NEARBY) { + emit(_nearbyBeaconGroupState.copyWith( + beacons: _nearbyBeacons, + message: _message, + )); + } else if (_currentFilter == filters.UPCOMING || + _currentFilter == filters.ACTIVE || + _currentFilter == filters.INACTIVE) { + emit(_statusFilterBeaconGroupState.copyWith( + beacons: _statusBeacons, message: _message, type: _currentFilter)); + } + } + + Future addBeacon(BeaconEntity newBeacon, String message) async { + List updatedBeacons = List.from(_beacons) + ..removeWhere((beacon) => beacon.id == newBeacon.id) + ..add(newBeacon); + _beacons = updatedBeacons; + updatedBeacons = sortHikes(updatedBeacons); + + print('here is come'); + + var newstate = _allBeaconGroupState.copyWith( + beacons: updatedBeacons, message: message); + print(newstate == _allBeaconGroupState); + emit(_shrimmerGroupState); + emit(_allBeaconGroupState.copyWith( + beacons: updatedBeacons, message: message)); + + if (state is NearbyBeaconGroupState) { + // first checking that the distance it is searching is that + + double distance = await locationService.calculateDistance( + LatLng(_currentPosition!.latitude, _currentPosition!.longitude), + LatLng(double.parse(newBeacon.location!.lat!), + double.parse(newBeacon.location!.lon!))); + + if (distance > _radius) return null; + + List updatedBeacons = List.from(_nearbyBeacons) + ..removeWhere((beacon) => beacon.id! == newBeacon.id!) + ..add(newBeacon); + + _nearbyBeacons = updatedBeacons; + + updatedBeacons = sortHikes(updatedBeacons); + emit(_nearbyBeaconGroupState.copyWith( + beacons: updatedBeacons, radius: _radius)); + } else if (state is StatusFilterBeaconGroupState) { + List updatedBeacons = List.from(_statusBeacons) + ..removeWhere((beacon) => beacon.id! == newBeacon.id!) + ..add(newBeacon); + + _statusBeacons = updatedBeacons; + updatedBeacons = sortHikes(updatedBeacons); + + emit(_statusFilterBeaconGroupState.copyWith( + beacons: updatedBeacons, + message: message, + )); + } + } + + Future removeBeacon(BeaconEntity deletedBeacon, String message) async { + for (int i = 0; i < _beacons.length; i++) { + if (_beacons[i].id! == deletedBeacon.id!) { + _beacons.removeAt(i); + break; + } + } + + var updatedBeacons = List.from(_beacons) + ..removeWhere((beacon) => beacon.id! == deletedBeacon.id!); + _beacons = updatedBeacons; + + emit(_allBeaconGroupState.copyWith( + beacons: updatedBeacons, + message: message, + )); + + if (state is NearbyBeaconGroupState) { + // first checking that the distance it is searching is that + + var updatedBeacons = List.from(_nearbyBeacons) + ..removeWhere((beacon) => beacon.id! == deletedBeacon.id!); + _nearbyBeacons = updatedBeacons; + emit(_nearbyBeaconGroupState.copyWith( + beacons: updatedBeacons, radius: _radius, message: message)); + } else if (state is StatusFilterBeaconGroupState) { + var updatedBeacons = List.from(_statusBeacons) + ..removeWhere((beacon) => beacon.id! == deletedBeacon.id!); + _statusBeacons = updatedBeacons; + emit(_statusFilterBeaconGroupState.copyWith( + beacons: updatedBeacons, + message: message, + )); + } + } + + Future rescheduleHike( + int newExpiresAt, int newStartsAt, String beaconId) async { + emit(ShrimmerGroupState()); + + DataState dataState = + await _groupUseCase.rescheduleHike(newExpiresAt, newStartsAt, beaconId); + + if (dataState is DataSuccess && dataState.data != null) { + BeaconEntity updatedBeacon = dataState.data!; + // adding the beacon in list and loading again + _beacons.removeWhere((beacon) => beacon.id! == updatedBeacon.id!); + _beacons.add(updatedBeacon); + _beacons = sortHikes(_beacons); + if (_currentFilter == filters.ALL) { + emit(_allBeaconGroupState.copyWith( + beacons: _beacons, message: 'Hike Rescheduled')); + return; + } + if (_currentFilter == filters.NEARBY) { + _nearbyBeacons.removeWhere((beacon) => beacon.id! == updatedBeacon.id!); + _nearbyBeacons.add(updatedBeacon); + _nearbyBeacons = sortHikes(_nearbyBeacons); + emit(_nearbyBeaconGroupState.copyWith( + beacons: _nearbyBeacons, radius: _radius)); + } else if (_currentFilter == filters.UPCOMING) { + _statusBeacons.removeWhere((beacon) => beacon.id! == updatedBeacon.id!); + _statusBeacons.add(updatedBeacon); + _statusBeacons = sortHikes(_statusBeacons); + + emit(_statusFilterBeaconGroupState.copyWith( + beacons: _nearbyBeacons, + message: 'Hike Rescheduled', + type: _currentFilter)); + } + } else { + if (_currentFilter == filters.ALL) { + emit(_allBeaconGroupState.copyWith( + beacons: _beacons, message: dataState.error)); + } else if (_currentFilter == filters.NEARBY) { + emit(_nearbyBeaconGroupState.copyWith( + beacons: _nearbyBeacons, + radius: _radius, + message: dataState.error)); + } else if (_currentFilter == filters.UPCOMING) { + emit(_statusFilterBeaconGroupState.copyWith( + beacons: _nearbyBeacons, + message: dataState.error, + type: _currentFilter)); + } + } + } + + void emitState({ + String? allBeaconMessage, + String? nearbyBeaconMessage, + String? statusBeaconMessage, + }) { + // creating this version to emit two same states consecutively + int version = DateTime.now().millisecondsSinceEpoch; + if (_currentFilter == filters.ALL) { + emit(_allBeaconGroupState.copyWith( + beacons: _beacons, + isCompletelyFetched: _isCompletelyFetched, + isLoadingMore: _isLoadingMore, + message: allBeaconMessage, + type: _currentFilter, + version: version)); + } else if (_currentFilter == filters.NEARBY) { + emit(_nearbyBeaconGroupState.copyWith( + beacons: _nearbyBeacons, + message: nearbyBeaconMessage, + type: _currentFilter, + radius: _radius, + version: version)); + } else { + emit(_statusFilterBeaconGroupState.copyWith( + beacons: _statusBeacons, + message: statusBeaconMessage, + type: _currentFilter, + version: version)); + } + return; + } + + _updateUserLocation(String beaconId) async { + var location = locationService.currentPosition; + if (location != null) { + // updating the current location before entering the map + await locator().changeUserLocation( + beaconId, LatLng(location.latitude, location.longitude)); + } else { + location = await locationService.getCurrentLocation(); + if (location == null) { + emit(ErrorGroupState(message: 'Please enable your location!')); + return; + } + await locator().changeUserLocation( + beaconId, LatLng(location.latitude, location.longitude)); + } + } + + Future joinBeacon( + BeaconEntity beacon, bool hasEnded, bool hasStarted) async { + if (hasEnded) { + String message = 'Beacon is not active anymore!'; + // function for emitting state on the basis of filter + if (beacon.leader!.id == localApi.userModel.id) { + // will allow the leader to join the beacon + + emit(_loadingGroupState); + + await _updateUserLocation(beacon.id!); + + appRouter.popAndPush(HikeScreenRoute( + beacon: beacon, + isLeader: (beacon.leader!.id == localApi.userModel.id))); + } + emitState( + allBeaconMessage: message, + nearbyBeaconMessage: message, + statusBeaconMessage: message); + return; + } + if (!hasStarted) { + String message = + 'Beacon has not yet started! \nPlease come back at ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}'; + emitState( + allBeaconMessage: message, + nearbyBeaconMessage: message, + statusBeaconMessage: message); + return; + } + bool isJoinee = false; + for (var i in beacon.followers!) { + if (i!.id == localApi.userModel.id) { + isJoinee = true; + } + } + if (hasStarted && + (beacon.leader!.id == localApi.userModel.id || isJoinee)) { + emit(_loadingGroupState); + + await _updateUserLocation(beacon.id!); + + appRouter.popAndPush(HikeScreenRoute( + beacon: beacon, + isLeader: (beacon.leader!.id == localApi.userModel.id))); + } else { + emit(_loadingGroupState); + await _updateUserLocation(beacon.id!); + final dataState = await _groupUseCase.joinHike(beacon.shortcode!); + if (dataState is DataFailed) return; + appRouter.popAndPush(HikeScreenRoute( + beacon: dataState.data!, + isLeader: dataState.data!.leader!.id == localApi.userModel.id)); + } + } + + Future joinBeaconWithShortCode(String shortcode) async { + _currentFilter = filters.ALL; + emit(_allBeaconGroupState.copyWith( + beacons: _beacons, + isCompletelyFetched: _isCompletelyFetched, + isLoadingMore: _isLoadingMore, + type: _currentFilter)); + emit(_loadingGroupState); + + for (var beacon in _beacons) { + if (beacon.shortcode == shortcode) { + bool hasEnded = DateTime.now() + .isAfter(DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!)); + bool hasStarted = DateTime.now() + .isAfter((DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!))); + await joinBeacon(beacon, hasEnded, hasStarted); + emitState(); + return; + } + } + + final dataState = await _groupUseCase.joinHike(shortcode); + + if (dataState is DataSuccess) { + var beacon = dataState.data!; + if (_groupId != beacon.group!.id) { + var message = 'The beacon is not the part of this group!'; + emitState( + allBeaconMessage: message, + nearbyBeaconMessage: message, + statusBeaconMessage: message); + return; + } + bool hasEnded = DateTime.now() + .isAfter(DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!)); + bool hasStarted = DateTime.now() + .isAfter((DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!))); + + _beacons.add(beacon); + await joinBeacon(beacon, hasEnded, hasStarted); + } else if (dataState is DataFailed) { + emitState(allBeaconMessage: dataState.error); + } + } +} diff --git a/lib/presentation/group/cubit/group_cubit/group_state.dart b/lib/presentation/group/cubit/group_cubit/group_state.dart new file mode 100644 index 00000000..f8043bd1 --- /dev/null +++ b/lib/presentation/group/cubit/group_cubit/group_state.dart @@ -0,0 +1,41 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +part 'group_state.freezed.dart'; + +enum filters { ALL, ACTIVE, UPCOMING, NEARBY, INACTIVE } + +@freezed +abstract class GroupState with _$GroupState { + const factory GroupState.initial() = InitialGroupState; + + const factory GroupState.loading() = LoadingGroupState; + + const factory GroupState.shrimmer() = ShrimmerGroupState; + + const factory GroupState.allBeacon( + {@Default(false) bool isLoadingMore, + @Default(false) bool isCompletelyFetched, + String? message, + @Default(filters.ALL) filters type, + required List beacons, + @Default(0) int version}) = AllBeaconGroupState; + + const factory GroupState.nearbyBeacon( + {String? message, + @Default(filters.NEARBY) filters type, + required List beacons, + @Default(1000.0) double radius, + @Default(0) int version}) = NearbyBeaconGroupState; + + const factory GroupState.statusFilterBeacon( + {@Default(false) bool isLoadingMore, + @Default(false) bool isCompletelyFetched, + String? message, + filters? type, + required List beacons, + @Default(0) int version}) = StatusFilterBeaconGroupState; + + const factory GroupState.error({ + required String message, + }) = ErrorGroupState; +} diff --git a/lib/presentation/group/cubit/group_cubit/group_state.freezed.dart b/lib/presentation/group/cubit/group_cubit/group_state.freezed.dart new file mode 100644 index 00000000..0ee4c3f4 --- /dev/null +++ b/lib/presentation/group/cubit/group_cubit/group_state.freezed.dart @@ -0,0 +1,1790 @@ +// 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_state.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 _$GroupState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() shrimmer, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version) + allBeacon, + required TResult Function(String? message, filters type, + List beacons, double radius, int version) + nearbyBeacon, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version) + statusFilterBeacon, + required TResult Function(String message) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? shrimmer, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult? Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult? Function(String message)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? shrimmer, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult Function(String message)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(InitialGroupState value) initial, + required TResult Function(LoadingGroupState value) loading, + required TResult Function(ShrimmerGroupState value) shrimmer, + required TResult Function(AllBeaconGroupState value) allBeacon, + required TResult Function(NearbyBeaconGroupState value) nearbyBeacon, + required TResult Function(StatusFilterBeaconGroupState value) + statusFilterBeacon, + required TResult Function(ErrorGroupState value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialGroupState value)? initial, + TResult? Function(LoadingGroupState value)? loading, + TResult? Function(ShrimmerGroupState value)? shrimmer, + TResult? Function(AllBeaconGroupState value)? allBeacon, + TResult? Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult? Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult? Function(ErrorGroupState value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialGroupState value)? initial, + TResult Function(LoadingGroupState value)? loading, + TResult Function(ShrimmerGroupState value)? shrimmer, + TResult Function(AllBeaconGroupState value)? allBeacon, + TResult Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult Function(ErrorGroupState value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $GroupStateCopyWith<$Res> { + factory $GroupStateCopyWith( + GroupState value, $Res Function(GroupState) then) = + _$GroupStateCopyWithImpl<$Res, GroupState>; +} + +/// @nodoc +class _$GroupStateCopyWithImpl<$Res, $Val extends GroupState> + implements $GroupStateCopyWith<$Res> { + _$GroupStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$InitialGroupStateImplCopyWith<$Res> { + factory _$$InitialGroupStateImplCopyWith(_$InitialGroupStateImpl value, + $Res Function(_$InitialGroupStateImpl) then) = + __$$InitialGroupStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$InitialGroupStateImplCopyWithImpl<$Res> + extends _$GroupStateCopyWithImpl<$Res, _$InitialGroupStateImpl> + implements _$$InitialGroupStateImplCopyWith<$Res> { + __$$InitialGroupStateImplCopyWithImpl(_$InitialGroupStateImpl _value, + $Res Function(_$InitialGroupStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$InitialGroupStateImpl implements InitialGroupState { + const _$InitialGroupStateImpl(); + + @override + String toString() { + return 'GroupState.initial()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$InitialGroupStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() shrimmer, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version) + allBeacon, + required TResult Function(String? message, filters type, + List beacons, double radius, int version) + nearbyBeacon, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version) + statusFilterBeacon, + required TResult Function(String message) error, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? shrimmer, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult? Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult? Function(String message)? error, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? shrimmer, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult Function(String message)? error, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialGroupState value) initial, + required TResult Function(LoadingGroupState value) loading, + required TResult Function(ShrimmerGroupState value) shrimmer, + required TResult Function(AllBeaconGroupState value) allBeacon, + required TResult Function(NearbyBeaconGroupState value) nearbyBeacon, + required TResult Function(StatusFilterBeaconGroupState value) + statusFilterBeacon, + required TResult Function(ErrorGroupState value) error, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialGroupState value)? initial, + TResult? Function(LoadingGroupState value)? loading, + TResult? Function(ShrimmerGroupState value)? shrimmer, + TResult? Function(AllBeaconGroupState value)? allBeacon, + TResult? Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult? Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult? Function(ErrorGroupState value)? error, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialGroupState value)? initial, + TResult Function(LoadingGroupState value)? loading, + TResult Function(ShrimmerGroupState value)? shrimmer, + TResult Function(AllBeaconGroupState value)? allBeacon, + TResult Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult Function(ErrorGroupState value)? error, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class InitialGroupState implements GroupState { + const factory InitialGroupState() = _$InitialGroupStateImpl; +} + +/// @nodoc +abstract class _$$LoadingGroupStateImplCopyWith<$Res> { + factory _$$LoadingGroupStateImplCopyWith(_$LoadingGroupStateImpl value, + $Res Function(_$LoadingGroupStateImpl) then) = + __$$LoadingGroupStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$LoadingGroupStateImplCopyWithImpl<$Res> + extends _$GroupStateCopyWithImpl<$Res, _$LoadingGroupStateImpl> + implements _$$LoadingGroupStateImplCopyWith<$Res> { + __$$LoadingGroupStateImplCopyWithImpl(_$LoadingGroupStateImpl _value, + $Res Function(_$LoadingGroupStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$LoadingGroupStateImpl implements LoadingGroupState { + const _$LoadingGroupStateImpl(); + + @override + String toString() { + return 'GroupState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$LoadingGroupStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() shrimmer, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version) + allBeacon, + required TResult Function(String? message, filters type, + List beacons, double radius, int version) + nearbyBeacon, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version) + statusFilterBeacon, + required TResult Function(String message) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? shrimmer, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult? Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult? Function(String message)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? shrimmer, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult Function(String message)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialGroupState value) initial, + required TResult Function(LoadingGroupState value) loading, + required TResult Function(ShrimmerGroupState value) shrimmer, + required TResult Function(AllBeaconGroupState value) allBeacon, + required TResult Function(NearbyBeaconGroupState value) nearbyBeacon, + required TResult Function(StatusFilterBeaconGroupState value) + statusFilterBeacon, + required TResult Function(ErrorGroupState value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialGroupState value)? initial, + TResult? Function(LoadingGroupState value)? loading, + TResult? Function(ShrimmerGroupState value)? shrimmer, + TResult? Function(AllBeaconGroupState value)? allBeacon, + TResult? Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult? Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult? Function(ErrorGroupState value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialGroupState value)? initial, + TResult Function(LoadingGroupState value)? loading, + TResult Function(ShrimmerGroupState value)? shrimmer, + TResult Function(AllBeaconGroupState value)? allBeacon, + TResult Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult Function(ErrorGroupState value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class LoadingGroupState implements GroupState { + const factory LoadingGroupState() = _$LoadingGroupStateImpl; +} + +/// @nodoc +abstract class _$$ShrimmerGroupStateImplCopyWith<$Res> { + factory _$$ShrimmerGroupStateImplCopyWith(_$ShrimmerGroupStateImpl value, + $Res Function(_$ShrimmerGroupStateImpl) then) = + __$$ShrimmerGroupStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$ShrimmerGroupStateImplCopyWithImpl<$Res> + extends _$GroupStateCopyWithImpl<$Res, _$ShrimmerGroupStateImpl> + implements _$$ShrimmerGroupStateImplCopyWith<$Res> { + __$$ShrimmerGroupStateImplCopyWithImpl(_$ShrimmerGroupStateImpl _value, + $Res Function(_$ShrimmerGroupStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$ShrimmerGroupStateImpl implements ShrimmerGroupState { + const _$ShrimmerGroupStateImpl(); + + @override + String toString() { + return 'GroupState.shrimmer()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$ShrimmerGroupStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() shrimmer, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version) + allBeacon, + required TResult Function(String? message, filters type, + List beacons, double radius, int version) + nearbyBeacon, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version) + statusFilterBeacon, + required TResult Function(String message) error, + }) { + return shrimmer(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? shrimmer, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult? Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult? Function(String message)? error, + }) { + return shrimmer?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? shrimmer, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult Function(String message)? error, + required TResult orElse(), + }) { + if (shrimmer != null) { + return shrimmer(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialGroupState value) initial, + required TResult Function(LoadingGroupState value) loading, + required TResult Function(ShrimmerGroupState value) shrimmer, + required TResult Function(AllBeaconGroupState value) allBeacon, + required TResult Function(NearbyBeaconGroupState value) nearbyBeacon, + required TResult Function(StatusFilterBeaconGroupState value) + statusFilterBeacon, + required TResult Function(ErrorGroupState value) error, + }) { + return shrimmer(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialGroupState value)? initial, + TResult? Function(LoadingGroupState value)? loading, + TResult? Function(ShrimmerGroupState value)? shrimmer, + TResult? Function(AllBeaconGroupState value)? allBeacon, + TResult? Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult? Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult? Function(ErrorGroupState value)? error, + }) { + return shrimmer?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialGroupState value)? initial, + TResult Function(LoadingGroupState value)? loading, + TResult Function(ShrimmerGroupState value)? shrimmer, + TResult Function(AllBeaconGroupState value)? allBeacon, + TResult Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult Function(ErrorGroupState value)? error, + required TResult orElse(), + }) { + if (shrimmer != null) { + return shrimmer(this); + } + return orElse(); + } +} + +abstract class ShrimmerGroupState implements GroupState { + const factory ShrimmerGroupState() = _$ShrimmerGroupStateImpl; +} + +/// @nodoc +abstract class _$$AllBeaconGroupStateImplCopyWith<$Res> { + factory _$$AllBeaconGroupStateImplCopyWith(_$AllBeaconGroupStateImpl value, + $Res Function(_$AllBeaconGroupStateImpl) then) = + __$$AllBeaconGroupStateImplCopyWithImpl<$Res>; + @useResult + $Res call( + {bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version}); +} + +/// @nodoc +class __$$AllBeaconGroupStateImplCopyWithImpl<$Res> + extends _$GroupStateCopyWithImpl<$Res, _$AllBeaconGroupStateImpl> + implements _$$AllBeaconGroupStateImplCopyWith<$Res> { + __$$AllBeaconGroupStateImplCopyWithImpl(_$AllBeaconGroupStateImpl _value, + $Res Function(_$AllBeaconGroupStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? isLoadingMore = null, + Object? isCompletelyFetched = null, + Object? message = freezed, + Object? type = null, + Object? beacons = null, + Object? version = null, + }) { + return _then(_$AllBeaconGroupStateImpl( + isLoadingMore: null == isLoadingMore + ? _value.isLoadingMore + : isLoadingMore // ignore: cast_nullable_to_non_nullable + as bool, + isCompletelyFetched: null == isCompletelyFetched + ? _value.isCompletelyFetched + : isCompletelyFetched // ignore: cast_nullable_to_non_nullable + as bool, + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as filters, + beacons: null == beacons + ? _value._beacons + : beacons // ignore: cast_nullable_to_non_nullable + as List, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$AllBeaconGroupStateImpl implements AllBeaconGroupState { + const _$AllBeaconGroupStateImpl( + {this.isLoadingMore = false, + this.isCompletelyFetched = false, + this.message, + this.type = filters.ALL, + required final List beacons, + this.version = 0}) + : _beacons = beacons; + + @override + @JsonKey() + final bool isLoadingMore; + @override + @JsonKey() + final bool isCompletelyFetched; + @override + final String? message; + @override + @JsonKey() + final filters type; + final List _beacons; + @override + List get beacons { + if (_beacons is EqualUnmodifiableListView) return _beacons; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_beacons); + } + + @override + @JsonKey() + final int version; + + @override + String toString() { + return 'GroupState.allBeacon(isLoadingMore: $isLoadingMore, isCompletelyFetched: $isCompletelyFetched, message: $message, type: $type, beacons: $beacons, version: $version)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AllBeaconGroupStateImpl && + (identical(other.isLoadingMore, isLoadingMore) || + other.isLoadingMore == isLoadingMore) && + (identical(other.isCompletelyFetched, isCompletelyFetched) || + other.isCompletelyFetched == isCompletelyFetched) && + (identical(other.message, message) || other.message == message) && + (identical(other.type, type) || other.type == type) && + const DeepCollectionEquality().equals(other._beacons, _beacons) && + (identical(other.version, version) || other.version == version)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + isLoadingMore, + isCompletelyFetched, + message, + type, + const DeepCollectionEquality().hash(_beacons), + version); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$AllBeaconGroupStateImplCopyWith<_$AllBeaconGroupStateImpl> get copyWith => + __$$AllBeaconGroupStateImplCopyWithImpl<_$AllBeaconGroupStateImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() shrimmer, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version) + allBeacon, + required TResult Function(String? message, filters type, + List beacons, double radius, int version) + nearbyBeacon, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version) + statusFilterBeacon, + required TResult Function(String message) error, + }) { + return allBeacon( + isLoadingMore, isCompletelyFetched, message, type, beacons, version); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? shrimmer, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult? Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult? Function(String message)? error, + }) { + return allBeacon?.call( + isLoadingMore, isCompletelyFetched, message, type, beacons, version); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? shrimmer, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult Function(String message)? error, + required TResult orElse(), + }) { + if (allBeacon != null) { + return allBeacon( + isLoadingMore, isCompletelyFetched, message, type, beacons, version); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialGroupState value) initial, + required TResult Function(LoadingGroupState value) loading, + required TResult Function(ShrimmerGroupState value) shrimmer, + required TResult Function(AllBeaconGroupState value) allBeacon, + required TResult Function(NearbyBeaconGroupState value) nearbyBeacon, + required TResult Function(StatusFilterBeaconGroupState value) + statusFilterBeacon, + required TResult Function(ErrorGroupState value) error, + }) { + return allBeacon(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialGroupState value)? initial, + TResult? Function(LoadingGroupState value)? loading, + TResult? Function(ShrimmerGroupState value)? shrimmer, + TResult? Function(AllBeaconGroupState value)? allBeacon, + TResult? Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult? Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult? Function(ErrorGroupState value)? error, + }) { + return allBeacon?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialGroupState value)? initial, + TResult Function(LoadingGroupState value)? loading, + TResult Function(ShrimmerGroupState value)? shrimmer, + TResult Function(AllBeaconGroupState value)? allBeacon, + TResult Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult Function(ErrorGroupState value)? error, + required TResult orElse(), + }) { + if (allBeacon != null) { + return allBeacon(this); + } + return orElse(); + } +} + +abstract class AllBeaconGroupState implements GroupState { + const factory AllBeaconGroupState( + {final bool isLoadingMore, + final bool isCompletelyFetched, + final String? message, + final filters type, + required final List beacons, + final int version}) = _$AllBeaconGroupStateImpl; + + bool get isLoadingMore; + bool get isCompletelyFetched; + String? get message; + filters get type; + List get beacons; + int get version; + @JsonKey(ignore: true) + _$$AllBeaconGroupStateImplCopyWith<_$AllBeaconGroupStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$NearbyBeaconGroupStateImplCopyWith<$Res> { + factory _$$NearbyBeaconGroupStateImplCopyWith( + _$NearbyBeaconGroupStateImpl value, + $Res Function(_$NearbyBeaconGroupStateImpl) then) = + __$$NearbyBeaconGroupStateImplCopyWithImpl<$Res>; + @useResult + $Res call( + {String? message, + filters type, + List beacons, + double radius, + int version}); +} + +/// @nodoc +class __$$NearbyBeaconGroupStateImplCopyWithImpl<$Res> + extends _$GroupStateCopyWithImpl<$Res, _$NearbyBeaconGroupStateImpl> + implements _$$NearbyBeaconGroupStateImplCopyWith<$Res> { + __$$NearbyBeaconGroupStateImplCopyWithImpl( + _$NearbyBeaconGroupStateImpl _value, + $Res Function(_$NearbyBeaconGroupStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? message = freezed, + Object? type = null, + Object? beacons = null, + Object? radius = null, + Object? version = null, + }) { + return _then(_$NearbyBeaconGroupStateImpl( + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as filters, + beacons: null == beacons + ? _value._beacons + : beacons // ignore: cast_nullable_to_non_nullable + as List, + radius: null == radius + ? _value.radius + : radius // ignore: cast_nullable_to_non_nullable + as double, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$NearbyBeaconGroupStateImpl implements NearbyBeaconGroupState { + const _$NearbyBeaconGroupStateImpl( + {this.message, + this.type = filters.NEARBY, + required final List beacons, + this.radius = 1000.0, + this.version = 0}) + : _beacons = beacons; + + @override + final String? message; + @override + @JsonKey() + final filters type; + final List _beacons; + @override + List get beacons { + if (_beacons is EqualUnmodifiableListView) return _beacons; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_beacons); + } + + @override + @JsonKey() + final double radius; + @override + @JsonKey() + final int version; + + @override + String toString() { + return 'GroupState.nearbyBeacon(message: $message, type: $type, beacons: $beacons, radius: $radius, version: $version)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$NearbyBeaconGroupStateImpl && + (identical(other.message, message) || other.message == message) && + (identical(other.type, type) || other.type == type) && + const DeepCollectionEquality().equals(other._beacons, _beacons) && + (identical(other.radius, radius) || other.radius == radius) && + (identical(other.version, version) || other.version == version)); + } + + @override + int get hashCode => Object.hash(runtimeType, message, type, + const DeepCollectionEquality().hash(_beacons), radius, version); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$NearbyBeaconGroupStateImplCopyWith<_$NearbyBeaconGroupStateImpl> + get copyWith => __$$NearbyBeaconGroupStateImplCopyWithImpl< + _$NearbyBeaconGroupStateImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() shrimmer, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version) + allBeacon, + required TResult Function(String? message, filters type, + List beacons, double radius, int version) + nearbyBeacon, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version) + statusFilterBeacon, + required TResult Function(String message) error, + }) { + return nearbyBeacon(message, type, beacons, radius, version); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? shrimmer, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult? Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult? Function(String message)? error, + }) { + return nearbyBeacon?.call(message, type, beacons, radius, version); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? shrimmer, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult Function(String message)? error, + required TResult orElse(), + }) { + if (nearbyBeacon != null) { + return nearbyBeacon(message, type, beacons, radius, version); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialGroupState value) initial, + required TResult Function(LoadingGroupState value) loading, + required TResult Function(ShrimmerGroupState value) shrimmer, + required TResult Function(AllBeaconGroupState value) allBeacon, + required TResult Function(NearbyBeaconGroupState value) nearbyBeacon, + required TResult Function(StatusFilterBeaconGroupState value) + statusFilterBeacon, + required TResult Function(ErrorGroupState value) error, + }) { + return nearbyBeacon(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialGroupState value)? initial, + TResult? Function(LoadingGroupState value)? loading, + TResult? Function(ShrimmerGroupState value)? shrimmer, + TResult? Function(AllBeaconGroupState value)? allBeacon, + TResult? Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult? Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult? Function(ErrorGroupState value)? error, + }) { + return nearbyBeacon?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialGroupState value)? initial, + TResult Function(LoadingGroupState value)? loading, + TResult Function(ShrimmerGroupState value)? shrimmer, + TResult Function(AllBeaconGroupState value)? allBeacon, + TResult Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult Function(ErrorGroupState value)? error, + required TResult orElse(), + }) { + if (nearbyBeacon != null) { + return nearbyBeacon(this); + } + return orElse(); + } +} + +abstract class NearbyBeaconGroupState implements GroupState { + const factory NearbyBeaconGroupState( + {final String? message, + final filters type, + required final List beacons, + final double radius, + final int version}) = _$NearbyBeaconGroupStateImpl; + + String? get message; + filters get type; + List get beacons; + double get radius; + int get version; + @JsonKey(ignore: true) + _$$NearbyBeaconGroupStateImplCopyWith<_$NearbyBeaconGroupStateImpl> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$StatusFilterBeaconGroupStateImplCopyWith<$Res> { + factory _$$StatusFilterBeaconGroupStateImplCopyWith( + _$StatusFilterBeaconGroupStateImpl value, + $Res Function(_$StatusFilterBeaconGroupStateImpl) then) = + __$$StatusFilterBeaconGroupStateImplCopyWithImpl<$Res>; + @useResult + $Res call( + {bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version}); +} + +/// @nodoc +class __$$StatusFilterBeaconGroupStateImplCopyWithImpl<$Res> + extends _$GroupStateCopyWithImpl<$Res, _$StatusFilterBeaconGroupStateImpl> + implements _$$StatusFilterBeaconGroupStateImplCopyWith<$Res> { + __$$StatusFilterBeaconGroupStateImplCopyWithImpl( + _$StatusFilterBeaconGroupStateImpl _value, + $Res Function(_$StatusFilterBeaconGroupStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? isLoadingMore = null, + Object? isCompletelyFetched = null, + Object? message = freezed, + Object? type = freezed, + Object? beacons = null, + Object? version = null, + }) { + return _then(_$StatusFilterBeaconGroupStateImpl( + isLoadingMore: null == isLoadingMore + ? _value.isLoadingMore + : isLoadingMore // ignore: cast_nullable_to_non_nullable + as bool, + isCompletelyFetched: null == isCompletelyFetched + ? _value.isCompletelyFetched + : isCompletelyFetched // ignore: cast_nullable_to_non_nullable + as bool, + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, + type: freezed == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as filters?, + beacons: null == beacons + ? _value._beacons + : beacons // ignore: cast_nullable_to_non_nullable + as List, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$StatusFilterBeaconGroupStateImpl + implements StatusFilterBeaconGroupState { + const _$StatusFilterBeaconGroupStateImpl( + {this.isLoadingMore = false, + this.isCompletelyFetched = false, + this.message, + this.type, + required final List beacons, + this.version = 0}) + : _beacons = beacons; + + @override + @JsonKey() + final bool isLoadingMore; + @override + @JsonKey() + final bool isCompletelyFetched; + @override + final String? message; + @override + final filters? type; + final List _beacons; + @override + List get beacons { + if (_beacons is EqualUnmodifiableListView) return _beacons; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_beacons); + } + + @override + @JsonKey() + final int version; + + @override + String toString() { + return 'GroupState.statusFilterBeacon(isLoadingMore: $isLoadingMore, isCompletelyFetched: $isCompletelyFetched, message: $message, type: $type, beacons: $beacons, version: $version)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$StatusFilterBeaconGroupStateImpl && + (identical(other.isLoadingMore, isLoadingMore) || + other.isLoadingMore == isLoadingMore) && + (identical(other.isCompletelyFetched, isCompletelyFetched) || + other.isCompletelyFetched == isCompletelyFetched) && + (identical(other.message, message) || other.message == message) && + (identical(other.type, type) || other.type == type) && + const DeepCollectionEquality().equals(other._beacons, _beacons) && + (identical(other.version, version) || other.version == version)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + isLoadingMore, + isCompletelyFetched, + message, + type, + const DeepCollectionEquality().hash(_beacons), + version); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$StatusFilterBeaconGroupStateImplCopyWith< + _$StatusFilterBeaconGroupStateImpl> + get copyWith => __$$StatusFilterBeaconGroupStateImplCopyWithImpl< + _$StatusFilterBeaconGroupStateImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() shrimmer, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version) + allBeacon, + required TResult Function(String? message, filters type, + List beacons, double radius, int version) + nearbyBeacon, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version) + statusFilterBeacon, + required TResult Function(String message) error, + }) { + return statusFilterBeacon( + isLoadingMore, isCompletelyFetched, message, type, beacons, version); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? shrimmer, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult? Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult? Function(String message)? error, + }) { + return statusFilterBeacon?.call( + isLoadingMore, isCompletelyFetched, message, type, beacons, version); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? shrimmer, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult Function(String message)? error, + required TResult orElse(), + }) { + if (statusFilterBeacon != null) { + return statusFilterBeacon( + isLoadingMore, isCompletelyFetched, message, type, beacons, version); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialGroupState value) initial, + required TResult Function(LoadingGroupState value) loading, + required TResult Function(ShrimmerGroupState value) shrimmer, + required TResult Function(AllBeaconGroupState value) allBeacon, + required TResult Function(NearbyBeaconGroupState value) nearbyBeacon, + required TResult Function(StatusFilterBeaconGroupState value) + statusFilterBeacon, + required TResult Function(ErrorGroupState value) error, + }) { + return statusFilterBeacon(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialGroupState value)? initial, + TResult? Function(LoadingGroupState value)? loading, + TResult? Function(ShrimmerGroupState value)? shrimmer, + TResult? Function(AllBeaconGroupState value)? allBeacon, + TResult? Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult? Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult? Function(ErrorGroupState value)? error, + }) { + return statusFilterBeacon?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialGroupState value)? initial, + TResult Function(LoadingGroupState value)? loading, + TResult Function(ShrimmerGroupState value)? shrimmer, + TResult Function(AllBeaconGroupState value)? allBeacon, + TResult Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult Function(ErrorGroupState value)? error, + required TResult orElse(), + }) { + if (statusFilterBeacon != null) { + return statusFilterBeacon(this); + } + return orElse(); + } +} + +abstract class StatusFilterBeaconGroupState implements GroupState { + const factory StatusFilterBeaconGroupState( + {final bool isLoadingMore, + final bool isCompletelyFetched, + final String? message, + final filters? type, + required final List beacons, + final int version}) = _$StatusFilterBeaconGroupStateImpl; + + bool get isLoadingMore; + bool get isCompletelyFetched; + String? get message; + filters? get type; + List get beacons; + int get version; + @JsonKey(ignore: true) + _$$StatusFilterBeaconGroupStateImplCopyWith< + _$StatusFilterBeaconGroupStateImpl> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$ErrorGroupStateImplCopyWith<$Res> { + factory _$$ErrorGroupStateImplCopyWith(_$ErrorGroupStateImpl value, + $Res Function(_$ErrorGroupStateImpl) then) = + __$$ErrorGroupStateImplCopyWithImpl<$Res>; + @useResult + $Res call({String message}); +} + +/// @nodoc +class __$$ErrorGroupStateImplCopyWithImpl<$Res> + extends _$GroupStateCopyWithImpl<$Res, _$ErrorGroupStateImpl> + implements _$$ErrorGroupStateImplCopyWith<$Res> { + __$$ErrorGroupStateImplCopyWithImpl( + _$ErrorGroupStateImpl _value, $Res Function(_$ErrorGroupStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? message = null, + }) { + return _then(_$ErrorGroupStateImpl( + message: null == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$ErrorGroupStateImpl implements ErrorGroupState { + const _$ErrorGroupStateImpl({required this.message}); + + @override + final String message; + + @override + String toString() { + return 'GroupState.error(message: $message)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ErrorGroupStateImpl && + (identical(other.message, message) || other.message == message)); + } + + @override + int get hashCode => Object.hash(runtimeType, message); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ErrorGroupStateImplCopyWith<_$ErrorGroupStateImpl> get copyWith => + __$$ErrorGroupStateImplCopyWithImpl<_$ErrorGroupStateImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() shrimmer, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version) + allBeacon, + required TResult Function(String? message, filters type, + List beacons, double radius, int version) + nearbyBeacon, + required TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version) + statusFilterBeacon, + required TResult Function(String message) error, + }) { + return error(message); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? shrimmer, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult? Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult? Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult? Function(String message)? error, + }) { + return error?.call(message); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? shrimmer, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters type, + List beacons, + int version)? + allBeacon, + TResult Function(String? message, filters type, List beacons, + double radius, int version)? + nearbyBeacon, + TResult Function( + bool isLoadingMore, + bool isCompletelyFetched, + String? message, + filters? type, + List beacons, + int version)? + statusFilterBeacon, + TResult Function(String message)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(message); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialGroupState value) initial, + required TResult Function(LoadingGroupState value) loading, + required TResult Function(ShrimmerGroupState value) shrimmer, + required TResult Function(AllBeaconGroupState value) allBeacon, + required TResult Function(NearbyBeaconGroupState value) nearbyBeacon, + required TResult Function(StatusFilterBeaconGroupState value) + statusFilterBeacon, + required TResult Function(ErrorGroupState value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialGroupState value)? initial, + TResult? Function(LoadingGroupState value)? loading, + TResult? Function(ShrimmerGroupState value)? shrimmer, + TResult? Function(AllBeaconGroupState value)? allBeacon, + TResult? Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult? Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult? Function(ErrorGroupState value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialGroupState value)? initial, + TResult Function(LoadingGroupState value)? loading, + TResult Function(ShrimmerGroupState value)? shrimmer, + TResult Function(AllBeaconGroupState value)? allBeacon, + TResult Function(NearbyBeaconGroupState value)? nearbyBeacon, + TResult Function(StatusFilterBeaconGroupState value)? statusFilterBeacon, + TResult Function(ErrorGroupState value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class ErrorGroupState implements GroupState { + const factory ErrorGroupState({required final String message}) = + _$ErrorGroupStateImpl; + + String get message; + @JsonKey(ignore: true) + _$$ErrorGroupStateImplCopyWith<_$ErrorGroupStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/presentation/group/cubit/members_cubit/members_cubit.dart b/lib/presentation/group/cubit/members_cubit/members_cubit.dart new file mode 100644 index 00000000..76cb2ced --- /dev/null +++ b/lib/presentation/group/cubit/members_cubit/members_cubit.dart @@ -0,0 +1,67 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/domain/usecase/group_usecase.dart'; +import 'package:beacon/presentation/home/home_cubit/home_cubit.dart'; +import 'package:beacon/presentation/group/cubit/members_cubit/members_state.dart'; +import 'package:beacon/locator.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class MembersCubit extends Cubit { + final GroupUseCase _groupUseCase; + + MembersCubit._internal(this._groupUseCase) : super(InitialMemberState()); + + static MembersCubit? _instance; + + factory MembersCubit(GroupUseCase _groupUseCase) { + return _instance ?? MembersCubit._internal(_groupUseCase); + } + + String? _groupId; + List _members = []; + + init(GroupEntity group) { + _groupId = group.id!; + _members.add(group.leader!); + group.members!.forEach((member) { + _members.add(member!); + }); + } + + clear() { + _groupId = null; + _members.clear(); + } + + loadMembers() { + emit(LoadedMemberState(members: _members)); + } + + void removeMember(String memberId) async { + emit(LoadingMemberState()); + final dataState = await _groupUseCase.removeMember(_groupId!, memberId); + + if (dataState is DataSuccess) { + locator().removeMember(_groupId!, dataState.data!); + var updatedList = List.from(_members) + ..removeWhere((member) => member.id == memberId); + _members = updatedList; + + emit(LoadedMemberState( + members: updatedList, + message: + '${dataState.data!.name} is no longer the member of group!')); + } else { + emit(LoadedMemberState(members: _members, message: dataState.error)); + } + } + + void addMember(UserEntity member) { + _members.add(member); + + emit(LoadedMemberState( + members: List.from(_members), + message: '${member.name} joined the group!')); + } +} diff --git a/lib/presentation/group/cubit/members_cubit/members_state.dart b/lib/presentation/group/cubit/members_cubit/members_state.dart new file mode 100644 index 00000000..178e0370 --- /dev/null +++ b/lib/presentation/group/cubit/members_cubit/members_state.dart @@ -0,0 +1,11 @@ +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'members_state.freezed.dart'; + +@freezed +class MembersState with _$MembersState { + factory MembersState.initial() = InitialMemberState; + factory MembersState.loading() = LoadingMemberState; + factory MembersState.reload({List? members, String? message}) = + LoadedMemberState; +} diff --git a/lib/presentation/group/cubit/members_cubit/members_state.freezed.dart b/lib/presentation/group/cubit/members_cubit/members_state.freezed.dart new file mode 100644 index 00000000..8f649350 --- /dev/null +++ b/lib/presentation/group/cubit/members_cubit/members_state.freezed.dart @@ -0,0 +1,462 @@ +// 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 'members_state.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 _$MembersState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List? members, String? message) + reload, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List? members, String? message)? reload, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List? members, String? message)? reload, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(InitialMemberState value) initial, + required TResult Function(LoadingMemberState value) loading, + required TResult Function(LoadedMemberState value) reload, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialMemberState value)? initial, + TResult? Function(LoadingMemberState value)? loading, + TResult? Function(LoadedMemberState value)? reload, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialMemberState value)? initial, + TResult Function(LoadingMemberState value)? loading, + TResult Function(LoadedMemberState value)? reload, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MembersStateCopyWith<$Res> { + factory $MembersStateCopyWith( + MembersState value, $Res Function(MembersState) then) = + _$MembersStateCopyWithImpl<$Res, MembersState>; +} + +/// @nodoc +class _$MembersStateCopyWithImpl<$Res, $Val extends MembersState> + implements $MembersStateCopyWith<$Res> { + _$MembersStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$InitialMemberStateImplCopyWith<$Res> { + factory _$$InitialMemberStateImplCopyWith(_$InitialMemberStateImpl value, + $Res Function(_$InitialMemberStateImpl) then) = + __$$InitialMemberStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$InitialMemberStateImplCopyWithImpl<$Res> + extends _$MembersStateCopyWithImpl<$Res, _$InitialMemberStateImpl> + implements _$$InitialMemberStateImplCopyWith<$Res> { + __$$InitialMemberStateImplCopyWithImpl(_$InitialMemberStateImpl _value, + $Res Function(_$InitialMemberStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$InitialMemberStateImpl implements InitialMemberState { + _$InitialMemberStateImpl(); + + @override + String toString() { + return 'MembersState.initial()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$InitialMemberStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List? members, String? message) + reload, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List? members, String? message)? reload, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List? members, String? message)? reload, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialMemberState value) initial, + required TResult Function(LoadingMemberState value) loading, + required TResult Function(LoadedMemberState value) reload, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialMemberState value)? initial, + TResult? Function(LoadingMemberState value)? loading, + TResult? Function(LoadedMemberState value)? reload, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialMemberState value)? initial, + TResult Function(LoadingMemberState value)? loading, + TResult Function(LoadedMemberState value)? reload, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class InitialMemberState implements MembersState { + factory InitialMemberState() = _$InitialMemberStateImpl; +} + +/// @nodoc +abstract class _$$LoadingMemberStateImplCopyWith<$Res> { + factory _$$LoadingMemberStateImplCopyWith(_$LoadingMemberStateImpl value, + $Res Function(_$LoadingMemberStateImpl) then) = + __$$LoadingMemberStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$LoadingMemberStateImplCopyWithImpl<$Res> + extends _$MembersStateCopyWithImpl<$Res, _$LoadingMemberStateImpl> + implements _$$LoadingMemberStateImplCopyWith<$Res> { + __$$LoadingMemberStateImplCopyWithImpl(_$LoadingMemberStateImpl _value, + $Res Function(_$LoadingMemberStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$LoadingMemberStateImpl implements LoadingMemberState { + _$LoadingMemberStateImpl(); + + @override + String toString() { + return 'MembersState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$LoadingMemberStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List? members, String? message) + reload, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List? members, String? message)? reload, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List? members, String? message)? reload, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialMemberState value) initial, + required TResult Function(LoadingMemberState value) loading, + required TResult Function(LoadedMemberState value) reload, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialMemberState value)? initial, + TResult? Function(LoadingMemberState value)? loading, + TResult? Function(LoadedMemberState value)? reload, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialMemberState value)? initial, + TResult Function(LoadingMemberState value)? loading, + TResult Function(LoadedMemberState value)? reload, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class LoadingMemberState implements MembersState { + factory LoadingMemberState() = _$LoadingMemberStateImpl; +} + +/// @nodoc +abstract class _$$LoadedMemberStateImplCopyWith<$Res> { + factory _$$LoadedMemberStateImplCopyWith(_$LoadedMemberStateImpl value, + $Res Function(_$LoadedMemberStateImpl) then) = + __$$LoadedMemberStateImplCopyWithImpl<$Res>; + @useResult + $Res call({List? members, String? message}); +} + +/// @nodoc +class __$$LoadedMemberStateImplCopyWithImpl<$Res> + extends _$MembersStateCopyWithImpl<$Res, _$LoadedMemberStateImpl> + implements _$$LoadedMemberStateImplCopyWith<$Res> { + __$$LoadedMemberStateImplCopyWithImpl(_$LoadedMemberStateImpl _value, + $Res Function(_$LoadedMemberStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? members = freezed, + Object? message = freezed, + }) { + return _then(_$LoadedMemberStateImpl( + members: freezed == members + ? _value._members + : members // ignore: cast_nullable_to_non_nullable + as List?, + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$LoadedMemberStateImpl implements LoadedMemberState { + _$LoadedMemberStateImpl({final List? members, this.message}) + : _members = members; + + 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 String? message; + + @override + String toString() { + return 'MembersState.reload(members: $members, message: $message)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LoadedMemberStateImpl && + const DeepCollectionEquality().equals(other._members, _members) && + (identical(other.message, message) || other.message == message)); + } + + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_members), message); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LoadedMemberStateImplCopyWith<_$LoadedMemberStateImpl> get copyWith => + __$$LoadedMemberStateImplCopyWithImpl<_$LoadedMemberStateImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List? members, String? message) + reload, + }) { + return reload(members, message); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List? members, String? message)? reload, + }) { + return reload?.call(members, message); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List? members, String? message)? reload, + required TResult orElse(), + }) { + if (reload != null) { + return reload(members, message); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialMemberState value) initial, + required TResult Function(LoadingMemberState value) loading, + required TResult Function(LoadedMemberState value) reload, + }) { + return reload(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialMemberState value)? initial, + TResult? Function(LoadingMemberState value)? loading, + TResult? Function(LoadedMemberState value)? reload, + }) { + return reload?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialMemberState value)? initial, + TResult Function(LoadingMemberState value)? loading, + TResult Function(LoadedMemberState value)? reload, + required TResult orElse(), + }) { + if (reload != null) { + return reload(this); + } + return orElse(); + } +} + +abstract class LoadedMemberState implements MembersState { + factory LoadedMemberState( + {final List? members, + final String? message}) = _$LoadedMemberStateImpl; + + List? get members; + String? get message; + @JsonKey(ignore: true) + _$$LoadedMemberStateImplCopyWith<_$LoadedMemberStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/presentation/group/group_screen.dart b/lib/presentation/group/group_screen.dart new file mode 100644 index 00000000..6001fe10 --- /dev/null +++ b/lib/presentation/group/group_screen.dart @@ -0,0 +1,415 @@ +import 'dart:developer'; + +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/presentation/group/cubit/group_cubit/group_cubit.dart'; +import 'package:beacon/presentation/group/cubit/group_cubit/group_state.dart'; +import 'package:beacon/presentation/group/cubit/members_cubit/members_cubit.dart'; +import 'package:beacon/presentation/group/widgets/create_join_dialog.dart'; +import 'package:beacon/presentation/group/widgets/beacon_card.dart'; +import 'package:beacon/presentation/group/widgets/group_widgets.dart'; +import 'package:beacon/presentation/home/home_cubit/home_cubit.dart'; +import 'package:beacon/presentation/widgets/shimmer.dart'; +import 'package:beacon/presentation/widgets/hike_button.dart'; +import 'package:beacon/presentation/widgets/loading_screen.dart'; +import 'package:beacon/presentation/widgets/shape_painter.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/core/utils/constants.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:gap/gap.dart'; +import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; + +@RoutePage() +class GroupScreen extends StatefulWidget { + final GroupEntity group; + + GroupScreen(this.group); + + @override + _GroupScreenState createState() => _GroupScreenState(); +} + +class _GroupScreenState extends State + with TickerProviderStateMixin { + late List fetchingUserBeacons; + late List fetchingNearbyBeacons; + late GroupCubit _groupCubit; + late MembersCubit _membersCubit; + late ScrollController _scrollController; + + @override + void initState() { + super.initState(); + _scrollController = ScrollController(); + _scrollController.addListener(_listener); + _groupCubit = BlocProvider.of(context); + _membersCubit = BlocProvider.of(context); + _groupCubit.init(widget.group); + _groupCubit.allHikes(widget.group.id!); + _membersCubit.init(widget.group); + } + + void _listener() { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + final state = _groupCubit.state; + if (state is AllBeaconGroupState && !state.isCompletelyFetched) { + _groupCubit.allHikes(widget.group.id!); + } + } + } + + @override + void dispose() { + _groupCubit.clear(); + _membersCubit.clear(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + TabController tabController = TabController(length: 1, vsync: this); + + return Scaffold( + resizeToAvoidBottomInset: false, + body: SafeArea( + child: BlocConsumer( + listener: (context, state) { + if (state is AllBeaconGroupState && state.message != null) { + utils.showSnackBar(state.message!, context); + } + }, + builder: (context, state) { + return ModalProgressHUD( + progressIndicator: const LoadingScreen(), + inAsyncCall: state is LoadingGroupState, + child: Stack( + children: [ + CustomPaint( + size: Size(100.w, 100.h - 200), + painter: ShapePainter(), + ), + _buildGroupName(), + Align( + alignment: Alignment(0.9, -0.70), + child: GroupWidgetUtils.filterBeacons( + context, widget.group.id!, _groupCubit), + ), + Align( + alignment: Alignment(0.5, -0.70), + child: GroupWidgetUtils.membersWidget(context), + ), + _buildJoinCreateButton(), + 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: Radius.circular(50.0), + topRight: Radius.circular(50.0), + ), + ), + child: Column( + children: [ + TabBar( + indicatorSize: TabBarIndicatorSize.tab, + indicatorColor: kBlue, + labelColor: kBlack, + tabs: [ + _buildTab(state), + ], + controller: tabController, + ), + Expanded( + child: TabBarView( + controller: tabController, + children: [ + _groupBeacons(state), + ], + ), + ) + ], + ), + ) + ], + ), + ], + ), + ); + }, + ), + ), + ); + } + + Widget _buildJoinCreateButton() { + return Padding( + padding: EdgeInsets.fromLTRB(4.w, 23.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!); + }, + ), + ), + 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); + }, + ), + ), + ], + ), + ); + } + + Widget _buildTab(GroupState state) { + return Tab( + text: state is AllBeaconGroupState + ? 'All Beacons' + : state is NearbyBeaconGroupState + ? 'Nearby Beacons' + : state is StatusFilterBeaconGroupState + ? '${state.type!.name[0] + state.type!.name.substring(1).toLowerCase()} Beacons' + : 'Loading Beacons..', + ); + } + + Widget _groupBeacons(GroupState state) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 2.0), + child: Builder( + builder: (context) { + if (state is ShrimmerGroupState) { + return Center(child: ShimmerWidget.getPlaceholder()); + } else if (state is AllBeaconGroupState) { + final beacons = state.beacons; + String message = 'You haven\'t joined or created any beacon yet'; + return _buildBeaconsList(beacons, state.isLoadingMore, + state.isCompletelyFetched, message); + } else if (state is NearbyBeaconGroupState) { + final beacons = state.beacons; + String message = + 'No beacons found under ${state.radius.toStringAsFixed(2)} m... radius'; + return _buildBeaconsList(beacons, false, false, message); + } else if (state is StatusFilterBeaconGroupState) { + final beacons = state.beacons; + var type = state.type!.name; + String message = + 'No ${type[0].toUpperCase() + type.substring(1).toLowerCase()} beacons found'; + return _buildBeaconsList(beacons, false, false, message); + } else if (state is ErrorGroupState) { + return _buildErrorWidget(state.message); + } + return _buildErrorWidget('Something went wrong!'); + }, + ), + ); + } + + Widget _buildGroupName() { + return 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), + ), + ), + ); + } + + Widget _buildBeaconsList(List beacons, bool isLoadingMore, + bool isCompletelyFetched, String message) { + return Container( + alignment: Alignment.center, + child: beacons.isEmpty + ? SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: _noBeaconsWidget(message), + ) + : ListView.builder( + controller: _scrollController, + physics: AlwaysScrollableScrollPhysics(), + scrollDirection: Axis.vertical, + itemCount: beacons.length + + (isLoadingMore && !isCompletelyFetched ? 1 : 0), + padding: EdgeInsets.all(8), + itemBuilder: (context, index) { + if (index == beacons.length) { + return LinearProgressIndicator(); + } + return _buildBeaconCard(beacons[index]); + }, + ), + ); + } + + Widget _buildBeaconCard(BeaconEntity beacon) { + return Slidable( + key: Key(beacon.id!.toString()), + startActionPane: ActionPane( + dragDismissible: true, + dismissible: DismissiblePane( + onDismissed: () { + _groupCubit.reloadState(message: 'Beacon deleted'); + }, + confirmDismiss: () async { + bool? value = await GroupWidgetUtils.deleteDialog(context); + if (value == null || !value) { + return false; + } + bool delete = await _groupCubit.deleteBeacon(beacon); + return delete; + }, + ), + motion: ScrollMotion(), + children: [ + SlidableAction( + onPressed: null, + backgroundColor: Color.fromARGB(255, 217, 100, 94), + foregroundColor: Colors.white, + icon: Icons.delete, + label: 'Delete', + ), + ], + ), + endActionPane: ActionPane( + motion: ScrollMotion(), + children: [ + SlidableAction( + flex: 1, + onPressed: (context) { + GroupWidgetUtils.reScheduleHikeDialog(context, beacon); + }, + backgroundColor: Colors.blueGrey, + foregroundColor: Colors.white, + icon: Icons.edit_calendar, + label: 'Reschedule', + ), + ], + ), + child: BeaconCard(beacon: beacon), + ); + } + + Widget _buildErrorWidget(String message) { + return Center( + child: SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: Column( + children: [ + Text( + message, + textAlign: TextAlign.center, + style: TextStyle(color: kBlack, fontSize: 20), + ), + Gap(5), + FloatingActionButton( + onPressed: () async { + try { + await locationService.openSettings(); + } catch (e) { + log('error: $e'); + } + }, + child: Icon( + Icons.settings, + color: kBlack, + ), + backgroundColor: kYellow, + ), + Gap(15), + 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! '), + ], + ), + ), + SizedBox( + height: 2.h, + ), + ], + ), + ), + ); + } + + Widget _noBeaconsWidget(String message) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: Column( + children: [ + Text( + message, + 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! '), + ], + ), + ), + SizedBox( + height: 2.h, + ), + ], + ), + ); + } +} diff --git a/lib/presentation/group/widgets/beacon_card.dart b/lib/presentation/group/widgets/beacon_card.dart new file mode 100644 index 00000000..e8a877d2 --- /dev/null +++ b/lib/presentation/group/widgets/beacon_card.dart @@ -0,0 +1,322 @@ +import 'dart:async'; +import 'dart:developer'; +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/core/utils/constants.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/usecase/group_usecase.dart'; +import 'package:beacon/domain/usecase/hike_usecase.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/presentation/group/cubit/group_cubit/group_cubit.dart'; +import 'package:beacon/presentation/hike/widgets/active_beacon.dart'; +import 'package:beacon/presentation/widgets/hike_button.dart'; +import 'package:beacon/presentation/group/widgets/timer.dart'; +import 'package:beacon/config/router/router.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:gap/gap.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:intl/intl.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; + +class BeaconCard extends StatefulWidget { + final BeaconEntity beacon; + const BeaconCard({required this.beacon}); + + @override + State createState() => _BeaconCardState(); +} + +class _BeaconCardState extends State { + late bool hasStarted; + late bool hasEnded; + late bool willStart; + DateTime now = DateTime.now(); + late DateTime startAt; + late DateTime expiresAt; + Timer? _rebuildTimer; + + @override + void initState() { + startAt = DateTime.fromMillisecondsSinceEpoch(widget.beacon.startsAt!); + expiresAt = DateTime.fromMillisecondsSinceEpoch(widget.beacon.expiresAt!); + hasStarted = now.isAfter(startAt); + hasEnded = now.isAfter(expiresAt); + willStart = now.isBefore(startAt); + scheduleRebuild(); + super.initState(); + } + + void scheduleRebuild() { + if (hasEnded) return; + + late int seconds; + + if (willStart) { + Duration difference = startAt.difference(now); + seconds = difference.inSeconds; + } else if (hasStarted && !hasEnded) { + Duration difference = expiresAt.difference(now); + seconds = difference.inSeconds; + } + _rebuildTimer?.cancel(); + + _rebuildTimer = Timer(Duration(milliseconds: seconds * 1000 + 1000), () { + var now = DateTime.now(); + hasStarted = now.isAfter(startAt); + hasEnded = now.isAfter(expiresAt); + willStart = now.isBefore(startAt); + setState(() {}); + + Future.delayed(Duration(seconds: 1), () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + duration: Duration(seconds: 5), + content: Text( + '${widget.beacon.title} is now active! \nYou can join the hike', + style: TextStyle(color: Colors.black), + ), + backgroundColor: kLightBlue.withOpacity(0.8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(10), + ), + ), + behavior: SnackBarBehavior.floating, + elevation: 5, + action: SnackBarAction( + textColor: kBlue, + label: 'Click to Join', + onPressed: () async { + appRouter.push(HikeScreenRoute( + beacon: widget.beacon, + isLeader: widget.beacon.id! == localApi.userModel.id!)); + }, + ), + ), + ); + }); + }); + } + + @override + void dispose() { + _rebuildTimer?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + BeaconEntity beacon = widget.beacon; + + return InkWell( + onTap: () async { + locator().joinBeacon(beacon, hasEnded, hasStarted); + }, + child: Container( + margin: const EdgeInsets.symmetric( + vertical: 10.0, + horizontal: 10.0, + ), + padding: EdgeInsets.only(left: 16.0, right: 16.0, bottom: 8, top: 8), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + width: 70.w, + child: Text( + '${beacon.title} by ${beacon.leader!.name} ', + style: Style.titleTextStyle, + ), + ), + Align( + alignment: Alignment.topRight, + child: (hasStarted && !hasEnded) + ? BlinkIcon() + : willStart + ? Align( + alignment: Alignment.topRight, + child: Icon( + Icons.circle, + color: kYellow, + size: 10, + ), + ) + : null, + ), + ], + ), + SizedBox(height: 4.0), + (hasStarted && !hasEnded) + ? RichText( + text: TextSpan( + text: 'Hike is ', + style: Style.commonTextStyle, + children: const [ + TextSpan( + text: 'Active', + style: TextStyle( + fontSize: 16.0, + color: Colors.white, + fontWeight: FontWeight.bold, + letterSpacing: 1.0), + ), + ], + ), + ) + : willStart + ? Row( + children: [ + RichText( + text: TextSpan( + text: 'Hike ', + style: Style.commonTextStyle, + children: const [ + TextSpan( + text: 'Starts ', + style: TextStyle( + fontSize: 16.0, + color: Colors.white, + fontWeight: FontWeight.bold, + letterSpacing: 1.0), + ), + TextSpan( + text: 'in ', + style: TextStyle( + color: const Color(0xffb6b2df), + fontSize: 14.0, + fontWeight: FontWeight.w400), + ), + ], + ), + ), + SizedBox( + width: 3.0, + ), + CountdownTimerPage( + dateTime: DateTime.fromMillisecondsSinceEpoch( + beacon.startsAt!), + name: beacon.title, + beacon: beacon, + ) + ], + ) + : Row( + children: [ + RichText( + text: TextSpan( + text: 'Hike ', + style: Style.commonTextStyle, + children: const [ + TextSpan( + text: 'is Ended', + style: TextStyle( + fontSize: 16.0, + color: Colors.white, + fontWeight: FontWeight.bold, + letterSpacing: 1.0), + ), + ], + ), + ), + ], + ), + SizedBox(height: 4.0), + Row( + children: [ + Text('Passkey: ${beacon.shortcode}', + style: Style.commonTextStyle), + Gap(10), + InkWell( + onTap: () { + Clipboard.setData( + ClipboardData(text: beacon.shortcode.toString())); + utils.showSnackBar('Shortcode copied!', context); + }, + child: Icon( + Icons.copy, + color: Colors.white, + size: 15, + )) + ], + ), + SizedBox(height: 4.0), + (beacon.startsAt != null) + ? Text( + willStart + ? 'Starting At: ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}' + : 'Started At: ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.startsAt!)).toString()}', + style: Style.commonTextStyle) + : Container(), + SizedBox(height: 4.0), + (beacon.expiresAt != null) + ? willStart + ? Text( + 'Expiring At: ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!)).toString()}', + style: Style.commonTextStyle) + : Text( + 'Expires At: ${DateFormat("hh:mm a, d/M/y").format(DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!)).toString()}', + style: Style.commonTextStyle) + : Container(), + ], + ) + ], + ), + decoration: BoxDecoration( + color: willStart + ? Color(0xFF141546) + : hasEnded + ? lightkBlue + : kBlue, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.circular(8.0), + boxShadow: [ + BoxShadow( + color: Colors.black26, + blurRadius: 10.0, + offset: Offset(0.0, 10.0), + ), + ], + ), + ), + ); + } + + Future deleteDialog(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), + content: Text( + 'Are you sure you want to delete this beacon?', + 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', + ), + ], + ), + ); + } +} diff --git a/lib/Bloc/presentation/widgets/create_join_dialog.dart b/lib/presentation/group/widgets/create_join_dialog.dart similarity index 54% rename from lib/Bloc/presentation/widgets/create_join_dialog.dart rename to lib/presentation/group/widgets/create_join_dialog.dart index 6e317824..fe4baa80 100644 --- a/lib/Bloc/presentation/widgets/create_join_dialog.dart +++ b/lib/presentation/group/widgets/create_join_dialog.dart @@ -1,15 +1,16 @@ 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/core/utils/validators.dart'; +import 'package:beacon/presentation/group/cubit/group_cubit/group_cubit.dart'; +import 'package:beacon/presentation/home/home_cubit/home_cubit.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/old/components/hike_button.dart'; -import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/presentation/widgets/hike_button.dart'; +import 'package:beacon/core/utils/constants.dart'; import 'package:duration_picker/duration_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:gap/gap.dart'; import 'package:intl/intl.dart'; -import 'package:sizer/sizer.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; class CreateJoinGroupDialog { static GlobalKey _groupKey = GlobalKey(); @@ -20,7 +21,7 @@ class CreateJoinGroupDialog { static Future createGroupDialog( BuildContext context, ) { - bool isSmallSized = MediaQuery.of(context).size.height < 800; + bool isSmallSized = 100.h < 800; return showDialog( context: context, builder: (context) => Dialog( @@ -31,7 +32,7 @@ class CreateJoinGroupDialog { child: Form( key: _groupKey, child: Container( - height: isSmallSized ? 35.h : 25.h, + height: isSmallSized ? 30.h : 25.h, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), @@ -77,7 +78,8 @@ class CreateJoinGroupDialog { onTap: () { if (!_groupKey.currentState!.validate()) return; AutoRouter.of(context).maybePop(); - BlocProvider.of(context) + context + .read() .createGroup(_groupNameController.text.trim()); _groupNameController.clear(); }), @@ -108,7 +110,7 @@ class CreateJoinGroupDialog { child: Form( key: _joinGroupKey, child: Container( - height: isSmallSized ? 35.h : 25.h, + height: isSmallSized ? 30.h : 25.h, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), child: Column( @@ -152,8 +154,9 @@ class CreateJoinGroupDialog { buttonColor: kYellow, onTap: () { if (!_joinGroupKey.currentState!.validate()) return; - AutoRouter.of(context).maybePop(); - BlocProvider.of(context) + appRouter.maybePop(); + context + .read() .joinGroup(_joinGroupController.text.trim()); _joinGroupController.clear(); }, @@ -169,27 +172,81 @@ class CreateJoinGroupDialog { } } +String title = ''; +DateTime? startDate = DateTime.now(); +TimeOfDay? startTime = + TimeOfDay(hour: TimeOfDay.now().hour, minute: TimeOfDay.now().minute + 1); +Duration? duration = Duration(minutes: 5); + class CreateJoinBeaconDialog { - 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 Future createHikeDialog(BuildContext context, String groupId) { + bool isSmallSized = 100.h < 800; + return showDialog( + context: context, + builder: (context) => Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + child: Container( + height: isSmallSized ? 30.h : 25.h, + child: ListView( + padding: EdgeInsets.symmetric(horizontal: 15.w), + children: [ + Gap(15), + Text( + 'Create hike', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + ), + ), + Gap(20), + HikeButton( + text: 'Start Hike', + buttonWidth: 2, + buttonHeight: 16, + buttonColor: kYellow, + onTap: () { + Navigator.of(context).pop(); + createHikeBox(context, groupId, true); + }, + ), + Gap(10), + HikeButton( + text: 'Schedule Hike', + buttonWidth: 5, + buttonHeight: 16, + buttonColor: kYellow, + onTap: () { + Navigator.of(context).pop(); + createHikeBox(context, groupId, false); + }, + ), + ], + ), + ), + ), + ); + } - static GlobalKey _createFormKey = GlobalKey(); + static Future createHikeBox( + BuildContext context, String? groupID, bool isInstant) { + bool isSmallSized = 100.h < 800; - static FocusNode _titleNode = FocusNode(); - static FocusNode _startDateNode = FocusNode(); - static FocusNode _startTimeNode = FocusNode(); - static FocusNode _durationNode = FocusNode(); + GlobalKey _createFormKey = GlobalKey(); - static TextEditingController _dateController = TextEditingController(); - static TextEditingController _startTimeController = TextEditingController(); - static TextEditingController _durationController = TextEditingController(); + FocusNode _titleNode = FocusNode(); + FocusNode _startDateNode = FocusNode(); + + TextEditingController _dateController = TextEditingController(); + TextEditingController _startTimeController = TextEditingController(); + TextEditingController _durationController = TextEditingController(); + String title = ''; + DateTime? startDate = DateTime.now(); + TimeOfDay? startTime = TimeOfDay( + hour: TimeOfDay.now().hour, minute: TimeOfDay.now().minute + 1); + Duration? duration = Duration(minutes: 5); - static Future createHikeDialog( - BuildContext context, String? groupID, GroupCubit groupCubit) { - bool isSmallSized = MediaQuery.of(context).size.height < 800; return showDialog( context: context, builder: (context) => GestureDetector( @@ -202,7 +259,13 @@ class CreateJoinBeaconDialog { child: Form( key: _createFormKey, child: Container( - height: isSmallSized ? 75.h : 65.h, + height: isInstant + ? isSmallSized + ? 45.h + : 40.h + : isSmallSized + ? 75.h + : 65.h, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), @@ -215,7 +278,7 @@ class CreateJoinBeaconDialog { child: TextFormField( style: TextStyle(fontSize: 22.0), validator: (value) => - Validator.validateBeaconTitle(value!), + Validator.validateBeaconTitle(value), onChanged: (name) { title = name; }, @@ -240,101 +303,120 @@ class CreateJoinBeaconDialog { ), color: kLightBlue, ), - 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 { - startDate = await showDatePicker( - context: context, - initialDate: startDate!, - firstDate: DateTime.now(), - lastDate: DateTime(2100), - builder: (context, child) => Theme( - data: ThemeData().copyWith( - textTheme: Theme.of(context).textTheme, - colorScheme: ColorScheme.light( - primary: kLightBlue, - onPrimary: Colors.grey, - surface: kBlue, - ), - ), - child: child!), - ); - _dateController.text = - DateFormat('yyyy-MM-dd').format(startDate!); - - _startDateNode.unfocus(); - FocusScope.of(context) - .requestFocus(_startTimeNode); - }, - child: TextFormField( - controller: _dateController, - enabled: false, - focusNode: _startDateNode, - onEditingComplete: () {}, - decoration: InputDecoration( - border: InputBorder.none, - hintText: 'Choose Start Date', - labelStyle: TextStyle( - fontSize: labelsize, color: kYellow), - hintStyle: TextStyle( - fontSize: hintsize, color: hintColor), - labelText: 'Start Date', - alignLabelWithHint: true, - floatingLabelBehavior: - FloatingLabelBehavior.always, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none), + isInstant ? Container() : SizedBox(height: 2.h), + // start date field + isInstant + ? Container() + : Container( + height: isSmallSized ? 12.h : 10.h, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: InkWell( + onTap: () async { + startDate = await showDatePicker( + context: context, + initialDate: startDate ?? DateTime.now(), + firstDate: startDate ?? DateTime.now(), + lastDate: DateTime(2100), + // builder: (context, child) => Theme( + // // data: ThemeData().copyWith( + // // textTheme: + // // Theme.of(context).textTheme, + // // colorScheme: ColorScheme.light( + // // primary: kLightBlue, + // // onPrimary: Colors.grey, + // // surface: kBlue, + // // ), + // // ), + // child: child!), + ); + if (startDate == null) return; + _dateController.text = + DateFormat('yyyy-MM-dd') + .format(startDate!); + }, + child: TextFormField( + validator: (value) => + Validator.validateDate(value), + controller: _dateController, + enabled: false, + focusNode: _startDateNode, + onEditingComplete: () {}, + decoration: InputDecoration( + border: InputBorder.none, + hintText: 'Choose Start Date', + labelStyle: TextStyle( + fontSize: labelsize, + color: kYellow), + hintStyle: TextStyle( + fontSize: hintsize, + color: hintColor), + labelText: 'Start Date', + alignLabelWithHint: true, + floatingLabelBehavior: + FloatingLabelBehavior.always, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none), + ), + ), + ), + color: kLightBlue, ), - ), - ), - color: kLightBlue, - ), - SizedBox(height: 2.h), + isInstant ? Container() : 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 { - startTime = await showTimePicker( - context: context, initialTime: startTime!); - - if (startTime != null) { - _startTimeController.text = - '${startTime!.hour}:${startTime!.minute}'; - } - }, - child: TextFormField( - controller: _startTimeController, - enabled: false, - onEditingComplete: () {}, - focusNode: _startTimeNode, - decoration: InputDecoration( - border: InputBorder.none, - alignLabelWithHint: true, - errorStyle: TextStyle(color: Colors.red[800]), - floatingLabelBehavior: - FloatingLabelBehavior.always, - labelText: 'Start Time', - labelStyle: TextStyle( - fontSize: labelsize, color: kYellow), - hintStyle: TextStyle( - fontSize: hintsize, color: hintColor), - hintText: 'Choose start time', - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, + isInstant + ? SizedBox.shrink() + : Container( + height: isSmallSized ? 12.h : 10.h, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: InkWell( + onTap: () async { + startTime = await showTimePicker( + context: context, + initialTime: startTime ?? + TimeOfDay( + hour: DateTime.now().hour, + minute: + DateTime.now().minute + 1)); + if (startTime != null) { + if (startTime!.minute < 10) { + _startTimeController.text = + '${startTime!.hour}:0${startTime!.minute} ${startTime!.period == DayPeriod.am ? 'AM' : 'PM'}'; + } else { + _startTimeController.text = + '${startTime!.hour}:${startTime!.minute} ${startTime!.period == DayPeriod.am ? 'AM' : 'PM'}'; + } + } + }, + child: TextFormField( + validator: (value) => + Validator.validateStartTime( + value, _dateController.text), + controller: _startTimeController, + enabled: false, + onEditingComplete: () {}, + decoration: InputDecoration( + border: InputBorder.none, + alignLabelWithHint: true, + errorStyle: + TextStyle(color: Colors.red[800]), + floatingLabelBehavior: + FloatingLabelBehavior.always, + labelText: 'Start Time', + labelStyle: TextStyle( + fontSize: labelsize, color: kYellow), + hintStyle: TextStyle( + fontSize: hintsize, color: hintColor), + hintText: 'Choose start time', + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ), ), + color: kLightBlue, ), - ), - ), - color: kLightBlue, - ), SizedBox(height: 2.h), // Duration Field Container( @@ -345,8 +427,9 @@ class CreateJoinBeaconDialog { onTap: () async { duration = await showDurationPicker( context: context, - initialTime: duration!, + initialTime: duration ?? Duration(minutes: 5), ); + if (duration == null) return; if (duration!.inHours != 0 && duration!.inMinutes != 0) { _durationController.text = @@ -355,17 +438,10 @@ class CreateJoinBeaconDialog { _durationController.text = '${duration!.inMinutes.toString()} minutes'; } - if (_durationController.text.isEmpty) { - _durationNode.unfocus(); - } }, child: TextFormField( enabled: false, - focusNode: _durationNode, controller: _durationController, - onEditingComplete: () { - _durationNode.unfocus(); - }, validator: (value) => Validator.validateDuration(value.toString()), decoration: InputDecoration( @@ -391,53 +467,50 @@ class CreateJoinBeaconDialog { Flexible( flex: 2, child: HikeButton( - text: 'Create', + text: isInstant ? 'Start' : 'Create', textSize: 18.0, textColor: Colors.white, buttonColor: kYellow, onTap: () async { if (_createFormKey.currentState!.validate()) { - DateTime startsAt = DateTime( - startDate!.year, - startDate!.month, - startDate!.day, - startTime!.hour, - startTime!.minute); + var groupCubit = locator(); + if (!isInstant) { + DateTime start = DateTime( + startDate!.year, + startDate!.month, + startDate!.day, + startTime!.hour, + startTime!.minute); - final startingTime = - startsAt.millisecondsSinceEpoch; + final startsAt = start.millisecondsSinceEpoch; - int currenTime = - DateTime.now().millisecondsSinceEpoch; + final expiresAt = start + .add(duration!) + .millisecondsSinceEpoch; - if (startingTime < currenTime) { - utils.showSnackBar( - 'Please chose a correct time!', context); - return; - } + groupCubit.createHike(title, startsAt, + expiresAt, groupID!, isInstant); + _durationController.clear(); + _startTimeController.clear(); + _durationController.clear(); + + appRouter.maybePop(); + } else { + int startsAt = + DateTime.now().millisecondsSinceEpoch; + + int expiresAt = DateTime.now() + .add(duration!) + .millisecondsSinceEpoch; - final endTime = startsAt - .copyWith( - hour: startsAt.hour + duration!.inHours, - minute: startsAt.minute + - duration!.inMinutes) - .millisecondsSinceEpoch; + groupCubit.createHike(title, startsAt, + expiresAt, groupID!, isInstant); - if (groupCubit.position == null) { - utils.showSnackBar( - 'Please give access to location!', - context); - groupCubit.fetchPosition(); - return; + _durationController.clear(); + _startTimeController.clear(); + _durationController.clear(); + appRouter.maybePop(); } - AutoRouter.of(context).maybePop(); - groupCubit.createHike( - title, - startingTime, - endTime, - groupCubit.position!.latitude.toString(), - groupCubit.position!.longitude.toString(), - groupID!); } }), ), @@ -454,7 +527,7 @@ class CreateJoinBeaconDialog { static GlobalKey _joinBeaconKey = GlobalKey(); static TextEditingController _joinBeaconController = TextEditingController(); - static Future joinBeaconDialog(BuildContext context, GroupCubit groupCubit) { + static Future joinBeaconDialog(BuildContext context) { bool isSmallSized = MediaQuery.of(context).size.height < 800; return showDialog( context: context, @@ -509,8 +582,9 @@ class CreateJoinBeaconDialog { buttonColor: kYellow, onTap: () { if (!_joinBeaconKey.currentState!.validate()) return; - AutoRouter.of(context).maybePop(); - groupCubit.joinHike(_joinBeaconController.text.trim()); + locator().joinBeaconWithShortCode( + _joinBeaconController.text); + appRouter.maybePop(); _joinBeaconController.clear(); }, ), diff --git a/lib/presentation/group/widgets/group_widgets.dart b/lib/presentation/group/widgets/group_widgets.dart new file mode 100644 index 00000000..0ad93de4 --- /dev/null +++ b/lib/presentation/group/widgets/group_widgets.dart @@ -0,0 +1,548 @@ +import 'dart:developer'; + +import 'package:beacon/core/utils/validators.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/presentation/group/cubit/members_cubit/members_cubit.dart'; +import 'package:beacon/presentation/group/cubit/members_cubit/members_state.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/presentation/widgets/shimmer.dart'; +import 'package:duration_picker/duration_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:beacon/presentation/group/cubit/group_cubit/group_cubit.dart'; +import 'package:beacon/presentation/group/cubit/group_cubit/group_state.dart'; +import 'package:beacon/presentation/widgets/hike_button.dart'; +import 'package:beacon/core/utils/constants.dart'; +import 'package:gap/gap.dart'; +import 'package:intl/intl.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; + +class GroupWidgetUtils { + static Widget membersWidget(BuildContext context) { + return FloatingActionButton( + heroTag: 'members', + backgroundColor: kYellow, + onPressed: () { + _showMembers(context); + }, + child: Icon(Icons.person, size: 30), + ); + } + + static void _showMembers(BuildContext context) { + // Dialog for filtering beacons + locator().loadMembers(); + showDialog( + context: context, + builder: (context) { + bool isSmallSized = 100.h < 800; + return AlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.group), + Gap(5), + Text( + 'Members', + textAlign: TextAlign.center, + ) + ], + ), + content: Container( + height: isSmallSized ? 30.h : 25.h, + width: isSmallSized ? 200 : 300, + child: BlocConsumer( + listener: (context, state) { + if (state is LoadedMemberState && state.message != null) { + utils.showSnackBar(state.message!, context); + } + }, + builder: (context, state) { + if (state is LoadingMemberState) { + return ShimmerWidget.getPlaceholder(); + } else if (state is LoadedMemberState) { + var members = state.members; + return members!.isEmpty + ? Container( + child: + Text('Please check your internet connection'), + ) + : ListView.builder( + shrinkWrap: true, + itemCount: members.length, + itemBuilder: (context, index) { + bool isLeader = + localApi.userModel.id! == members[0].id!; + return Container( + margin: EdgeInsets.symmetric(vertical: 10), + decoration: BoxDecoration( + color: kLightBlue, + borderRadius: + BorderRadius.all(Radius.circular(10))), + child: ListTile( + leading: index == 0 + ? Icon( + Icons.star, + color: kYellow, + ) + : Icon(Icons.person), + trailing: index == 0 + ? Text('Leader') + : isLeader + ? IconButton( + onPressed: () { + context + .read() + .removeMember( + members[index].id ?? + ''); + }, + icon: Icon( + Icons.person_remove_alt_1, + weight: 20, + color: const Color.fromARGB( + 255, 215, 103, 95), + )) + : null, + subtitle: localApi.userModel.id! == + members[index].id! + ? Text( + '(YOU)', + style: TextStyle(fontSize: 12), + ) + : null, + title: + Text(members[index].name ?? 'Anonymous'), + ), + ); + }, + ); + } + return Container(); + }, + )), + ); + }, + ); + } + + static Future deleteDialog(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), + content: Text( + 'Are you sure you want to delete this beacon?', + style: TextStyle(fontSize: 18, color: kBlack), + ), + actions: [ + HikeButton( + buttonHeight: 2.5.h, + buttonWidth: 8.w, + onTap: () => appRouter.maybePop(false), + text: 'No', + ), + HikeButton( + buttonHeight: 2.5.h, + buttonWidth: 8.w, + onTap: () => appRouter.maybePop(true), + text: 'Yes', + ), + ], + ), + ); + } + + static Widget filterBeacons( + BuildContext context, String groupId, GroupCubit groupCubit) { + // Widget for filtering beacons + return FloatingActionButton( + heroTag: 'filter beacon', + backgroundColor: kYellow, + onPressed: () => _showFilterBeaconAlertBox(context, groupId, groupCubit), + child: ImageIcon( + AssetImage(AppConstants.filterIconPath), + size: 35, + semanticLabel: 'Filter', + color: Colors.black, + ), + ); + } + + static Future reScheduleHikeDialog( + BuildContext context, BeaconEntity beacon) { + var startsAt = beacon.startsAt!; + var expiresAt = beacon.expiresAt!; + var previousStartDate = DateTime.fromMillisecondsSinceEpoch(startsAt); + var previousExpireDate = DateTime.fromMillisecondsSinceEpoch(expiresAt); + + var previousDuration = previousExpireDate.difference(previousStartDate); + + DateTime? newstartDate = previousStartDate; + TextEditingController _dateController = TextEditingController( + text: DateFormat('yyyy-MM-dd').format(previousStartDate)); + + TimeOfDay? startTime = TimeOfDay( + hour: previousStartDate.hour, minute: previousStartDate.minute); + TextEditingController _startTimeController = TextEditingController( + text: DateFormat('HH:mm').format(previousStartDate)); + + Duration? duration = previousDuration; + TextEditingController _durationController = TextEditingController( + text: previousDuration.inMinutes < 60 + ? '${previousDuration.inMinutes} minutes' + : '${previousDuration.inHours} hours'); + + GlobalKey _createFormKey = GlobalKey(); + bool isSmallSized = 100.h < 800; + + bool isExpired = DateTime.now() + .isAfter(DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!)); + 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: _createFormKey, + child: Container( + height: isSmallSized ? 68.h : 62.h, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 32, vertical: 16), + child: Column( + children: [ + Text( + isExpired ? 'Activate Hike' : 'Reschedule Hike', + style: TextStyle(fontSize: 30), + ), + SizedBox(height: 2.h), + // start date field + Container( + height: isSmallSized ? 14.h : 12.h, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: InkWell( + onTap: () async { + newstartDate = await showDatePicker( + context: context, + initialDate: newstartDate ?? DateTime.now(), + firstDate: newstartDate ?? DateTime.now(), + lastDate: DateTime(2100), + // builder: (context, child) => Theme( + // data: ThemeData().copyWith( + // textTheme: Theme.of(context).textTheme, + // colorScheme: ColorScheme.light( + // primary: kLightBlue, + // onPrimary: Colors.grey, + // surface: kBlue, + // ), + // ), + // child: child!), + ); + if (newstartDate == null) return; + _dateController.text = DateFormat('yyyy-MM-dd') + .format(newstartDate!); + }, + child: TextFormField( + validator: (value) => + Validator.validateDate(value), + controller: _dateController, + enabled: false, + onEditingComplete: () {}, + decoration: InputDecoration( + border: InputBorder.none, + hintText: 'Choose Start Date', + labelStyle: TextStyle( + fontSize: labelsize, color: kYellow), + hintStyle: TextStyle( + fontSize: hintsize, color: hintColor), + labelText: 'Start Date', + alignLabelWithHint: true, + floatingLabelBehavior: + FloatingLabelBehavior.always, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none), + ), + ), + ), + color: kLightBlue, + ), + SizedBox(height: 2.h), + // Start Time Field + Container( + height: isSmallSized ? 14.h : 12.h, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: InkWell( + onTap: () async { + startTime = await showTimePicker( + context: context, + initialTime: startTime ?? + TimeOfDay( + hour: DateTime.now().hour, + minute: DateTime.now().minute + 1)); + if (startTime != null) { + if (startTime!.minute < 10) { + _startTimeController.text = + '${startTime!.hour}:0${startTime!.minute} ${startTime!.period == DayPeriod.am ? 'AM' : 'PM'}'; + } else { + _startTimeController.text = + '${startTime!.hour}:${startTime!.minute} ${startTime!.period == DayPeriod.am ? 'AM' : 'PM'}'; + } + } + }, + child: TextFormField( + validator: (value) => Validator.validateStartTime( + value, _dateController.text), + controller: _startTimeController, + enabled: false, + onEditingComplete: () {}, + decoration: InputDecoration( + border: InputBorder.none, + alignLabelWithHint: true, + errorStyle: TextStyle(color: Colors.red[800]), + floatingLabelBehavior: + FloatingLabelBehavior.always, + labelText: 'Start Time', + labelStyle: TextStyle( + fontSize: labelsize, color: kYellow), + hintStyle: TextStyle( + fontSize: hintsize, color: hintColor), + hintText: 'Choose start time', + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ), + ), + color: kLightBlue, + ), + 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 { + duration = await showDurationPicker( + context: context, + initialTime: duration ?? Duration(minutes: 5), + ); + if (duration == null) return; + 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'; + } + }, + child: TextFormField( + enabled: false, + controller: _durationController, + validator: (value) => + Validator.validateDuration(value), + decoration: InputDecoration( + border: InputBorder.none, + alignLabelWithHint: true, + errorStyle: TextStyle(color: Colors.red[800]), + floatingLabelBehavior: + FloatingLabelBehavior.always, + labelText: 'Duration', + labelStyle: TextStyle( + fontSize: labelsize, color: kYellow), + hintStyle: TextStyle( + fontSize: hintsize, color: hintColor), + hintText: 'Enter duration of hike', + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none), + ), + ), + ), + color: kLightBlue, + ), + SizedBox(height: 2.h), + Flexible( + flex: 2, + child: HikeButton( + text: 'Update', + textSize: 18.0, + textColor: Colors.white, + buttonColor: kYellow, + onTap: () async { + if (!_createFormKey.currentState!.validate()) + return; + DateTime startsAt = DateTime( + newstartDate!.year, + newstartDate!.month, + newstartDate!.day, + startTime!.hour, + startTime!.minute); + + final newStartsAt = + startsAt.millisecondsSinceEpoch; + + final newExpiresAT = startsAt + .copyWith( + hour: startsAt.hour + duration!.inHours, + minute: + startsAt.minute + duration!.inMinutes) + .millisecondsSinceEpoch; + + context.read().rescheduleHike( + newExpiresAT, newStartsAt, beacon.id!); + _dateController.clear(); + _startTimeController.clear(); + _durationController.clear(); + appRouter.maybePop(); + // } + }), + ), + ], + ), + ), + ), + ), + ), + ), + ), + ); + } + + static void _showFilterBeaconAlertBox( + BuildContext context, String groupId, GroupCubit groupCubit) { + log(100.h.toString()); + // Dialog for filtering beacons + showDialog( + context: context, + builder: (context) { + bool isSmallSized = 100.h < 800; + return AlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ImageIcon( + AssetImage(AppConstants.filterIconPath), + size: 30, + semanticLabel: 'Filter', + color: Colors.black, + ), + Gap(10), + Text( + 'Filter', + textAlign: TextAlign.center, + ), + ], + ), + content: SizedBox( + width: 200, + height: isSmallSized ? 32.h : 30.h, + child: BlocBuilder( + builder: (context, state) => ListView.builder( + itemCount: filters.values.length, + itemBuilder: (context, index) { + String type = filters.values[index].name; + + return HikeButton( + buttonWidth: 2.w, + buttonHeight: 1.h, + text: type, + onTap: () { + Navigator.pop(context); + if (filters.values[index] == filters.NEARBY) { + _neabyFilterAlertBox(context, groupId, groupCubit); + } else { + locator() + .changeFilter(filters.values[index]); + } + }, + buttonColor: kYellow, + ); + }, + ), + ), + ), + ); + }, + ); + } + + static void _neabyFilterAlertBox( + BuildContext context, String groupId, GroupCubit groupCubit) { + GlobalKey _key = GlobalKey(); + showDialog( + context: context, + builder: (context) { + double value = 1000.0 / + 100000; // Default radius for range (100 km) // creating a 100.0 km range + bool isSmallSized = 100.h < 800; + return AlertDialog( + content: SizedBox( + height: isSmallSized ? 28.h : 25.h, + child: Form( + key: _key, + child: Column( + children: [ + Gap(5), + Container( + color: kLightBlue, + child: StatefulBuilder( + builder: (context, setState) => Stack( + children: [ + Container( + height: 14.h, + child: Slider( + activeColor: kYellow, + value: value, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, + ), + ), + Align( + alignment: Alignment(0, 0), + child: Text( + '${(value * 100).toStringAsFixed(2)} km', + style: TextStyle(fontSize: 20, color: hintColor), + ), + ), + ], + ), + ), + ), + Gap(10), + HikeButton( + text: 'Fetch', + buttonColor: kYellow, + onTap: () { + if (_key.currentState!.validate()) { + appRouter.maybePop(); + locator() + .nearbyHikes(groupId, radius: value * 100000); + } + }, + buttonWidth: 60, + borderColor: Colors.white, + ), + ], + ), + ), + ), + ); + }, + ); + } +} diff --git a/lib/old/components/timer.dart b/lib/presentation/group/widgets/timer.dart similarity index 52% rename from lib/old/components/timer.dart rename to lib/presentation/group/widgets/timer.dart index 0cf975d7..a05d0e1b 100644 --- a/lib/old/components/timer.dart +++ b/lib/presentation/group/widgets/timer.dart @@ -1,8 +1,7 @@ -import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.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/Bloc/presentation/screens/hike_screen.dart'; +import 'package:beacon/core/utils/constants.dart'; +import 'package:beacon/config/router/router.dart'; import 'package:flutter/material.dart'; import 'package:flutter_countdown_timer/index.dart'; @@ -32,40 +31,7 @@ class _CountdownTimerPageState extends State setState(() { endTime = DateTime.now().millisecondsSinceEpoch + 1000 * timeDiff; }); - controller = - CountdownTimerController(endTime: endTime, onEnd: onEnd, vsync: this); - } - - void onEnd() async { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - duration: Duration(seconds: 5), - content: Text( - '${widget.name} is now active! \nYou can join the hike', - style: TextStyle(color: Colors.black), - ), - backgroundColor: kLightBlue.withOpacity(0.8), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(10), - ), - ), - behavior: SnackBarBehavior.floating, - elevation: 5, - action: SnackBarAction( - textColor: kBlue, - label: 'Click to Join', - onPressed: () async { - bool isLeader = - widget.beacon.leader!.id == userConfig!.currentUser!.id; - navigationService!.pushScreen( - '/hikeScreen', - // arguments: HikeScreen(widget.beacon, isLeader: isLeader), - ); - }, - ), - ), - ); + controller = CountdownTimerController(endTime: endTime, vsync: this); } @override diff --git a/lib/presentation/hike/cubit/hike_cubit/hike_cubit.dart b/lib/presentation/hike/cubit/hike_cubit/hike_cubit.dart new file mode 100644 index 00000000..f8297981 --- /dev/null +++ b/lib/presentation/hike/cubit/hike_cubit/hike_cubit.dart @@ -0,0 +1,373 @@ +// import 'dart:async'; +// import 'dart:developer'; +// import 'package:beacon/config/enviornment_config.dart'; +// import 'package:beacon/core/resources/data_state.dart'; +// import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +// import 'package:beacon/domain/entities/landmark/landmark_entity.dart'; +// import 'package:beacon/domain/entities/location/location_entity.dart'; +// import 'package:beacon/domain/entities/user/user_entity.dart'; +// import 'package:beacon/domain/usecase/group_usecase.dart'; +// import 'package:beacon/domain/usecase/hike_usecase.dart'; +// import 'package:beacon/locator.dart'; +// import 'package:bloc/bloc.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_animarker/flutter_map_marker_animation.dart'; +// import 'package:flutter_polyline_points/flutter_polyline_points.dart'; +// import 'package:geolocator/geolocator.dart'; +// import 'package:google_maps_flutter/google_maps_flutter.dart'; +// import 'package:intl/intl.dart'; + +// abstract class HikeState { +// final LocationEntity? updatedLocation; +// final BeaconEntity? updateBeacon; +// final String? error; + +// HikeState({this.updatedLocation, this.error, this.updateBeacon}); +// } + +// class InitialHikeState extends HikeState { +// InitialHikeState() : super(); +// } + +// class BeaconLoadingState extends HikeState { +// BeaconLoadingState() : super(); +// } + +// class BeaconLocationLoaded extends HikeState { +// final LocationEntity? updatedLocation; + +// BeaconLocationLoaded({required this.updatedLocation}) +// : super(updatedLocation: updatedLocation); +// } + +// class BeaconUpdateLoaded extends HikeState { +// final BeaconEntity? updateBeacon; + +// BeaconUpdateLoaded({required this.updateBeacon}) +// : super(updateBeacon: updateBeacon); +// } + +// class BeaconErrorState extends HikeState { +// final String error; + +// BeaconErrorState({required this.error}) : super(error: error); +// } + +// class BeaconLocationError extends HikeState { +// final String message; +// BeaconLocationError({required this.message}); +// } + +// class BeaconReloadState extends HikeState {} + +// class MapReloadState extends HikeState {} + +// class HikeCubit extends Cubit { +// final HikeUseCase hikeUsecase; +// final GroupUseCase groupUseCase; +// HikeCubit({required this.hikeUsecase, required this.groupUseCase}) +// : super(BeaconLoadingState()); + +// bool? isActive; +// String? time; +// String? endsAt; +// LatLng? beaconLeaderLocation; +// Set markers = Set(); +// StreamSubscription? _positionStream; +// Position? position; +// Completer mapController = +// Completer(); +// BeaconEntity? beacon; +// StreamSubscription>? _locationSubscription; +// List members = []; +// StreamSubscription>? beaconUpdateStream; +// List routes = []; + +// Future fetchBeaconDetails(String beaconId, BuildContext context) async { +// emit(BeaconLoadingState()); +// DataState state = +// await hikeUsecase.fetchBeaconDetails(beaconId); + +// if (state is DataSuccess && state.data != null) { +// beacon = state.data!; + +// createLeaderMarker(beacon!.location!); +// currentAndPrevious.add(LatLng(double.parse(beacon!.location!.lat!), +// double.parse(beacon!.location!.lon!))); + +// segregateBeaconData(beacon!); + +// beaconUpdateSubscription(beaconId, context); + +// print('landmark length: ${beacon!.landmarks!.length.toString()}'); + +// for (var landmark in beacon!.landmarks!) { +// createLandmarkMarker(landmark!); +// } + +// // if leader +// if (beacon!.leader!.id == localApi.userModel.id) { +// await updateBeaconLocation(beaconId, context); +// } else { +// // if follower +// await beaconLocationSubscription(beaconId, context); +// } +// emit(BeaconReloadState()); +// } else { +// emit(BeaconErrorState(error: state.error!)); +// } +// } + +// void createLeaderMarker(LocationEntity beaconlocation) { +// // leader location variable +// beaconLeaderLocation = LatLng( +// double.parse(beaconlocation.lat!), double.parse(beaconlocation.lon!)); + +// // ripple marker for leader +// markers.add(RippleMarker( +// infoWindow: InfoWindow(title: beacon?.leader?.name), +// ripple: false, +// markerId: MarkerId(beacon!.leader!.id!), +// position: beaconLeaderLocation!, +// icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueRed))); +// } + +// List currentAndPrevious = []; + +// Future updateBeaconLocation( +// String beaconId, BuildContext context) async { +// _positionStream?.cancel(); +// _positionStream = await Geolocator.getPositionStream( +// locationSettings: LocationSettings( +// accuracy: LocationAccuracy.high, +// distanceFilter: 5, +// )).listen((newPosition) async { +// utils.showSnackBar('New Position: ', context, top: true, icon: true); + +// routes.add(LatLng(newPosition.latitude, newPosition.latitude)); + +// setPolyline(); + +// LatLng newCord = LatLng(newPosition.latitude, newPosition.longitude); +// changeMarkerPosition(newCord); +// emit(MapReloadState()); +// // await hikeUsecase.updateBeaconLocation(beaconId, newCord); +// }); +// } + +// Future beaconLocationSubscription( +// String beaconId, BuildContext context) async { +// _locationSubscription?.cancel(); +// _locationSubscription = await hikeUsecase +// .beaconLocationSubscription(beaconId) +// .listen((dataState) async { +// if (dataState is DataSuccess && dataState.data != null) { +// utils.showSnackBar('leader location updated', context); +// LocationEntity newLocation = dataState.data!; +// LatLng newPosition = LatLng( +// double.parse(newLocation.lat!), double.parse(newLocation.lon!)); + +// // changing marker position +// changeMarkerPosition(newPosition); +// // changing camera position + +// emit(MapReloadState()); +// } else if (dataState is DataFailed) { +// // log('error while getting subscription: ${dataState.error}'); +// } +// }); +// } + +// void changeMarkerPosition(LatLng newPosition) { +// final leaderId = beacon!.leader!.id!; +// final leaderMarker = +// markers.firstWhere((element) => element.markerId == MarkerId(leaderId)); +// final updatedMarker = leaderMarker.copyWith(positionParam: newPosition); +// markers.remove(leaderMarker); +// markers.add(updatedMarker); +// } + +// Future segregateBeaconData(BeaconEntity beacon) async { +// if (beacon.expiresAt! > DateTime.now().millisecondsSinceEpoch) { +// // adding leaders and followers +// members.add(beacon.leader!); +// for (var follower in beacon.followers!) { +// members.add(follower!); +// } +// isActive = true; +// DateTime expireDate = +// DateTime.fromMillisecondsSinceEpoch(beacon.expiresAt!); +// endsAt = DateFormat('hh:mm a, dd/MM/yyyy').format(expireDate); + +// // TODO: Implement address from location +// } else { +// isActive = false; +// } +// } + +// // creating address from coordinate +// Future corToAdd(String latitude, String longitude) async {} + +// Future changeCameraPosition(LatLng newPosition) async { +// // final GoogleMapController controller = await mapController.future; + +// // // new camera position +// // final CameraPosition newCamera = CameraPosition( +// // target: newPosition, +// // zoom: 20, +// // ); +// // await controller.animateCamera(CameraUpdate.newCameraPosition(newCamera)); +// } + +// Future> joinBeacon(String shortcode) async { +// return await groupUseCase.joinHike(shortcode); +// } + +// Future beaconUpdateSubscription( +// String beaconId, BuildContext context) async { +// beaconUpdateStream?.cancel(); +// beaconUpdateStream = await hikeUsecase +// .beaconUpdateSubscription(beaconId) +// .listen((dataState) { +// if (dataState is DataSuccess) { +// if (dataState.data is UserEntity) { +// final user = dataState.data as UserEntity; +// members.add(user); +// utils.showSnackBar( +// '${user.name} is now following the beacon!', context, +// top: true, icon: true); + +// emit(BeaconReloadState()); +// } else if (dataState.data is LandMarkEntity) { +// createLandmarkMarker(dataState.data!); +// utils.showSnackBar('New landmark created', context); +// emit(MapReloadState()); +// } +// } else if (dataState is DataFailed) {} +// }); +// } + +// void createLandmarkMarker(LandMarkEntity landMark) { +// markers.add(Marker( +// infoWindow: InfoWindow(title: landMark.title), +// markerId: MarkerId(landMark.id!), +// position: LatLng(double.parse(landMark.location!.lat!), +// double.parse(landMark.location!.lon!)), +// icon: +// BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueAzure))); +// } + +// Future createLandMark( +// String id, String title, String lat, String lon) async { +// final state = await hikeUsecase.createLandMark(id, title, lat, lon); + +// if (state is DataSuccess) { +// // log('new marker created'); +// // createLandmarkMarker(state.data!); +// // emit(MapReloadState()); +// } else { +// // showing error +// } +// } + +// @override +// Future close() { +// _locationSubscription?.cancel(); +// _positionStream?.cancel(); +// return super.close(); +// } + +// List polylineCoordinates = []; +// Set polylines = Set(); + +// Future setPolyline() async { +// PolylinePoints polylinePoints = PolylinePoints(); + +// PolylineResult? result = await polylinePoints.getRouteBetweenCoordinates( +// EnvironmentConfig.googleMapApi!, // Google Maps API Key +// PointLatLng(routes.first.latitude, routes.first.longitude), +// PointLatLng(routes.last.latitude, routes.last.longitude), +// ); + +// log('result: ${result.points.length.toString()}'); + +// if (result.points.isNotEmpty) { +// result.points.forEach((PointLatLng point) { +// polylineCoordinates.add(LatLng(point.latitude, point.longitude)); +// }); +// } + +// Polyline polyline = Polyline( +// polylineId: PolylineId('poly'), +// color: Colors.red, +// points: polylineCoordinates, +// width: 3, +// ); +// polylines.add(polyline); +// } + +// MapType mapType = MapType.normal; + +// void changeMapType(MapType newMapType) { +// mapType = newMapType; +// emit(MapReloadState()); +// } + +// clear() { +// beaconUpdateStream?.cancel(); +// _locationSubscription?.cancel(); +// members.clear(); +// _positionStream?.cancel(); +// markers.clear(); +// beaconLeaderLocation = null; +// isActive = null; +// time = null; +// endsAt = null; +// } +// } + +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/usecase/hike_usecase.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/presentation/hike/cubit/hike_cubit/hike_state.dart'; +import 'package:beacon/presentation/hike/cubit/location_cubit/location_cubit.dart'; +import 'package:beacon/presentation/hike/cubit/panel_cubit/panel_cubit.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:location/location.dart'; + +class HikeCubit extends Cubit { + final HikeUseCase _hikeUseCase; + HikeCubit._internal(this._hikeUseCase) : super(LoadedHikeState()); + + static HikeCubit? _instance; + + factory HikeCubit(HikeUseCase hikeUseCase) { + return _instance ?? HikeCubit._internal(hikeUseCase); + } + + BeaconEntity? _beacon; + String? _beaconId; + + Future startHike(String beaconId) async { + emit(InitialHikeState()); + _beaconId = beaconId; + final dataState = await _hikeUseCase.fetchBeaconDetails(beaconId); + + if (dataState is DataSuccess && dataState.data != null) { + final beacon = dataState.data!; + _beacon = beacon; + + locator().loadBeaconData(beacon); + locator().loadBeaconData(beacon); + emit(LoadedHikeState(beacon: _beacon, message: 'Welcome to hike!')); + } else { + emit(ErrorHikeState(errmessage: dataState.error)); + } + } + + clear() { + _beacon = null; + _beaconId = null; + } +} diff --git a/lib/presentation/hike/cubit/hike_cubit/hike_state.dart b/lib/presentation/hike/cubit/hike_cubit/hike_state.dart new file mode 100644 index 00000000..2ffb9995 --- /dev/null +++ b/lib/presentation/hike/cubit/hike_cubit/hike_state.dart @@ -0,0 +1,12 @@ +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'hike_state.freezed.dart'; + +@freezed +class HikeState with _$HikeState { + factory HikeState.initial() = InitialHikeState; + factory HikeState.loaded({BeaconEntity? beacon, String? message}) = + LoadedHikeState; + + factory HikeState.error({String? errmessage}) = ErrorHikeState; +} diff --git a/lib/presentation/hike/cubit/hike_cubit/hike_state.freezed.dart b/lib/presentation/hike/cubit/hike_cubit/hike_state.freezed.dart new file mode 100644 index 00000000..94b72b12 --- /dev/null +++ b/lib/presentation/hike/cubit/hike_cubit/hike_state.freezed.dart @@ -0,0 +1,493 @@ +// 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 'hike_state.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 _$HikeState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function(BeaconEntity? beacon, String? message) loaded, + required TResult Function(String? errmessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function(BeaconEntity? beacon, String? message)? loaded, + TResult? Function(String? errmessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function(BeaconEntity? beacon, String? message)? loaded, + TResult Function(String? errmessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(InitialHikeState value) initial, + required TResult Function(LoadedHikeState value) loaded, + required TResult Function(ErrorHikeState value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialHikeState value)? initial, + TResult? Function(LoadedHikeState value)? loaded, + TResult? Function(ErrorHikeState value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialHikeState value)? initial, + TResult Function(LoadedHikeState value)? loaded, + TResult Function(ErrorHikeState value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $HikeStateCopyWith<$Res> { + factory $HikeStateCopyWith(HikeState value, $Res Function(HikeState) then) = + _$HikeStateCopyWithImpl<$Res, HikeState>; +} + +/// @nodoc +class _$HikeStateCopyWithImpl<$Res, $Val extends HikeState> + implements $HikeStateCopyWith<$Res> { + _$HikeStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$InitialHikeStateImplCopyWith<$Res> { + factory _$$InitialHikeStateImplCopyWith(_$InitialHikeStateImpl value, + $Res Function(_$InitialHikeStateImpl) then) = + __$$InitialHikeStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$InitialHikeStateImplCopyWithImpl<$Res> + extends _$HikeStateCopyWithImpl<$Res, _$InitialHikeStateImpl> + implements _$$InitialHikeStateImplCopyWith<$Res> { + __$$InitialHikeStateImplCopyWithImpl(_$InitialHikeStateImpl _value, + $Res Function(_$InitialHikeStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$InitialHikeStateImpl implements InitialHikeState { + _$InitialHikeStateImpl(); + + @override + String toString() { + return 'HikeState.initial()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$InitialHikeStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function(BeaconEntity? beacon, String? message) loaded, + required TResult Function(String? errmessage) error, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function(BeaconEntity? beacon, String? message)? loaded, + TResult? Function(String? errmessage)? error, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function(BeaconEntity? beacon, String? message)? loaded, + TResult Function(String? errmessage)? error, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialHikeState value) initial, + required TResult Function(LoadedHikeState value) loaded, + required TResult Function(ErrorHikeState value) error, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialHikeState value)? initial, + TResult? Function(LoadedHikeState value)? loaded, + TResult? Function(ErrorHikeState value)? error, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialHikeState value)? initial, + TResult Function(LoadedHikeState value)? loaded, + TResult Function(ErrorHikeState value)? error, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class InitialHikeState implements HikeState { + factory InitialHikeState() = _$InitialHikeStateImpl; +} + +/// @nodoc +abstract class _$$LoadedHikeStateImplCopyWith<$Res> { + factory _$$LoadedHikeStateImplCopyWith(_$LoadedHikeStateImpl value, + $Res Function(_$LoadedHikeStateImpl) then) = + __$$LoadedHikeStateImplCopyWithImpl<$Res>; + @useResult + $Res call({BeaconEntity? beacon, String? message}); + + $BeaconEntityCopyWith<$Res>? get beacon; +} + +/// @nodoc +class __$$LoadedHikeStateImplCopyWithImpl<$Res> + extends _$HikeStateCopyWithImpl<$Res, _$LoadedHikeStateImpl> + implements _$$LoadedHikeStateImplCopyWith<$Res> { + __$$LoadedHikeStateImplCopyWithImpl( + _$LoadedHikeStateImpl _value, $Res Function(_$LoadedHikeStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? beacon = freezed, + Object? message = freezed, + }) { + return _then(_$LoadedHikeStateImpl( + beacon: freezed == beacon + ? _value.beacon + : beacon // ignore: cast_nullable_to_non_nullable + as BeaconEntity?, + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, + )); + } + + @override + @pragma('vm:prefer-inline') + $BeaconEntityCopyWith<$Res>? get beacon { + if (_value.beacon == null) { + return null; + } + + return $BeaconEntityCopyWith<$Res>(_value.beacon!, (value) { + return _then(_value.copyWith(beacon: value)); + }); + } +} + +/// @nodoc + +class _$LoadedHikeStateImpl implements LoadedHikeState { + _$LoadedHikeStateImpl({this.beacon, this.message}); + + @override + final BeaconEntity? beacon; + @override + final String? message; + + @override + String toString() { + return 'HikeState.loaded(beacon: $beacon, message: $message)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LoadedHikeStateImpl && + (identical(other.beacon, beacon) || other.beacon == beacon) && + (identical(other.message, message) || other.message == message)); + } + + @override + int get hashCode => Object.hash(runtimeType, beacon, message); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LoadedHikeStateImplCopyWith<_$LoadedHikeStateImpl> get copyWith => + __$$LoadedHikeStateImplCopyWithImpl<_$LoadedHikeStateImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function(BeaconEntity? beacon, String? message) loaded, + required TResult Function(String? errmessage) error, + }) { + return loaded(beacon, message); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function(BeaconEntity? beacon, String? message)? loaded, + TResult? Function(String? errmessage)? error, + }) { + return loaded?.call(beacon, message); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function(BeaconEntity? beacon, String? message)? loaded, + TResult Function(String? errmessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(beacon, message); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialHikeState value) initial, + required TResult Function(LoadedHikeState value) loaded, + required TResult Function(ErrorHikeState value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialHikeState value)? initial, + TResult? Function(LoadedHikeState value)? loaded, + TResult? Function(ErrorHikeState value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialHikeState value)? initial, + TResult Function(LoadedHikeState value)? loaded, + TResult Function(ErrorHikeState value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class LoadedHikeState implements HikeState { + factory LoadedHikeState({final BeaconEntity? beacon, final String? message}) = + _$LoadedHikeStateImpl; + + BeaconEntity? get beacon; + String? get message; + @JsonKey(ignore: true) + _$$LoadedHikeStateImplCopyWith<_$LoadedHikeStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$ErrorHikeStateImplCopyWith<$Res> { + factory _$$ErrorHikeStateImplCopyWith(_$ErrorHikeStateImpl value, + $Res Function(_$ErrorHikeStateImpl) then) = + __$$ErrorHikeStateImplCopyWithImpl<$Res>; + @useResult + $Res call({String? errmessage}); +} + +/// @nodoc +class __$$ErrorHikeStateImplCopyWithImpl<$Res> + extends _$HikeStateCopyWithImpl<$Res, _$ErrorHikeStateImpl> + implements _$$ErrorHikeStateImplCopyWith<$Res> { + __$$ErrorHikeStateImplCopyWithImpl( + _$ErrorHikeStateImpl _value, $Res Function(_$ErrorHikeStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errmessage = freezed, + }) { + return _then(_$ErrorHikeStateImpl( + errmessage: freezed == errmessage + ? _value.errmessage + : errmessage // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$ErrorHikeStateImpl implements ErrorHikeState { + _$ErrorHikeStateImpl({this.errmessage}); + + @override + final String? errmessage; + + @override + String toString() { + return 'HikeState.error(errmessage: $errmessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ErrorHikeStateImpl && + (identical(other.errmessage, errmessage) || + other.errmessage == errmessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errmessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ErrorHikeStateImplCopyWith<_$ErrorHikeStateImpl> get copyWith => + __$$ErrorHikeStateImplCopyWithImpl<_$ErrorHikeStateImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function(BeaconEntity? beacon, String? message) loaded, + required TResult Function(String? errmessage) error, + }) { + return error(errmessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function(BeaconEntity? beacon, String? message)? loaded, + TResult? Function(String? errmessage)? error, + }) { + return error?.call(errmessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function(BeaconEntity? beacon, String? message)? loaded, + TResult Function(String? errmessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errmessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialHikeState value) initial, + required TResult Function(LoadedHikeState value) loaded, + required TResult Function(ErrorHikeState value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialHikeState value)? initial, + TResult? Function(LoadedHikeState value)? loaded, + TResult? Function(ErrorHikeState value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialHikeState value)? initial, + TResult Function(LoadedHikeState value)? loaded, + TResult Function(ErrorHikeState value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class ErrorHikeState implements HikeState { + factory ErrorHikeState({final String? errmessage}) = _$ErrorHikeStateImpl; + + String? get errmessage; + @JsonKey(ignore: true) + _$$ErrorHikeStateImplCopyWith<_$ErrorHikeStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/presentation/hike/cubit/location_cubit/location_cubit.dart b/lib/presentation/hike/cubit/location_cubit/location_cubit.dart new file mode 100644 index 00000000..0167a391 --- /dev/null +++ b/lib/presentation/hike/cubit/location_cubit/location_cubit.dart @@ -0,0 +1,635 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:developer'; +import 'dart:ui'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/core/utils/constants.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/landmark/landmark_entity.dart'; +import 'package:beacon/domain/entities/location/location_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/beacon_locations_entity/beacon_locations_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/domain/usecase/hike_usecase.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/presentation/hike/cubit/location_cubit/location_state.dart'; +import 'package:beacon/presentation/widgets/custom_label_marker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_polyline_points/flutter_polyline_points.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:location/location.dart'; +import 'package:http/http.dart' as http; + +class LocationCubit extends Cubit { + final HikeUseCase _hikeUseCase; + LocationCubit._internal(this._hikeUseCase) : super(InitialLocationState()); + + static LocationCubit? _instance; + + factory LocationCubit(HikeUseCase hikeUseCase) { + return _instance ?? LocationCubit._internal(hikeUseCase); + } + + String? _beaconId; + BeaconEntity? _beacon; + GoogleMapController? _mapController; + Set _hikeMarkers = {}; + UserEntity? _currentUser; + UserEntity? _leader; + List _followers = []; + Set _polyline = {}; + String? _currentUserId; + List _points = []; + String? _address; + LocationData? _lastLocation; + Set _geofence = {}; + MapType _mapType = MapType.normal; + + StreamSubscription>? + _beaconlocationsSubscription; + StreamSubscription? _streamLocaitonData; + + void onMapCreated(GoogleMapController controller) { + _mapController = controller; + } + + Future loadBeaconData(BeaconEntity beacon) async { + emit(InitialLocationState()); + _beaconId = beacon.id!; + _beacon = beacon; + + _currentUserId = localApi.userModel.id!; + + // // adding leader location + if (beacon.leader != null) { + _leader = beacon.leader!; + // creating leader location + + if (_currentUserId == _leader!.id) { + _currentUser = _leader; + } + if (_leader!.location != null) { + _createUserMarker(_leader!, isLeader: true); + getLeaderAddress(locationToLatLng(_leader!.location!)); + } + } + // adding members location + if (beacon.followers != null) { + for (var follower in beacon.followers!) { + if (_currentUserId == follower!.id) { + _currentUser = follower; + } + _followers.add(follower); + if (follower.location != null) { + _createUserMarker(follower); + } + } + } + + if (beacon.route != null) { + // handling polyline here + for (var point in beacon.route!) { + _points.add(locationToLatLng(point!)); + } + _polyline.add(Polyline( + polylineId: PolylineId('leader path'), + color: kYellow, + width: 1, + points: _points)); + } + + // // adding landmarks + if (beacon.landmarks != null) { + for (var landmark in beacon.landmarks!) { + await _createLandMarkMarker(landmark!); + } + } + + await locationUpdateSubscription(beacon.id!); + await _getlocation(); + + emit(LoadedLocationState( + polyline: _polyline, + geofence: _geofence, + locationMarkers: _hikeMarkers, + address: _address, + mapType: _mapType, + message: 'Welcome to hike!')); + } + + Future _getlocation() async { + if (_streamLocaitonData != null) { + _streamLocaitonData!.cancel(); + } + + Location location = new Location(); + location.changeSettings( + interval: 5000, accuracy: LocationAccuracy.high, distanceFilter: 0); + + _streamLocaitonData = + location.onLocationChanged.listen((LocationData newPosition) async { + var latLng = locationDataToLatLng(newPosition); + + if (_lastLocation == null) { + _lastLocation = newPosition; + _points.add(latLng); + } else { + final distance = await locationService.calculateDistance( + latLng, + locationDataToLatLng(_lastLocation!), + ); + + if (distance < 10) { + return; + } + // is Leader + + if (_beacon!.leader!.id == localApi.userModel.id) { + _lastLocation = newPosition; + var updatedUser = _currentUser! + .copywith(location: locationDataToLocationEntity(newPosition)); + _currentUser = updatedUser; + _points.add(latLng); + var newPolyline = await setPolyline(); + log('existes: $newPolyline'); + if (newPolyline == false) return; + + getLeaderAddress(latLng); + _hikeUseCase.changeUserLocation(_beaconId!, latLng); + } + // is follower + else { + _lastLocation = newPosition; + var updatedUser = _currentUser! + .copywith(location: locationDataToLocationEntity(newPosition)); + _currentUser = updatedUser; + // updating location of marker + _createUserMarker(_currentUser!); + + _hikeUseCase.changeUserLocation(_beaconId!, latLng); + } + + emit(LoadedLocationState( + geofence: _geofence, + locationMarkers: _hikeMarkers, + polyline: _polyline, + version: DateTime.now().millisecondsSinceEpoch, + address: _address, + mapType: _mapType, + )); + } + }); + } + + Future setPolyline() async { + PolylinePoints polylinePoints = PolylinePoints(); + try { + PolylineResult result = await polylinePoints.getRouteBetweenCoordinates( + 'AIzaSyBdIpiEfBE5DohHgBvwPTljZQAcNWcKwCs', + PointLatLng(_points.first.latitude, _points.first.longitude), + PointLatLng(_points.last.longitude, _points.last.longitude)); + + log(result.toString()); + + if (result.points.isNotEmpty) { + _polyline.clear(); + _polyline.add(Polyline( + polylineId: PolylineId('leader path'), + points: pointLatLngToLatLng(result.points), + width: 5, + color: kYellow)); + + emit(LoadedLocationState( + geofence: _geofence, + locationMarkers: _hikeMarkers, + polyline: _polyline, + version: DateTime.now().millisecondsSinceEpoch, + address: _address, + mapType: _mapType, + )); + return true; + } else { + return false; + } + } catch (e) { + log('plyresult: $e'); + return false; + } + } + + List pointLatLngToLatLng(List pointLatLngs) { + List newpoints = []; + + for (var pointLatLng in pointLatLngs) { + newpoints.add(LatLng(pointLatLng.latitude, pointLatLng.longitude)); + } + + return newpoints; + } + + void changeCameraPosition(LatLng latLng) { + _mapController!.moveCamera( + CameraUpdate.newCameraPosition(CameraPosition(target: latLng))); + } + + void focusUser(String userId) { + LatLng? latlng; + if (userId == _leader!.id) { + latlng = locationToLatLng(_leader!.location!); + } else { + _followers.forEach((element) { + if (element!.id == userId) { + latlng = locationToLatLng(element.location!); + } + }); + } + + _mapController!.animateCamera(CameraUpdate.newCameraPosition( + CameraPosition(target: latlng!, zoom: 100))); + } + + LatLngBounds calculateMapBoundsFromListOfLatLng(List pointsList, + {double padding = 0.0005}) { + double southWestLatitude = 90; + double southWestLongitude = 90; + double northEastLatitude = -180; + double northEastLongitude = -180; + pointsList.forEach((point) { + if (point.latitude < southWestLatitude) { + southWestLatitude = point.latitude; + } + if (point.longitude < southWestLongitude) { + southWestLongitude = point.longitude; + } + if (point.latitude > northEastLatitude) { + northEastLatitude = point.latitude; + } + if (point.longitude > northEastLongitude) { + northEastLongitude = point.longitude; + } + }); + southWestLatitude = southWestLatitude - padding; + southWestLongitude = southWestLongitude - padding; + northEastLatitude = northEastLatitude + padding; + northEastLongitude = northEastLongitude + padding; + LatLngBounds bound = LatLngBounds( + southwest: LatLng(southWestLatitude, southWestLongitude), + northeast: LatLng(northEastLatitude, northEastLongitude)); + return bound; + } + + Future locationUpdateSubscription(String beaconId) async { + _beaconlocationsSubscription?.cancel(); + + _beaconlocationsSubscription = _hikeUseCase + .beaconlocationsSubscription(beaconId) + .listen((dataState) async { + if (dataState is DataSuccess && dataState.data != null) { + BeaconLocationsEntity beaconLocationsEntity = dataState.data!; + + if (beaconLocationsEntity.geofence != null) { + // geofence recieved + } else if (beaconLocationsEntity.landmark != null) { + LandMarkEntity newLandMark = beaconLocationsEntity.landmark!; + + await _createLandMarkMarker(newLandMark); + + emit(LoadedLocationState( + polyline: _polyline, + locationMarkers: _hikeMarkers, + address: _address, + mapType: _mapType, + geofence: _geofence, + message: + 'A landmark is created by ${beaconLocationsEntity.landmark!.createdBy!.name ?? 'Anonymous'}')); + } else if (beaconLocationsEntity.user != null) { + // location of follower or leader changing + + UserEntity userlocation = beaconLocationsEntity.user!; + + _createUserMarker(userlocation); + + emit(LoadedLocationState( + polyline: _polyline, + geofence: _geofence, + locationMarkers: _hikeMarkers, + address: _address, + mapType: _mapType, + version: DateTime.now().microsecond)); + // add marker for user + } else if (beaconLocationsEntity.route != null) { + var routes = beaconLocationsEntity.route; + _points.clear(); + for (var route in routes!) { + _points.add(locationToLatLng(route!)); + } + _polyline.clear(); + + _polyline.add(Polyline( + polylineId: PolylineId(''), + points: _points, + width: 5, + color: kYellow)); + + emit(LoadedLocationState( + address: _address, + geofence: _geofence, + locationMarkers: _hikeMarkers, + mapType: _mapType, + polyline: _polyline, + version: DateTime.now().millisecondsSinceEpoch)); + } else if (beaconLocationsEntity.userSOS != null) { + var user = beaconLocationsEntity.userSOS; + + // TODO: will update ui to ripple the marker + + // var marker = _hikeMarkers + // .firstWhere((marker) => marker.markerId.value == user!.id); + + // _hikeMarkers + // .removeWhere((hmarker) => hmarker.markerId == marker.markerId); + } + } + }); + } + + Future getLeaderAddress(LatLng latlng) async { + try { + log('leader func'); + var headers = { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Credentials': 'true', + 'Access-Control-Allow-Headers': 'Content-Type', + 'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE' + }; + var response = await http.post( + Uri.parse( + 'https://geocode.maps.co/reverse?lat=${latlng.latitude}&lon=${latlng.longitude}&api_key=6696ae9d4ebc2317438148rjq134731'), + headers: headers); + + log(response.toString()); + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + + final addressString = data['address']; + final city = addressString['city']; + final county = addressString['county']; + final stateDistrict = addressString['state_district']; + final state = addressString['state']; + final postcode = addressString['postcode']; + final country = addressString['country']; + + _address = + '$city, $county, $stateDistrict, $state, $postcode, $country'; + + log('got address: $_address'); + + emit(LoadedLocationState( + geofence: _geofence, + locationMarkers: _hikeMarkers, + polyline: _polyline, + version: DateTime.now().millisecondsSinceEpoch, + address: _address, + mapType: _mapType, + )); + } + } catch (e) { + log(e.toString()); + } + } + + Future createLandmark( + String beaconId, String title, LatLng latlng) async { + var dataState = await _hikeUseCase.createLandMark(beaconId, title, + latlng.latitude.toString(), latlng.longitude.toString()); + + if (dataState is DataSuccess && dataState.data != null) { + await _createLandMarkMarker(dataState.data!); + emit(LoadedLocationState( + polyline: _polyline, + geofence: _geofence, + address: _address, + mapType: _mapType, + locationMarkers: Set.from(_hikeMarkers), + message: 'New marker created by ${dataState.data!.createdBy!.name}')); + } + } + + Future sendSOS(String id, BuildContext context) async { + final dataState = await _hikeUseCase.sos(id); + + if (dataState is DataSuccess) { + // // Ensure _hikeMarkers is a Set of marker objects + + var userId = localApi.userModel.id; + var marker = + _hikeMarkers.firstWhere((marker) => marker.markerId.value == userId); + + _hikeMarkers.removeWhere( + (hmarker) => hmarker.markerId.value == marker.markerId.value, + ); + + _hikeMarkers.add(Marker( + markerId: marker.mapsId, + position: marker.position, + infoWindow: marker.infoWindow)); + + emit(LoadedLocationState( + address: _address, + geofence: _geofence, + locationMarkers: _hikeMarkers, + mapType: _mapType, + message: 'SOS is send with your current\ location!', + polyline: _polyline, + version: DateTime.now().millisecond, + )); + } else { + utils.showSnackBar('Beacon is not active anymore!', context); + } + } + + Future _createLandMarkMarker(LandMarkEntity landMark) async { + final markerId = MarkerId(landMark.id!); + final markerPosition = locationToLatLng(landMark.location!); + + final existingMarkers = + _hikeMarkers.where((element) => element.markerId == markerId); + + if (existingMarkers.isEmpty) { + var newMarker = await createMarker(landMark); + _hikeMarkers.add(newMarker); + } else { + // If the marker exists, update its position + final updatedMarker = existingMarkers.first.copyWith( + positionParam: markerPosition, + ); + _hikeMarkers + ..remove(existingMarkers.first) + ..add(updatedMarker); + } + } + + void _createUserMarker(UserEntity user, {bool isLeader = false}) async { + final markerId = MarkerId(user.id!); + final markerPosition = locationToLatLng(user.location!); + + // final bitmap = await _createCustomMarkerBitmap(); + + final existingMarkers = + _hikeMarkers.where((element) => element.markerId == markerId); + + if (existingMarkers.isEmpty) { + // If the marker does not exist, create and add a new one + final newMarker = Marker( + markerId: markerId, + position: markerPosition, + infoWindow: InfoWindow(title: user.name ?? 'Anonymous'), + icon: BitmapDescriptor.defaultMarkerWithHue( + isLeader ? BitmapDescriptor.hueRed : BitmapDescriptor.hueOrange)); + _hikeMarkers.add(newMarker); + } else { + // If the marker exists, update its position + final updatedMarker = existingMarkers.first.copyWith( + positionParam: markerPosition, + ); + _hikeMarkers + ..remove(existingMarkers.first) + ..add(updatedMarker); + } + } + + Future createMarker(LandMarkEntity landmark) async { + final pictureRecorder = PictureRecorder(); + final canvas = Canvas(pictureRecorder); + final customMarker = CustomMarker(text: landmark.title!); + customMarker.paint(canvas, Size(100, 100)); + final picture = pictureRecorder.endRecording(); + final image = await picture.toImage(100, 100); + final bytes = await image.toByteData(format: ImageByteFormat.png); + + return Marker( + markerId: MarkerId(landmark.id!.toString()), + position: locationToLatLng(landmark.location!), + icon: BitmapDescriptor.bytes(bytes!.buffer.asUint8List()), + ); + } + + void changeGeofenceRadius(double radius, LatLng center) { + var index = _geofence + .toList() + .indexWhere((element) => element.circleId.value == 'geofence'); + + if (index >= 0) { + var newGeofence = _geofence.toList()[index].copyWith(radiusParam: radius); + _geofence.removeWhere((element) => element.circleId.value == 'geofence'); + _geofence.add(newGeofence); + } else { + _geofence.add(Circle( + circleId: CircleId('geofence'), + center: center, + radius: radius, + strokeColor: Colors.blue, + strokeWidth: 2, + fillColor: Colors.blue.withOpacity(0.1), + )); + } + emit(LoadedLocationState( + polyline: _polyline, + locationMarkers: _hikeMarkers, + geofence: _geofence, + address: _address, + mapType: _mapType, + version: DateTime.now().microsecond)); + } + + void removeUncreatedGeofence() { + _geofence.removeWhere((geofence) { + return geofence.circleId.value == 'geofence'; + }); + + emit(LoadedLocationState( + polyline: _polyline, + locationMarkers: _hikeMarkers, + geofence: _geofence, + address: _address, + mapType: _mapType, + version: DateTime.now().microsecond)); + } + + LatLng locationToLatLng(LocationEntity location) { + return LatLng(stringTodouble(location.lat!), stringTodouble(location.lon!)); + } + + double stringTodouble(String coord) { + return double.parse(coord); + } + + Future createGeofence( + String beaconId, LatLng latlng, double radius) async { + var dataState = await _hikeUseCase.createGeofence(beaconId, latlng, radius); + + if (dataState is DataSuccess && dataState.data != null) { + _geofence.clear(); + + var geofence = dataState.data!; + + _geofence.add(Circle( + circleId: CircleId(DateTime.now().millisecondsSinceEpoch.toString()), + center: locationToLatLng(geofence.center!), + radius: (geofence.radius! * 1000), + strokeColor: kYellow, + strokeWidth: 2, + fillColor: kYellow.withOpacity(0.2), + )); + + emit(LoadedLocationState( + polyline: _polyline, + locationMarkers: _hikeMarkers, + geofence: _geofence, + address: _address, + mapType: _mapType, + message: 'New geofence created!', + version: DateTime.now().microsecond)); + } + } + + void changeMap(MapType mapType) { + if (mapType == _mapType) return; + _mapType = mapType; + + emit(LoadedLocationState( + polyline: _polyline, + locationMarkers: _hikeMarkers, + geofence: _geofence, + address: _address, + mapType: mapType, + )); + } + + LatLng locationDataToLatLng(LocationData locationData) { + return LatLng(locationData.latitude!, locationData.longitude!); + } + + LocationEntity locationDataToLocationEntity(LocationData locationData) { + return LocationEntity( + lat: locationData.latitude.toString(), + lon: locationData.longitude.toString()); + } + + clear() { + _points.clear(); + _polyline.clear(); + _geofence.clear(); + _followers.clear(); + _leader = null; + _beacon = null; + _beaconId = null; + _mapType = MapType.normal; + _beaconlocationsSubscription?.cancel(); + _streamLocaitonData?.cancel(); + _mapController?.dispose(); + _hikeMarkers.clear(); + } +} diff --git a/lib/presentation/hike/cubit/location_cubit/location_state.dart b/lib/presentation/hike/cubit/location_cubit/location_state.dart new file mode 100644 index 00000000..cb97a7bc --- /dev/null +++ b/lib/presentation/hike/cubit/location_cubit/location_state.dart @@ -0,0 +1,19 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +part 'location_state.freezed.dart'; + +@freezed +class LocationState with _$LocationState { + factory LocationState.initial() = InitialLocationState; + factory LocationState.loaded({ + @Default(MapType.normal) MapType mapType, + @Default({}) Set geofence, + @Default({}) Set locationMarkers, + @Default({}) Set polyline, + String? address, + String? message, + @Default(0) int version, + }) = LoadedLocationState; + + factory LocationState.error({String? message}) = LocationErrorState; +} diff --git a/lib/presentation/hike/cubit/location_cubit/location_state.freezed.dart b/lib/presentation/hike/cubit/location_cubit/location_state.freezed.dart new file mode 100644 index 00000000..84276374 --- /dev/null +++ b/lib/presentation/hike/cubit/location_cubit/location_state.freezed.dart @@ -0,0 +1,680 @@ +// 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_state.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 _$LocationState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version) + loaded, + required TResult Function(String? message) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version)? + loaded, + TResult? Function(String? message)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version)? + loaded, + TResult Function(String? message)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(InitialLocationState value) initial, + required TResult Function(LoadedLocationState value) loaded, + required TResult Function(LocationErrorState value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialLocationState value)? initial, + TResult? Function(LoadedLocationState value)? loaded, + TResult? Function(LocationErrorState value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialLocationState value)? initial, + TResult Function(LoadedLocationState value)? loaded, + TResult Function(LocationErrorState value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LocationStateCopyWith<$Res> { + factory $LocationStateCopyWith( + LocationState value, $Res Function(LocationState) then) = + _$LocationStateCopyWithImpl<$Res, LocationState>; +} + +/// @nodoc +class _$LocationStateCopyWithImpl<$Res, $Val extends LocationState> + implements $LocationStateCopyWith<$Res> { + _$LocationStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$InitialLocationStateImplCopyWith<$Res> { + factory _$$InitialLocationStateImplCopyWith(_$InitialLocationStateImpl value, + $Res Function(_$InitialLocationStateImpl) then) = + __$$InitialLocationStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$InitialLocationStateImplCopyWithImpl<$Res> + extends _$LocationStateCopyWithImpl<$Res, _$InitialLocationStateImpl> + implements _$$InitialLocationStateImplCopyWith<$Res> { + __$$InitialLocationStateImplCopyWithImpl(_$InitialLocationStateImpl _value, + $Res Function(_$InitialLocationStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$InitialLocationStateImpl implements InitialLocationState { + _$InitialLocationStateImpl(); + + @override + String toString() { + return 'LocationState.initial()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$InitialLocationStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version) + loaded, + required TResult Function(String? message) error, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version)? + loaded, + TResult? Function(String? message)? error, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version)? + loaded, + TResult Function(String? message)? error, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialLocationState value) initial, + required TResult Function(LoadedLocationState value) loaded, + required TResult Function(LocationErrorState value) error, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialLocationState value)? initial, + TResult? Function(LoadedLocationState value)? loaded, + TResult? Function(LocationErrorState value)? error, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialLocationState value)? initial, + TResult Function(LoadedLocationState value)? loaded, + TResult Function(LocationErrorState value)? error, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class InitialLocationState implements LocationState { + factory InitialLocationState() = _$InitialLocationStateImpl; +} + +/// @nodoc +abstract class _$$LoadedLocationStateImplCopyWith<$Res> { + factory _$$LoadedLocationStateImplCopyWith(_$LoadedLocationStateImpl value, + $Res Function(_$LoadedLocationStateImpl) then) = + __$$LoadedLocationStateImplCopyWithImpl<$Res>; + @useResult + $Res call( + {MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version}); +} + +/// @nodoc +class __$$LoadedLocationStateImplCopyWithImpl<$Res> + extends _$LocationStateCopyWithImpl<$Res, _$LoadedLocationStateImpl> + implements _$$LoadedLocationStateImplCopyWith<$Res> { + __$$LoadedLocationStateImplCopyWithImpl(_$LoadedLocationStateImpl _value, + $Res Function(_$LoadedLocationStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? mapType = null, + Object? geofence = null, + Object? locationMarkers = null, + Object? polyline = null, + Object? address = freezed, + Object? message = freezed, + Object? version = null, + }) { + return _then(_$LoadedLocationStateImpl( + mapType: null == mapType + ? _value.mapType + : mapType // ignore: cast_nullable_to_non_nullable + as MapType, + geofence: null == geofence + ? _value._geofence + : geofence // ignore: cast_nullable_to_non_nullable + as Set, + locationMarkers: null == locationMarkers + ? _value._locationMarkers + : locationMarkers // ignore: cast_nullable_to_non_nullable + as Set, + polyline: null == polyline + ? _value._polyline + : polyline // ignore: cast_nullable_to_non_nullable + as Set, + address: freezed == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String?, + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$LoadedLocationStateImpl implements LoadedLocationState { + _$LoadedLocationStateImpl( + {this.mapType = MapType.normal, + final Set geofence = const {}, + final Set locationMarkers = const {}, + final Set polyline = const {}, + this.address, + this.message, + this.version = 0}) + : _geofence = geofence, + _locationMarkers = locationMarkers, + _polyline = polyline; + + @override + @JsonKey() + final MapType mapType; + final Set _geofence; + @override + @JsonKey() + Set get geofence { + if (_geofence is EqualUnmodifiableSetView) return _geofence; + // ignore: implicit_dynamic_type + return EqualUnmodifiableSetView(_geofence); + } + + final Set _locationMarkers; + @override + @JsonKey() + Set get locationMarkers { + if (_locationMarkers is EqualUnmodifiableSetView) return _locationMarkers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableSetView(_locationMarkers); + } + + final Set _polyline; + @override + @JsonKey() + Set get polyline { + if (_polyline is EqualUnmodifiableSetView) return _polyline; + // ignore: implicit_dynamic_type + return EqualUnmodifiableSetView(_polyline); + } + + @override + final String? address; + @override + final String? message; + @override + @JsonKey() + final int version; + + @override + String toString() { + return 'LocationState.loaded(mapType: $mapType, geofence: $geofence, locationMarkers: $locationMarkers, polyline: $polyline, address: $address, message: $message, version: $version)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LoadedLocationStateImpl && + (identical(other.mapType, mapType) || other.mapType == mapType) && + const DeepCollectionEquality().equals(other._geofence, _geofence) && + const DeepCollectionEquality() + .equals(other._locationMarkers, _locationMarkers) && + const DeepCollectionEquality().equals(other._polyline, _polyline) && + (identical(other.address, address) || other.address == address) && + (identical(other.message, message) || other.message == message) && + (identical(other.version, version) || other.version == version)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + mapType, + const DeepCollectionEquality().hash(_geofence), + const DeepCollectionEquality().hash(_locationMarkers), + const DeepCollectionEquality().hash(_polyline), + address, + message, + version); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LoadedLocationStateImplCopyWith<_$LoadedLocationStateImpl> get copyWith => + __$$LoadedLocationStateImplCopyWithImpl<_$LoadedLocationStateImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version) + loaded, + required TResult Function(String? message) error, + }) { + return loaded(mapType, geofence, locationMarkers, polyline, address, + message, version); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version)? + loaded, + TResult? Function(String? message)? error, + }) { + return loaded?.call(mapType, geofence, locationMarkers, polyline, address, + message, version); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version)? + loaded, + TResult Function(String? message)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(mapType, geofence, locationMarkers, polyline, address, + message, version); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialLocationState value) initial, + required TResult Function(LoadedLocationState value) loaded, + required TResult Function(LocationErrorState value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialLocationState value)? initial, + TResult? Function(LoadedLocationState value)? loaded, + TResult? Function(LocationErrorState value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialLocationState value)? initial, + TResult Function(LoadedLocationState value)? loaded, + TResult Function(LocationErrorState value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class LoadedLocationState implements LocationState { + factory LoadedLocationState( + {final MapType mapType, + final Set geofence, + final Set locationMarkers, + final Set polyline, + final String? address, + final String? message, + final int version}) = _$LoadedLocationStateImpl; + + MapType get mapType; + Set get geofence; + Set get locationMarkers; + Set get polyline; + String? get address; + String? get message; + int get version; + @JsonKey(ignore: true) + _$$LoadedLocationStateImplCopyWith<_$LoadedLocationStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$LocationErrorStateImplCopyWith<$Res> { + factory _$$LocationErrorStateImplCopyWith(_$LocationErrorStateImpl value, + $Res Function(_$LocationErrorStateImpl) then) = + __$$LocationErrorStateImplCopyWithImpl<$Res>; + @useResult + $Res call({String? message}); +} + +/// @nodoc +class __$$LocationErrorStateImplCopyWithImpl<$Res> + extends _$LocationStateCopyWithImpl<$Res, _$LocationErrorStateImpl> + implements _$$LocationErrorStateImplCopyWith<$Res> { + __$$LocationErrorStateImplCopyWithImpl(_$LocationErrorStateImpl _value, + $Res Function(_$LocationErrorStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? message = freezed, + }) { + return _then(_$LocationErrorStateImpl( + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$LocationErrorStateImpl implements LocationErrorState { + _$LocationErrorStateImpl({this.message}); + + @override + final String? message; + + @override + String toString() { + return 'LocationState.error(message: $message)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LocationErrorStateImpl && + (identical(other.message, message) || other.message == message)); + } + + @override + int get hashCode => Object.hash(runtimeType, message); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LocationErrorStateImplCopyWith<_$LocationErrorStateImpl> get copyWith => + __$$LocationErrorStateImplCopyWithImpl<_$LocationErrorStateImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version) + loaded, + required TResult Function(String? message) error, + }) { + return error(message); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version)? + loaded, + TResult? Function(String? message)? error, + }) { + return error?.call(message); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function( + MapType mapType, + Set geofence, + Set locationMarkers, + Set polyline, + String? address, + String? message, + int version)? + loaded, + TResult Function(String? message)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(message); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialLocationState value) initial, + required TResult Function(LoadedLocationState value) loaded, + required TResult Function(LocationErrorState value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialLocationState value)? initial, + TResult? Function(LoadedLocationState value)? loaded, + TResult? Function(LocationErrorState value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialLocationState value)? initial, + TResult Function(LoadedLocationState value)? loaded, + TResult Function(LocationErrorState value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class LocationErrorState implements LocationState { + factory LocationErrorState({final String? message}) = + _$LocationErrorStateImpl; + + String? get message; + @JsonKey(ignore: true) + _$$LocationErrorStateImplCopyWith<_$LocationErrorStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/presentation/hike/cubit/panel_cubit/panel_cubit.dart b/lib/presentation/hike/cubit/panel_cubit/panel_cubit.dart new file mode 100644 index 00000000..e05ba0a2 --- /dev/null +++ b/lib/presentation/hike/cubit/panel_cubit/panel_cubit.dart @@ -0,0 +1,86 @@ +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/join_leave_beacon_entity/join_leave_beacon_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/domain/usecase/hike_usecase.dart'; +import 'package:beacon/presentation/hike/cubit/panel_cubit/panel_state.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:intl/intl.dart'; + +class PanelCubit extends Cubit { + final HikeUseCase _hikeUseCase; + static PanelCubit? _instance; + + PanelCubit._internal(this._hikeUseCase) : super(SlidingPanelState.initial()); + + factory PanelCubit(HikeUseCase hikeUseCase) { + return _instance ??= PanelCubit._internal(hikeUseCase); + } + + BeaconEntity? _beacon; + String? _beaconId; + List _followers = []; + UserEntity? _leader; + + loadCollapsedPanel() { + _beacon!.startsAt; + } + + void loadBeaconData(BeaconEntity beacon) async { + _beacon = beacon; + _beaconId = beacon.id!; + + _followers = beacon.followers ?? []; + _leader = beacon.leader; + + beaconJoinLeaveSubscription(); + + var expiresAT = DateTime.fromMillisecondsSinceEpoch(_beacon!.expiresAt!); + var isBeaconActive = expiresAT.isAfter(DateTime.now()); + + String? expiringTime; + if (isBeaconActive) { + var expireTime = DateFormat('hh:mm a').format(expiresAT); // 02:37 PM + var expireDate = DateFormat('dd/MM/yyyy').format(expiresAT); // 24/03/2023 + expiringTime = '$expireTime, $expireDate'; + } + + emit(SlidingPanelState.loaded( + expiringTime: expiringTime, + isActive: isBeaconActive, + followers: _followers, + leader: _leader, + )); + } + + Future beaconJoinLeaveSubscription() async { + await _hikeUseCase + .joinleavebeaconSubscription(_beaconId!) + .listen((dataState) { + if (dataState is DataSuccess) { + JoinLeaveBeaconEntity joinLeaveBeacon = dataState.data!; + if (joinLeaveBeacon.newfollower != null) { + var newFollower = joinLeaveBeacon.newfollower!; + addUser(newFollower); + emit(SlidingPanelState.loaded( + followers: _followers, + leader: _leader, + message: '${newFollower.name} is now following the beacon!')); + } else if (joinLeaveBeacon.inactiveuser != null) {} + } + }); + } + + void addUser(UserEntity user) { + if (user.id == _beacon!.leader!.id) { + _leader = user; + } else { + _followers.removeWhere((element) => element!.id == user.id); + _followers.add(user); + } + } + + // void removeUser(UserEntity user){ + // if(user.id==_beacon) + // } +} diff --git a/lib/presentation/hike/cubit/panel_cubit/panel_state.dart b/lib/presentation/hike/cubit/panel_cubit/panel_state.dart new file mode 100644 index 00000000..482e3570 --- /dev/null +++ b/lib/presentation/hike/cubit/panel_cubit/panel_state.dart @@ -0,0 +1,19 @@ +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'panel_state.freezed.dart'; + +@freezed +class SlidingPanelState with _$SlidingPanelState { + factory SlidingPanelState.initial() = InitialPanelState; + factory SlidingPanelState.loaded({ + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message, + }) = LoadedPanelState; + + factory SlidingPanelState.error({String? message}) = ErrorPanelState; +} diff --git a/lib/presentation/hike/cubit/panel_cubit/panel_state.freezed.dart b/lib/presentation/hike/cubit/panel_cubit/panel_state.freezed.dart new file mode 100644 index 00000000..ff5fb374 --- /dev/null +++ b/lib/presentation/hike/cubit/panel_cubit/panel_state.freezed.dart @@ -0,0 +1,653 @@ +// 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 'panel_state.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 _$SlidingPanelState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message) + loaded, + required TResult Function(String? message) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message)? + loaded, + TResult? Function(String? message)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message)? + loaded, + TResult Function(String? message)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(InitialPanelState value) initial, + required TResult Function(LoadedPanelState value) loaded, + required TResult Function(ErrorPanelState value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialPanelState value)? initial, + TResult? Function(LoadedPanelState value)? loaded, + TResult? Function(ErrorPanelState value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialPanelState value)? initial, + TResult Function(LoadedPanelState value)? loaded, + TResult Function(ErrorPanelState value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SlidingPanelStateCopyWith<$Res> { + factory $SlidingPanelStateCopyWith( + SlidingPanelState value, $Res Function(SlidingPanelState) then) = + _$SlidingPanelStateCopyWithImpl<$Res, SlidingPanelState>; +} + +/// @nodoc +class _$SlidingPanelStateCopyWithImpl<$Res, $Val extends SlidingPanelState> + implements $SlidingPanelStateCopyWith<$Res> { + _$SlidingPanelStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$InitialPanelStateImplCopyWith<$Res> { + factory _$$InitialPanelStateImplCopyWith(_$InitialPanelStateImpl value, + $Res Function(_$InitialPanelStateImpl) then) = + __$$InitialPanelStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$InitialPanelStateImplCopyWithImpl<$Res> + extends _$SlidingPanelStateCopyWithImpl<$Res, _$InitialPanelStateImpl> + implements _$$InitialPanelStateImplCopyWith<$Res> { + __$$InitialPanelStateImplCopyWithImpl(_$InitialPanelStateImpl _value, + $Res Function(_$InitialPanelStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$InitialPanelStateImpl implements InitialPanelState { + _$InitialPanelStateImpl(); + + @override + String toString() { + return 'SlidingPanelState.initial()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$InitialPanelStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message) + loaded, + required TResult Function(String? message) error, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message)? + loaded, + TResult? Function(String? message)? error, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message)? + loaded, + TResult Function(String? message)? error, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialPanelState value) initial, + required TResult Function(LoadedPanelState value) loaded, + required TResult Function(ErrorPanelState value) error, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialPanelState value)? initial, + TResult? Function(LoadedPanelState value)? loaded, + TResult? Function(ErrorPanelState value)? error, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialPanelState value)? initial, + TResult Function(LoadedPanelState value)? loaded, + TResult Function(ErrorPanelState value)? error, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class InitialPanelState implements SlidingPanelState { + factory InitialPanelState() = _$InitialPanelStateImpl; +} + +/// @nodoc +abstract class _$$LoadedPanelStateImplCopyWith<$Res> { + factory _$$LoadedPanelStateImplCopyWith(_$LoadedPanelStateImpl value, + $Res Function(_$LoadedPanelStateImpl) then) = + __$$LoadedPanelStateImplCopyWithImpl<$Res>; + @useResult + $Res call( + {bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message}); + + $UserEntityCopyWith<$Res>? get leader; +} + +/// @nodoc +class __$$LoadedPanelStateImplCopyWithImpl<$Res> + extends _$SlidingPanelStateCopyWithImpl<$Res, _$LoadedPanelStateImpl> + implements _$$LoadedPanelStateImplCopyWith<$Res> { + __$$LoadedPanelStateImplCopyWithImpl(_$LoadedPanelStateImpl _value, + $Res Function(_$LoadedPanelStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? isActive = freezed, + Object? expiringTime = freezed, + Object? leaderAddress = freezed, + Object? leader = freezed, + Object? followers = freezed, + Object? message = freezed, + }) { + return _then(_$LoadedPanelStateImpl( + isActive: freezed == isActive + ? _value.isActive + : isActive // ignore: cast_nullable_to_non_nullable + as bool?, + expiringTime: freezed == expiringTime + ? _value.expiringTime + : expiringTime // ignore: cast_nullable_to_non_nullable + as String?, + leaderAddress: freezed == leaderAddress + ? _value.leaderAddress + : leaderAddress // 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?, + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, + )); + } + + @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)); + }); + } +} + +/// @nodoc + +class _$LoadedPanelStateImpl implements LoadedPanelState { + _$LoadedPanelStateImpl( + {this.isActive, + this.expiringTime, + this.leaderAddress, + this.leader, + final List? followers, + this.message}) + : _followers = followers; + + @override + final bool? isActive; + @override + final String? expiringTime; + @override + final String? leaderAddress; + @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); + } + + @override + final String? message; + + @override + String toString() { + return 'SlidingPanelState.loaded(isActive: $isActive, expiringTime: $expiringTime, leaderAddress: $leaderAddress, leader: $leader, followers: $followers, message: $message)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LoadedPanelStateImpl && + (identical(other.isActive, isActive) || + other.isActive == isActive) && + (identical(other.expiringTime, expiringTime) || + other.expiringTime == expiringTime) && + (identical(other.leaderAddress, leaderAddress) || + other.leaderAddress == leaderAddress) && + (identical(other.leader, leader) || other.leader == leader) && + const DeepCollectionEquality() + .equals(other._followers, _followers) && + (identical(other.message, message) || other.message == message)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + isActive, + expiringTime, + leaderAddress, + leader, + const DeepCollectionEquality().hash(_followers), + message); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LoadedPanelStateImplCopyWith<_$LoadedPanelStateImpl> get copyWith => + __$$LoadedPanelStateImplCopyWithImpl<_$LoadedPanelStateImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message) + loaded, + required TResult Function(String? message) error, + }) { + return loaded( + isActive, expiringTime, leaderAddress, leader, followers, message); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message)? + loaded, + TResult? Function(String? message)? error, + }) { + return loaded?.call( + isActive, expiringTime, leaderAddress, leader, followers, message); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message)? + loaded, + TResult Function(String? message)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded( + isActive, expiringTime, leaderAddress, leader, followers, message); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialPanelState value) initial, + required TResult Function(LoadedPanelState value) loaded, + required TResult Function(ErrorPanelState value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialPanelState value)? initial, + TResult? Function(LoadedPanelState value)? loaded, + TResult? Function(ErrorPanelState value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialPanelState value)? initial, + TResult Function(LoadedPanelState value)? loaded, + TResult Function(ErrorPanelState value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class LoadedPanelState implements SlidingPanelState { + factory LoadedPanelState( + {final bool? isActive, + final String? expiringTime, + final String? leaderAddress, + final UserEntity? leader, + final List? followers, + final String? message}) = _$LoadedPanelStateImpl; + + bool? get isActive; + String? get expiringTime; + String? get leaderAddress; + UserEntity? get leader; + List? get followers; + String? get message; + @JsonKey(ignore: true) + _$$LoadedPanelStateImplCopyWith<_$LoadedPanelStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$ErrorPanelStateImplCopyWith<$Res> { + factory _$$ErrorPanelStateImplCopyWith(_$ErrorPanelStateImpl value, + $Res Function(_$ErrorPanelStateImpl) then) = + __$$ErrorPanelStateImplCopyWithImpl<$Res>; + @useResult + $Res call({String? message}); +} + +/// @nodoc +class __$$ErrorPanelStateImplCopyWithImpl<$Res> + extends _$SlidingPanelStateCopyWithImpl<$Res, _$ErrorPanelStateImpl> + implements _$$ErrorPanelStateImplCopyWith<$Res> { + __$$ErrorPanelStateImplCopyWithImpl( + _$ErrorPanelStateImpl _value, $Res Function(_$ErrorPanelStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? message = freezed, + }) { + return _then(_$ErrorPanelStateImpl( + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$ErrorPanelStateImpl implements ErrorPanelState { + _$ErrorPanelStateImpl({this.message}); + + @override + final String? message; + + @override + String toString() { + return 'SlidingPanelState.error(message: $message)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ErrorPanelStateImpl && + (identical(other.message, message) || other.message == message)); + } + + @override + int get hashCode => Object.hash(runtimeType, message); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ErrorPanelStateImplCopyWith<_$ErrorPanelStateImpl> get copyWith => + __$$ErrorPanelStateImplCopyWithImpl<_$ErrorPanelStateImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message) + loaded, + required TResult Function(String? message) error, + }) { + return error(message); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message)? + loaded, + TResult? Function(String? message)? error, + }) { + return error?.call(message); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function( + bool? isActive, + String? expiringTime, + String? leaderAddress, + UserEntity? leader, + List? followers, + String? message)? + loaded, + TResult Function(String? message)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(message); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialPanelState value) initial, + required TResult Function(LoadedPanelState value) loaded, + required TResult Function(ErrorPanelState value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialPanelState value)? initial, + TResult? Function(LoadedPanelState value)? loaded, + TResult? Function(ErrorPanelState value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialPanelState value)? initial, + TResult Function(LoadedPanelState value)? loaded, + TResult Function(ErrorPanelState value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class ErrorPanelState implements SlidingPanelState { + factory ErrorPanelState({final String? message}) = _$ErrorPanelStateImpl; + + String? get message; + @JsonKey(ignore: true) + _$$ErrorPanelStateImplCopyWith<_$ErrorPanelStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/presentation/hike/hike_screen.dart b/lib/presentation/hike/hike_screen.dart new file mode 100644 index 00000000..cc9c4e1f --- /dev/null +++ b/lib/presentation/hike/hike_screen.dart @@ -0,0 +1,315 @@ +import 'dart:developer'; + +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/config/pip_manager.dart'; +import 'package:beacon/core/utils/constants.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/presentation/hike/cubit/hike_cubit/hike_cubit.dart'; +import 'package:beacon/presentation/hike/cubit/hike_cubit/hike_state.dart'; +import 'package:beacon/presentation/hike/cubit/location_cubit/location_cubit.dart'; +import 'package:beacon/presentation/hike/cubit/location_cubit/location_state.dart'; +import 'package:beacon/presentation/hike/cubit/panel_cubit/panel_cubit.dart'; +import 'package:beacon/presentation/hike/cubit/panel_cubit/panel_state.dart'; +import 'package:beacon/presentation/hike/widgets/hike_screen_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:gap/gap.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; +import 'package:sliding_up_panel/sliding_up_panel.dart'; + +@RoutePage() +class HikeScreen extends StatefulWidget { + final BeaconEntity beacon; + final bool? isLeader; + const HikeScreen({super.key, required this.beacon, required this.isLeader}); + + @override + State createState() => _HikeScreenState(); +} + +class _HikeScreenState extends State with WidgetsBindingObserver { + HikeCubit _hikeCubit = locator(); + LocationCubit _locationCubit = locator(); + @override + void initState() { + WidgetsBinding.instance.addObserver(this); + PIPMode.switchPIPMode(); + _hikeCubit.startHike(widget.beacon.id!); + super.initState(); + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + PIPMode.disablePIPMode(); + _hikeCubit.clear(); + _locationCubit.clear(); + super.dispose(); + } + + bool isSmallsized = 100.h < 800; + PanelController _panelController = PanelController(); + + bool _isPipMode = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: _isPipMode + ? Container() + : BlocBuilder( + builder: (context, state) { + if (state is InitialHikeState) { + return Center( + child: SpinKitWave( + color: kYellow, + )); + } else if (state is ErrorHikeState) { + return Container( + child: Center(child: Text('Restart beacon')), + ); + } else { + return Scaffold( + body: Stack( + children: [ + SlidingUpPanel( + controller: _panelController, + maxHeight: 60.h, + minHeight: isSmallsized ? 22.h : 18.h, + panel: _SlidingPanelWidget(), + collapsed: _collapsedWidget(), + body: BlocConsumer( + listener: (context, state) { + if (state is LoadedLocationState) { + state.message != null + ? utils.showSnackBar( + state.message!, context) + : null; + } + }, + builder: (context, state) { + if (state is InitialLocationState) { + return SpinKitPianoWave(); + } else if (state is LoadedLocationState) { + return GoogleMap( + polylines: state.polyline, + mapType: state.mapType, + compassEnabled: true, + onTap: (latlng) { + HikeScreenWidget.selectionButton( + context, widget.beacon.id!, latlng); + }, + zoomControlsEnabled: true, + onMapCreated: _locationCubit.onMapCreated, + markers: state.locationMarkers, + initialCameraPosition: CameraPosition( + zoom: 15, + target: state + .locationMarkers.first.position)); + } + return Container(); + }, + )), + Align( + alignment: Alignment(-0.9, -0.9), + child: FloatingActionButton( + heroTag: 'BackButton', + backgroundColor: kYellow, + onPressed: () { + PIPMode.enterPIPMode(); + }, + child: Icon( + CupertinoIcons.back, + color: kBlue, + ), + ), + ), + Align( + alignment: Alignment(0.85, -0.9), + child: HikeScreenWidget.shareButton( + context, widget.beacon.shortcode)), + Align( + alignment: Alignment(1, -0.7), + child: HikeScreenWidget.showMapViewSelector(context)), + Align( + alignment: Alignment(0.85, -0.5), + child: HikeScreenWidget.sosButton( + widget.beacon.id!, context)), + ], + )); + } + }, + ), + ); + } + + Widget _collapsedWidget() { + var beacon = widget.beacon; + return Container( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(15), topRight: Radius.circular(15)), + color: kBlue, + ), + child: BlocBuilder( + builder: (context, state) { + return state.when( + initial: () { + return CircularProgressIndicator(); + }, + loaded: ( + isActive, + expiringTime, + leaderAddress, + leader, + followers, + message, + ) { + followers = followers ?? []; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + alignment: Alignment.center, + child: Container( + alignment: Alignment.center, + height: 0.5.h, + width: 18.w, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: + BorderRadius.all(Radius.circular(10))), + ), + ), + Gap(10), + Text( + isActive == true + ? 'Beacon expiring at ${expiringTime ?? '<>'}' + : 'Beacon is expired', + style: TextStyle( + fontSize: 18, + color: Colors.white, + fontFamily: '', + fontWeight: FontWeight.w700)), + Text('Beacon leader at: <>', + maxLines: 2, + style: TextStyle( + fontSize: 18, + color: Colors.white, + fontFamily: '', + fontWeight: FontWeight.w600)), + Text('Total followers: ${followers.length} ', + style: TextStyle( + fontSize: 17, + color: Colors.white, + fontFamily: '', + fontWeight: FontWeight.w500)), + Text('Share the pass key to join user: ${beacon.shortcode}', + style: TextStyle( + fontSize: 16, + color: Colors.white, + fontFamily: '', + fontWeight: FontWeight.w500)) + ], + ); + }, + error: (message) { + return Text(message.toString()); + }, + ); + }, + )); + } + + Widget _SlidingPanelWidget() { + // return Container(); + return BlocBuilder( + builder: (context, state) { + return state.when( + initial: () { + return CircularProgressIndicator(); + }, + loaded: ( + isActive, + expiringTime, + leaderAddress, + leader, + followers, + message, + ) { + List members = []; + members.add(leader!); + if (followers != null) { + followers.forEach((element) { + members.add(element!); + }); + } + return Column( + children: [ + Gap(10), + Container( + height: 1.h, + width: 20.w, + decoration: BoxDecoration( + color: Colors.blueGrey, + borderRadius: BorderRadius.all(Radius.circular(10))), + ), + Gap(10), + Expanded( + child: ListView.builder( + itemCount: members.length, + itemBuilder: (context, index) { + var member = members[index]; + return Container( + padding: EdgeInsets.symmetric(vertical: 5), + child: Row( + children: [ + Gap(10), + CircleAvatar( + radius: 25, + backgroundColor: kYellow, + child: Icon( + Icons.person_2_rounded, + color: Colors.white, + size: 40, + ), + ), + Gap(10), + Text( + member.name ?? 'Anonymous', + style: TextStyle(fontSize: 19), + ), + Spacer(), + Container( + height: 40, + width: 40, + child: FloatingActionButton( + backgroundColor: kYellow, + onPressed: () async {}, + child: Icon(Icons.location_city), + ), + ), + Gap(10), + ], + ), + ); + }, + ), + ), + ], + ); + }, + error: (message) { + return Text(message.toString()); + }, + ); + }, + ); + } +} diff --git a/lib/old/components/active_beacon.dart b/lib/presentation/hike/widgets/active_beacon.dart similarity index 100% rename from lib/old/components/active_beacon.dart rename to lib/presentation/hike/widgets/active_beacon.dart diff --git a/lib/presentation/hike/widgets/hike_screen_widget.dart b/lib/presentation/hike/widgets/hike_screen_widget.dart new file mode 100644 index 00000000..25d603bc --- /dev/null +++ b/lib/presentation/hike/widgets/hike_screen_widget.dart @@ -0,0 +1,391 @@ +import 'dart:developer'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/presentation/hike/cubit/location_cubit/location_cubit.dart'; +import 'package:beacon/presentation/widgets/hike_button.dart'; +import 'package:beacon/core/utils/constants.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_geocoder_alternative/flutter_geocoder_alternative.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:gap/gap.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; +import 'package:share_plus/share_plus.dart'; + +class HikeScreenWidget { + static copyPasskey(String? passkey) { + Clipboard.setData(ClipboardData(text: passkey!)); + Fluttertoast.showToast(msg: 'PASSKEY: $passkey COPIED'); + } + + static Geocoder geocoder = Geocoder(); + + static generateUrl(String? shortcode) async { + Uri url = Uri.parse('https://beacon.aadibajpai.com/?shortcode=$shortcode'); + Share.share('To join beacon follow this link: $url'); + } + + static Widget sosButton(String id, BuildContext context) { + return FloatingActionButton( + heroTag: 'sos', + backgroundColor: kYellow, + onPressed: () { + locator().sendSOS(id, context); + }, + child: Icon(Icons.sos), + ); + } + + static Widget shareButton(BuildContext context, String? passkey) { + return FloatingActionButton( + heroTag: + 'shareRouteTag', //had to pass this tag else we would get error since there will be two FAB in the same subtree with the same tag. + onPressed: () { + showDialog( + context: context, + builder: (context) => Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + child: Container( + height: 100.h < 800 ? 40.h : 35.h, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 32, vertical: 16), + child: Column( + children: [ + Container( + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Text( + 'Invite Friends', + style: TextStyle(fontSize: 24), + ), + ), + ), + SizedBox( + height: 3.5.h, + ), + Flexible( + child: HikeButton( + buttonHeight: optbheight - 4, + textSize: 16, + text: 'Generate URL', + textColor: Colors.white, + buttonColor: kYellow, + onTap: () async { + generateUrl(passkey); + }), + ), + SizedBox( + height: 2.h, + ), + Flexible( + child: HikeButton( + buttonHeight: optbheight - 4, + textSize: 16, + text: 'Copy Passkey', + textColor: Colors.white, + buttonColor: kYellow, + onTap: () { + copyPasskey(passkey); + }, + ), + ), + Gap(2.h), + Flexible( + child: HikeButton( + buttonHeight: optbheight - 4, + textSize: 16, + text: 'Share Image', + textColor: Colors.white, + buttonColor: kYellow, + onTap: () { + appRouter.maybePop(); + }, + ), + ) + ], + ), + ), + ), + ), + ); + }, + backgroundColor: kYellow, + child: Icon(Icons.share), + ); + } + + static Widget shareRouteButton( + BuildContext context, + BeaconEntity? beacon, + GoogleMapController mapController, + List beaconRoute, + ) { + return FloatingActionButton( + heroTag: 'shareRouteTag1', + onPressed: () async {}, + backgroundColor: kYellow, + child: Icon( + Icons.share, + ), + ); + } + + static final Map mapTypeNames = { + MapType.hybrid: 'Hybrid', + MapType.normal: 'Normal', + MapType.satellite: 'Satellite', + MapType.terrain: 'Terrain', + }; + + static MapType _selectedMapType = MapType.normal; + + static Widget showMapViewSelector(BuildContext context) { + return DropdownButton( + icon: Icon(CupertinoIcons.map), + value: _selectedMapType, + items: mapTypeNames.entries.map((entry) { + return DropdownMenuItem( + onTap: () { + locator().changeMap(entry.key); + }, + value: entry.key, + child: Text(entry.value), + ); + }).toList(), + onChanged: (newValue) {}, + selectedItemBuilder: (BuildContext context) { + return mapTypeNames.entries.map((entry) { + return FloatingActionButton( + backgroundColor: kYellow, + onPressed: null, + child: Icon(CupertinoIcons.map), + ); + }).toList(); + }, + ); + } + + static TextEditingController _landMarkeController = TextEditingController(); + static GlobalKey _landmarkFormKey = GlobalKey(); + + static void selectionButton( + BuildContext context, String beaconId, LatLng loc) { + showDialog( + context: context, + builder: (context) => Dialog( + child: Container( + height: 100.h < 800 ? 33.h : 22.h, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), + child: Column( + children: [ + HikeButton( + text: 'Create Landmark', + onTap: () { + Navigator.pop(context); + showCreateLandMarkDialogueDialog(context, beaconId, loc); + }, + ), + Gap(10), + HikeButton( + text: 'Create Geofence', + onTap: () { + Navigator.pop(context); + locator() + .changeGeofenceRadius(_value * 1000, loc); + showCreateGeofenceDialogueDialog(context, beaconId, loc); + }, + ) + ], + ), + ), + ), + ), + ); + } + + static GlobalKey _geofenceKey = GlobalKey(); + static double _value = 0.1; + + static void showCreateGeofenceDialogueDialog( + BuildContext context, + String beaconId, + LatLng loc, + ) { + bool isSmallSized = 100.h < 800; + bool isGeofenceCreated = false; + + showModalBottomSheet( + context: context, + isDismissible: false, + builder: (context) { + return Stack( + children: [ + Container( + height: isSmallSized ? 30.h : 25.h, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + ), + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 32, vertical: 16), + child: Form( + key: _geofenceKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + alignment: Alignment.topRight, + child: IconButton( + onPressed: () { + appRouter.maybePop().then((value) { + locator() + .removeUncreatedGeofence(); + }); + }, + icon: Icon( + Icons.cancel, + color: kBlue, + )), + ), + StatefulBuilder( + builder: (context, setState) { + return Stack( + children: [ + Slider( + activeColor: kBlue, + inactiveColor: kYellow, + value: _value, + onChanged: (value) { + setState(() { + _value = value; + }); + locator() + .changeGeofenceRadius(_value * 1000, loc); + }, + ), + Align( + alignment: Alignment(1, -1), + child: Text( + '${(_value * 1000).toStringAsFixed(0)} meters', + ), + ), + ], + ); + }, + ), + Gap(10), + Flexible( + child: HikeButton( + buttonHeight: 15, + onTap: () async { + if (!_geofenceKey.currentState!.validate()) return; + locator() + .createGeofence(beaconId, loc, _value) + .then((onvalue) { + isGeofenceCreated = true; + }); + appRouter.maybePop().then((onValue) { + if (isGeofenceCreated) { + locator() + .removeUncreatedGeofence(); + } + }); + }, + text: 'Create Geofence', + ), + ), + ], + ), + ), + ), + ), + ], + ); + }, + ); + } + + static void showCreateLandMarkDialogueDialog( + BuildContext context, + String beaconId, + LatLng loc, + ) { + showDialog( + context: context, + builder: (context) => Dialog( + child: Container( + height: MediaQuery.of(context).size.height < 800 ? 33.h : 25.h, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), + child: Form( + key: _landmarkFormKey, + child: Column( + children: [ + Container( + height: + MediaQuery.of(context).size.height < 800 ? 14.h : 12.h, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: TextFormField( + controller: _landMarkeController, + style: TextStyle(fontSize: 20.0), + onChanged: (key) {}, + validator: (value) { + if (value == null || value.isEmpty) { + return "Please enter title for landmark"; + } else { + return null; + } + }, + decoration: InputDecoration( + border: InputBorder.none, + alignLabelWithHint: true, + floatingLabelBehavior: FloatingLabelBehavior.always, + hintText: 'Add title for the landmark', + hintStyle: + TextStyle(fontSize: hintsize, color: hintColor), + labelText: 'Title', + labelStyle: + TextStyle(fontSize: labelsize, color: kYellow), + ), + ), + ), + color: kLightBlue, + ), + SizedBox( + height: 2.h, + ), + Flexible( + child: HikeButton( + text: 'Create Landmark', + textSize: 14.0, + textColor: Colors.white, + buttonColor: kYellow, + onTap: () { + if (!_landmarkFormKey.currentState!.validate()) return; + appRouter.maybePop(); + locator().createLandmark( + beaconId, _landMarkeController.text, loc); + _landMarkeController.clear(); + }, + ), + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/presentation/home/home_cubit/home_cubit.dart b/lib/presentation/home/home_cubit/home_cubit.dart new file mode 100644 index 00000000..512b5995 --- /dev/null +++ b/lib/presentation/home/home_cubit/home_cubit.dart @@ -0,0 +1,387 @@ +import 'dart:async'; +import 'dart:developer'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/beacon/beacon_entity.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/domain/entities/subscriptions/updated_group_entity/updated_group_entity.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/domain/usecase/home_usecase.dart'; +import 'package:beacon/presentation/group/cubit/group_cubit/group_cubit.dart'; +import 'package:beacon/presentation/home/home_cubit/home_state.dart'; +import 'package:beacon/presentation/group/cubit/members_cubit/members_cubit.dart'; +import 'package:beacon/locator.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class HomeCubit extends Cubit { + final HomeUseCase homeUseCase; + static HomeCubit? _instance; + + HomeCubit._internal({required this.homeUseCase}) : super(InitialHomeState()) { + _loadedhomeState = const LoadedHomeState(groups: [], message: null); + _shimmerhomeState = const ShimmerHomeState(); + _loadinghomeState = const LoadingHomeState(); + } + + factory HomeCubit(HomeUseCase homeUseCase) { + if (_instance != null) { + return _instance!; + } else { + _instance = HomeCubit._internal(homeUseCase: homeUseCase); + return _instance!; + } + } + + int _page = 1; + int _pageSize = 4; + bool _hasReachedEnd = false; + List _totalGroups = []; + late List _groupIds; + StreamSubscription>? _groupUpdateSubscription; + bool _isLoadingMore = false; + // this will store the group that user is currently present + String? _currentGroupId; + + late LoadedHomeState _loadedhomeState; + late ShimmerHomeState _shimmerhomeState; + late LoadingHomeState _loadinghomeState; + + Future createGroup(String title) async { + emit(_loadinghomeState); + final dataState = await homeUseCase.createGroup(title); + + if (dataState is DataSuccess && dataState.data != null) { + GroupEntity group = dataState.data!; + List updatedGroups = List.from(_totalGroups) + ..removeWhere((element) => element.id == group.id) + ..insert(0, group); + + _totalGroups = updatedGroups; + + emit(_loadedhomeState.copyWith( + groups: updatedGroups, message: 'New group created!')); + + // adding new id for setting subscription + _groupIds.add(group.id!); + + _groupUpdateSubscription?.cancel(); + _groupSubscription(); + } else { + emit(_loadedhomeState.copyWith( + groups: _totalGroups, message: dataState.error)); + } + } + + Future joinGroup(String shortCode) async { + emit(_loadinghomeState); + DataState dataState = await homeUseCase.joinGroup(shortCode); + + if (dataState is DataSuccess && dataState.data != null) { + GroupEntity? newGroup = dataState.data; + + if (newGroup != null) { + _totalGroups.removeWhere((group) => group.id == newGroup.id); + _totalGroups.insert(0, newGroup); + _groupIds.add(newGroup.id!); + + emit(_loadedhomeState.copyWith( + groups: _totalGroups, + message: 'You are member of ${newGroup.title ?? 'group'}')); + + _groupUpdateSubscription?.cancel(); + _groupSubscription(); + } + } else { + emit(_loadedhomeState.copyWith( + groups: _totalGroups, message: dataState.error)); + } + } + + Future changeShortCode(GroupEntity group) async { + if (group.leader!.id! != localApi.userModel.id) { + emit(_loadinghomeState); + Future.delayed(Duration(milliseconds: 200), () { + emit(_loadedhomeState.copyWith( + groups: _totalGroups, message: 'You are not the leader of group')); + }); + return; + } + emit(_loadinghomeState); + + final dataState = await homeUseCase.changeShortcode(group.id!); + + if (dataState is DataSuccess && dataState.data != null) { + var updatedGroup = dataState.data!; + int index = + _totalGroups.indexWhere((group) => group.id == updatedGroup.id); + + if (index != -1) { + _totalGroups[index] = updatedGroup; + } + emit(_loadedhomeState.copyWith( + groups: _totalGroups, message: 'Short code changed!')); + } else { + emit(_loadedhomeState.copyWith( + groups: _totalGroups, message: dataState.error)); + } + } + + Future fetchUserGroups() async { + if (_hasReachedEnd || _isLoadingMore) return; + + if (_page == 1) { + emit(_shimmerhomeState); + } else { + _isLoadingMore = true; + emit(_loadedhomeState.copyWith( + groups: _totalGroups, isLoadingmore: _isLoadingMore)); + } + + DataState> state = + await homeUseCase.groups(_page, _pageSize); + + if (state is DataFailed) { + emit(_loadedhomeState.copyWith( + groups: _totalGroups, message: state.error!)); + } else if (state is DataSuccess && state.data != null) { + List newGroups = state.data!; + + Map groupMap = { + for (var group in _totalGroups) group.id!: group + }; + + for (var newGroup in newGroups) { + groupMap[newGroup.id!] = newGroup; + } + _totalGroups = groupMap.values.toList(); + _page++; + _isLoadingMore = false; + if (newGroups.length < _pageSize) { + _hasReachedEnd = true; + } + emit(_loadedhomeState.copyWith( + groups: _totalGroups, + hasReachedEnd: _hasReachedEnd, + isLoadingmore: _isLoadingMore)); + } + } + + Future _groupSubscription() async { + // getting all group ids for subscription + if (_groupIds.isEmpty) return; + + var membersCubit = locator(); + var groupCubit = locator(); + + // creating subscription + _groupUpdateSubscription = await homeUseCase + .groupUpdateSubscription(_groupIds) + .listen((dataState) async { + if (dataState is DataSuccess) { + UpdatedGroupEntity updatedGroup = dataState.data!; + String groupId = updatedGroup.id!; + + // first taking the group from list of total groups + var group = await _getGroup(groupId); + + // something went wrong or maybe group don't exist now // + + if (group == null) { + return; + } + + if (updatedGroup.newUser != null) { + UserEntity newUser = updatedGroup.newUser!; + + // _currentGroupId is the id of the Group that the user has opened + // if it is null then it is in homeScreen + // groupId is the group for which Group update has come + + var groups = addNewMember(groupId, updatedGroup.newUser!); + if (_currentGroupId != groupId) { + String message = + '${newUser.name ?? 'Anonymous'} has joined the ${group!.title ?? 'title'}'; + emit(LoadedHomeState(groups: groups, message: message)); + showNotification(message, ''); + } else { + membersCubit.addMember(updatedGroup.newUser!); + } + } else if (updatedGroup.newBeacon != null) { + var newBeacon = updatedGroup.newBeacon!; + + String message = + 'A new beacon is created in ${updatedGroup.newBeacon!.group!.title ?? 'group'}'; + var updatedgroups = await addBeaconInGroup(newBeacon, groupId); + if (_currentGroupId != groupId) { + emit(_loadedhomeState.copyWith( + groups: updatedgroups, message: message)); + showNotification(message, ''); + } else { + groupCubit.addBeacon(newBeacon, message); + } + } else if (updatedGroup.updatedBeacon != null) { + BeaconEntity updatedBeacon = updatedGroup.updatedBeacon!; + + String message = + '${updatedBeacon.title ?? 'Beacon'} is rescheduled by ${updatedBeacon.leader!.name ?? 'Anonymous'}'; + var updatedGroups = addBeaconInGroup(updatedBeacon, groupId); + + if (_currentGroupId != groupId) { + emit(_loadedhomeState.copyWith( + groups: updatedGroups, message: message)); + showNotification(message, ''); + } else { + groupCubit.addBeacon(updatedBeacon, message); + } + + // a new beacon is rescheduled .... + } else if (updatedGroup.deletedBeacon != null) { + BeaconEntity deletedBeacon = updatedGroup.deletedBeacon!; + + String message = + '${deletedBeacon.title ?? 'Beacon'} is deleted by ${deletedBeacon.leader!.name ?? 'Anonymous'}'; + var updatedGroups = + deleteBeaconFromGroup(updatedGroup.deletedBeacon!, groupId); + if (_currentGroupId != groupId) { + emit(_loadedhomeState.copyWith( + groups: updatedGroups, message: message)); + showNotification(message, ''); + } else { + groupCubit.removeBeacon(deletedBeacon, message); + } + } + } + }); + } + + Future _getGroup(String groupId) async { + var index = _totalGroups.indexWhere((group) => group.id == groupId); + if (index == -1) { + var dataState = await homeUseCase.group(groupId); + if (dataState is DataSuccess) { + _totalGroups.insert(0, dataState.data!); + return dataState.data!; + } + return null; + } + return _totalGroups[index]; + } + + // this function is used for emitting state or reload the sate + void resetGroupActivity({String? groupId}) { + + if (groupId != null) { + for (int i = 0; i < _totalGroups.length; i++) { + if (_totalGroups[i].id == groupId) { + var group = _totalGroups[i]; + _totalGroups.removeAt(i); + group = + group.copywith(hasBeaconActiby: false, hasMemberActivity: false); + _totalGroups.insert(i, group); + } + } + } + emit(_loadedhomeState.copyWith(groups: List.from(_totalGroups))); + } + + void showNotification(String title, String body) { + localNotif!.showInstantNotification(title, body); + } + + List addBeaconInGroup(BeaconEntity newBeacon, String groupId) { + var groups = _totalGroups.where((group) => group.id! == groupId).toList(); + + if (groups.isEmpty) return List.from(_totalGroups); + + var group = groups.first; + + // while adding we'll be already checking for duplicate groups + var beacons = List.from(group.beacons ?? []); + beacons.removeWhere((beacon) => beacon.id! == newBeacon.id!); + beacons.add(newBeacon); + + var updatedGroup = group.copywith(beacons: beacons, hasBeaconActiby: true); + + var updatedGroups = List.from(_totalGroups) + ..removeWhere((group) => group.id == groupId); + + updatedGroups.insert(0, updatedGroup); + _totalGroups = updatedGroups; + + return updatedGroups; + } + + List deleteBeaconFromGroup( + BeaconEntity deletedBeacon, String groupId) { + var groups = _totalGroups.where((group) => group.id! == groupId).toList(); + + if (groups.isEmpty) return List.from(_totalGroups); + + var updatedGroups = List.from(_totalGroups) + ..removeWhere((group) => group.id! == groupId); + + var beacons = List.from(groups.first.beacons ?? []); + beacons.removeWhere((beacon) => beacon.id! == deletedBeacon.id!); + var group = groups.first.copywith(beacons: beacons, hasBeaconActiby: true); + + updatedGroups.insert(0, group); + _totalGroups = updatedGroups; + + return updatedGroups; + } + + List addNewMember(String groupId, UserEntity newUser) { + var updatedGroups = List.from(_totalGroups); + int groupIndex = updatedGroups.indexWhere((group) => group.id == groupId); + if (groupIndex == -1) { + return updatedGroups; + } + var group = updatedGroups[groupIndex]; + var updatedMembers = List.from(group.members ?? []); + updatedMembers.removeWhere((member) => member.id == newUser.id); + updatedMembers.add(newUser); + var updatedGroup = group.copywith( + members: updatedMembers, + hasMemberActivity: true, + ); + updatedGroups[groupIndex] = updatedGroup; + _totalGroups = updatedGroups; + return updatedGroups; + } + + List removeMember(String groupId, UserEntity userToRemove) { + var updatedGroups = List.from(_totalGroups); + int groupIndex = updatedGroups.indexWhere((group) => group.id == groupId); + if (groupIndex == -1) { + return updatedGroups; + } + var group = updatedGroups[groupIndex]; + var updatedMembers = List.from(group.members ?? []); + updatedMembers.removeWhere((member) => member.id == userToRemove.id); + var updatedGroup = group.copywith( + members: updatedMembers, + hasMemberActivity: true, + ); + updatedGroups[groupIndex] = updatedGroup; + _totalGroups = updatedGroups; + return updatedGroups; + } + + void updateCurrentGroupId(String? groupId) { + _currentGroupId = groupId; + } + + void init() async { + var groups = localApi.userModel.groups ?? []; + _groupIds = List.generate(groups.length, (index) => groups[index]!.id!); + await _groupSubscription(); + } + + void clear() { + _groupIds.clear(); + _groupUpdateSubscription?.cancel(); + _page = 1; + _hasReachedEnd = false; + _totalGroups.clear(); + emit(InitialHomeState()); + } +} diff --git a/lib/presentation/home/home_cubit/home_state.dart b/lib/presentation/home/home_cubit/home_state.dart new file mode 100644 index 00000000..764a9002 --- /dev/null +++ b/lib/presentation/home/home_cubit/home_state.dart @@ -0,0 +1,17 @@ +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'home_state.freezed.dart'; + +@freezed +abstract class HomeState with _$HomeState { + const factory HomeState.initial() = InitialHomeState; + const factory HomeState.shimmer() = ShimmerHomeState; + const factory HomeState.loading() = LoadingHomeState; + const factory HomeState.loaded({ + required List groups, + String? message, + @Default(false) bool isLoadingmore, + @Default(false) bool hasReachedEnd, + }) = LoadedHomeState; +} diff --git a/lib/presentation/home/home_cubit/home_state.freezed.dart b/lib/presentation/home/home_cubit/home_state.freezed.dart new file mode 100644 index 00000000..506b8d75 --- /dev/null +++ b/lib/presentation/home/home_cubit/home_state.freezed.dart @@ -0,0 +1,659 @@ +// 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 'home_state.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 _$HomeState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() shimmer, + required TResult Function() loading, + required TResult Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd) + loaded, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? shimmer, + TResult? Function()? loading, + TResult? Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd)? + loaded, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? shimmer, + TResult Function()? loading, + TResult Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd)? + loaded, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(InitialHomeState value) initial, + required TResult Function(ShimmerHomeState value) shimmer, + required TResult Function(LoadingHomeState value) loading, + required TResult Function(LoadedHomeState value) loaded, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialHomeState value)? initial, + TResult? Function(ShimmerHomeState value)? shimmer, + TResult? Function(LoadingHomeState value)? loading, + TResult? Function(LoadedHomeState value)? loaded, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialHomeState value)? initial, + TResult Function(ShimmerHomeState value)? shimmer, + TResult Function(LoadingHomeState value)? loading, + TResult Function(LoadedHomeState value)? loaded, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $HomeStateCopyWith<$Res> { + factory $HomeStateCopyWith(HomeState value, $Res Function(HomeState) then) = + _$HomeStateCopyWithImpl<$Res, HomeState>; +} + +/// @nodoc +class _$HomeStateCopyWithImpl<$Res, $Val extends HomeState> + implements $HomeStateCopyWith<$Res> { + _$HomeStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$InitialHomeStateImplCopyWith<$Res> { + factory _$$InitialHomeStateImplCopyWith(_$InitialHomeStateImpl value, + $Res Function(_$InitialHomeStateImpl) then) = + __$$InitialHomeStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$InitialHomeStateImplCopyWithImpl<$Res> + extends _$HomeStateCopyWithImpl<$Res, _$InitialHomeStateImpl> + implements _$$InitialHomeStateImplCopyWith<$Res> { + __$$InitialHomeStateImplCopyWithImpl(_$InitialHomeStateImpl _value, + $Res Function(_$InitialHomeStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$InitialHomeStateImpl implements InitialHomeState { + const _$InitialHomeStateImpl(); + + @override + String toString() { + return 'HomeState.initial()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$InitialHomeStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() shimmer, + required TResult Function() loading, + required TResult Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd) + loaded, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? shimmer, + TResult? Function()? loading, + TResult? Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd)? + loaded, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? shimmer, + TResult Function()? loading, + TResult Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd)? + loaded, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialHomeState value) initial, + required TResult Function(ShimmerHomeState value) shimmer, + required TResult Function(LoadingHomeState value) loading, + required TResult Function(LoadedHomeState value) loaded, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialHomeState value)? initial, + TResult? Function(ShimmerHomeState value)? shimmer, + TResult? Function(LoadingHomeState value)? loading, + TResult? Function(LoadedHomeState value)? loaded, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialHomeState value)? initial, + TResult Function(ShimmerHomeState value)? shimmer, + TResult Function(LoadingHomeState value)? loading, + TResult Function(LoadedHomeState value)? loaded, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class InitialHomeState implements HomeState { + const factory InitialHomeState() = _$InitialHomeStateImpl; +} + +/// @nodoc +abstract class _$$ShimmerHomeStateImplCopyWith<$Res> { + factory _$$ShimmerHomeStateImplCopyWith(_$ShimmerHomeStateImpl value, + $Res Function(_$ShimmerHomeStateImpl) then) = + __$$ShimmerHomeStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$ShimmerHomeStateImplCopyWithImpl<$Res> + extends _$HomeStateCopyWithImpl<$Res, _$ShimmerHomeStateImpl> + implements _$$ShimmerHomeStateImplCopyWith<$Res> { + __$$ShimmerHomeStateImplCopyWithImpl(_$ShimmerHomeStateImpl _value, + $Res Function(_$ShimmerHomeStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$ShimmerHomeStateImpl implements ShimmerHomeState { + const _$ShimmerHomeStateImpl(); + + @override + String toString() { + return 'HomeState.shimmer()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$ShimmerHomeStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() shimmer, + required TResult Function() loading, + required TResult Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd) + loaded, + }) { + return shimmer(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? shimmer, + TResult? Function()? loading, + TResult? Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd)? + loaded, + }) { + return shimmer?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? shimmer, + TResult Function()? loading, + TResult Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd)? + loaded, + required TResult orElse(), + }) { + if (shimmer != null) { + return shimmer(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialHomeState value) initial, + required TResult Function(ShimmerHomeState value) shimmer, + required TResult Function(LoadingHomeState value) loading, + required TResult Function(LoadedHomeState value) loaded, + }) { + return shimmer(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialHomeState value)? initial, + TResult? Function(ShimmerHomeState value)? shimmer, + TResult? Function(LoadingHomeState value)? loading, + TResult? Function(LoadedHomeState value)? loaded, + }) { + return shimmer?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialHomeState value)? initial, + TResult Function(ShimmerHomeState value)? shimmer, + TResult Function(LoadingHomeState value)? loading, + TResult Function(LoadedHomeState value)? loaded, + required TResult orElse(), + }) { + if (shimmer != null) { + return shimmer(this); + } + return orElse(); + } +} + +abstract class ShimmerHomeState implements HomeState { + const factory ShimmerHomeState() = _$ShimmerHomeStateImpl; +} + +/// @nodoc +abstract class _$$LoadingHomeStateImplCopyWith<$Res> { + factory _$$LoadingHomeStateImplCopyWith(_$LoadingHomeStateImpl value, + $Res Function(_$LoadingHomeStateImpl) then) = + __$$LoadingHomeStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$LoadingHomeStateImplCopyWithImpl<$Res> + extends _$HomeStateCopyWithImpl<$Res, _$LoadingHomeStateImpl> + implements _$$LoadingHomeStateImplCopyWith<$Res> { + __$$LoadingHomeStateImplCopyWithImpl(_$LoadingHomeStateImpl _value, + $Res Function(_$LoadingHomeStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$LoadingHomeStateImpl implements LoadingHomeState { + const _$LoadingHomeStateImpl(); + + @override + String toString() { + return 'HomeState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$LoadingHomeStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() shimmer, + required TResult Function() loading, + required TResult Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd) + loaded, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? shimmer, + TResult? Function()? loading, + TResult? Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd)? + loaded, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? shimmer, + TResult Function()? loading, + TResult Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd)? + loaded, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialHomeState value) initial, + required TResult Function(ShimmerHomeState value) shimmer, + required TResult Function(LoadingHomeState value) loading, + required TResult Function(LoadedHomeState value) loaded, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialHomeState value)? initial, + TResult? Function(ShimmerHomeState value)? shimmer, + TResult? Function(LoadingHomeState value)? loading, + TResult? Function(LoadedHomeState value)? loaded, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialHomeState value)? initial, + TResult Function(ShimmerHomeState value)? shimmer, + TResult Function(LoadingHomeState value)? loading, + TResult Function(LoadedHomeState value)? loaded, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class LoadingHomeState implements HomeState { + const factory LoadingHomeState() = _$LoadingHomeStateImpl; +} + +/// @nodoc +abstract class _$$LoadedHomeStateImplCopyWith<$Res> { + factory _$$LoadedHomeStateImplCopyWith(_$LoadedHomeStateImpl value, + $Res Function(_$LoadedHomeStateImpl) then) = + __$$LoadedHomeStateImplCopyWithImpl<$Res>; + @useResult + $Res call( + {List groups, + String? message, + bool isLoadingmore, + bool hasReachedEnd}); +} + +/// @nodoc +class __$$LoadedHomeStateImplCopyWithImpl<$Res> + extends _$HomeStateCopyWithImpl<$Res, _$LoadedHomeStateImpl> + implements _$$LoadedHomeStateImplCopyWith<$Res> { + __$$LoadedHomeStateImplCopyWithImpl( + _$LoadedHomeStateImpl _value, $Res Function(_$LoadedHomeStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? groups = null, + Object? message = freezed, + Object? isLoadingmore = null, + Object? hasReachedEnd = null, + }) { + return _then(_$LoadedHomeStateImpl( + groups: null == groups + ? _value._groups + : groups // ignore: cast_nullable_to_non_nullable + as List, + message: freezed == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String?, + isLoadingmore: null == isLoadingmore + ? _value.isLoadingmore + : isLoadingmore // ignore: cast_nullable_to_non_nullable + as bool, + hasReachedEnd: null == hasReachedEnd + ? _value.hasReachedEnd + : hasReachedEnd // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc + +class _$LoadedHomeStateImpl implements LoadedHomeState { + const _$LoadedHomeStateImpl( + {required final List groups, + this.message, + this.isLoadingmore = false, + this.hasReachedEnd = false}) + : _groups = groups; + + final List _groups; + @override + List get groups { + if (_groups is EqualUnmodifiableListView) return _groups; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_groups); + } + + @override + final String? message; + @override + @JsonKey() + final bool isLoadingmore; + @override + @JsonKey() + final bool hasReachedEnd; + + @override + String toString() { + return 'HomeState.loaded(groups: $groups, message: $message, isLoadingmore: $isLoadingmore, hasReachedEnd: $hasReachedEnd)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LoadedHomeStateImpl && + const DeepCollectionEquality().equals(other._groups, _groups) && + (identical(other.message, message) || other.message == message) && + (identical(other.isLoadingmore, isLoadingmore) || + other.isLoadingmore == isLoadingmore) && + (identical(other.hasReachedEnd, hasReachedEnd) || + other.hasReachedEnd == hasReachedEnd)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_groups), + message, + isLoadingmore, + hasReachedEnd); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LoadedHomeStateImplCopyWith<_$LoadedHomeStateImpl> get copyWith => + __$$LoadedHomeStateImplCopyWithImpl<_$LoadedHomeStateImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() shimmer, + required TResult Function() loading, + required TResult Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd) + loaded, + }) { + return loaded(groups, message, isLoadingmore, hasReachedEnd); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? shimmer, + TResult? Function()? loading, + TResult? Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd)? + loaded, + }) { + return loaded?.call(groups, message, isLoadingmore, hasReachedEnd); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? shimmer, + TResult Function()? loading, + TResult Function(List groups, String? message, + bool isLoadingmore, bool hasReachedEnd)? + loaded, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(groups, message, isLoadingmore, hasReachedEnd); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(InitialHomeState value) initial, + required TResult Function(ShimmerHomeState value) shimmer, + required TResult Function(LoadingHomeState value) loading, + required TResult Function(LoadedHomeState value) loaded, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(InitialHomeState value)? initial, + TResult? Function(ShimmerHomeState value)? shimmer, + TResult? Function(LoadingHomeState value)? loading, + TResult? Function(LoadedHomeState value)? loaded, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(InitialHomeState value)? initial, + TResult Function(ShimmerHomeState value)? shimmer, + TResult Function(LoadingHomeState value)? loading, + TResult Function(LoadedHomeState value)? loaded, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class LoadedHomeState implements HomeState { + const factory LoadedHomeState( + {required final List groups, + final String? message, + final bool isLoadingmore, + final bool hasReachedEnd}) = _$LoadedHomeStateImpl; + + List get groups; + String? get message; + bool get isLoadingmore; + bool get hasReachedEnd; + @JsonKey(ignore: true) + _$$LoadedHomeStateImplCopyWith<_$LoadedHomeStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/Bloc/presentation/screens/home_screen.dart b/lib/presentation/home/home_screen.dart similarity index 69% rename from lib/Bloc/presentation/screens/home_screen.dart rename to lib/presentation/home/home_screen.dart index 9e494185..10636ae7 100644 --- a/lib/Bloc/presentation/screens/home_screen.dart +++ b/lib/presentation/home/home_screen.dart @@ -1,18 +1,22 @@ +import 'dart:developer'; + 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/domain/entities/group/group_entity.dart'; +import 'package:beacon/presentation/home/home_cubit/home_cubit.dart'; +import 'package:beacon/presentation/home/home_cubit/home_state.dart'; +import 'package:beacon/presentation/group/widgets/create_join_dialog.dart'; +import 'package:beacon/presentation/widgets/shimmer.dart'; +import 'package:beacon/presentation/home/widgets/group_card.dart'; +import 'package:beacon/presentation/widgets/hike_button.dart'; +import 'package:beacon/presentation/widgets/loading_screen.dart'; +import 'package:beacon/presentation/widgets/shape_painter.dart'; import 'package:beacon/locator.dart'; -import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/core/utils/constants.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; -import 'package:sizer/sizer.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; @RoutePage() class HomeScreen extends StatefulWidget { @@ -40,13 +44,16 @@ class _HomeScreenState extends State { 'Do you really want to exit?', style: TextStyle(fontSize: 18, color: kBlack), ), - actions: [ + actions: [ HikeButton( buttonHeight: 2.5.h, buttonWidth: 8.w, onTap: () => AutoRouter.of(context).maybePop(false), text: 'No', ), + SizedBox( + height: 5, + ), HikeButton( buttonHeight: 2.5.h, buttonWidth: 8.w, @@ -65,7 +72,9 @@ class _HomeScreenState extends State { void initState() { _scrollController = ScrollController(); if (localApi.userModel.isGuest == false) { + locationService.getCurrentLocation(); _homeCubit = BlocProvider.of(context); + _homeCubit.init(); _homeCubit.fetchUserGroups(); _scrollController.addListener(_onScroll); } @@ -75,7 +84,6 @@ class _HomeScreenState extends State { void _onScroll() { if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { - if (_homeCubit.isCompletelyFetched) return; _homeCubit.fetchUserGroups(); } } @@ -92,13 +100,20 @@ class _HomeScreenState extends State { @override Widget build(BuildContext context) { return PopScope( - onPopInvoked: (didPop) { - _onPopHome(context); + canPop: false, + onPopInvoked: (didPop) async { + bool? popped = await _onPopHome(context); + + if (popped == true) { + await SystemNavigator.pop(); + } }, child: BlocConsumer( listener: (context, state) { - if (state is ErrorHomeState) { - utils.showSnackBar(state.error, context); + if (state is LoadedHomeState) { + state.message != null + ? utils.showSnackBar(state.message!, context) + : null; } }, builder: (context, state) { @@ -106,15 +121,18 @@ class _HomeScreenState extends State { resizeToAvoidBottomInset: false, body: SafeArea( child: ModalProgressHUD( - inAsyncCall: state is NewGroupLoadingState ? true : false, + inAsyncCall: state is LoadingHomeState ? true : false, progressIndicator: LoadingScreen(), child: Stack( children: [ CustomPaint( - size: Size(MediaQuery.of(context).size.width, - MediaQuery.of(context).size.height - 200), + size: Size(100.w, 100.h - 200), painter: ShapePainter(), ), + // CustomPaint( + // size: Size(100.w, 100.h), + // painter: DrawCircle(), + // ), Align( alignment: Alignment(0.9, -0.8), child: FloatingActionButton( @@ -134,7 +152,7 @@ class _HomeScreenState extends State { content: Text( localApi.userModel.isGuest == true ? 'Would you like to create an account?' - : 'Are you sure you wanna logout?', + : 'Are you sure you want to logout?', style: TextStyle( fontSize: 16, color: kBlack), ), @@ -147,12 +165,14 @@ class _HomeScreenState extends State { text: 'No', textSize: 18.0, ), + SizedBox( + height: 5, + ), HikeButton( buttonHeight: 2.5.h, buttonWidth: 8.w, - onTap: () { - AutoRouter.of(context) - .replaceNamed('/auth'); + onTap: () async { + appRouter.replaceNamed('/auth'); localApi.deleteUser(); }, text: 'Yes', @@ -166,30 +186,26 @@ class _HomeScreenState extends State { : Icon(Icons.logout)), ), Padding( - padding: EdgeInsets.fromLTRB(4.w, 25.h, 4.w, 5), + padding: EdgeInsets.fromLTRB(4.w, 23.h, 4.w, 0), 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); - }, - ), - ); - }, + 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: () async { + CreateJoinGroupDialog.createGroupDialog( + context); + }, + ), ), SizedBox( width: 1.w, @@ -289,71 +305,71 @@ class _HomeScreenState extends State { Widget _buildList() { return Expanded( child: BlocBuilder( + buildWhen: (previous, current) { + return true; + }, builder: (context, state) { - if (state is ShrimmerState) { + if (state is ShimmerHomeState) { return Center( - child: BeaconCustomWidgets.getPlaceholder(), + child: ShimmerWidget.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( + } else if (state is LoadedHomeState) { + List groups = state.groups; + 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), - 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, + 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 + + (state.isLoadingmore && !state.hasReachedEnd ? 1 : 0), + padding: EdgeInsets.all(8), + itemBuilder: (context, index) { + if (index == groups.length) { + return Center(child: LinearProgressIndicator()); } else { - return SizedBox.shrink(); + return GroupCustomWidgets.getGroupCard( + context, groups[index]); } - } - return GroupCustomWidgets.getGroupCard(context, groups[index]); - }, - ); + }, + ); + } } + + return Center( + child: Text(''), + ); }, ), ); diff --git a/lib/presentation/home/widgets/group_card.dart b/lib/presentation/home/widgets/group_card.dart new file mode 100644 index 00000000..4e369cbe --- /dev/null +++ b/lib/presentation/home/widgets/group_card.dart @@ -0,0 +1,264 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/core/resources/data_state.dart'; +import 'package:beacon/domain/entities/group/group_entity.dart'; +import 'package:beacon/domain/usecase/home_usecase.dart'; +import 'package:beacon/presentation/home/home_cubit/home_cubit.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/core/utils/constants.dart'; +import 'package:beacon/config/router/router.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:gap/gap.dart'; +import 'package:responsive_sizer/responsive_sizer.dart'; +import 'package:skeleton_text/skeleton_text.dart'; + +class GroupCustomWidgets { + static final Color textColor = Color(0xFFAFAFAF); + + 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 member in group.members!) { + if (member!.id == localApi.userModel.id) { + isMember = true; + } + } + if (group.leader!.id == localApi.userModel.id || isMember) { + var homeCubit = locator(); + homeCubit.updateCurrentGroupId(group.id!); + appRouter.push(GroupScreenRoute(group: group)).then((value) { + homeCubit.resetGroupActivity(groupId: group.id!); + homeCubit.updateCurrentGroupId(null); + }); + } else { + HomeUseCase _homeUseCase = locator(); + DataState state = + await _homeUseCase.joinGroup(group.shortcode!); + if (state is DataSuccess && state.data != null) { + var homeCubit = locator(); + homeCubit.updateCurrentGroupId(group.id!); + appRouter.push(GroupScreenRoute(group: state.data!)).then((value) { + homeCubit.resetGroupActivity(groupId: group.id); + homeCubit.updateCurrentGroupId(null); + }); + } + } + }, + child: Slidable( + key: ValueKey(group.id!.toString()), + endActionPane: ActionPane( + motion: ScrollMotion(), + children: [ + SlidableAction( + padding: EdgeInsets.symmetric(horizontal: 10), + onPressed: (context) { + context.read().changeShortCode(group); + }, + backgroundColor: kCupertinoModalBarrierColor, + foregroundColor: kDefaultIconDarkColor, + icon: Icons.code, + label: 'Change Code', + ), + ], + ), + child: Container( + margin: const EdgeInsets.symmetric( + vertical: 10.0, + horizontal: 10.0, + ), + padding: EdgeInsets.only(left: 16.0, right: 16.0, bottom: 8, top: 8), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + width: 70.w, + child: Text( + '${group.title} by ${group.leader!.name} ', + style: Style.titleTextStyle, + ), + ), + ], + ), + SizedBox(height: 4.0), + Row( + children: [ + Text( + 'Group has $noMembers members ', + style: Style.commonTextStyle, + ), + group.hasMemberActivity + ? Align( + alignment: Alignment.topRight, + child: Icon( + Icons.circle, + color: kYellow, + size: 10, + ), + ) + : Container(), + ], + ), + SizedBox(height: 4.0), + Row( + children: [ + Text( + 'Group has $noBeacons beacons ', + style: Style.commonTextStyle, + ), + Gap(5), + group.hasBeaconActivity + ? Align( + alignment: Alignment.topRight, + child: Icon( + Icons.circle, + color: kYellow, + size: 10, + ), + ) + : Container(), + ], + ), + SizedBox(height: 4.0), + Row( + children: [ + Text('Passkey: ${group.shortcode}', + style: Style.commonTextStyle), + Gap(10), + InkWell( + onTap: () { + Clipboard.setData(ClipboardData( + text: group.shortcode.toString())); + utils.showSnackBar('Shortcode copied!', context); + }, + child: Icon( + Icons.copy, + size: 17, + color: Colors.white, + )) + ], + ) + ], + ), + ], + ), + decoration: BoxDecoration( + color: (group.hasMemberActivity == true || + group.hasBeaconActivity == true) + ? Color(0xFF141546) + : kBlue, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.circular(8.0), + boxShadow: [ + BoxShadow( + color: Colors.black26, + blurRadius: 10.0, + offset: Offset(0.0, 10.0), + ), + ], + ), + ), + ), + ); + } + + static ListView getPlaceholder() { + final BorderRadius borderRadius = BorderRadius.circular(10.0); + return ListView.builder( + scrollDirection: Axis.vertical, + physics: BouncingScrollPhysics(), + itemCount: 3, + padding: const EdgeInsets.all(8.0), + itemBuilder: (BuildContext context, int index) { + return Container( + margin: const EdgeInsets.symmetric( + vertical: 10.0, + horizontal: 10.0, + ), + height: 110, + decoration: BoxDecoration( + color: kBlue, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.circular(8.0), + boxShadow: [ + BoxShadow( + color: Colors.black26, + blurRadius: 10.0, + offset: Offset(0.0, 10.0), + ), + ], + ), + padding: + EdgeInsets.only(left: 16.0, right: 16.0, bottom: 10, top: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 15.0, bottom: 10.0, right: 15.0), + child: ClipRRect( + borderRadius: borderRadius, + child: SkeletonAnimation( + child: Container( + height: 15.0, + decoration: BoxDecoration(color: shimmerSkeletonColor), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 30.0, bottom: 10.0), + child: ClipRRect( + borderRadius: borderRadius, + child: SkeletonAnimation( + child: Container( + height: 10.0, + decoration: BoxDecoration(color: shimmerSkeletonColor), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 45.0, bottom: 10.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: SkeletonAnimation( + child: Container( + height: 10.0, + decoration: BoxDecoration(color: shimmerSkeletonColor), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 15.0, right: 60.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: SkeletonAnimation( + child: Container( + height: 10.0, + decoration: BoxDecoration(color: shimmerSkeletonColor), + ), + ), + ), + ), + ], + ), + ); + }); + } +} diff --git a/lib/presentation/splash/splash_screen.dart b/lib/presentation/splash/splash_screen.dart new file mode 100644 index 00000000..4a3a08a5 --- /dev/null +++ b/lib/presentation/splash/splash_screen.dart @@ -0,0 +1,89 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:beacon/config/router/router.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; +import 'package:beacon/domain/usecase/auth_usecase.dart'; +import 'package:beacon/locator.dart'; +import 'package:beacon/presentation/auth/verification_cubit/verification_cubit.dart'; +import 'package:flutter/material.dart'; +import 'package:beacon/locator.dart'; +import '../widgets/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 sp.init(); + 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) { + await func(userInfo.data!); + } else { + appRouter.replaceNamed('/auth'); + } + } else { + appRouter.replaceNamed('/home'); + } + } else { + appRouter.replaceNamed('/auth'); + } + } + + Future func(UserEntity user) async { + var time = await sp.loadData('time'); + var otp = await sp.loadData('otp'); + if (user.isVerified == true) { + await sp.deleteData('time'); + await sp.deleteData('otp'); + appRouter.pushNamed('/home'); + } else { + if (time != null && otp != null) { + if (DateTime.now().difference(DateTime.parse(time)).inMinutes < 2) { + locator().emitVerificationSentstate(otp); + appRouter.push(VerificationScreenRoute()); + utils.showSnackBar('Please verify your email', context); + } else { + await sp.deleteData('time'); + await sp.deleteData('otp'); + appRouter.pushNamed('/auth'); + } + } else { + await sp.deleteData('time'); + await sp.deleteData('otp'); + appRouter.replaceNamed('/auth'); + } + } + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: LoadingScreen(), + ); + } +} diff --git a/lib/presentation/widgets/custom_label_marker.dart b/lib/presentation/widgets/custom_label_marker.dart new file mode 100644 index 00000000..a0c3f5f1 --- /dev/null +++ b/lib/presentation/widgets/custom_label_marker.dart @@ -0,0 +1,48 @@ +import 'package:beacon/core/utils/constants.dart'; +import 'package:flutter/material.dart'; + +class CustomMarker extends CustomPainter { + final String text; + CustomMarker({required this.text}); + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = kYellow + ..style = PaintingStyle.fill; + + // Draw the bottom part (triangle) + final path = Path() + ..moveTo(size.width / 2, size.height) + ..lineTo(size.width / 2 - 10, size.height - 10) + ..lineTo(size.width / 2 + 10, size.height - 10) + ..close(); + canvas.drawPath(path, paint); + + // Draw the top part (rounded rectangle) + final rect = Rect.fromLTWH( + 0, size.height * 0.5 + 10, size.width, size.height * .5 - 20); + final rRect = RRect.fromRectAndRadius(rect, Radius.circular(8)); + canvas.drawRRect(rRect, paint); + + // Draw the text + final textPainter = TextPainter( + text: TextSpan( + text: text, + style: TextStyle( + color: Colors.white, fontSize: 14, fontWeight: FontWeight.w800), + ), + textDirection: TextDirection.ltr, + ); + textPainter.layout(minWidth: 0, maxWidth: size.width); + final offset = Offset( + (size.width - textPainter.width) / 2, + (size.height * 0.55 + 10), + ); + textPainter.paint(canvas, offset); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/old/components/hike_button.dart b/lib/presentation/widgets/hike_button.dart similarity index 88% rename from lib/old/components/hike_button.dart rename to lib/presentation/widgets/hike_button.dart index 9cebe747..420b5641 100644 --- a/lib/old/components/hike_button.dart +++ b/lib/presentation/widgets/hike_button.dart @@ -1,4 +1,4 @@ -import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/core/utils/constants.dart'; import 'package:flutter/material.dart'; class HikeButton extends StatelessWidget { @@ -16,8 +16,8 @@ class HikeButton extends StatelessWidget { this.buttonColor = kYellow, this.text, this.textColor = Colors.white, - this.buttonWidth = optbwidth, - this.buttonHeight = optbheight, + this.buttonWidth = 15, + this.buttonHeight = 20, this.textSize = 18}); @override diff --git a/lib/old/components/utilities/indication_painter.dart b/lib/presentation/widgets/indication_painter.dart similarity index 95% rename from lib/old/components/utilities/indication_painter.dart rename to lib/presentation/widgets/indication_painter.dart index 953db2cb..e647ef51 100644 --- a/lib/old/components/utilities/indication_painter.dart +++ b/lib/presentation/widgets/indication_painter.dart @@ -1,6 +1,6 @@ import 'dart:math'; -import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/core/utils/constants.dart'; import 'package:flutter/material.dart'; class TabIndicationPainter extends CustomPainter { diff --git a/lib/presentation/widgets/label_marker.dart b/lib/presentation/widgets/label_marker.dart new file mode 100644 index 00000000..758bdfd1 --- /dev/null +++ b/lib/presentation/widgets/label_marker.dart @@ -0,0 +1,218 @@ +/// A widget to create markers with text label on Google Maps +library label_marker; + +import 'dart:typed_data'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'dart:ui' as ui; + +extension AddExtension on Set { + /// Add a LabelMarker to existing set of Markers + /// + /// * Pass the [LabelMarker] object to add to the set + /// * !!! IMPORTANT!!! + /// * Call setstate after calling this function, as shown in the example + /// + /// Example + /// + /// markers.addLabelMarker(LabelMarker( + /// label: "makerLabel", + /// markerId: MarkerId("markerIdString"), + /// position: LatLng(11.1203, 45.33),), + /// ).then((_) { + /// setState(() {}); + /// }); + Future addLabelMarker(LabelMarker labelMarker) async { + bool result = false; + await createCustomMarkerBitmap( + labelMarker.label, + backgroundColor: labelMarker.backgroundColor, + textStyle: labelMarker.textStyle, + removePointyTriangle: labelMarker.removePointyTriangle, + ).then((value) { + add(Marker( + markerId: labelMarker.markerId, + position: labelMarker.position, + icon: value, + alpha: labelMarker.alpha, + anchor: labelMarker.anchor, + consumeTapEvents: labelMarker.consumeTapEvents, + draggable: labelMarker.draggable, + flat: labelMarker.flat, + infoWindow: labelMarker.infoWindow, + rotation: labelMarker.rotation, + visible: labelMarker.visible, + zIndex: labelMarker.zIndex, + onTap: labelMarker.onTap, + onDragStart: labelMarker.onDragStart, + onDrag: labelMarker.onDrag, + onDragEnd: labelMarker.onDragEnd)); + result = true; + }); + return (result); + } +} + +Future createCustomMarkerBitmap( + String title, { + required TextStyle textStyle, + Color backgroundColor = Colors.blueAccent, + bool removePointyTriangle = false, +}) async { + TextSpan span = TextSpan( + style: textStyle, + text: title, + ); + TextPainter painter = TextPainter( + text: span, + textAlign: TextAlign.center, + textDirection: ui.TextDirection.ltr, + ); + painter.text = TextSpan( + text: title.toString(), + style: textStyle, + ); + ui.PictureRecorder pictureRecorder = ui.PictureRecorder(); + Canvas canvas = Canvas(pictureRecorder); + painter.layout(); + painter.paint(canvas, const Offset(20.0, 10.0)); + int textWidth = painter.width.toInt(); + int textHeight = painter.height.toInt(); + canvas.drawRRect( + RRect.fromLTRBAndCorners(0, 0, textWidth + 40, textHeight + 20, + bottomLeft: const Radius.circular(10), + bottomRight: const Radius.circular(10), + topLeft: const Radius.circular(10), + topRight: const Radius.circular(10)), + Paint()..color = backgroundColor); + if (!removePointyTriangle) { + var arrowPath = Path(); + arrowPath.moveTo((textWidth + 40) / 2 - 15, textHeight + 20); + arrowPath.lineTo((textWidth + 40) / 2, textHeight + 40); + arrowPath.lineTo((textWidth + 40) / 2 + 15, textHeight + 20); + arrowPath.close(); + canvas.drawPath(arrowPath, Paint()..color = backgroundColor); + } + painter.layout(); + painter.paint(canvas, const Offset(20.0, 10.0)); + ui.Picture p = pictureRecorder.endRecording(); + ByteData? pngBytes = await (await p.toImage( + painter.width.toInt() + 40, painter.height.toInt() + 50)) + .toByteData(format: ui.ImageByteFormat.png); + Uint8List data = Uint8List.view(pngBytes!.buffer); + return BitmapDescriptor.fromBytes(data); +} + +class LabelMarker { + /// The text to be displayed on the marker + final String label; + + /// Uniquely identifies a [Marker]. + final MarkerId markerId; + + /// Geographical location of the marker. + final LatLng position; + + /// Background color of the label marker. + final Color backgroundColor; + + /// TextStyle for the text to be displayed in the label marker. + final TextStyle textStyle; + + /// The opacity of the marker, between 0.0 and 1.0 inclusive. + /// + /// 0.0 means fully transparent, 1.0 means fully opaque. + final double alpha; + + /// The icon image point that will be placed at the [position] of the marker. + /// + /// The image point is specified in normalized coordinates: An anchor of + /// (0.0, 0.0) means the top left corner of the image. An anchor + /// of (1.0, 1.0) means the bottom right corner of the image. + final Offset anchor; + + /// True if the marker icon consumes tap events. If not, the map will perform + /// default tap handling by centering the map on the marker and displaying its + /// info window. + final bool consumeTapEvents; + + /// True if the marker is draggable by user touch events. + final bool draggable; + + /// True if the marker is rendered flatly against the surface of the Earth, so + /// that it will rotate and tilt along with map camera movements. + final bool flat; + + /// A description of the bitmap used to draw the marker icon. + final BitmapDescriptor icon; + + /// A Google Maps InfoWindow. + /// + /// The window is displayed when the marker is tapped. + final InfoWindow infoWindow; + + /// Rotation of the marker image in degrees clockwise from the [anchor] point. + final double rotation; + + /// True if the marker is visible. + final bool visible; + + /// The z-index of the marker, used to determine relative drawing order of + /// map overlays. + /// + /// Overlays are drawn in order of z-index, so that lower values means drawn + /// earlier, and thus appearing to be closer to the surface of the Earth. + final double zIndex; + + /// Callbacks to receive tap events for markers placed on this map. + final VoidCallback? onTap; + + /// Signature reporting the new [LatLng] at the start of a drag event. + final ValueChanged? onDragStart; + + /// Signature reporting the new [LatLng] at the end of a drag event. + final ValueChanged? onDragEnd; + + /// Signature reporting the new [LatLng] during the drag event. + final ValueChanged? onDrag; + + /// An option to remove pointy from label + final bool removePointyTriangle; + + /// Creates a marker with text label + /// + /// * Pass the [label] to be displayed on the marker + /// * Pass the [markerId] to be used as a key for the marker + /// * Pass the [position] to be used as the marker's position + /// * Optionally pass the [backgroundColor] to be used as the marker's background color + /// * Optionally pass the [textStyle] to be used as the marker's text style + /// * Optionally you could pass all the other parameters passed for a normal marker + /// + LabelMarker({ + required this.label, + required this.markerId, + required this.position, + this.backgroundColor = Colors.blueAccent, + this.textStyle = const TextStyle( + fontSize: 27.0, + color: Colors.white, + letterSpacing: 1.0, + fontFamily: 'Roboto Bold', + ), + this.alpha = 1.0, + this.anchor = const Offset(0.5, 1.0), + this.consumeTapEvents = false, + this.draggable = false, + this.flat = false, + this.icon = BitmapDescriptor.defaultMarker, + this.infoWindow = InfoWindow.noText, + this.rotation = 0.0, + this.visible = true, + this.zIndex = 0.0, + this.onTap, + this.onDrag, + this.onDragStart, + this.onDragEnd, + this.removePointyTriangle = false, + }); +} diff --git a/lib/old/components/loading_screen.dart b/lib/presentation/widgets/loading_screen.dart similarity index 96% rename from lib/old/components/loading_screen.dart rename to lib/presentation/widgets/loading_screen.dart index a9c9a5c9..c2927d9c 100644 --- a/lib/old/components/loading_screen.dart +++ b/lib/presentation/widgets/loading_screen.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; -import 'utilities/constants.dart'; +import '../../core/utils/constants.dart'; class LoadingScreen extends StatelessWidget { const LoadingScreen({Key? key}) : super(key: key); diff --git a/lib/presentation/widgets/ripple_marker.dart b/lib/presentation/widgets/ripple_marker.dart new file mode 100644 index 00000000..fc843b59 --- /dev/null +++ b/lib/presentation/widgets/ripple_marker.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; + +class RippleMarker extends StatefulWidget { + final double size; + final Color color; + const RippleMarker({super.key, this.size = 100, required this.color}); + + @override + State createState() => _RippleMarkerState(); +} + +class _RippleMarkerState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation; + @override + void initState() { + _controller = + AnimationController(vsync: this, duration: Duration(seconds: 2)) + ..repeat(reverse: true); + + _animation = Tween(begin: 0, end: 1).animate(_controller); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _animation, + builder: (context, child) { + return Container( + height: widget.size * _animation.value, + width: widget.size * _animation.value, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: widget.color.withOpacity(1 - _animation.value)), + ); + }, + ); + } +} + +class RipplePainter extends CustomPainter { + final double animationValue; + + RipplePainter(this.animationValue); + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = Colors.red.withOpacity(1 - animationValue) + ..style = PaintingStyle.stroke + ..strokeWidth = 4; + + final radius = size.width / 2 * animationValue; + canvas.drawCircle(size.center(Offset.zero), radius, paint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/old/components/shape_painter.dart b/lib/presentation/widgets/shape_painter.dart similarity index 93% rename from lib/old/components/shape_painter.dart rename to lib/presentation/widgets/shape_painter.dart index 5c31eff5..c5b7df91 100644 --- a/lib/old/components/shape_painter.dart +++ b/lib/presentation/widgets/shape_painter.dart @@ -1,5 +1,5 @@ import 'package:flutter/cupertino.dart'; -import 'utilities/constants.dart'; +import '../../core/utils/constants.dart'; class ShapePainter extends CustomPainter { @override @@ -26,6 +26,6 @@ class ShapePainter extends CustomPainter { @override bool shouldRepaint(CustomPainter oldDelegate) { - return true; + return false; } } diff --git a/lib/presentation/widgets/shimmer.dart b/lib/presentation/widgets/shimmer.dart new file mode 100644 index 00000000..f50c7172 --- /dev/null +++ b/lib/presentation/widgets/shimmer.dart @@ -0,0 +1,95 @@ +import 'package:beacon/core/utils/constants.dart'; +import 'package:flutter/material.dart'; +import 'package:skeleton_text/skeleton_text.dart'; + +class ShimmerWidget { + static ListView getPlaceholder() { + final BorderRadius borderRadius = BorderRadius.circular(10.0); + return ListView.builder( + scrollDirection: Axis.vertical, + physics: BouncingScrollPhysics(), + itemCount: 3, + padding: const EdgeInsets.all(8.0), + itemBuilder: (BuildContext context, int index) { + return Container( + margin: const EdgeInsets.symmetric( + vertical: 10.0, + horizontal: 10.0, + ), + height: 110, + decoration: BoxDecoration( + color: kBlue, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.circular(8.0), + boxShadow: [ + BoxShadow( + color: Colors.black26, + blurRadius: 10.0, + offset: Offset(0.0, 10.0), + ), + ], + ), + padding: + EdgeInsets.only(left: 16.0, right: 16.0, bottom: 10, top: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 15.0, bottom: 10.0, right: 15.0), + child: ClipRRect( + borderRadius: borderRadius, + child: SkeletonAnimation( + child: Container( + height: 15.0, + decoration: BoxDecoration(color: shimmerSkeletonColor), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 30.0, bottom: 10.0), + child: ClipRRect( + borderRadius: borderRadius, + child: SkeletonAnimation( + child: Container( + height: 10.0, + decoration: BoxDecoration(color: shimmerSkeletonColor), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 45.0, bottom: 10.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: SkeletonAnimation( + child: Container( + height: 10.0, + decoration: BoxDecoration(color: shimmerSkeletonColor), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 15.0, right: 60.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: SkeletonAnimation( + child: Container( + height: 10.0, + decoration: BoxDecoration(color: shimmerSkeletonColor), + ), + ), + ), + ), + ], + ), + ); + }); + } +} diff --git a/lib/Bloc/presentation/widgets/text_field.dart b/lib/presentation/widgets/text_field.dart similarity index 96% rename from lib/Bloc/presentation/widgets/text_field.dart rename to lib/presentation/widgets/text_field.dart index db87ca98..32945050 100644 --- a/lib/Bloc/presentation/widgets/text_field.dart +++ b/lib/presentation/widgets/text_field.dart @@ -1,4 +1,4 @@ -import 'package:beacon/old/components/utilities/constants.dart'; +import 'package:beacon/core/utils/constants.dart'; import 'package:flutter/material.dart'; class CustomTextField extends StatefulWidget { diff --git a/lib/router.dart b/lib/router.dart deleted file mode 100644 index d6e235f2..00000000 --- a/lib/router.dart +++ /dev/null @@ -1,53 +0,0 @@ -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/Bloc/presentation/screens/home_screen.dart'; -import 'package:flutter/material.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'; -import 'package:beacon/Bloc/domain/entities/beacon/beacon_entity.dart'; -part 'router.gr.dart'; - -Route generateRoute(RouteSettings settings) { - switch (settings.name) { - case Routes.authScreen: - return MaterialPageRoute( - builder: (context) => const AuthScreen(key: Key('auth'))); - case Routes.mainScreen: - return MaterialPageRoute( - builder: (context) => HomeScreen(key: Key('MainScreen'))); - // case Routes.hikeScreen: - // HikeScreen? arguments = settings.arguments as HikeScreen?; - // return MaterialPageRoute( - // builder: (context) => HikeScreen( - // arguments!.beacon, - // isLeader: arguments.isLeader, - // )); - case Routes.groupScreen: - GroupScreen? arguments = settings.arguments as GroupScreen?; - return MaterialPageRoute( - builder: (context) => GroupScreen( - arguments!.group, - )); - default: - return MaterialPageRoute( - 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/Bloc/theme/theme.dart b/lib/theme.dart similarity index 100% rename from lib/Bloc/theme/theme.dart rename to lib/theme.dart diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index f1775918..f6f23bfe 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,13 +6,9 @@ #include "generated_plugin_registrant.h" -#include #include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) modal_progress_hud_nsn_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "ModalProgressHudNsnPlugin"); - modal_progress_hud_nsn_plugin_register_with_registrar(modal_progress_hud_nsn_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 812da58b..f16b4c34 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,7 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - modal_progress_hud_nsn url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 685496f9..a817fd6d 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,11 +5,10 @@ import FlutterMacOS import Foundation -import connectivity_plus_macos +import connectivity_plus import flutter_local_notifications import geolocator_apple import location -import modal_progress_hud_nsn import path_provider_foundation import share_plus import shared_preferences_foundation @@ -19,7 +18,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin")) - ModalProgressHudNsnPlugin.register(with: registry.registrar(forPlugin: "ModalProgressHudNsnPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 7e4f3ece..ce5c339a 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - connectivity_plus_macos (0.0.1): + - connectivity_plus (0.0.1): - FlutterMacOS - ReachabilitySwift - flutter_local_notifications (0.0.1): @@ -22,7 +22,7 @@ PODS: - FlutterMacOS DEPENDENCIES: - - connectivity_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos`) + - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - geolocator_apple (from `Flutter/ephemeral/.symlinks/plugins/geolocator_apple/macos`) @@ -37,8 +37,8 @@ SPEC REPOS: - ReachabilitySwift EXTERNAL SOURCES: - connectivity_plus_macos: - :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos + connectivity_plus: + :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos flutter_local_notifications: :path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos FlutterMacOS: @@ -57,7 +57,7 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin SPEC CHECKSUMS: - connectivity_plus_macos: f6e86fd000e971d361e54b5afcadc8c8fa773308 + connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747 flutter_local_notifications: 3805ca215b2fb7f397d78b66db91f6a747af52e4 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 geolocator_apple: 72a78ae3f3e4ec0db62117bd93e34523f5011d58 diff --git a/pubspec.lock b/pubspec.lock index 81e23e0d..d1060935 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,34 +5,34 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" url: "https://pub.dev" source: hosted - version: "64.0.0" + version: "67.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.4.1" archive: dependency: transitive description: name: archive - sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d url: "https://pub.dev" source: hosted - version: "3.4.10" + version: "3.6.1" args: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" async: dependency: transitive description: @@ -45,10 +45,10 @@ packages: dependency: "direct main" description: name: auto_route - sha256: "6cad3f408863ffff2b5757967c802b18415dac4acb1b40c5cdd45d0a26e5080f" + sha256: "878186aae276296bf1cfc0a02cd2788cfb473eb622e0f5e4293f40ecdf86d80d" url: "https://pub.dev" source: hosted - version: "8.1.3" + version: "8.2.0" auto_route_generator: dependency: "direct dev" description: @@ -93,10 +93,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.0.2" build_resolvers: dependency: transitive description: @@ -109,18 +109,18 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7" url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.4.11" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" + sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe url: "https://pub.dev" source: hosted - version: "7.3.0" + version: "7.3.1" built_collection: dependency: transitive description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: built_value - sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6 + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.9.0" + version: "8.9.2" characters: dependency: transitive description: @@ -153,6 +153,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + url: "https://pub.dev" + source: hosted + version: "0.4.1" clock: dependency: transitive description: @@ -181,26 +189,10 @@ packages: dependency: "direct main" description: name: connectivity_plus - sha256: "3f8fe4e504c2d33696dac671a54909743bc6a902a9bb0902306f7a2aed7e528e" + sha256: b74247fad72c171381dbe700ca17da24deac637ab6d43c343b42867acb95c991 url: "https://pub.dev" source: hosted - version: "2.3.9" - connectivity_plus_linux: - dependency: transitive - description: - name: connectivity_plus_linux - sha256: "3caf859d001f10407b8e48134c761483e4495ae38094ffcca97193f6c271f5e2" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - connectivity_plus_macos: - dependency: transitive - description: - name: connectivity_plus_macos - sha256: "488d2de1e47e1224ad486e501b20b088686ba1f4ee9c4420ecbc3b9824f0b920" - url: "https://pub.dev" - source: hosted - version: "1.2.6" + version: "3.0.6" connectivity_plus_platform_interface: dependency: transitive description: @@ -209,22 +201,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.4" - connectivity_plus_web: - dependency: transitive - description: - name: connectivity_plus_web - sha256: "81332be1b4baf8898fed17bb4fdef27abb7c6fd990bf98c54fd978478adf2f1a" - url: "https://pub.dev" - source: hosted - version: "1.2.5" - connectivity_plus_windows: - dependency: transitive - description: - name: connectivity_plus_windows - sha256: "535b0404b4d5605c4dd8453d67e5d6d2ea0dd36e3b477f50f31af51b0aeab9dd" - url: "https://pub.dev" - source: hosted - version: "1.2.2" convert: dependency: transitive description: @@ -237,10 +213,10 @@ packages: dependency: transitive description: name: coverage - sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" + sha256: "3945034e86ea203af7a056d98e98e42a5518fff200d6e8e6647e1886b07e936e" url: "https://pub.dev" source: hosted - version: "1.7.2" + version: "1.8.0" cross_file: dependency: transitive description: @@ -269,18 +245,18 @@ packages: dependency: "direct main" description: name: cupertino_icons - sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.6" + version: "1.0.8" dart_style: dependency: transitive description: name: dart_style - sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.6" data_connection_checker_nulls: dependency: "direct main" description: @@ -305,22 +281,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.10" - dev: - dependency: "direct main" - description: - name: dev - sha256: e7e806af20d53e293a7878212d2246d3e9fccd2b49d597600f9898ed83501cb4 - url: "https://pub.dev" - source: hosted - version: "1.0.0" duration_picker: dependency: "direct main" description: name: duration_picker - sha256: "052b34dac04c29f3849bb3817a26c5aebe9e5f0697c3a374be87db2b84d75753" + sha256: e505a749c93f3218aa4194d339e5d5480d927df23a81f075b5282511f6ac11ab url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" fake_async: dependency: transitive description: @@ -333,10 +301,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file: dependency: transitive description: @@ -370,10 +338,10 @@ packages: dependency: "direct main" description: name: flutter_bloc - sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2 + sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a url: "https://pub.dev" source: hosted - version: "8.1.5" + version: "8.1.6" flutter_config: dependency: "direct main" description: @@ -390,6 +358,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.0" + flutter_geocoder: + dependency: "direct main" + description: + name: flutter_geocoder + sha256: adeef7d9fd21ecb8b82aaa02dfe1fd461b524a1236fb98e494aaf081a5f9f56d + url: "https://pub.dev" + source: hosted + version: "0.2.2-nullsafety" flutter_geocoder_alternative: dependency: "direct main" description: @@ -410,18 +386,18 @@ packages: dependency: "direct dev" description: name: flutter_launcher_icons - sha256: "559c600f056e7c704bd843723c21e01b5fba47e8824bd02422165bcc02a5de1d" + sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" url: "https://pub.dev" source: hosted - version: "0.9.3" + version: "0.13.1" flutter_local_notifications: dependency: "direct main" description: name: flutter_local_notifications - sha256: c18f1de98fe0bb9dd5ba91e1330d4febc8b6a7de6aae3ffe475ef423723e72f3 + sha256: "0a9068149f0225e81642b03562e99776106edbd967816ee68bc16310d457c60e" url: "https://pub.dev" source: hosted - version: "16.3.2" + version: "17.2.1+1" flutter_local_notifications_linux: dependency: transitive description: @@ -434,18 +410,18 @@ packages: dependency: transitive description: name: flutter_local_notifications_platform_interface - sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef" + sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66" url: "https://pub.dev" source: hosted - version: "7.0.0+1" + version: "7.2.0" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.0.20" flutter_polyline_points: dependency: "direct main" description: @@ -454,14 +430,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + flutter_slidable: + dependency: "direct main" + description: + name: flutter_slidable + sha256: "673403d2eeef1f9e8483bd6d8d92aae73b1d8bd71f382bc3930f699c731bc27c" + url: "https://pub.dev" + source: hosted + version: "3.1.0" flutter_spinkit: dependency: "direct main" description: name: flutter_spinkit - sha256: b39c753e909d4796906c5696a14daf33639a76e017136c8d82bf3e620ce5bb8e + sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472 url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.2.1" flutter_test: dependency: "direct dev" description: flutter @@ -476,10 +460,10 @@ packages: dependency: "direct main" description: name: fluttertoast - sha256: dfdde255317af381bfc1c486ed968d5a43a2ded9c931e87cbecd88767d6a71c1 + sha256: "7eae679e596a44fdf761853a706f74979f8dd3cd92cf4e23cae161fda091b847" url: "https://pub.dev" source: hosted - version: "8.2.4" + version: "8.2.6" freezed: dependency: "direct dev" description: @@ -492,15 +476,55 @@ packages: dependency: "direct main" description: name: freezed_annotation - sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + sha256: f9f6597ac43cc262fa7d7f2e65259a6060c23a560525d1f2631be374540f2a9b url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.3" frontend_server_client: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + gap: + dependency: "direct main" + description: + name: gap + sha256: f19387d4e32f849394758b91377f9153a1b41d79513ef7668c088c77dbc6955d + url: "https://pub.dev" + source: hosted + version: "3.0.1" + geocoding: + dependency: "direct main" + description: + name: geocoding + sha256: d580c801cba9386b4fac5047c4c785a4e19554f46be42f4f5e5b7deacd088a66 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + geocoding_android: + dependency: transitive + description: + name: geocoding_android + sha256: "1b13eca79b11c497c434678fed109c2be020b158cec7512c848c102bc7232603" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + geocoding_ios: + dependency: transitive + description: + name: geocoding_ios + sha256: "94ddba60387501bd1c11e18dca7c5a9e8c645d6e3da9c38b9762434941870c24" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + geocoding_platform_interface: + dependency: transitive + description: + name: geocoding_platform_interface + sha256: "8c2c8226e5c276594c2e18bfe88b19110ed770aeb7c1ab50ede570be8b92229b" url: "https://pub.dev" source: hosted version: "3.2.0" @@ -524,18 +548,18 @@ packages: dependency: transitive description: name: geolocator_apple - sha256: "79babf44b692ec5e789d322dc736ef71586056e8e6828f747c9e005456b248bf" + sha256: bc2aca02423ad429cb0556121f56e60360a2b7d694c8570301d06ea0c00732fd url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.3.7" geolocator_platform_interface: dependency: transitive description: name: geolocator_platform_interface - sha256: c6005787efe9e27cb0f6b50230c217e6f0ef8e1e7a8b854efb4f46489e502603 + sha256: "386ce3d9cce47838355000070b1d0b13efb5bc430f8ecda7e9238c8409ace012" url: "https://pub.dev" source: hosted - version: "4.2.3" + version: "4.2.4" geolocator_web: dependency: transitive description: @@ -548,26 +572,18 @@ packages: dependency: transitive description: name: geolocator_windows - sha256: a92fae29779d5c6dc60e8411302f5221ade464968fe80a36d330e80a71f087af - url: "https://pub.dev" - source: hosted - version: "0.2.2" - gestures: - dependency: transitive - description: - name: gestures - sha256: "6e75e4ba1ad033a8be9a682974dfe6a2be96ab07b4aa8335ed37bbecb75b7770" + sha256: "53da08937d07c24b0d9952eb57a3b474e29aae2abf9dd717f7e1230995f13f0e" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "0.2.3" get_it: dependency: "direct main" description: name: get_it - sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7 + sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1 url: "https://pub.dev" source: hosted - version: "7.6.7" + version: "7.7.0" glob: dependency: transitive description: @@ -580,50 +596,50 @@ packages: dependency: transitive description: name: google_maps - sha256: "555d5d736339b0478e821167ac521c810d7b51c3b2734e6802a9f046b64ea37a" + sha256: "47eef3836b49bb030d5cb3afc60b8451408bf34cf753e571b645d6529eb4251a" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "7.1.0" google_maps_flutter: dependency: "direct main" description: name: google_maps_flutter - sha256: ae66fef3e71261d7df2eff29b2a119e190b2884325ecaa55321b1e17b5504066 + sha256: acf0ec482d86b2ac55ade80597ce7f797a47971f5210ebfd030f0d58130e0a94 url: "https://pub.dev" source: hosted - version: "2.5.3" + version: "2.7.0" google_maps_flutter_android: dependency: transitive description: name: google_maps_flutter_android - sha256: "714530f865f13bb3b9505c58821c3baed5d247a871724acf5d2ea5808fbed02c" + sha256: f6306d83edddba7aa017ca6f547d6f36a1443f90ed49d91d48ef70d7aa86e2e1 url: "https://pub.dev" source: hosted - version: "2.6.2" + version: "2.12.0" google_maps_flutter_ios: dependency: transitive description: name: google_maps_flutter_ios - sha256: c89556ed0338fcb4b843c9fcdafac7ad2df601c8b41286d82f0727f7f66434e4 + sha256: a6e3c6ecdda6c985053f944be13a0645ebb919da2ef0f5bc579c5e1670a5b2a8 url: "https://pub.dev" source: hosted - version: "2.3.6" + version: "2.10.0" google_maps_flutter_platform_interface: dependency: transitive description: name: google_maps_flutter_platform_interface - sha256: "6060779f020638a8eedeb0fb14234818e5fa32ec45a4653d6428ab436e2bbc64" + sha256: bd60ca330e3c7763b95b477054adec338a522d982af73ecc520b232474063ac5 url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.8.0" google_maps_flutter_web: dependency: transitive description: name: google_maps_flutter_web - sha256: "6245721c160d6f531c1ef568cf9bef8d660cd585a982aa75121269030163785a" + sha256: f3155c12119d8a5c2732fdf39ceb5cc095bc662059a03b4ea23294ecebe1d199 url: "https://pub.dev" source: hosted - version: "0.5.4+3" + version: "0.5.8" gql: dependency: transitive description: @@ -684,18 +700,18 @@ packages: dependency: transitive description: name: graphql - sha256: b061201579040e9548cec2bae17bbdea0ab30666cb4e7ba48b9675f14d982199 + sha256: bda5b794345087ccbd16942045be8091e2ac4619285bb22e73555d5fd88c4043 url: "https://pub.dev" source: hosted - version: "5.1.3" + version: "5.2.0-beta.1" graphql_flutter: dependency: "direct main" description: name: graphql_flutter - sha256: "9ff835973d9b0e23194153944ecc7d12953d30ffe3ed23431bf476e2b0386ca4" + sha256: "06059ac9e8417c71582f05e28a59b1416d43959d34a6a0d9565341e3a362e117" url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "5.1.2" graphs: dependency: transitive description: @@ -729,7 +745,7 @@ packages: source: hosted version: "0.15.4" http: - dependency: transitive + dependency: "direct main" description: name: http sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" @@ -752,14 +768,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + hydrated_bloc: + dependency: "direct main" + description: + name: hydrated_bloc + sha256: af35b357739fe41728df10bec03aad422cdc725a1e702e03af9d2a41ea05160c + url: "https://pub.dev" + source: hosted + version: "9.1.5" image: dependency: transitive description: name: image - sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "4.2.0" intl: dependency: "direct main" description: @@ -793,7 +817,7 @@ packages: source: hosted version: "0.7.4" json_annotation: - dependency: "direct main" + dependency: "direct dev" description: name: json_annotation sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" @@ -801,7 +825,7 @@ packages: source: hosted version: "4.9.0" json_serializable: - dependency: "direct main" + dependency: "direct dev" description: name: json_serializable sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b @@ -812,50 +836,50 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.3" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" location: dependency: "direct main" description: name: location - sha256: "9051959f6f2ccadd887b28b66e9cbbcc25b6838e37cf9e894c421ccc0ebf80b5" + sha256: "6463a242973bf247e3fb1c7722919521b98026978ee3b5177202e103a39c145e" url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "7.0.0" location_platform_interface: dependency: transitive description: name: location_platform_interface - sha256: "62eeaf1658e92e4459b727f55a3c328eccbac8ba043fa6d262ac5286ad48384c" + sha256: "1e535ccc8b4a9612de4e4319871136b45d2b5d1fb0c2a8bf99687242bf7ca5f7" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "5.0.0" location_web: dependency: transitive description: name: location_web - sha256: "6c08c408a040534c0269c4ff9fe17eebb5a36dea16512fbaf116b9c8bc21545b" + sha256: "613597b489beb396f658c6f4358dd383c5ed0a1402d95e287642a5f2d8171cb0" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "5.0.3" logging: dependency: transitive description: @@ -884,10 +908,10 @@ packages: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.12.0" mime: dependency: transitive description: @@ -908,10 +932,10 @@ packages: dependency: "direct main" description: name: modal_progress_hud_nsn - sha256: "408b9bcce97567de94637de932260e50be48db1842edc761aeea61670e5ec30c" + sha256: "7d1b2eb50da63c994f8ec2da5738183dbc8235a528e840ecbf67439adb7a6cc2" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.5.1" nested: dependency: transitive description: @@ -940,10 +964,18 @@ packages: dependency: transitive description: name: normalize - sha256: baf8caf2d8b745af5737cca6c24f7fe3cf3158897fdbcde9a909b9c8d3e2e5af + sha256: "8a60e37de5b608eeaf9b839273370c71ebba445e9f73b08eee7725e0d92dbc43" + url: "https://pub.dev" + source: hosted + version: "0.8.2+1" + otp_pin_field: + dependency: "direct main" + description: + name: otp_pin_field + sha256: a9dca37f66934719de6bae7cf873c17444b4faffd5880d4ccc5f7d529230f8c8 url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "1.2.9" overlay_support: dependency: "direct main" description: @@ -972,26 +1004,26 @@ packages: dependency: "direct main" description: name: path_provider - sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + sha256: "30c5aa827a6ae95ce2853cdc5fe3971daaac00f6f081c419c013f7f57bff2f5e" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.7" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" path_provider_linux: dependency: transitive description: @@ -1012,10 +1044,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" petitparser: dependency: transitive description: @@ -1024,14 +1056,22 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.2" + pinput: + dependency: "direct main" + description: + name: pinput + sha256: "7bf9aa7d0eeb3da9f7d49d2087c7bc7d36cd277d2e94cc31c6da52e1ebb048d0" + url: "https://pub.dev" + source: hosted + version: "5.0.0" platform: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -1040,14 +1080,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" - pointycastle: - dependency: transitive - description: - name: pointycastle - sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" - url: "https://pub.dev" - source: hosted - version: "3.7.4" pool: dependency: transitive description: @@ -1060,10 +1092,10 @@ packages: dependency: "direct main" description: name: provider - sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.1.1" + version: "6.1.2" pub_semver: dependency: transitive description: @@ -1076,10 +1108,18 @@ packages: dependency: transitive description: name: pubspec_parse - sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "1.3.0" + responsive_sizer: + dependency: "direct main" + description: + name: responsive_sizer + sha256: "6aefee6065c0883681bc7559147a24d8fa1846d296a216abcda25ff349340712" + url: "https://pub.dev" + source: hosted + version: "3.3.1" rxdart: dependency: "direct main" description: @@ -1100,42 +1140,42 @@ packages: dependency: "direct main" description: name: share_plus - sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900" + sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544 url: "https://pub.dev" source: hosted - version: "7.2.2" + version: "9.0.0" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - sha256: df08bc3a07d01f5ea47b45d03ffcba1fa9cd5370fb44b3f38c70e42cced0f956 + sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "4.0.0" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.3" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.4.0" shared_preferences_linux: dependency: transitive description: @@ -1200,14 +1240,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" - sizer: - dependency: "direct main" - description: - name: sizer - sha256: d2b3cb6cbc4a637f508dacd786bae55df31e5fc088044248a43e4fd1e050c117 - url: "https://pub.dev" - source: hosted - version: "2.0.15" skeleton_text: dependency: "direct main" description: @@ -1301,6 +1333,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" term_glyph: dependency: transitive description: @@ -1313,34 +1353,34 @@ packages: dependency: "direct dev" description: name: test - sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" url: "https://pub.dev" source: hosted - version: "1.24.9" + version: "1.25.2" test_api: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.0" test_core: dependency: transitive description: name: test_core - sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" url: "https://pub.dev" source: hosted - version: "0.5.9" + version: "0.6.0" timezone: dependency: transitive description: name: timezone - sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" + sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" url: "https://pub.dev" source: hosted - version: "0.9.2" + version: "0.9.4" timing: dependency: transitive description: @@ -1381,14 +1421,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.0" - universal_io: + universal_platform: dependency: transitive description: - name: universal_io - sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + name: universal_platform + sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "1.1.0" url_launcher_linux: dependency: transitive description: @@ -1401,10 +1441,10 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" url_launcher_web: dependency: transitive description: @@ -1441,10 +1481,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.1" watcher: dependency: transitive description: @@ -1462,13 +1502,13 @@ packages: source: hosted version: "0.5.1" web_socket_channel: - dependency: transitive + dependency: "direct main" description: name: web_socket_channel - sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd" + sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.5" webkit_inspection_protocol: dependency: transitive description: @@ -1481,10 +1521,10 @@ packages: dependency: transitive description: name: win32 - sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.5.1" xdg_directories: dependency: transitive description: @@ -1510,5 +1550,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.19.0" + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.22.0" diff --git a/pubspec.yaml b/pubspec.yaml index ba00c26a..14e64806 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,7 +9,7 @@ environment: sdk: '>=3.2.3 <4.0.0' dependencies: - connectivity_plus: ^2.1.0 + connectivity_plus: any cupertino_icons: ^1.0.5 date_time_picker: ^2.1.0 duration_picker: ^1.1.1 @@ -18,43 +18,59 @@ dependencies: flutter_animarker: ^3.2.0 flutter_config: ^2.0.2 flutter_countdown_timer: ^4.1.0 - flutter_local_notifications: ^16.3.0 + flutter_local_notifications: ^17.2.1+1 flutter_polyline_points: ^1.0.0 flutter_spinkit: ^5.2.0 fluttertoast: ^8.2.4 - geolocator: any get_it: ^7.6.4 google_maps_flutter: ^2.5.3 - graphql_flutter: ^5.1.0 hive: ^2.2.3 intl: ^0.17.0 - location: ^4.4.0 + location: ^7.0.0 mockito: - modal_progress_hud_nsn: ^0.3.0 + modal_progress_hud_nsn: ^0.5.1 overlay_support: ^2.1.0 path_provider: ^2.0.4 provider: ^6.1.1 rxdart: ^0.27.7 - share_plus: ^7.2.1 + share_plus: ^9.0.0 shared_preferences: ^2.0.7 - sizer: ^2.0.15 + responsive_sizer: ^3.3.1 skeleton_text: ^3.0.1 sliding_up_panel: ^2.0.0+1 uni_links: ^0.5.1 data_connection_checker_nulls: ^0.0.2 flutter_geocoder_alternative: any + gap: ^3.0.1 - # for routing + # routing auto_route: ^8.1.1 - - # for state management + # state management bloc: ^8.1.4 flutter_bloc: ^8.1.5 + + # class comparison freezed_annotation: ^2.4.1 - json_annotation: ^4.9.0 - dev: ^1.0.0 - json_serializable: ^6.8.0 + + + + # for dismissable widget + flutter_slidable: ^3.1.0 + graphql_flutter: ^5.1.2 + web_socket_channel: ^2.4.5 + geolocator: ^12.0.0 + flutter_geocoder: ^0.2.2-nullsafety + geocoding: ^3.0.0 + http: ^0.13.6 + otp_pin_field: ^1.2.9 + hydrated_bloc: ^9.1.5 + pinput: ^5.0.0 + + + + + @@ -63,12 +79,14 @@ dependencies: dev_dependencies: build_runner: ^2.1.2 - flutter_launcher_icons: ^0.9.3 + flutter_launcher_icons: ^0.13.1 flutter_test: sdk: flutter freezed: ^2.5.2 - hive_generator: test: ^1.16.5 + hive_generator: + json_annotation: ^4.9.0 + json_serializable: ^6.8.0 auto_route_generator: flutter_icons: diff --git a/test/model_tests/beacon_test.dart b/test/model_tests/beacon_test.dart index d459740c..7f80032e 100644 --- a/test/model_tests/beacon_test.dart +++ b/test/model_tests/beacon_test.dart @@ -1,59 +1,58 @@ -import 'package:beacon/old/components/models/beacon/beacon.dart'; import 'package:test/test.dart'; void main() { //structered according to fetchBeaconDetail Query. - Map dummyJson = { - "_id": "61fd51b4f0c4c3219ce356f5", - "title": "new_beacon", - "leader": {"name": "test_leader"}, - "followers": [ - { - "_id": "61fd509bf0c4c3219ce356ed", - "name": "test_leader", - "location": {"lat": "10", "lon": "20"} - } - ], - "landmarks": [ - { - "title": "landmark", - "location": {"lat": "1", "lon": "2"} - } - ], - "location": {"lat": "1", "lon": "2"}, - "startsAt": 1669746600000, - "expiresAt": 1669746600001, - "shortcode": "WCQDUR" - }; + // Map dummyJson = { + // "_id": "61fd51b4f0c4c3219ce356f5", + // "title": "new_beacon", + // "leader": {"name": "test_leader"}, + // "followers": [ + // { + // "_id": "61fd509bf0c4c3219ce356ed", + // "name": "test_leader", + // "location": {"lat": "10", "lon": "20"} + // } + // ], + // "landmarks": [ + // { + // "title": "landmark", + // "location": {"lat": "1", "lon": "2"} + // } + // ], + // "location": {"lat": "1", "lon": "2"}, + // "startsAt": 1669746600000, + // "expiresAt": 1669746600001, + // "shortcode": "WCQDUR" + // }; - test('Beacon.fromJson method works or not: ', () { - Beacon beacon = Beacon.fromJson(dummyJson); - //beacon id - expect("61fd51b4f0c4c3219ce356f5", beacon.id); - //title - expect("new_beacon", beacon.title); - //leader name - expect("test_leader", beacon.leader!.name); - //follower id - expect("61fd509bf0c4c3219ce356ed", beacon.followers!.first.id); - //follower name - expect("test_leader", beacon.followers!.first.name); - //follower location - expect("10", beacon.followers!.first.location!.lat); - //longitude - expect("20", beacon.followers!.first.location!.lon); - //landmark - expect("landmark", beacon.landmarks!.first!.title); - expect("1", beacon.landmarks!.first!.location!.lat); - expect("2", beacon.landmarks!.first!.location!.lon); - //beacon location - expect("1", beacon.location!.lat); - expect("2", beacon.location!.lon); - //starts at - expect(1669746600000, beacon.startsAt); - //expires at - expect(1669746600001, beacon.expiresAt); - //short code - expect("WCQDUR", beacon.shortcode); - }); + // test('Beacon.fromJson method works or not: ', () { + // Beacon beacon = Beacon.fromJson(dummyJson); + // //beacon id + // expect("61fd51b4f0c4c3219ce356f5", beacon.id); + // //title + // expect("new_beacon", beacon.title); + // //leader name + // expect("test_leader", beacon.leader!.name); + // //follower id + // expect("61fd509bf0c4c3219ce356ed", beacon.followers!.first.id); + // //follower name + // expect("test_leader", beacon.followers!.first.name); + // //follower location + // expect("10", beacon.followers!.first.location!.lat); + // //longitude + // expect("20", beacon.followers!.first.location!.lon); + // //landmark + // expect("landmark", beacon.landmarks!.first!.title); + // expect("1", beacon.landmarks!.first!.location!.lat); + // expect("2", beacon.landmarks!.first!.location!.lon); + // //beacon location + // expect("1", beacon.location!.lat); + // expect("2", beacon.location!.lon); + // //starts at + // expect(1669746600000, beacon.startsAt); + // //expires at + // expect(1669746600001, beacon.expiresAt); + // //short code + // expect("WCQDUR", beacon.shortcode); + // }); } diff --git a/test/model_tests/user_test.dart b/test/model_tests/user_test.dart index 40fbfa7f..9121b9f5 100644 --- a/test/model_tests/user_test.dart +++ b/test/model_tests/user_test.dart @@ -1,162 +1,164 @@ -import 'package:beacon/old/components/models/beacon/beacon.dart'; -import 'package:beacon/old/components/models/user/user_info.dart'; +import 'package:beacon/data/models/beacon/beacon_model.dart'; +import 'package:beacon/data/models/user/user_model.dart'; +import 'package:beacon/domain/entities/user/user_entity.dart'; import 'package:test/test.dart'; void main() { //structered according to fetchBeaconDetail Query. - Map dummyJson = { - "_id": "61fd509bf0c4c3219ce356ed", - "name": "test_user", - "email": "test_user@gmail.com", - "location": {"lat": "10", "lon": "20"}, - "beacons": [ - { - "_id": "61fd51b4f0c4c3219ce356f5", - "title": "new_beacon", - "leader": {"name": "test_user"}, - "followers": [ - { - "_id": "61fd509bf0c4c3219ce356ed", - "name": "test_user", - "location": {"lat": "10", "lon": "20"} - } - ], - "landmarks": [ - { - "title": "landmark_one", - "location": {"lat": "1", "lon": "2"} - } - ], - "location": {"lat": "1", "lon": "2"}, - "startsAt": 1669746600000, - "expiresAt": 1669746600001, - "shortcode": "WCQDUR" - } - ], - }; - Map dummyJson2 = { - "_id": "61fd509bf0c4c3219ce356de", - "name": "test_user_two", - "email": "test_user_two@gmail.com", - "location": {"lat": "20", "lon": "10"}, - "beacons": [ - { - "_id": "61fd51b4f0c4c3219ce3565f", - "title": "beacon_two", - "leader": {"name": "test_user_two"}, - "followers": [ - { - "_id": "61fd509bf0c4c3219ce356de", - "name": "test_user_two", - "location": {"lat": "20", "lon": "10"} - } - ], - "landmarks": [ - { - "title": "landmark", - "location": {"lat": "2", "lon": "1"} - } - ], - "location": {"lat": "2", "lon": "1"}, - "startsAt": 1669746600001, - "expiresAt": 1669746600002, - "shortcode": "WCQDUK" - } - ], - }; + // Map dummyJson = { + // "_id": "61fd509bf0c4c3219ce356ed", + // "name": "test_user", + // "email": "test_user@gmail.com", + // "location": {"lat": "10", "lon": "20"}, + // "beacons": [ + // { + // "_id": "61fd51b4f0c4c3219ce356f5", + // "title": "new_beacon", + // "leader": {"name": "test_user"}, + // "followers": [ + // { + // "_id": "61fd509bf0c4c3219ce356ed", + // "name": "test_user", + // "location": {"lat": "10", "lon": "20"} + // } + // ], + // "landmarks": [ + // { + // "title": "landmark_one", + // "location": {"lat": "1", "lon": "2"} + // } + // ], + // "location": {"lat": "1", "lon": "2"}, + // "startsAt": 1669746600000, + // "expiresAt": 1669746600001, + // "shortcode": "WCQDUR" + // } + // ], + // }; + // Map dummyJson2 = { + // "_id": "61fd509bf0c4c3219ce356de", + // "name": "test_user_two", + // "email": "test_user_two@gmail.com", + // "location": {"lat": "20", "lon": "10"}, + // "beacons": [ + // { + // "_id": "61fd51b4f0c4c3219ce3565f", + // "title": "beacon_two", + // "leader": {"name": "test_user_two"}, + // "followers": [ + // { + // "_id": "61fd509bf0c4c3219ce356de", + // "name": "test_user_two", + // "location": {"lat": "20", "lon": "10"} + // } + // ], + // "landmarks": [ + // { + // "title": "landmark", + // "location": {"lat": "2", "lon": "1"} + // } + // ], + // "location": {"lat": "2", "lon": "1"}, + // "startsAt": 1669746600001, + // "expiresAt": 1669746600002, + // "shortcode": "WCQDUK" + // } + // ], + // }; - group('Testing User Model', () { - test('User.fromJson method works or not: ', () { - User user = User.fromJson(dummyJson); - Beacon beacon = user.beacon!.first; - //user id; - expect("61fd509bf0c4c3219ce356ed", user.id); - //name - expect("test_user", user.name); - //email - expect("test_user@gmail.com", user.email); - //isGuest - expect(false, user.isGuest); - //location - expect("10", user.location!.lat); - expect("20", user.location!.lon); - //beacon id - expect("61fd51b4f0c4c3219ce356f5", beacon.id); - //title - expect("new_beacon", beacon.title); - //leader name - expect("test_user", beacon.leader!.name); - //follower id - expect("61fd509bf0c4c3219ce356ed", beacon.followers!.first.id); - //follower name - expect("test_user", beacon.followers!.first.name); - //follower location - expect("10", beacon.followers!.first.location!.lat); - //longitude - expect("20", beacon.followers!.first.location!.lon); - //landmark - expect("landmark_one", beacon.landmarks!.first!.title); - expect("1", beacon.landmarks!.first!.location!.lat); - expect("2", beacon.landmarks!.first!.location!.lon); - //beacon location - expect("1", beacon.location!.lat); - expect("2", beacon.location!.lon); - //starts at - expect(1669746600000, beacon.startsAt); - //expires at - expect(1669746600001, beacon.expiresAt); - //short code - expect("WCQDUR", beacon.shortcode); - }); +// group('Testing User Model', () { +// test('User.fromJson method works or not: ', () { +// UserModel user = UserModel.fromJson(dummyJson); +// BeaconModel beacon = user.beacons!.first!; +// //user id; +// expect("61fd509bf0c4c3219ce356ed", user.id); +// //name +// expect("test_user", user.name); +// //email +// expect("test_user@gmail.com", user.email); +// //isGuest +// expect(false, user.isGuest); +// //location +// expect("10", user.location!.lat); +// expect("20", user.location!.lon); +// //beacon id +// expect("61fd51b4f0c4c3219ce356f5", beacon.id); +// //title +// expect("new_beacon", beacon.title); +// //leader name +// expect("test_user", beacon.leader!.name); +// //follower id +// expect("61fd509bf0c4c3219ce356ed", beacon.followers!.first.id); +// //follower name +// expect("test_user", beacon.followers!.first.name); +// //follower location +// expect("10", beacon.followers!.first.location!.lat); +// //longitude +// expect("20", beacon.followers!.first.location!.lon); +// //landmark +// expect("landmark_one", beacon.landmarks!.first!.title); +// expect("1", beacon.landmarks!.first!.location!.lat); +// expect("2", beacon.landmarks!.first!.location!.lon); +// //beacon location +// expect("1", beacon.location!.lat); +// expect("2", beacon.location!.lon); +// //starts at +// expect(1669746600000, beacon.startsAt); +// //expires at +// expect(1669746600001, beacon.expiresAt); +// //short code +// expect("WCQDUR", beacon.shortcode); +// }); - test('Testing if update() method works', () { - User user = User.fromJson(dummyJson); - user.authToken = 'authTokenIntial'; - User updateToUser = User.fromJson(dummyJson2); - updateToUser.authToken = 'FinalAuthToken'; - updateToUser.isGuest = true; - user.update(updateToUser); - Beacon beacon = user.beacon!.first; - //auth token - expect("FinalAuthToken", user.authToken); - //userID - expect("61fd509bf0c4c3219ce356ed", user.id); - //name - expect("test_user_two", user.name); - //email - expect("test_user_two@gmail.com", user.email); - //isGuest - expect(true, user.isGuest); - //location - expect("20", user.location!.lat); - expect("10", user.location!.lon); - //beacon id - expect("61fd51b4f0c4c3219ce3565f", beacon.id); - //title - expect("beacon_two", beacon.title); - //leader name - expect("test_user_two", beacon.leader!.name); - //follower id - expect("61fd509bf0c4c3219ce356de", beacon.followers!.first.id); - //follower name - expect("test_user_two", beacon.followers!.first.name); - //follower location - expect("20", beacon.followers!.first.location!.lat); - //longitude - expect("10", beacon.followers!.first.location!.lon); - //landmark - expect("landmark", beacon.landmarks!.first!.title); - expect("2", beacon.landmarks!.first!.location!.lat); - expect("1", beacon.landmarks!.first!.location!.lon); - //beacon location - expect("2", beacon.location!.lat); - expect("1", beacon.location!.lon); - //starts at - expect(1669746600001, beacon.startsAt); - //expires at - expect(1669746600002, beacon.expiresAt); - //short code - expect("WCQDUK", beacon.shortcode); - }); - }); +// test('Testing if update() method works', () { +// User user = User.fromJson(dummyJson); +// user.authToken = 'authTokenIntial'; +// User updateToUser = User.fromJson(dummyJson2); +// updateToUser.authToken = 'FinalAuthToken'; +// updateToUser.isGuest = true; +// user.update(updateToUser); +// Beacon beacon = user.beacon!.first; +// //auth token +// expect("FinalAuthToken", user.authToken); +// //userID +// expect("61fd509bf0c4c3219ce356ed", user.id); +// //name +// expect("test_user_two", user.name); +// //email +// expect("test_user_two@gmail.com", user.email); +// //isGuest +// expect(true, user.isGuest); +// //location +// expect("20", user.location!.lat); +// expect("10", user.location!.lon); +// //beacon id +// expect("61fd51b4f0c4c3219ce3565f", beacon.id); +// //title +// expect("beacon_two", beacon.title); +// //leader name +// expect("test_user_two", beacon.leader!.name); +// //follower id +// expect("61fd509bf0c4c3219ce356de", beacon.followers!.first.id); +// //follower name +// expect("test_user_two", beacon.followers!.first.name); +// //follower location +// expect("20", beacon.followers!.first.location!.lat); +// //longitude +// expect("10", beacon.followers!.first.location!.lon); +// //landmark +// expect("landmark", beacon.landmarks!.first!.title); +// expect("2", beacon.landmarks!.first!.location!.lat); +// expect("1", beacon.landmarks!.first!.location!.lon); +// //beacon location +// expect("2", beacon.location!.lat); +// expect("1", beacon.location!.lon); +// //starts at +// expect(1669746600001, beacon.startsAt); +// //expires at +// expect(1669746600002, beacon.expiresAt); +// //short code +// expect("WCQDUK", beacon.shortcode); +// }); +// }); +// } } diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index ccc9bd9d..1032d3a8 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,8 @@ #include "generated_plugin_registrant.h" -#include +#include #include -#include #include #include @@ -17,8 +16,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); GeolocatorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("GeolocatorWindows")); - ModalProgressHudNsnPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("ModalProgressHudNsnPlugin")); SharePlusWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 71052214..684998e8 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,9 +3,8 @@ # list(APPEND FLUTTER_PLUGIN_LIST - connectivity_plus_windows + connectivity_plus geolocator_windows - modal_progress_hud_nsn share_plus url_launcher_windows )