diff --git a/assets/icons/tutorial.png b/assets/icons/tutorial.png new file mode 100644 index 0000000..6f5d21f Binary files /dev/null and b/assets/icons/tutorial.png differ diff --git a/lib/components/MapKmlElement.dart b/lib/components/MapKmlElement.dart index 5ecdda7..be094c7 100644 --- a/lib/components/MapKmlElement.dart +++ b/lib/components/MapKmlElement.dart @@ -153,6 +153,9 @@ class _MapkmlelementState extends State { elementIndex: widget.elementIndex, submitData: widget.submitData)); widget.submitData(kmlElement); + if(kmlElement != null) { + setMapdata(kmlElement); + } }, icon: const Icon( Icons.fullscreen_rounded, @@ -308,6 +311,36 @@ class _MapkmlelementState extends State { } return list; } + + void setMapdata(KmlElement kmlElement) { + points.clear(); + if(kmlElement.index==0) + { + Placemark mark = kmlElement.elementData; + points.add(mark.coordinate.toLatLngMap(mark.coordinate)); + } + else + if(kmlElement.index==1) + { + LineString line = kmlElement.elementData; + points.addAll(line.coordinates.map((coord)=>coord.toLatLngMap(coord))); + } + else + if(kmlElement.index==2) + { + PolyGon line = kmlElement.elementData; + points.addAll(line.coordinates.map((coord)=>coord.toLatLngMap(coord))); + } + calculateMarkers(); + polyline.clear(); + polygon.clear(); + polyline.add(calculatePolyLine()); + polygon.add(calculatePolygon()); + setState(() { + reloadMap(); + print(points); + }); + } } class CallbackHandler { diff --git a/lib/components/apimanager_block.dart b/lib/components/apimanager_block.dart index 2f655ce..3edde86 100644 --- a/lib/components/apimanager_block.dart +++ b/lib/components/apimanager_block.dart @@ -1,12 +1,15 @@ import 'dart:ui'; + import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:lottie/lottie.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:super_liquid_galaxy_controller/controllers/api_manager.dart'; + import '../generated/assets.dart'; +import '../utils/galaxy_colors.dart'; import 'custom_dialog.dart'; import 'galaxytextfield.dart'; -import 'package:lottie/lottie.dart'; -import 'package:get/get.dart'; -import 'package:shared_preferences/shared_preferences.dart'; class ApiManagerBlock extends StatefulWidget { ApiManagerBlock( @@ -18,7 +21,7 @@ class ApiManagerBlock extends StatefulWidget { this.urlLauncher1, this.urlLauncher2, required this.keyController, - required this.width}); + required this.width}); String title; String description; @@ -33,10 +36,7 @@ class ApiManagerBlock extends StatefulWidget { State createState() => _ApiManagerBlockState(); } - - class _ApiManagerBlockState extends State { - @override void initState() { loadSetValues(); @@ -52,8 +52,7 @@ class _ApiManagerBlockState extends State { child: Container( width: widget.width, decoration: BoxDecoration( - border: - Border.all(color: Colors.white.withOpacity(0.1)), + border: Border.all(color: Colors.white.withOpacity(0.1)), borderRadius: BorderRadius.circular(5), gradient: LinearGradient(colors: [ Colors.white.withOpacity(0.1), @@ -73,7 +72,7 @@ class _ApiManagerBlockState extends State { children: [ Text( widget.title, - style:const TextStyle( + style: const TextStyle( color: Colors.white, fontSize: 35, fontWeight: FontWeight.w400, @@ -142,7 +141,9 @@ class _ApiManagerBlockState extends State { ), ), ), - const SizedBox(width: 20.0,), + const SizedBox( + width: 20.0, + ), Expanded( child: Material( color: Colors.transparent, @@ -153,7 +154,6 @@ class _ApiManagerBlockState extends State { Colors.blue.withOpacity(0.3), onTap: widget.urlLauncher2, child: Container( - child: FittedBox( fit: BoxFit.fitHeight, child: Text( @@ -183,25 +183,72 @@ class _ApiManagerBlockState extends State { iconData: Icons.code, textInputType: TextInputType.text, controller: widget.keyController, - isPassword: false, - buttonAction: () { + isPassword: true, + /*buttonAction: () { if (widget.keyController.text.isNotEmpty) { saveApiKey('places_apikey'); + } else { + if (!Get.isSnackbarOpen) { + Get.showSnackbar(GetSnackBar( + backgroundColor: Colors.red.shade300, + title: "EMPTY FIELD", + message: "API Key Field is Empty!", + isDismissible: true, + duration: 3.seconds, + )); + } } - else - { - if (!Get.isSnackbarOpen) { - Get.showSnackbar(GetSnackBar( - backgroundColor: Colors.red.shade300, - title: "EMPTY FIELD", - message: "API Key Field is Empty!", - isDismissible: true, - duration: 3.seconds, - )); - } + }, + endIcon: Icons.save_alt_outlined,*/ + ), + const SizedBox( + height: 10.0, + ), + MaterialButton( + color: GalaxyColors.blue, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30.0), + ), + onPressed: () async { + //await formSubmitted(); + if (widget.keyController.text.isNotEmpty) { + saveApiKey('places_apikey'); + } else { + if (!Get.isSnackbarOpen) { + Get.showSnackbar(GetSnackBar( + backgroundColor: Colors.red.shade300, + title: "EMPTY FIELD", + message: "API Key Field is Empty!", + isDismissible: true, + duration: 3.seconds, + )); } + } }, - endIcon: Icons.save_alt_outlined, + child: const Padding( + padding: EdgeInsets.symmetric( + vertical: 10.0, + horizontal: 20.0 + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.key, + size: 30, + color: Colors.white, + ), + SizedBox(width: 10.0), + Text( + "CONNECT TO API", + style: TextStyle( + fontSize: 20, + color: Colors.white, + fontWeight: FontWeight.bold), + ) + ], + ), + ), ), const SizedBox( height: 10.0, @@ -210,22 +257,18 @@ class _ApiManagerBlockState extends State { ))) ])))); } - void loadSetValues() async { + void loadSetValues() async { try { SharedPreferences preferences = await SharedPreferences.getInstance(); var key = preferences.getString("places_apikey") ?? ""; key = key.trim(); widget.keyController.text = key; - } - catch(e) - { + } catch (e) { print(e); } - } - void saveApiKey(String prefKey) async { SharedPreferences preferences = await SharedPreferences.getInstance(); await preferences.setString(prefKey, widget.keyController.text); @@ -233,32 +276,61 @@ class _ApiManagerBlockState extends State { await apiClient.testApiKey(); var dialog = apiClient.isConnected.value ? CustomDialog( - content: Text("All Api Services now available!"), - title: Text("API KEY VALIDATED",style: TextStyle(color: Colors.green.shade500,fontSize: 25.0,fontWeight: FontWeight.bold),), - firstColor: Colors.green, - secondColor: Colors.white, - headerIcon: Lottie.asset(Assets.lottieConnected, - decoder: customDecoder, repeat: false,width: 200.0,height: 200.0)) + content: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25.0), + child: Text("All Api Services now available!"), + ), + title: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Text( + "API KEY VALIDATED", + style: TextStyle( + color: Colors.green.shade500, + fontSize: 25.0, + fontWeight: FontWeight.bold), + ), + ), + firstColor: Colors.green, + secondColor: Colors.white, + headerIcon: Lottie.asset(Assets.lottieConnected, + decoder: customDecoder, + repeat: false, + width: 200.0, + height: 200.0)) : CustomDialog( - content: Text("Api services unavailable"), - title: Text("API KEY INVALID",style: TextStyle(color: Colors.red.shade500,fontSize: 25.0,fontWeight: FontWeight.bold),), - firstColor: Colors.red.shade400, - secondColor: Colors.white, - headerIcon: Lottie.asset(Assets.lottieConnectionfailed, - decoder: customDecoder, repeat: false,width: 200.0,height: 200.0)); + content: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25.0), + child: Text("Api services unavailable"), + ), + title: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Text( + "API KEY INVALID", + style: TextStyle( + color: Colors.red.shade500, + fontSize: 25.0, + fontWeight: FontWeight.bold), + ), + ), + firstColor: Colors.red.shade400, + secondColor: Colors.white, + headerIcon: Lottie.asset(Assets.lottieConnectionfailed, + decoder: customDecoder, + repeat: false, + width: 200.0, + height: 200.0)); showDialog( context: context, builder: (BuildContext context) { return dialog; }, ); - } Future customDecoder(List bytes) { return LottieComposition.decodeZip(bytes, filePicker: (files) { return files.firstWhere( - (f) => f.name.startsWith('animations/') && f.name.endsWith('.json'), + (f) => f.name.startsWith('animations/') && f.name.endsWith('.json'), ); }); } diff --git a/lib/components/custom_dialog.dart b/lib/components/custom_dialog.dart index 5c9bb07..0f5b004 100644 --- a/lib/components/custom_dialog.dart +++ b/lib/components/custom_dialog.dart @@ -64,13 +64,16 @@ class CustomDialog extends StatelessWidget { bottomLeft: Radius.circular(20.0), bottomRight: Radius.circular(20.0), )), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - title, - content, - ], + child: FittedBox( + fit: BoxFit.contain, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + title, + content, + ], + ), ), ), ) diff --git a/lib/controllers/showcase_controller.dart b/lib/controllers/showcase_controller.dart index cf69bdc..a7abbe9 100644 --- a/lib/controllers/showcase_controller.dart +++ b/lib/controllers/showcase_controller.dart @@ -148,5 +148,16 @@ class ShowcaseController extends GetxController { print("set-poi-done"); } + clearTutorialNeeds() + { + setPOICompleted(); + setToursCompleted(); + setMapsCompleted(); + setSettingsCompleted(); + setDashboardCompleted(); + setGeoQuestCompleted(); + setKmlBuilderCompleted(); + } + } \ No newline at end of file diff --git a/lib/controllers/speech_controller.dart b/lib/controllers/speech_controller.dart index 89883ee..b3ddffa 100644 --- a/lib/controllers/speech_controller.dart +++ b/lib/controllers/speech_controller.dart @@ -130,8 +130,11 @@ class SpeechController extends GetxController { void detectCommandWord() { var traversalList = wordQueue.value.toList().reversed.toList(); if(_needsDirectionWord) { - detectDirectionWord(wordQueue.value.toList(),0); - return; + var foundDir = detectDirectionWord(wordQueue.value.toList(),0); + //return; + if(foundDir) { + return; + } } for (final (index,token) in traversalList.indexed) { if (commands.contains(token.toLowerCase())) { @@ -148,11 +151,12 @@ class SpeechController extends GetxController { } } - void detectDirectionWord(List traversalList, int index) + bool detectDirectionWord(List traversalList, int index) { if(_currentCommand == SpeechCommands.STOP) { executeCommand(-1); + return true; } for(final (i,token) in traversalList.indexed) @@ -166,7 +170,7 @@ class SpeechController extends GetxController { if(moveDirections.contains(token)) { _needsDirectionWord = false; executeCommand(moveDirections.indexOf(token)); - return; + return true; } } case SpeechCommands.ZOOM: @@ -174,22 +178,24 @@ class SpeechController extends GetxController { if(zoomDirections.contains(token)) { _needsDirectionWord = false; executeCommand(zoomDirections.indexOf(token)); - return; + return true; } } case SpeechCommands.STOP: { _needsDirectionWord = false; executeCommand(-1); - return; + return true; } default: { print("mapTest: default/none case"); + return false; } } } + return false; } void executeCommand(int index) { diff --git a/lib/generated/assets.dart b/lib/generated/assets.dart index 6fba817..6a15a23 100644 --- a/lib/generated/assets.dart +++ b/lib/generated/assets.dart @@ -41,6 +41,7 @@ class Assets { static const String iconsTest = 'assets/icons/test.jpeg'; static const String iconsToursnotfound = 'assets/icons/toursnotfound.png'; static const String iconsTravel = 'assets/icons/travel.png'; + static const String iconsTutorial = 'assets/icons/tutorial.png'; static const String iconsVoices = 'assets/icons/voices.png'; static const String lottieAddplaces = 'assets/lottie/addplaces.lottie'; static const String lottieCongrats = 'assets/lottie/congrats.json'; diff --git a/lib/main.dart b/lib/main.dart index 3c0ac59..f2f32c8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -35,7 +35,6 @@ void main() { Get.lazyPut(() => GeoQuestController(),fenix: true); Get.lazyPut(() => ShowcaseController(),fenix: true); - // Get.lazyPut(() => WikiDataFetcher(), fenix: true); LGConnection client = Get.find(); client.connectToLG(); @@ -60,7 +59,7 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, initialRoute: '/', routes: { - '/': (context) => SplashScreen(), // Root route + '/': (context) => const SplashScreen(), // Root route // Settings route }, theme: ThemeData( diff --git a/lib/screens/dashboard.dart b/lib/screens/dashboard.dart index c6dac21..b3a1cb2 100644 --- a/lib/screens/dashboard.dart +++ b/lib/screens/dashboard.dart @@ -16,6 +16,7 @@ import 'package:super_liquid_galaxy_controller/screens/settings.dart'; import 'package:super_liquid_galaxy_controller/utils/galaxy_colors.dart'; import '../components/connection_flag.dart'; +import '../components/custom_dialog.dart'; import '../components/glassbox.dart'; import '../utils/constants.dart'; @@ -39,6 +40,7 @@ class _DashBoardState extends State { int selectedIndex = 0; TextEditingController keyController = TextEditingController(); + // late TutorialCoachMark tutorialCoachMark; final _key1 = GlobalKey(); final _key2 = GlobalKey(); final _key3 = GlobalKey(); @@ -50,13 +52,11 @@ class _DashBoardState extends State { initializeLGClient(); initializeApiClient(); showcaseController = Get.find(); - + /*createTutorial(); + Future.delayed(Duration.zero, showTutorial);*/ + //askForTutorial(); if (showcaseController.isFirstLaunchDashboard()) { - WidgetsBinding.instance.addPostFrameCallback( - (_) => ShowCaseWidget.of(context).startShowCase( - [_key1, _key2, _key3], - ), - ); + Future.delayed(Duration.zero, askForTutorial); } } @@ -157,6 +157,24 @@ class _DashBoardState extends State { Row( mainAxisSize: MainAxisSize.min, children: [ + Padding( + padding: EdgeInsets.symmetric( + vertical: 12.0, horizontal: 8.0), + child: GlassBox( + height: screenHeight * 0.05, + width: screenHeight * 0.05, + child: Icon( + Icons.info_outline, + size: screenHeight * 0.045, + color: Colors.white, + ), + onTap: () { + WidgetsBinding.instance.addPostFrameCallback( + (_) => ShowCaseWidget.of(context).startShowCase( + [_key1, _key2, _key3], + ), + ); + })), Padding( padding: EdgeInsets.symmetric( vertical: 12.0, horizontal: 20.0), @@ -210,7 +228,7 @@ class _DashBoardState extends State { FontWeight.bold), ), ), - ) + ), ], ), ); @@ -393,7 +411,8 @@ class _DashBoardState extends State { padding: const EdgeInsets.all(25.0), child: Showcase( key: _key3, - description: 'This is the Navigation Island to access all the various features.', + description: + 'This is the Navigation Island to access all the various features.', descTextStyle: const TextStyle( fontWeight: FontWeight.w500, color: Colors.black, @@ -808,6 +827,88 @@ class _DashBoardState extends State { } } + void askForTutorial() async { + print("here"); + var dialog = CustomDialog( + content: FittedBox( + fit: BoxFit.contain, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + InkWell( + onTap: () { + showcaseController.clearTutorialNeeds(); + Get.back(); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(5.0), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + " No ", + style: TextStyle(color: Colors.white, fontSize: 20.0), + ), + )), + ), + SizedBox(width: 25.0), + InkWell( + onTap: () { + WidgetsBinding.instance.addPostFrameCallback( + (_) => ShowCaseWidget.of(context).startShowCase( + [_key1, _key2, _key3], + ), + ); + Get.back(); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.green, + borderRadius: BorderRadius.circular(5.0), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "Sure", + style: TextStyle(color: Colors.white, fontSize: 20.0), + ), + )), + ), + ], + ), + ), + title: FittedBox( + fit: BoxFit.contain, + child: Padding( + padding: EdgeInsets.all(25.0), + child: Text( + "Would you Like to be shown \na tutorial of the app?", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.black, + fontSize: 25.0, + ), + )), + ), + firstColor: Colors.grey, + secondColor: Colors.white, + headerIcon: Padding( + padding: const EdgeInsets.all(16.0), + child: Image.asset(Assets.iconsTutorial, width: 150.0, height: 150.0), + )); + showDialog( + context: context, + builder: (BuildContext context) { + print("here2"); + return dialog; + }, + ); + } +} + /*Future testRun(String kml) async { await connectionClient.connectToLG(); File? file = await connectionClient.makeFile("TEST", kml); @@ -826,4 +927,119 @@ class _DashBoardState extends State { duration: 5.seconds, )); }*/ -} + +/*void showTutorial() { + tutorialCoachMark.show(context: context); + } + + void createTutorial() { + tutorialCoachMark = TutorialCoachMark( + targets: _createTargets(), + colorShadow: Colors.red, + textSkip: "SKIP", + paddingFocus: 10, + opacityShadow: 0.5, + imageFilter: ImageFilter.blur(sigmaX: 8, sigmaY: 8), + onFinish: () { + print("finish"); + }, + onClickTarget: (target) { + print('onClickTarget: $target'); + }, + onClickTargetWithTapPosition: (target, tapDetails) { + print("target: $target"); + print( + "clicked at position local: ${tapDetails.localPosition} - global: ${tapDetails.globalPosition}"); + }, + onClickOverlay: (target) { + print('onClickOverlay: $target'); + }, + onSkip: () { + print("skip"); + return true; + }, + ); + } + + List _createTargets() { + List targets = []; + targets.add( + TargetFocus( + identify: "keyBottomNavigation2", + keyTarget: _key1, + alignSkip: Alignment.bottomRight, + contents: [ + TargetContent( + align: ContentAlignz, + builder: (context, controller) { + return const Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Titulo lorem ipsum", + style: TextStyle( + color: Colors.white, + ), + ), + ], + ); + }, + ), + ], + ), + ); + targets.add( + TargetFocus( + identify: "keyBottomNavigation2", + keyTarget: _key2, + alignSkip: Alignment.bottomRight, + contents: [ + TargetContent( + align: ContentAlign.top, + builder: (context, controller) { + return const Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Titulo lorem ipsum", + style: TextStyle( + color: Colors.white, + ), + ), + ], + ); + }, + ), + ], + ), + ); + targets.add( + TargetFocus( + identify: "keyBottomNavigation2", + keyTarget: _key3, + alignSkip: Alignment.bottomRight, + contents: [ + TargetContent( + align: ContentAlign.top, + builder: (context, controller) { + return const Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Titulo lorem ipsum", + style: TextStyle( + color: Colors.white, + ), + ), + ], + ); + }, + ), + ], + ), + ); + return targets; + }*/ diff --git a/lib/screens/geoquest.dart b/lib/screens/geoquest.dart index b34c92b..5fbb3e0 100644 --- a/lib/screens/geoquest.dart +++ b/lib/screens/geoquest.dart @@ -134,7 +134,7 @@ class GeoQuestState extends State with TickerProviderStateMixin { children: [ Showcase( key: _key1, - description: 'You can check your accumulated score here.', + description: 'This is a Geo-Guessr like game where the goal is to place \nthe pointer as close to the mentioned state as quick as possible. \nEarn the highest scores! \nYou can check your accumulated score here.', descTextStyle: const TextStyle( fontWeight: FontWeight.w500, color: Colors.black, @@ -216,7 +216,12 @@ class GeoQuestState extends State with TickerProviderStateMixin { ), IconButton( onPressed: () { - geoQuestController.showStartMessage(); + //geoQuestController.showStartMessage(); + WidgetsBinding.instance.addPostFrameCallback( + (_) => ShowCaseWidget.of(context).startShowCase( + [_key1, _key2, _key3, _key4,_key5, _key6], + ), + ); }, color: Colors.white, icon: Icon( diff --git a/lib/screens/kml_builder.dart b/lib/screens/kml_builder.dart index 3f8b316..6571f30 100644 --- a/lib/screens/kml_builder.dart +++ b/lib/screens/kml_builder.dart @@ -134,6 +134,70 @@ class _KmlUploaderState extends State { ], ), centerTitle: true, + actions: [ + Padding( + padding: EdgeInsets.symmetric( + vertical: 12.0, horizontal: 8.0), + child: GlassBox( + height: screenHeight * 0.05, + width: screenHeight * 0.05, + child: Icon( + Icons.info_outline, + size: screenHeight * 0.045, + color: Colors.white, + ), + onTap: () { + WidgetsBinding.instance.addPostFrameCallback( + (_) => ShowCaseWidget.of(context).startShowCase( + [_key5, _key1, _key2, _key3, _key4], + ), + ); + })), + Obx(() { + return Padding( + padding: const EdgeInsets.all(12.0), + child: GlassBox( + height: screenHeight * 0.1, + width: screenHeight * 0.1, + cornerRadius: 8.0, + backgroundGradient: LinearGradient(colors: [ + Colors.grey.withOpacity(0.2), + Colors.grey.withOpacity(0.2) + ]), + child: ImageIcon( + const AssetImage(Assets.iconsSshIndicator), + color: + sshClient.isConnected.value + ? Colors.green + : Colors.red, + size: screenHeight * 0.06, + )), + ); + }), + /*Obx(() { + return Padding( + padding: const EdgeInsets.all(12.0), + child: GlassBox( + height: screenHeight * 0.1, + width: screenHeight * 0.1, + cornerRadius: 8.0, + backgroundGradient: LinearGradient(colors: [ + Colors.grey.withOpacity(0.2), + Colors.grey.withOpacity(0.2), + ]), + child: ImageIcon( + const AssetImage(Assets.iconsApiIndicator), + color: apiClient.isConnected.value + ? Colors.green + : Colors.red, + size: screenHeight * 0.07, + )), + ); + }),*/ + const SizedBox( + width: 50.0, + ) + ] ), body: Row( mainAxisSize: MainAxisSize.max, @@ -252,7 +316,7 @@ class _KmlUploaderState extends State { Showcase( key: _key2, description: - 'This can be used as a Visual Editor to add KML elements. \nThe pins are hold-and-drag to edit. \nThe Submit data button sends info from visual editor to the custom editor on the right side. \nAdd point is used to increase the KML element. \nIt also has a fullscreen mode to edit the element.', + 'This can be used as a Visual Editor to add KML elements. \nThe pins are hold-and-drag to edit. \nThe Submit data button sends info from visual editor to the custom editor. \nAdd point is used to increase the KML element.', descTextStyle: const TextStyle( fontWeight: FontWeight.w500, color: Colors.black, @@ -300,6 +364,13 @@ class _KmlUploaderState extends State { isLeading: true, onTap: () async { print("tapped"); + + if(!sshClient.isConnected.value) + { + showErrorSnackBar(); + return; + } + String filename = generateRandomString(7); await sshClient.connectToLG(); //await sshClient.clearKml(); @@ -405,7 +476,7 @@ class _KmlUploaderState extends State { callbackController.callBack!(elementIndex); }); }, - textStyle: TextStyle( + textStyle: const TextStyle( color: Colors.white, fontSize: 20.0), leadingIcon: Icon(kmlElements[elementIndex][1]), trailingIcon: const Row( @@ -655,4 +726,16 @@ class _KmlUploaderState extends State { )); } } + + void showErrorSnackBar() { + if (!Get.isSnackbarOpen) { + Get.showSnackbar(GetSnackBar( + backgroundColor: Colors.red.shade300, + title: "CONNECTION FAILED", + message: "The app is not connected to the LG rig.", + isDismissible: true, + duration: 5.seconds, + )); + } + } } diff --git a/lib/screens/maps_controller.dart b/lib/screens/maps_controller.dart index 6c5e0bf..5c137bf 100644 --- a/lib/screens/maps_controller.dart +++ b/lib/screens/maps_controller.dart @@ -21,6 +21,8 @@ import 'package:super_liquid_galaxy_controller/data_class/map_position.dart'; import 'package:super_liquid_galaxy_controller/data_class/place_suggestion_response.dart'; import 'package:super_liquid_galaxy_controller/generated/assets.dart'; +import '../components/glassbox.dart'; + class MapController extends StatefulWidget { const MapController({super.key}); @@ -114,31 +116,53 @@ class MapControllerState extends State { child: Material( color: Colors.transparent, child: Padding( - padding: const EdgeInsets.all(8.0), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - color: Colors.green.withOpacity(0.2), - child: Showcase( - key: _key1, - description: - 'You can use this to search any location by Address. \nIt automatically seeks you to the selected location.', - descTextStyle: const TextStyle( - fontWeight: FontWeight.w500, - color: Colors.black, - fontSize: 16, - ), - child: AutoCompleteLocationField( - hintText: "Enter Location to search here", - labelText: "", - iconData: Icons.search_rounded, - textInputType: TextInputType.text, - isPassword: false, - fillColor: Colors.white, - textColor: Colors.black, - autocompleteController: textController, - seekTo: goToSearchFeature, - ), + padding: const EdgeInsets.all(16.0), + child: Container( + child: Showcase( + key: _key1, + description: + 'You can use this to search any location by Address. \nIt automatically seeks you to the selected location.', + descTextStyle: const TextStyle( + fontWeight: FontWeight.w500, + color: Colors.black, + fontSize: 16, + ), + child: Row( + children: [ + Expanded( + flex: 9, + child: AutoCompleteLocationField( + hintText: "Enter Location to search here", + labelText: "", + iconData: Icons.search_rounded, + textInputType: TextInputType.text, + isPassword: false, + fillColor: Colors.white, + textColor: Colors.black, + autocompleteController: textController, + seekTo: goToSearchFeature, + ), + ), + Padding( + padding: EdgeInsets.symmetric( + vertical: 12.0, horizontal: 8.0), + child: GlassBox( + height: screenHeight * 0.05, + width: screenHeight * 0.05, + child: Icon( + Icons.info_outline, + size: screenHeight * 0.045, + color: Colors.white, + ), + onTap: () { + WidgetsBinding.instance.addPostFrameCallback( + (_) => ShowCaseWidget.of(context).startShowCase( + [_key1, _key2, _key3, _key4, _key5], + ), + ); + + })), + ], ), ), )), diff --git a/lib/screens/poi_exploration.dart b/lib/screens/poi_exploration.dart index 5226f63..028d3cc 100644 --- a/lib/screens/poi_exploration.dart +++ b/lib/screens/poi_exploration.dart @@ -229,6 +229,24 @@ class _PoiExplorationState extends State { ), centerTitle: true, actions: [ + Padding( + padding: EdgeInsets.symmetric( + vertical: 12.0, horizontal: 8.0), + child: GlassBox( + height: screenHeight * 0.05, + width: screenHeight * 0.05, + child: Icon( + Icons.info_outline, + size: screenHeight * 0.045, + color: Colors.white, + ), + onTap: () { + WidgetsBinding.instance.addPostFrameCallback( + (_) => ShowCaseWidget.of(context).startShowCase( + [_key1, _key2, _key3], + ), + ); + })), Obx(() { return Padding( padding: const EdgeInsets.all(12.0), diff --git a/lib/screens/tour_builder.dart b/lib/screens/tour_builder.dart index 28bda5b..92ef1f8 100644 --- a/lib/screens/tour_builder.dart +++ b/lib/screens/tour_builder.dart @@ -269,6 +269,24 @@ class _TourBuilderState extends State ), centerTitle: true, actions: [ + Padding( + padding: EdgeInsets.symmetric( + vertical: 12.0, horizontal: 8.0), + child: GlassBox( + height: screenHeight * 0.05, + width: screenHeight * 0.05, + child: Icon( + Icons.info_outline, + size: screenHeight * 0.045, + color: Colors.white, + ), + onTap: () { + WidgetsBinding.instance.addPostFrameCallback( + (_) => ShowCaseWidget.of(context).startShowCase( + [_key1, _key2, _key3, _key4,_key5], + ), + ); + })), Obx(() { return Padding( padding: const EdgeInsets.all(12.0), diff --git a/lib/tabs/apikey_tab.dart b/lib/tabs/apikey_tab.dart index 73d6df9..0b20edb 100644 --- a/lib/tabs/apikey_tab.dart +++ b/lib/tabs/apikey_tab.dart @@ -18,6 +18,7 @@ class ApiKeyTab extends StatefulWidget { class _ApiKeyTabState extends State with AutomaticKeepAliveClientMixin{ late double screenHeight; late double screenWidth; + TextEditingController keyController = TextEditingController(); @override Widget build(BuildContext context) { @@ -44,7 +45,7 @@ class _ApiKeyTabState extends State with AutomaticKeepAliveClientMixi }, urlLauncher2:(){ launchUrlFromLink( Uri.parse("https://myprojects.geoapify.com/projects"));}, - keyController: TextEditingController(), + keyController: keyController, ), ]), ), diff --git a/lib/tabs/connection_tab.dart b/lib/tabs/connection_tab.dart index 22ade67..f18a33c 100644 --- a/lib/tabs/connection_tab.dart +++ b/lib/tabs/connection_tab.dart @@ -137,15 +137,27 @@ class _ConnectionTabState extends State await lgConnection.showLogos(); var dialog = lgConnection.connectStatus() ? CustomDialog( - content: Text("SSH operations are now possible."), - title: Text("Connection established",style: TextStyle(color: Colors.green.shade500,fontSize: 25.0,fontWeight: FontWeight.bold),), + content: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25.0), + child: Text("SSH operations are now possible."), + ), + title: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Text("Connection established",style: TextStyle(color: Colors.green.shade500,fontSize: 25.0,fontWeight: FontWeight.bold),), + ), firstColor: Colors.green, secondColor: Colors.white, headerIcon: Lottie.asset(Assets.lottieConnected, decoder: customDecoder, repeat: false,width: 200.0,height: 200.0)) : CustomDialog( - content: Text("SSH operations unavailable."), - title: Text("Connection failed",style: TextStyle(color: Colors.red.shade500,fontSize: 25.0,fontWeight: FontWeight.bold),), + content: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25.0), + child: Text("SSH operations unavailable."), + ), + title: Padding( + padding: const EdgeInsets.all(16.0), + child: Text("Connection failed",style: TextStyle(color: Colors.red.shade500,fontSize: 25.0,fontWeight: FontWeight.bold),), + ), firstColor: Colors.red.shade400, secondColor: Colors.white, headerIcon: Lottie.asset(Assets.lottieConnectionfailed, diff --git a/lib/utils/balloongenerator.dart b/lib/utils/balloongenerator.dart index 6ef13a8..c71ecb5 100644 --- a/lib/utils/balloongenerator.dart +++ b/lib/utils/balloongenerator.dart @@ -168,18 +168,6 @@ class BalloonGenerator { " \n" + " \n'''; - /*Iterator iterator = nearbyPlaces.iterator(); - int iterationCount = 0; // Counter variable to keep track of iterations - while (iterator.hasNext() && iterationCount < 10) { - PlaceInfo placeInfo = iterator.next(); - sentence += " \n" + - " \n" + - " \n"; - iterationCount++; // Increment the counter variable - }*/ List nearbyPois = []; nearbyPois.addAll(list); int i =0; diff --git a/lib/utils/kmlgenerator.dart b/lib/utils/kmlgenerator.dart index 2af3352..2221664 100644 --- a/lib/utils/kmlgenerator.dart +++ b/lib/utils/kmlgenerator.dart @@ -8,7 +8,6 @@ import 'package:super_liquid_galaxy_controller/data_class/kml_element.dart'; import 'package:super_liquid_galaxy_controller/data_class/map_position.dart'; import 'package:super_liquid_galaxy_controller/data_class/place_details_response.dart'; import 'package:super_liquid_galaxy_controller/data_class/place_info.dart'; -import 'package:super_liquid_galaxy_controller/data_class/place_response.dart' as pr; import 'package:super_liquid_galaxy_controller/utils/constants.dart'; import 'package:super_liquid_galaxy_controller/utils/geo_utils.dart'; @@ -47,7 +46,7 @@ class KMLGenerator { static getCoordinateList(List list) { var coordinates = ''; for (final coordinate in list) { - coordinates += '${coordinate.longitude},${coordinate.latitude},250 '; + coordinates += '${coordinate.longitude},${coordinate.latitude},380 '; } return '''${coordinates}'''; } @@ -73,7 +72,7 @@ class KMLGenerator { 1 1 - clampToGround + relativeToGround ${getCoordinateList(placeMark.coordinates)} @@ -402,14 +401,14 @@ class KMLGenerator { 2 1 - clampToGround + relativeToGround '''; for (LatLng point in footprintPoints) { - kml += '${point.longitude},${point.latitude},0 '; + kml += '${point.longitude},${point.latitude},380 '; } kml += ''' @@ -483,14 +482,14 @@ class KMLGenerator { 2 1 - clampToGround + relativeToGround '''; for (LatLng point in footprintPoints) { - kml += '${point.longitude},${point.latitude},0 '; + kml += '${point.longitude},${point.latitude},380 '; } kml += ''' @@ -505,7 +504,6 @@ class KMLGenerator { } //MAIN FOOTPRINT FUNCTION BELOW - static String generatefootPrintLine( LatLng start, LatLng end, double dashLength, double gapLength) { final Distance distance = Distance(); @@ -582,6 +580,8 @@ class KMLGenerator { return kml; } + + //unused static double transformAngle(double angle) { // Normalize the input angle to be within [-180, 180] angle = angle % 360; @@ -602,6 +602,8 @@ class KMLGenerator { return transformedAngle; } + + //unused static String generateDashedLineString( LatLng start, LatLng end, double dashLength, double gapLength) { final Distance distance = Distance(); @@ -649,7 +651,7 @@ class KMLGenerator { 1 1 - clampToGround + relativeToGround ${getCoordinateList([ Coordinates.fromLatLng(roadEnd1), @@ -860,14 +862,14 @@ class KMLGenerator { 2 1 - clampToGround + relativeToGround '''; for (LatLng point in ellipsePoints) { - kml += '${point.longitude},${point.latitude},100 '; + kml += '${point.longitude},${point.latitude},380 '; } kml += ''' @@ -976,7 +978,7 @@ class KMLGenerator { 1 1 - clampToGround + relativeToGround ${getCoordinateList(coords)} diff --git a/pubspec.yaml b/pubspec.yaml index 79febed..e404725 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.10+11 +version: 1.0.11+12 environment: sdk: '>=3.2.3 <4.0.0'
\n" + - " \"picture\"\n" + - "

" + placeInfo.getTitle() + " " + placeInfo.getDescription() + "

\n" + - "