Skip to content

Commit

Permalink
Merge pull request #9 from LiquidGalaxyLAB/development
Browse files Browse the repository at this point in the history
PR9: Version 1.0
  • Loading branch information
VSBDev authored Aug 13, 2024
2 parents ac62e66 + 70c00ce commit c6da64a
Show file tree
Hide file tree
Showing 23 changed files with 1,604 additions and 932 deletions.
84 changes: 74 additions & 10 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,16 +1,80 @@
# lg_space_visualizations
# 🚀 Space Visualizations for Liquid Galaxy

This is an educational application dedicated to visualizing orbits and the Mars 2020 mission, utilizing the Liquid Galaxy platform, to provide immersive space exploration experiences.
## 📄Table of Contents
* [📚 About](#-about)
* [📝 Requirements](#-requirements)
* [👨‍💻 Building from source](#-building-from-source)
* [🌐 Connecting to Liquid Galaxy](#-connecting-to-LG)

## Getting Started
<a name="-about"></a>
## 📚 About

This project is a starting point for a Flutter application.
Space Visualizations for Liquid Galaxy is an application that showcases the [Mars 2020](https://science.nasa.gov/mission/mars-2020-perseverance/) NASA mission and some of the most famous Earth orbits. The application uses the [Liquid Galaxy](https://www.liquidgalaxy.eu) platform to provide immersive space exploration experiences. In the Mars mission section, users can interactively learn about the mission by visualizing 3D models, technical data, and the path of the Perseverance rover and Ingenuity drone. Users can see Mars from the perspective of the Perseverance rover with more than 220000 photos available. The photos can also be displayed on all Liquid Galaxy screens, providing a very immersive experience.

A few resources to get you started if this is your first Flutter project:
In the Earth orbit section, a list of orbits can be displayed in both the application and, with a realistic representation, on Liquid Galaxy Google Earth. Users can interact with these orbits and learn more about them.

- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
This project has been started as a [Google Summer of Code](https://summerofcode.withgoogle.com/about) 2024 project with the Liquid Galaxy Org.
Developed by Mattia Baggini
Mentor: Victor Sanchez
Liquid Galaxy Org Director: Andreu Ibañez

For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
<a name="-requirements"></a>
## 📝 Requirements

1. **Device Compatibility:**
- The application requires an Android tablet running **Android 13 (API level 33)** or higher.

2. **Liquid Galaxy Integration (Optional):**
- To fully utilize the Liquid Galaxy features, ensure that the **Liquid Galaxy core** is installed. For detailed installation instructions, please refer to the [Liquid Galaxy repository](https://github.com/LiquidGalaxyLAB/liquid-galaxy).

3. **Displaying Rover Photos on Liquid Galaxy (Optional):**
- To enable the display of rover photos on the Liquid Galaxy screens, install the **display_images_service**. For more information and installation guidelines, visit the [display_images_service repository](https://github.com/0xbaggi/display_images_service).


<a name="-building-from-source"></a>
## 👨‍💻 Building from source

First, open a new terminal and clone the repository with the command:

```bash
git clone https://github.com/LiquidGalaxyLAB/LG-Space-Visualizations.git
```

To use the Google Maps widget, you'll need to set up an API key for the [Google Maps SDK](https://developers.google.com/maps/documentation/android-sdk/overview). Follow these steps:

1. Obtain a Google Maps API Key by following the instructions [here](https://developers.google.com/maps/documentation/android-sdk/get-api-key).
2. Once you have the API key, navigate to the `android/app/main` directory within the cloned repository.
3. Open the **AndroidManifest.xml** file in a text editor.
4. Locate the following section in the **AndroidManifest.xml** file:

```XML
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY" />
```

Now we can run the application, follow these steps:

1. Navigate to the project directory:
```bash
cd LG-Space-Visualizations
```
2. Install the necessary dependencies:
```bash
flutter pub get
```
3. Launch the app:
```bash
flutter run
```
> **Important:** Ensure you have a tablet device connected or an Android tablet emulator running before executing the `flutter run` command.
<a name="-connecting-to-LG"></a>
## 🌐 Connecting to Liquid Galaxy

1. **Open the Application**: Launch the application on your device and go to the settings page.
![usage1](assets/readme_images/usage1.png)
2. **Enter Liquid Galaxy Details**: Insert your Liquid Galaxy information into the form and click "Connect"
![usage2](assets/readme_images/usage2.png)
3. **Confirmation**: If a confirmation message appears, your application is successfully connected!
![usage3](assets/readme_images/usage3.png)
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ android {
minSdkVersion 33
targetSdkVersion 34
versionCode 6
versionName '1.6.0'
versionName '2.0.0'
}

signingConfigs {
Expand Down
Binary file added assets/readme_images/usage1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/readme_images/usage2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/readme_images/usage3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 21 additions & 18 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:lg_space_visualizations/utils/routes.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:showcaseview/showcaseview.dart';

void main() {
// Ensures that an instance of the widgets library is initialized.
Expand Down Expand Up @@ -34,23 +35,25 @@ class Launcher extends StatelessWidget {

@override
Widget build(BuildContext context) {
return Container(
// Set a background image for the entire app.
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/background.jpg"),
fit: BoxFit.fill,
),
),
child: MaterialApp(
title: 'SpaceVisualizations',
// Set the app theme with a custom font.
theme: ThemeData(fontFamily: 'Forgotten Futurist'),
// Define the route generator function.
onGenerateRoute: makeRoute,
// Set the initial route to the splash screen.
initialRoute: '/splash',
),
);
return ShowCaseWidget(
builder: (context) => Container(
// Set a background image for the entire app.
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/background.jpg"),
fit: BoxFit.fill,
),
),
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'SpaceVisualizations',
// Set the app theme with a custom font.
theme: ThemeData(fontFamily: 'Forgotten Futurist'),
// Define the route generator function.
onGenerateRoute: makeRoute,
// Set the initial route to the splash screen.
initialRoute: '/splash',
),
));
}
}
152 changes: 96 additions & 56 deletions lib/pages/cameras_filters_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import 'package:lg_space_visualizations/widget/button.dart';
import 'package:lg_space_visualizations/widget/custom_dialog.dart';
import 'package:lg_space_visualizations/widget/custom_icon.dart';
import 'package:lg_space_visualizations/widget/pop_up.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:showcaseview/showcaseview.dart';

/// A page that allows users to filter camera images by date and number of photos.
///
Expand Down Expand Up @@ -43,6 +45,12 @@ class _CamerasFiltersPageState extends State<CamerasFiltersPage> {
// Custom thumb shape for the range slider
late IndicatorRangeSliderThumbShape<int> indicatorRangeSliderThumbShape;

/// The showcase keys
final GlobalKey _oneShowCase = GlobalKey();
final GlobalKey _twoShowCase = GlobalKey();
final GlobalKey _threeShowCase = GlobalKey();
final GlobalKey _fourShowCase = GlobalKey();

@override
void initState() {
super.initState();
Expand All @@ -55,6 +63,17 @@ class _CamerasFiltersPageState extends State<CamerasFiltersPage> {
indicatorRangeSliderThumbShape = IndicatorRangeSliderThumbShape(
widget.filter.rangePhotosValuesStart,
widget.filter.rangePhotosValuesEnd);

// Show the showcase tutorial if it's the first time the user opens the page
SharedPreferences.getInstance().then((prefs) {
if (prefs.getBool('showcaseCamerasFilterPage') ?? true) {
WidgetsBinding.instance.addPostFrameCallback((_) {
ShowCaseWidget.of(context).startShowCase(
[_oneShowCase, _twoShowCase, _threeShowCase, _fourShowCase]);
prefs.setBool('showcaseCamerasFilterPage', false);
});
}
});
}

/// Displays a date picker dialog to select a date.
Expand Down Expand Up @@ -152,19 +171,24 @@ class _CamerasFiltersPageState extends State<CamerasFiltersPage> {
left: spaceBetweenWidgets,
right: spaceBetweenWidgets,
bottom: spaceBetweenWidgets / 2),
child: Row(
children: [
CustomIcon(
name: 'startdate', size: 40, color: secondaryColor),
SizedBox(width: spaceBetweenWidgets),
_buildDateSelector('start', true, _selectedStartDate),
SizedBox(width: 4 * spaceBetweenWidgets),
CustomIcon(
name: 'enddate', size: 40, color: secondaryColor),
SizedBox(width: spaceBetweenWidgets),
_buildDateSelector('end', false, _selectedEndDate),
],
)),
child: Showcase(
key: _oneShowCase,
targetBorderRadius: BorderRadius.circular(borderRadius),
title: oneShowcaseCamerasFiltersTitle,
description: oneShowcaseCamerasFiltersDescription,
child: Row(
children: [
CustomIcon(
name: 'startdate', size: 40, color: secondaryColor),
SizedBox(width: spaceBetweenWidgets),
_buildDateSelector('start', true, _selectedStartDate),
SizedBox(width: 4 * spaceBetweenWidgets),
CustomIcon(
name: 'enddate', size: 40, color: secondaryColor),
SizedBox(width: spaceBetweenWidgets),
_buildDateSelector('end', false, _selectedEndDate),
],
))),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(filterPhotoNumberText, style: middleTitle),
Button(
Expand All @@ -191,28 +215,34 @@ class _CamerasFiltersPageState extends State<CamerasFiltersPage> {
offset: const Offset(0, -10),
child: Divider(color: grey, thickness: 1)),
SizedBox(height: spaceBetweenWidgets / 4),
SliderTheme(
data: SliderThemeData(
showValueIndicator: ShowValueIndicator.never,
rangeThumbShape: indicatorRangeSliderThumbShape,
),
child: RangeSlider(
values: _currentRangeValues,
onChanged: (values) {
indicatorRangeSliderThumbShape.start = values.start.toInt();
indicatorRangeSliderThumbShape.end = values.end.toInt();
setState(() => _currentRangeValues = values);
},
activeColor: secondaryColor,
inactiveColor: secondaryColor.withOpacity(0.5),
max: divisions.toDouble(),
min: 1,
divisions: divisions,
labels: RangeLabels(
_currentRangeValues.start.round().toString(),
_currentRangeValues.end.round().toString(),
),
)),
Showcase(
key: _twoShowCase,
targetBorderRadius: BorderRadius.circular(borderRadius),
title: twoShowcaseCamerasFiltersTitle,
description: twoShowcaseCamerasFiltersDescription,
child: SliderTheme(
data: SliderThemeData(
showValueIndicator: ShowValueIndicator.never,
rangeThumbShape: indicatorRangeSliderThumbShape,
),
child: RangeSlider(
values: _currentRangeValues,
onChanged: (values) {
indicatorRangeSliderThumbShape.start =
values.start.toInt();
indicatorRangeSliderThumbShape.end = values.end.toInt();
setState(() => _currentRangeValues = values);
},
activeColor: secondaryColor,
inactiveColor: secondaryColor.withOpacity(0.5),
max: divisions.toDouble(),
min: 1,
divisions: divisions,
labels: RangeLabels(
_currentRangeValues.start.round().toString(),
_currentRangeValues.end.round().toString(),
),
))),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expand Down Expand Up @@ -243,28 +273,38 @@ class _CamerasFiltersPageState extends State<CamerasFiltersPage> {
Transform.translate(
offset: const Offset(0, -10),
child: Divider(color: grey, thickness: 1)),
_buildCameraGrid(),
Showcase(
key: _threeShowCase,
targetBorderRadius: BorderRadius.circular(borderRadius),
title: threeShowcaseCamerasFiltersTitle,
description: threeShowcaseCamerasFiltersDescription,
child: _buildCameraGrid()),
const Spacer(),
Button(
color: secondaryColor,
padding: EdgeInsets.only(
top: spaceBetweenWidgets / 4,
bottom: spaceBetweenWidgets / 4),
text: showResultButtonText,
borderRadius: BorderRadius.circular(borderRadius),
icon:
CustomIcon(name: 'search', size: 40, color: backgroundColor),
onPressed: () {
Filter.storeFilter(
_currentRangeValues.start.round(),
_currentRangeValues.end.round(),
_selectedStartDate,
_selectedEndDate,
_selectedCameras);
Navigator.removeRoute(context, ModalRoute.of(context)!);
Navigator.pushReplacementNamed(context, '/cameras');
},
)
Showcase(
key: _fourShowCase,
targetBorderRadius: BorderRadius.circular(borderRadius),
title: fourShowcaseCamerasFiltersTitle,
description: fourShowcaseCamerasFiltersDescription,
child: Button(
color: secondaryColor,
padding: EdgeInsets.only(
top: spaceBetweenWidgets / 4,
bottom: spaceBetweenWidgets / 4),
text: showResultButtonText,
borderRadius: BorderRadius.circular(borderRadius),
icon: CustomIcon(
name: 'search', size: 40, color: backgroundColor),
onPressed: () {
Filter.storeFilter(
_currentRangeValues.start.round(),
_currentRangeValues.end.round(),
_selectedStartDate,
_selectedEndDate,
_selectedCameras);
Navigator.removeRoute(context, ModalRoute.of(context)!);
Navigator.pushReplacementNamed(context, '/cameras');
},
))
],
),
),
Expand Down
Loading

0 comments on commit c6da64a

Please sign in to comment.