Compare commits

..

3 Commits

Author SHA1 Message Date
Darshan
4298f4d32b fix: spacing. 2025-03-18 13:46:59 +05:30
Darshan
43de5c17f1 Merge remote-tracking branch 'origin/env-support' into env-support 2025-03-18 13:10:27 +05:30
Darshan
2dea779758 design fixes. 2025-03-18 13:10:17 +05:30
105 changed files with 445 additions and 4347 deletions

3
.env.example Normal file
View File

@ -0,0 +1,3 @@
APPWRITE_PROJECT_ID=
APPWRITE_PROJECT_NAME=
APPWRITE_PUBLIC_ENDPOINT=

View File

@ -1,7 +0,0 @@
APPWRITE_PROJECT_ID=<APPWRITE_PROJECT_ID>
APPWRITE_PROJECT_NAME=<Flutter Projects Name>
APPWRITE_PUBLIC_ENDPOINT=<YOUR_API_ENDPOINT/v1>
PTV_GEOLINK_API_KEY=<YOUR_GEOLINK_API_KEY>
APPWRITE_DATABASE_ID=<DatabaseID>
APPWRITE_COLLECTION_ID=<Collection_ID>
TANKSTOPS_BASE_URL=https://api.e-control.at/sprit/1.0/search/gas-stations/by-address?latitude=<lat>&longitude=<lon>&fuelType=DIE<SUPSuperOrDIEDiesel>&includeClosed=false

View File

@ -14,7 +14,7 @@ This guide will help you quickly set up, customize, and build your Flutter app.
Clone this repository to your local machine using Git or directly from `Android Studio`:
```bash
git clone https://gitea.joshihomeserver.ipv64.net/josiadmin/MyNewAppWriteTankApp.git
git clone https://github.com/appwrite/starter-for-flutter
```
Alternatively, open the repository URL in `Android Studio` to clone it directly.

View File

@ -7,11 +7,6 @@
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
analyzer:
errors:
unused_field: ignore
avoid_print: ignore
unnecessary_overrides: ignore
include: package:flutter_lints/flutter.yaml
linter:

View File

@ -5,8 +5,8 @@ plugins {
}
android {
ndkVersion = "27.0.12077973"
namespace = "com.example.flutter_new_tank_app310725"
ndkVersion = "25.1.8937393"
namespace = "io.appwrite.flutter"
compileSdk = flutter.compileSdkVersion
compileOptions {
@ -19,7 +19,7 @@ android {
}
defaultConfig {
applicationId = "com.example.flutter_new_tank_app310725"
applicationId = "io.appwrite.flutter"
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion

View File

@ -1,18 +1,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:label="Tank Guru">
<service android:name="com.baseflow.geolocator.GeolocatorLocationService"
android:foregroundServiceType="location" />
android:label="AppwriteStarterKit">
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"

View File

@ -1,4 +1,4 @@
package com.example.flutter_new_tank_app310725
package io.appwrite.flutter
import io.flutter.embedding.android.FlutterActivity

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item>
<item>
<bitmap android:gravity="center" android:src="@drawable/splash"/>
</item>
<item android:bottom="24dp">
<bitmap android:gravity="bottom" android:src="@drawable/branding"/>
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item>
<item>
<bitmap android:gravity="center" android:src="@drawable/splash"/>
</item>
<item android:bottom="24dp">
<bitmap android:gravity="bottom" android:src="@drawable/branding"/>
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
<item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item>
<item>
<bitmap android:gravity="center" android:src="@drawable/splash"/>
</item>
<item android:bottom="24dp">
<bitmap android:gravity="bottom" android:src="@drawable/branding"/>
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
<item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item>
<item>
<bitmap android:gravity="center" android:src="@drawable/splash"/>
</item>
<item android:bottom="24dp">
<bitmap android:gravity="bottom" android:src="@drawable/branding"/>
</item>
</layer-list>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#19191D</item>
<item name="android:windowSplashScreenIconBackgroundColor">#19191D</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -5,6 +5,10 @@
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#EDEDF0</item>
<item name="android:windowSplashScreenIconBackgroundColor">#EDEDF0</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -2,16 +2,14 @@
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip

View File

@ -1,29 +0,0 @@
#!/bin/bash
# Check if .env file exists
if [ ! -f .env ]; then
{
echo "APPWRITE_PROJECT_ID=$APPWRITE_PROJECT_ID"
echo "APPWRITE_PROJECT_NAME=$APPWRITE_PROJECT_NAME"
echo "APPWRITE_PUBLIC_ENDPOINT=$APPWRITE_PUBLIC_ENDPOINT"
} >> .env
fi
# Read .env file and convert it to --dart-define arguments
ARGS=""
while IFS='=' read -r key value || [ -n "$key" ]; do
# Ignore empty lines and comments
if [[ -n "$key" && ! "$key" =~ ^# ]]; then
ARGS+=" --dart-define=${key}=\"${value}\""
fi
done < .env
# Build Flutter web
eval flutter build web "$ARGS"
# If --preview flag is provided, run a local preview server
if [ "$1" == "--preview" ]; then
echo "Starting preview server at http://localhost:3000..."
cd build/web || exit 1
python3 -m http.server 3000
fi

View File

@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>13.0</string>
<string>12.0</string>
</dict>
</plist>

View File

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '13.0'
# platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

View File

@ -6,16 +6,11 @@ PODS:
- Flutter
- flutter_web_auth_2 (3.0.0):
- Flutter
- geolocator_apple (1.2.0):
- Flutter
- FlutterMacOS
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- printing (1.0.0):
- Flutter
- url_launcher_ios (0.0.1):
- Flutter
@ -24,10 +19,8 @@ DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- flutter_web_auth_2 (from `.symlinks/plugins/flutter_web_auth_2/ios`)
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- printing (from `.symlinks/plugins/printing/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
EXTERNAL SOURCES:
@ -39,28 +32,22 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_native_splash/ios"
flutter_web_auth_2:
:path: ".symlinks/plugins/flutter_web_auth_2/ios"
geolocator_apple:
:path: ".symlinks/plugins/geolocator_apple/darwin"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
printing:
:path: ".symlinks/plugins/printing/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_native_splash: 6cad9122ea0fad137d23137dd14b937f3e90b145
flutter_web_auth_2: 5c8d9dcd7848b5a9efb086d24e7a9adcae979c80
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
printing: 54ff03f28fe9ba3aa93358afb80a8595a071dd07
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_native_splash: f71420956eb811e6d310720fee915f1d42852e7a
flutter_web_auth_2: 06d500582775790a0d4c323222fcb6d7990f9603
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
PODFILE CHECKSUM: 4f1c12611da7338d21589c0b2ecd6bd20b109694
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
COCOAPODS: 1.16.2

View File

@ -454,11 +454,10 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
@ -466,21 +465,21 @@
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9AAEF3FADF29177722D56E5C /* Pods-Runner.profile.xcconfig */;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = NTNRKTMT87;
DEVELOPMENT_TEAM = Y9G8UWM9SH;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_new_tank_app310725;
PRODUCT_BUNDLE_IDENTIFIER = io.appwrite.flutter;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -498,7 +497,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_new_tank_app310725.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = io.appwrite.flutter.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -516,7 +515,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_new_tank_app310725.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = io.appwrite.flutter.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@ -532,7 +531,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_new_tank_app310725.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = io.appwrite.flutter.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@ -588,7 +587,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -639,11 +638,10 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
@ -660,14 +658,14 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = NTNRKTMT87;
DEVELOPMENT_TEAM = Y9G8UWM9SH;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_new_tank_app310725;
PRODUCT_BUNDLE_IDENTIFIER = io.appwrite.flutter;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -679,21 +677,21 @@
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 6CF6DACC519FF36038FF3CFC /* Pods-Runner.release.xcconfig */;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = NTNRKTMT87;
DEVELOPMENT_TEAM = Y9G8UWM9SH;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_new_tank_app310725;
PRODUCT_BUNDLE_IDENTIFIER = io.appwrite.flutter;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -713,7 +711,7 @@
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Profile;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
@ -723,7 +721,7 @@
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Profile;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
@ -733,7 +731,7 @@
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Profile;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};

View File

@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
@ -55,13 +54,11 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">

View File

@ -2,14 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to your location to find nearby gas stations and services.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to your location to track your position even when the app is in the background.</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>

View File

@ -1,24 +0,0 @@
//import 'pages/appwritetest/home.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import './utils/extensions/sample_routes.dart';
import './pages/login/login_view.dart';
class AppwriteApp extends StatelessWidget {
const AppwriteApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Tank Guru AppWrite',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.dark(),
),
initialRoute: LoginPage.namedRoute,
getPages: SampleRouts.samplePages,
);
}
}

View File

@ -1,36 +0,0 @@
class ChartData {
final double dateInMilliseconds;
final double liters;
final double pricePerLiter;
final double totalPrice;
ChartData({
required this.dateInMilliseconds,
required this.liters,
required this.pricePerLiter,
required this.totalPrice,
});
}
class PricePoints {
final double x;
final double y;
PricePoints({required this.x, required this.y});
}
class SumDataModel {
late String? szMonth;
late String? szSumme;
late String? szVerbrauch;
late int? mnTankungen;
SumDataModel(this.szMonth, this.szSumme, this.szVerbrauch, this.mnTankungen);
}
class YearModel {
final String szDescription;
final int mnYear;
YearModel(this.szDescription, this.mnYear);
}

View File

@ -1,294 +0,0 @@
// ignore_for_file: unnecessary_this
class GasModel {
int? id;
String? name;
Location? location;
Contact? contact;
List<OpeningHours>? openingHours;
OfferInformation? offerInformation;
PaymentMethods? paymentMethods;
PaymentArrangements? paymentArrangements;
int? position;
bool? open;
double? distance;
List<Prices>? prices;
GasModel(
{int? id,
String? name,
Location? location,
Contact? contact,
List<OpeningHours>? openingHours,
OfferInformation? offerInformation,
PaymentMethods? paymentMethods,
PaymentArrangements? paymentArrangements,
int? position,
bool? open,
double? distance,
List<Prices>? prices}) {
if (id != null) {
this.id = id;
}
if (name != null) {
this.name = name;
}
if (location != null) {
this.location = location;
}
if (contact != null) {
this.contact = contact;
}
if (openingHours != null) {
this.openingHours = openingHours;
}
if (offerInformation != null) {
this.offerInformation = offerInformation;
}
if (paymentMethods != null) {
this.paymentMethods = paymentMethods;
}
if (paymentArrangements != null) {
this.paymentArrangements = paymentArrangements;
}
if (position != null) {
this.position = position;
if (open != null) {
this.open = open;
}
if (distance != null) {
this.distance = distance;
}
if (prices != null) {
this.prices = prices;
}
}
}
GasModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
location =
json['location'] != null ? Location.fromJson(json['location']) : null;
contact =
json['contact'] != null ? Contact.fromJson(json['contact']) : null;
if (json['openingHours'] != null) {
openingHours = <OpeningHours>[];
json['openingHours'].forEach((v) {
openingHours!.add(OpeningHours.fromJson(v));
});
}
offerInformation = json['offerInformation'] != null
? OfferInformation.fromJson(json['offerInformation'])
: null;
paymentMethods = json['paymentMethods'] != null
? PaymentMethods.fromJson(json['paymentMethods'])
: null;
paymentArrangements = json['paymentArrangements'] != null
? PaymentArrangements.fromJson(json['paymentArrangements'])
: null;
position = json['position'];
open = json['open'];
distance = json['distance'];
if (json['prices'] != null) {
prices = <Prices>[];
json['prices'].forEach((v) {
prices!.add(Prices.fromJson(v));
});
}
}
}
class Location {
String? address;
String? postalCode;
String? city;
double? latitude;
double? longitude;
Location(
{String? address,
String? postalCode,
String? city,
double? latitude,
double? longitude}) {
if (address != null) {
this.address = address;
}
if (postalCode != null) {
this.postalCode = postalCode;
}
if (city != null) {
this.city = city;
}
if (latitude != null) {
this.latitude = latitude;
}
if (longitude != null) {
this.longitude = longitude;
}
}
Location.fromJson(Map<String, dynamic> json) {
address = json['address'];
postalCode = json['postalCode'];
city = json['city'];
latitude = json['latitude'];
longitude = json['longitude'];
}
}
class Contact {
String? telephone;
String? website;
Contact({String? telephone, String? website}) {
if (telephone != null) {
this.telephone = telephone;
}
if (website != null) {
this.website = website;
}
}
Contact.fromJson(Map<String, dynamic> json) {
telephone = json['telephone'];
website = json['website'];
}
}
class OpeningHours {
String? day;
String? label;
int? order;
String? from;
String? to;
OpeningHours(
{String? day, String? label, int? order, String? from, String? to}) {
if (day != null) {
this.day = day;
}
if (label != null) {
this.label = label;
}
if (order != null) {
this.order = order;
}
if (from != null) {
this.from = from;
}
if (to != null) {
this.to = to;
}
}
OpeningHours.fromJson(Map<String, dynamic> json) {
day = json['day'];
label = json['label'];
order = json['order'];
from = json['from'];
to = json['to'];
}
}
class OfferInformation {
bool? service;
bool? selfService;
bool? unattended;
OfferInformation({bool? service, bool? selfService, bool? unattended}) {
if (service != null) {
this.service = service;
}
if (selfService != null) {
this.selfService = selfService;
}
if (unattended != null) {
this.unattended = unattended;
}
}
OfferInformation.fromJson(Map<String, dynamic> json) {
service = json['service'];
selfService = json['selfService'];
unattended = json['unattended'];
}
}
class PaymentMethods {
bool? cash;
bool? debitCard;
bool? creditCard;
String? others;
PaymentMethods( {bool? cash, bool? debitCard, bool? creditCard, String? others}) {
if (cash != null) {
this.cash = cash;
}
if (debitCard != null) {
this.debitCard = debitCard;
}
if (creditCard != null) {
this.creditCard = creditCard;
}
if (others != null) {
this.others = others;
}
}
PaymentMethods.fromJson(Map<String, dynamic> json) {
cash = json['cash'];
debitCard = json['debitCard'];
creditCard = json['creditCard'];
others = json['others'];
}
}
class PaymentArrangements {
bool? cooperative;
bool? clubCard;
PaymentArrangements({bool? cooperative, bool? clubCard}) {
if (cooperative != null) {
this.cooperative = cooperative;
}
if (clubCard != null) {
this.clubCard = clubCard;
}
}
PaymentArrangements.fromJson(Map<String, dynamic> json) {
cooperative = json['cooperative'];
clubCard = json['clubCard'];
}
}
class Prices {
String? fuelType;
double? amount;
String? label;
Prices({String? fuelType, double? amount, String? label}) {
if (fuelType != null) {
this.fuelType = fuelType;
}
if (amount != null) {
this.amount = amount;
}
if (label != null) {
this.label = label;
}
}
Prices.fromJson(Map<String, dynamic> json) {
fuelType = json['fuelType'];
amount = json['amount'];
label = json['label'];
}
}

View File

@ -1,10 +0,0 @@
class AppWriteLoginModel {
String clientName;
String clientId;
AppWriteLoginModel({
this.clientName ='',
this.clientId='',
});
}

View File

@ -1,15 +0,0 @@
class AppWriteMapTrackPointsModel {
String szUserId;
String szAppWriteTrackUniqueId;
double mnLongitudeTrackPoint;
double mnLatitudeTrackPoint;
String szDateTimeTrackPoint;
AppWriteMapTrackPointsModel({
required this.szUserId,
required this.szAppWriteTrackUniqueId,
required this.mnLongitudeTrackPoint,
required this.mnLatitudeTrackPoint,
required this.szDateTimeTrackPoint,
});
}

View File

@ -1,58 +0,0 @@
class AppWriteTankModel {
String documentId;
String userId;
String date;
String odometer;
String liters;
String pricePerLiter;
String location;
String? imageFileId;
String? imageFileName;
String? imageFileUrl;
int? mnIndexCount;
String? szSummePreis;
AppWriteTankModel({
required this.documentId,
required this.userId,
required this.date,
required this.odometer,
required this.liters,
required this.pricePerLiter,
required this.location,
this.imageFileId,
this.imageFileName,
this.imageFileUrl,
}):szSummePreis = (double.tryParse(liters) != null && double.tryParse(pricePerLiter) != null)
? (double.parse(liters) * double.parse(pricePerLiter)).toStringAsFixed(2)
: null;
factory AppWriteTankModel.fromMap(Map<String, dynamic> map) {
return AppWriteTankModel(
documentId: map['\$id'] ?? '',
userId: map['userId'] ?? '',
date: map['date'] ?? '',
odometer: map['odometer']?.toString() ?? '',
liters: map['liters']?.toString() ?? '',
pricePerLiter: map['pricePerLiter']?.toString() ?? '',
location: map['location'] ?? '',
imageFileId: map['imageFileId'],
imageFileName: map['imageFileName'],
imageFileUrl: map['imageFileUrl'],
);
}
Map<String, dynamic> toMap() {
return {
'\$id': documentId,
'userId': userId,
'date': date,
'odometer': odometer,
'liters': liters,
'pricePerLiter': pricePerLiter,
'location': location,
'imageFileId': imageFileId,
'imageFileName': imageFileName,
'imageFileUrl': imageFileUrl,
};
}
}

View File

@ -1,22 +1,20 @@
import 'package:appwrite/models.dart' as models;
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:intl/intl.dart';
import 'package:appwrite/appwrite.dart';
import '../../data/models/log.dart';
import '../../data/models/project_info.dart';
import 'package:appwrite_flutter_starter_kit/data/models/log.dart';
import 'package:appwrite_flutter_starter_kit/data/models/project_info.dart';
/// A repository responsible for handling network interactions with the Appwrite server.
///
/// It provides a helper method to ping the server.
class AppwriteRepository {
static const String pingPath = "/ping";
// static const String appwriteProjectId = String.fromEnvironment('APPWRITE_PROJECT_ID');
// static const String appwriteProjectName = String.fromEnvironment('APPWRITE_PROJECT_NAME');
// static const String appwritePublicEndpoint = String.fromEnvironment('APPWRITE_PUBLIC_ENDPOINT');
static const String appwriteProjectId = String.fromEnvironment('APPWRITE_PROJECT_ID');
static const String appwriteProjectName = String.fromEnvironment('APPWRITE_PROJECT_NAME');
static const String appwritePublicEndpoint = String.fromEnvironment('APPWRITE_PUBLIC_ENDPOINT');
final Client _client = Client()
.setProject(dotenv.get('APPWRITE_PROJECT_ID'))
.setEndpoint(dotenv.get('APPWRITE_PUBLIC_ENDPOINT'));
.setProject(appwriteProjectId)
.setEndpoint(appwritePublicEndpoint);
late final Account _account;
late final Databases _databases;
@ -33,9 +31,9 @@ class AppwriteRepository {
ProjectInfo getProjectInfo() {
return ProjectInfo(
endpoint: dotenv.get('APPWRITE_PUBLIC_ENDPOINT'),
projectId: dotenv.get('APPWRITE_PROJECT_ID'),
projectName: dotenv.get('APPWRITE_PROJECT_NAME'),
endpoint: appwritePublicEndpoint,
projectId: appwriteProjectId,
projectName: appwriteProjectName,
);
}
@ -70,64 +68,4 @@ class AppwriteRepository {
String _getCurrentDate() {
return DateFormat("MMM dd, HH:mm").format(DateTime.now());
}
Future<dynamic> logout() async =>
await _account.deleteSession(sessionId: 'current');
Future<models.Session> login(Map map) async =>
await _account.createEmailPasswordSession(
email: map['email'],
password: map['password'],
);
Future<models.Session> signUpAnonymus() async =>
await _account.createAnonymousSession();
Future<models.User> signup(Map map) async => _account.create(
userId: ID.unique(),
email: map['email'],
password: map['password'],
name: map['name'],
);
Future<models.User> get getCurrentUser => _account.get();
// Tank Stop CRUD operations
// Create, Update, Get, List Tank Stops
Future<models.Document> createTankStop(Map map) async {
final response = await _databases.createDocument(
databaseId: dotenv.get('APPWRITE_DATABASE_ID'),
collectionId: dotenv.get('APPWRITE_COLLECTION_ID'),
documentId: ID.unique(),
data: map,
);
return response;
}
Future<models.DocumentList> listTankStops(String userId) async {
final response = await _databases.listDocuments(
databaseId: dotenv.get('APPWRITE_DATABASE_ID'),
collectionId: dotenv.get('APPWRITE_COLLECTION_ID'),
queries: [Query.equal('userId', userId)],
);
return response;
}
Future<models.Document> updateTankStop(String documentId, Map<String, dynamic> map) async {
final response = await _databases.updateDocument(
databaseId: dotenv.get('APPWRITE_DATABASE_ID'),
collectionId: dotenv.get('APPWRITE_COLLECTION_ID'),
documentId: documentId,
data: map,
);
return response;
}
Future<dynamic> deleteTankStop(String documentId) async {
return await _databases.deleteDocument(
databaseId: dotenv.get('APPWRITE_DATABASE_ID'),
collectionId: dotenv.get('APPWRITE_COLLECTION_ID'),
documentId: documentId,
);
}
}

View File

@ -1,40 +0,0 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:http/http.dart' as http;
class GasStationRepository {
static final GasStationRepository _instance =
GasStationRepository._internal();
/// Singleton instance getter
factory GasStationRepository() => _instance;
//Constructor???
GasStationRepository._internal() {
//init for something
}
Future<dynamic> getGasStationsLocations(Map map) async {
List<dynamic> data = [];
var lat = map['lat'];
var lng = map['lng'];
var gas = map['gas'];
// Hier kannst du die Logik hinzufügen, um den Standort zu verwenden, z.B.
String baseUrl = dotenv.get('TANKSTOPS_BASE_URL');
String getGasLocationLink ='$baseUrl?latitude=$lat&longitude=$lng&fuelType=$gas&includeClosed=false';
final client = http.Client();
var response = await client.get(Uri.parse(getGasLocationLink),headers: {'Content-Type': 'application/json', 'charset': 'utf-8'});
//Response Data status
if (response.statusCode == 200) {
//Response is succsessful
data = json.decode(utf8.decode(response.bodyBytes)); //get response data
} else {
debugPrint(response.statusCode.toString());
}
client.close();
return data;
}
}

View File

@ -1,97 +0,0 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
class LocationRepository {
static final LocationRepository _instance = LocationRepository._internal();
/// Singleton instance getter
factory LocationRepository() => _instance;
//Constructor???
LocationRepository._internal() {
//init for something
}
/// Überprüft, ob der Standortdienst aktiviert ist.
Future<bool> isLocationServiceEnabled() async {
return await Geolocator.isLocationServiceEnabled();
}
/// Fragt die Berechtigung für den Standort ab.
Future<LocationPermission> checkPermission() async {
return await Geolocator.checkPermission();
}
/// Fordert die Berechtigung für den Standort an.
Future<LocationPermission> requestPermission() async {
return await Geolocator.requestPermission();
}
/// Liefert die aktuelle Position des Geräts.
/// Wirft eine Exception, wenn der Dienst nicht aktiviert ist oder keine Berechtigung vorliegt.
Future<Position> getCurrentPosition() async {
bool serviceEnabled = await isLocationServiceEnabled();
if (!serviceEnabled) {
// Standortdienste sind nicht aktiviert.
return Future.error('Location services are disabled.');
}
LocationPermission permission = await checkPermission();
if (permission == LocationPermission.denied) {
permission = await requestPermission();
if (permission == LocationPermission.denied) {
// Berechtigungen sind verweigert.
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
// Berechtigungen sind dauerhaft verweigert.
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.',
);
}
// Wenn alles in Ordnung ist, die Position zurückgeben.
return await Geolocator.getCurrentPosition();
}
Future<String> getNearbyLocation(Map map) async {
String locationOrt = '?';
var lat = map['lat'];
var lng = map['lng'];
// Hier kannst du die Logik hinzufügen, um den Standort zu verwenden, z.B.
String ptvGeoLink =
'https://api.myptv.com/geocoding/v1/locations/by-position/$lat/$lng?language=de&apiKey=${dotenv.get('PTV_GEOLINK_API_KEY')}';
final client = http.Client();
var response = await client.get(
Uri.parse(ptvGeoLink),
headers: {'Content-Type': 'application/json', 'charset': 'utf-8'},
);
//Response Data status
if (response.statusCode == 200) {
//Response is succsessful
Map<String, dynamic> data = json.decode(
utf8.decode(response.bodyBytes),
); //get response data
Map<String, dynamic> mapOfAddressfromPosition =
data['locations'][0]['address']; //get response address of position
if (mapOfAddressfromPosition.isNotEmpty) {
locationOrt =
'${mapOfAddressfromPosition['street'].toString()} ${mapOfAddressfromPosition['houseNumber'].toString()}, ${mapOfAddressfromPosition['postalCode'].toString()} ${mapOfAddressfromPosition['city'].toString()}';
}
} else {
debugPrint(response.statusCode.toString());
}
client.close();
return locationOrt;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

View File

@ -1,8 +1,98 @@
import 'package:appwrite_flutter_starter_kit/data/models/log.dart';
import 'package:appwrite_flutter_starter_kit/data/models/status.dart';
import 'package:appwrite_flutter_starter_kit/data/repository/appwrite_repository.dart';
import 'package:appwrite_flutter_starter_kit/ui/components/checkered_background.dart';
import 'package:appwrite_flutter_starter_kit/ui/components/collapsible_bottomsheet.dart';
import 'package:appwrite_flutter_starter_kit/ui/components/connection_status_view.dart';
import 'package:appwrite_flutter_starter_kit/ui/components/getting_started_cards.dart';
import 'package:appwrite_flutter_starter_kit/ui/components/top_platform_view.dart';
import 'package:appwrite_flutter_starter_kit/utils/app_initializer.dart';
import 'package:appwrite_flutter_starter_kit/utils/extensions/build_context.dart';
import 'package:flutter/material.dart';
import './app.dart';
import './utils/app_initializer.dart';
void main() async {
await AppInitializer.initialize();
runApp(AppwriteApp());
}
class AppwriteApp extends StatelessWidget {
const AppwriteApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Appwrite StarterKit',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const AppwriteStarterKit(),
);
}
}
class AppwriteStarterKit extends StatefulWidget {
const AppwriteStarterKit({super.key});
@override
State<AppwriteStarterKit> createState() => _AppwriteStarterKit();
}
class _AppwriteStarterKit extends State<AppwriteStarterKit> {
final List<Log> _logs = [];
Status _status = Status.idle;
final AppwriteRepository _repository = AppwriteRepository();
@override
Widget build(BuildContext context) {
return Scaffold(
body: CheckeredBackground(
child: SafeArea(
minimum: EdgeInsets.only(top: context.isLargeScreen ? 24 : 16),
child: Stack(
children: [
SingleChildScrollView(
child: Column(
spacing: context.isLargeScreen ? 64 : 32,
children: [
TopPlatformView(status: _status),
ConnectionStatusView(
status: _status,
onButtonClick: () async {
setState(() => _status = Status.loading);
final log = await _repository.ping();
_logs.add(log);
await Future.delayed(
const Duration(milliseconds: 1250),
);
setState(
() => _status =
(200 <= log.status && log.status <= 399)
? Status.success
: Status.error,
);
},
),
GettingStartedCards()
],
),
),
// bottomsheet
Align(
alignment: Alignment.bottomCenter,
child: CollapsibleBottomSheet(
logs: _logs,
projectInfo: _repository.getProjectInfo(),
),
),
],
),
),
),
);
}
}

View File

@ -1,80 +0,0 @@
import 'package:flutter/material.dart';
import '../../data/models/log.dart';
import '../../data/models/status.dart';
import '../../data/repository/appwrite_repository.dart';
import '../../ui/components/checkered_background.dart';
import '../../ui/components/collapsible_bottomsheet.dart';
import '../../ui/components/connection_status_view.dart';
import '../../ui/components/getting_started_cards.dart';
import '../../ui/components/top_platform_view.dart';
import '../../utils/extensions/build_context.dart';
class AppwriteStarterKit extends StatefulWidget {
const AppwriteStarterKit({super.key});
@override
State<AppwriteStarterKit> createState() => _AppwriteStarterKit();
}
class _AppwriteStarterKit extends State<AppwriteStarterKit> {
final List<Log> _logs = [];
Status _status = Status.idle;
final AppwriteRepository _repository = AppwriteRepository();
@override
Widget build(BuildContext context) {
return Scaffold(
body: CheckeredBackground(
child: SafeArea(
minimum: EdgeInsets.only(
top: context.isExtraWideScreen
? 156
: context.isLargeScreen
? 24
: 32),
child: Stack(
children: [
SingleChildScrollView(
child: Column(
spacing: 16,
children: [
TopPlatformView(status: _status),
ConnectionStatusView(
status: _status,
onButtonClick: () async {
setState(() => _status = Status.loading);
final log = await _repository.ping();
_logs.add(log);
await Future.delayed(
const Duration(milliseconds: 1250),
);
setState(
() => _status =
(200 <= log.status && log.status <= 399)
? Status.success
: Status.error,
);
},
),
GettingStartedCards()
],
),
),
// bottomsheet
Align(
alignment: Alignment.bottomCenter,
child: CollapsibleBottomSheet(
logs: _logs,
projectInfo: _repository.getProjectInfo(),
),
),
],
),
),
),
);
}
}

View File

@ -1,86 +0,0 @@
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import '../../data/models/gas_model.dart';
import '../../data/repository/appwrite_repository.dart';
import '../../pages/login/login_view.dart';
import '../../pages/tanklist/tanklist_view.dart';
import './widgets/map_view.dart' show MapDialogView;
import '../../data/repository/gasstation_repository.dart';
class GaslistController extends GetxController {
final _dataBox = GetStorage('MyUserStorage');
final szRxGasArt = 'DIE'.obs;
//Gas Station Repository
final GasStationRepository _gasStationRepository = GasStationRepository();
final AppwriteRepository _authRepository = AppwriteRepository();
final isLoadingList = false.obs;
var gasStationsList = <GasModel>[].obs;
@override
void onInit() {
loadListData();
super.onInit();
}
@override
void onReady() {}
@override
void onClose() {}
Future<void> loadListData() async {
isLoadingList(true);
var lat = _dataBox.read('lastLatitude');
var lng = _dataBox.read('lastLongitude');
var gas = szRxGasArt.value;
var result =
await getGasStationsFromApi({'lat': lat, 'lng': lng, 'gas': gas});
print('Gas Stations from API: $result');
//Hier die Logik zum Laden der Daten einfügen
gasStationsList.clear();
gasStationsList.refresh();
// add Map to GasModelList
for (var element in result) {
Map<String, dynamic> gasModelMap = (element as Map<String, dynamic>);
var gasModelItem = GasModel.fromJson(gasModelMap);
gasStationsList.add(gasModelItem);
}
//Simulate a delay for loading data
isLoadingList(false);
update();
}
Future<dynamic> getGasStationsFromApi(Map map) async {
var result = await _gasStationRepository.getGasStationsLocations(map);
return result;
}
void goToListView() {
Get.offAndToNamed(TanklistPage.namedRoute);
}
Future<void> logoutSessionAndGoToLoginPage() async {
// Handle logout logic here
print('Logout session and go to login page');
// Clear GetStorage session ID
_dataBox.remove('sessionId');
_dataBox.remove('userId');
_dataBox.remove('userName');
_dataBox.remove('userEmail');
print('Session ID removed from GetStorage');
await _authRepository.logout();
Get.offAndToNamed(LoginPage.namedRoute);
}
Future<void> openDirectionMaps(double lat, double lng) async {
Get.dialog(
MapDialogView(
latitude: lat,
longitude: lng,
),
barrierDismissible: true,
);
}
}

View File

@ -1,146 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'gaslist_controller.dart';
class GaslistPage extends GetView<GaslistController> {
static const namedRoute = '/gas-stations-list-page';
const GaslistPage({super.key});
@override
Widget build(BuildContext context) {
var gasCtrl = controller;
return PopScope(
canPop: false,
child: SafeArea(
child: Scaffold(
appBar: AppBar(
shadowColor: Colors.grey,
title: const Text('Gas Stations'),
centerTitle: true,
actions: [
IconButton(
icon: Icon(Icons.list, color: Colors.grey.shade300),
onPressed: () async {
// Handle go to Chart View
gasCtrl.goToListView();
},
),
IconButton(
icon: Icon(Icons.logout, color: Colors.grey.shade300),
onPressed: () async {
// Handle logout logic here
gasCtrl.logoutSessionAndGoToLoginPage();
},
),
],
),
body: Obx(
() => gasCtrl.isLoadingList.value == true
? Center(
child: Text('GasStations'),
)
: Column(
children: [
SizedBox(
child: Wrap(
alignment: WrapAlignment.center,
spacing: 50,
children: [
Divider(
color: Colors.grey.shade300,
),
ElevatedButton(
onPressed: () async {
gasCtrl.szRxGasArt.value = 'DIE';
await gasCtrl.loadListData();
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey.shade800,
foregroundColor: Colors
.orange, // Hintergrundfarbe des Buttons
),
child: Column(
children: [
Text('Diesel'),
Text('DIE'),
],
),
),
ElevatedButton(
onPressed: () async {
gasCtrl.szRxGasArt.value = 'SUP';
await gasCtrl.loadListData();
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey.shade800,
foregroundColor: Colors
.orange, // Hintergrundfarbe des Buttons
),
child: Column(
children: [
Text('Benzin'),
Text('SUP'),
],
),
),
],
),
),
Divider(
color: Colors.grey.shade300,
),
Expanded(
child: ListView.builder(
itemCount: 5,
itemBuilder: (context, index) {
var gasStation = gasCtrl.gasStationsList[index];
return ListTile(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.grey, // Border color
width: 1.0, // Border thickness
),
borderRadius: BorderRadius.circular(5.0),
),
onTap: () {
// Handle item tap if needed
gasCtrl.openDirectionMaps(
gasStation.location!.latitude!,
gasStation.location!.longitude!);
},
title: Text(gasStation.name ?? 'No Name'),
subtitle: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(gasStation.location?.address ??
'No Address'),
Text(gasStation.distance != null
? '${gasStation.distance?.toStringAsFixed(2)} km'
: 'No Distance'),
],
),
trailing: gasStation.prices != null &&
gasStation.prices!.isNotEmpty
? Column(
children: [
Text(gasStation.prices?[0].fuelType ??
'N/A'),
Text(
'${gasStation.prices?[0].amount?.toStringAsPrecision(4) ?? 'N/A'}'),
],
)
: const Text('N/A'),
);
},
),
),
],
),
),
),
),
);
}
}

View File

@ -1,76 +0,0 @@
// map_dialog_view.dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:url_launcher/url_launcher.dart';
class MapDialogView extends StatelessWidget {
final double latitude;
final double longitude;
const MapDialogView({
super.key,
required this.latitude,
required this.longitude,
});
// Funktion zum Öffnen der Karten-URL
void _openMap() async {
String url = '';
final coords = '$latitude,$longitude';
if (Platform.isAndroid) {
// Android: Startet die Google Maps Navigation
url =
'https://www.google.com/maps/dir/?api=1&destination=$coords'; // mode=d für Fahren
} else if (Platform.isIOS) {
// iOS: Startet die Apple Maps Navigation
url =
'https://maps.apple.com/?daddr=$coords&dirflg=d'; // daddr für destination, dirflg=d für driving
} else {
// Fallback-URL für die Google Maps Website mit Wegbeschreibung
url = 'https://www.google.com/maps/dir/?api=1&destination=$coords';
}
// Hier die URL-Logik einfügen, die Sie bereits kennen
//final url = 'http://googleusercontent.com/maps.google.com/8';
final uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
} else {
// Eine Snackbar oder ein Dialog, um den Fehler zu melden
print('Fehler: Konnte Karten-App nicht öffnen.');
}
Get.back();
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Karte öffnen'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.start, // Passt die Höhe an den Inhalt an
children: [
Text('Koordinaten'),
Text('Latitude: $latitude'),
Text('Longitude: $longitude'),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _openMap, // Ruft die Methode zum Öffnen der Karte auf
child: const Text('Karten-App öffnen'),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(), // Schließt den Dialog
child: const Text('Schließen'),
),
],
);
}
}

View File

@ -1,264 +0,0 @@
import 'package:appwrite/appwrite.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import '../../data/models/chart_model.dart';
import '../../data/models/tank_model.dart';
import '../../data/repository/appwrite_repository.dart';
import '../../utils/extensions/static_helper.dart';
class GraphController extends GetxController {
//AppWrite API-REST get Data
final AppwriteRepository _authRepository = AppwriteRepository();
final _dataBox = GetStorage('MyUserStorage');
final szRxUserId = 'NoUser'.obs;
final szBarTitle = ''.obs;
final listYearModel = <YearModel>[].obs;
late List<AppWriteTankModel> tankListOriginal;
final tankList = <AppWriteTankModel>[].obs;
final yearValue = DateTime.now().year.obs;
final blIsLoading = false.obs;
final dataPointsEuro = <double>[].obs;
final dataPointsGasoline = <double>[].obs;
final pointsEuro = <PricePoints>[].obs;
final pointsGasoline = <PricePoints>[].obs;
final sumListData = <SumDataModel>[].obs;
final mnCurrentAveragePerLiter = 0.00.obs;
final pointsPerLiter = <PricePoints>[].obs;
final dataPointsPerLiter = <double>[].obs;
final mnCurrentSummEuroYear = 0.0.obs;
final mnCurrentSummLiterYear = 0.0.obs;
@override
void onInit() {
szRxUserId(_dataBox.read('userId'));
_getTankList();
super.onInit();
}
@override
void onReady() {
super.onReady();
}
@override
void onClose() {}
void _getTankList() async {
blIsLoading(true);
bool isErrorByLoading = false;
String message = '';
try {
await _authRepository
.listTankStops(szRxUserId.value)
.then((tankListData) {
if (tankListData.documents.isEmpty) {
blIsLoading(false);
isErrorByLoading = true;
message = 'Leere Liste keine Daten vorhanden';
return;
}
tankList.clear();
var data = tankListData.toMap();
List d = data['documents'].toList();
tankList.value = d
.map((e) => AppWriteTankModel.fromMap(e['data']))
.toList();
tankList.sort((a, b) {
final DateTime dateA = DateTime.parse(a.date);
final DateTime dateB = DateTime.parse(b.date);
return dateB.compareTo(dateA);
});
message = 'Liste wurde erfolgreich geladen';
})
.catchError((error) {
blIsLoading(true);
isErrorByLoading = true;
if (error is AppwriteException) {
message = error.message!;
} else {
message = 'Uuups da ist was schief gelaufen';
}
});
} catch (e) {
blIsLoading(true);
isErrorByLoading = true;
message = 'Fehler beim Laden der Tankliste';
print('Error fetching tank list: $e');
}
String title = isErrorByLoading ? 'Fehler' : 'Erfolg';
Get.snackbar(
title,
message,
backgroundColor: isErrorByLoading ? Colors.red : Colors.green,
snackPosition: SnackPosition.BOTTOM,
duration: const Duration(seconds: 4),
);
tankListOriginal = tankList;
update();
setListMapYear();
getTankListPerYear();
}
List<String> getHeadDescription() {
List<String> localListString = [];
tankList.sort((a, b) {
final DateTime dateA = DateTime.parse(a.date);
final DateTime dateB = DateTime.parse(b.date);
return dateB.compareTo(dateA);
});
if (tankList.isNotEmpty) {
for (var benzinItem in tankList) {
String szDay = '';
var dateDay = DateTime.parse(benzinItem.date);
if (dateDay.day <= 9) {
szDay = '0${dateDay.day}';
} else {
szDay = '${dateDay.day}';
}
String szMonth = '';
if (dateDay.month <= 9) {
szMonth = '0${dateDay.month}';
} else {
szMonth = '${dateDay.month}';
}
String szData = '$szDay$szMonth';
localListString.add(szData);
}
}
update();
return localListString;
}
void setListMapYear() {
int year = 2022;
for (var i = year; i <= DateTime.now().year; i++) {
listYearModel.add(YearModel('Jahr $year', year));
year = year + 1;
}
update();
}
void getTankListPerYear() {
blIsLoading.value = true;
tankList
.where((e) => DateTime.parse(e.date).year == yearValue.value)
.toList();
getDataPointsForGraph();
getMonthListData();
blIsLoading.value = false;
update();
}
void getDataPointsForGraph() {
//daten ermitteln für Jahr xxxx
//debugPrint('${yearValue.value}');
List<double> mnDataPointsEuro = [];
List<double> mnDataPointsGasoline = [];
// 08.08.23 Mod. add Price per Liter
List<double> mnDataPointsPerLiter = [];
var mnSummPerLiter = 0.0;
var mnTankListCount = tankList.length;
for (var item in tankList) {
var mnLiterGesamt = double.parse(item.liters);
var mnEuroGesamt =
double.parse(item.liters) * double.parse(item.pricePerLiter);
var mnPerLiter = double.parse(item.pricePerLiter);
mnDataPointsEuro.add(mnEuroGesamt);
mnDataPointsGasoline.add(mnLiterGesamt);
mnDataPointsPerLiter.add(mnPerLiter.toPrecision(2));
mnSummPerLiter += mnPerLiter;
}
if (mnSummPerLiter > 0 && mnTankListCount > 0) {
mnCurrentAveragePerLiter.value = (mnSummPerLiter / mnTankListCount)
.toPrecision(2);
}
dataPointsEuro.value = mnDataPointsEuro;
dataPointsGasoline.value = mnDataPointsGasoline;
dataPointsPerLiter.value = mnDataPointsPerLiter;
getPricePointsEuro();
getPricePointsGasoline();
getPricePointsPerLiter();
update();
}
void getMonthListData() {
if (tankList.isNotEmpty) {
sumListData.clear();
List<AppWriteTankModel> tankListPerYear = tankList;
List<dynamic> monthList = StaticHelper.listMonth;
for (var monthMap in monthList) {
var szMonth = monthMap['month'].toString();
var szValueMonth = monthMap['value'];
var result = StaticHelper.staticListGetDaysInBetween(
tankListPerYear,
szValueMonth,
yearValue.value,
);
var tankListPerMon = result as List<AppWriteTankModel>;
if (tankListPerMon.isNotEmpty) {
SumDataModel sumDataModel = SumDataModel('', '', '', 0);
sumDataModel.szMonth = szMonth;
sumDataModel.mnTankungen = tankListPerMon.length;
double mnSumEuro = 0.0;
double mnSumBenzin = 0.0;
for (var tankungModel in tankListPerMon) {
var mnEuroGesamt =
double.parse(tankungModel.liters) *
double.parse(tankungModel.pricePerLiter);
mnSumBenzin += double.parse(tankungModel.liters);
mnSumEuro += mnEuroGesamt;
}
sumDataModel.szVerbrauch = mnSumBenzin.toStringAsFixed(2);
sumDataModel.szSumme = mnSumEuro.toStringAsFixed(2);
sumListData.add(sumDataModel);
}
}
_currentSumForYear();
}
}
void getPricePointsEuro() {
var listPoints = dataPointsEuro.indexed
.map((e) => PricePoints(x: e.$1.toDouble(), y: e.$2))
.toList();
pointsEuro.value = listPoints;
update();
}
void getPricePointsGasoline() {
var listPoints = dataPointsGasoline.indexed
.map((e) => PricePoints(x: e.$1.toDouble(), y: e.$2))
.toList();
pointsGasoline.value = listPoints;
update();
}
void getPricePointsPerLiter() {
var listPoints = dataPointsPerLiter.indexed
.map((e) => PricePoints(x: e.$1.toDouble(), y: e.$2))
.toList();
pointsPerLiter.value = listPoints;
update();
}
void _currentSumForYear() {
mnCurrentSummEuroYear.value = 0.0;
mnCurrentSummLiterYear.value = 0.0;
if (sumListData.isNotEmpty) {
for (var rxListItem in sumListData) {
mnCurrentSummEuroYear.value =
mnCurrentSummEuroYear.value + double.parse(rxListItem.szSumme!);
mnCurrentSummLiterYear.value =
mnCurrentSummLiterYear.value +
double.parse(rxListItem.szVerbrauch!);
}
}
update();
}
}

View File

@ -1,148 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../utils/extensions/constants.dart';
import './graph_controller.dart';
import './widgets/chart_desc.dart';
import './widgets/chart_lines.dart';
import './widgets/chart_single_lines.dart';
import './widgets/my_list_tile_card.dart';
import '../../pages/tanklist/tanklist_view.dart';
class GraphPage extends GetView<GraphController> {
static const namedRoute = '/graph-statistic-page';
const GraphPage({super.key});
@override
Widget build(BuildContext context) {
Size queryDisplaySize = MediaQuery.of(context).size;
var graphCtrl = controller;
return PopScope(
canPop: false,
child: SafeArea(
child: Scaffold(
body: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 50,
child: IconButton(
onPressed: () =>
Get.offAndToNamed(TanklistPage.namedRoute),
icon: const Icon(Icons.list),
),
),
SizedBox(
width: queryDisplaySize.width - 70,
child: Obx(() => _displayDropDownMenue(graphCtrl)),
),
],
),
),
const SizedBox(height: 8.0),
Obx(
() => Container(
color: Colors.grey.shade900,
padding: const EdgeInsets.symmetric(horizontal: 40),
width: MediaQuery.of(context).size.width,
child: Column(
children: [
ChartDescription(
backgroundColor: kColorEuroChart,
mnWidth: double.infinity,
szDescText: '€ Jahressumme',
szCurrentSumData:
graphCtrl.mnCurrentSummEuroYear.toStringAsFixed(2),
),
ChartDescription(
backgroundColor: kColorBenzinChart,
mnWidth: double.infinity,
szDescText: 'L Jahresverbrauch',
szCurrentSumData:
graphCtrl.mnCurrentSummLiterYear.toStringAsFixed(2),
),
],
),
),
),
const Divider(),
LineChartLines(
firstLineColor: kColorEuroChart,
secondLineColor: kColorBenzinChart,
),
Obx(
() => graphCtrl.blIsLoading.value
? const Center(
child: CircularProgressIndicator(color: Colors.cyan),
)
: const SizedBox.shrink(),
),
const Divider(),
Obx(
() => Container(
color: Colors.grey.shade900,
padding: const EdgeInsets.symmetric(horizontal: 40),
child: ChartDescription(
backgroundColor: kColorPerLiterChart,
mnWidth: queryDisplaySize.width,
szDescText: '€/L Durchschnitt',
szCurrentSumData: graphCtrl.mnCurrentAveragePerLiter.value
.toStringAsFixed(2),
),
),
),
const Divider(),
LineChartSingleLine(singleLineColor: kColorPerLiterChart),
const Divider(),
Obx(
() => graphCtrl.blIsLoading.value
? const Center(
child: CircularProgressIndicator(color: Colors.cyan),
)
: const SizedBox.shrink(),
),
Obx(
() => Expanded(
child: ListView.builder(
itemCount: graphCtrl.sumListData.length,
itemBuilder: (context, index) {
return MyListTileCard(graphCtrl: graphCtrl, index: index);
},
),
),
),
],
),
),
),
);
}
DropdownButtonFormField _displayDropDownMenue(GraphController controller) {
var graphCtrl = controller;
var list = graphCtrl.listYearModel;
var valueOfList = graphCtrl.yearValue.value;
return DropdownButtonFormField(
decoration: kInputDecorationDropDownMenueYear,
items: list.map((map) {
return DropdownMenuItem(
value: map.mnYear,
child: Text(map.szDescription),
);
}).toList(),
isDense: true,
isExpanded: true,
initialValue: valueOfList,
onChanged: ((value) {
valueOfList = value;
graphCtrl.yearValue.value = valueOfList;
if (graphCtrl.yearValue.value > 0) {
graphCtrl.getTankListPerYear();
}
}),
);
}
}

View File

@ -1,124 +0,0 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import '../../../utils/extensions/constants.dart';
import '../graph_controller.dart';
class BarChartWidget extends StatelessWidget {
final GraphController graphCtrl;
const BarChartWidget({super.key, required this.graphCtrl});
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 2,
child: BarChart(
BarChartData(
//alignment: BarChartAlignment.center,
maxY: 50,
baselineY: 0,
barTouchData: barTouchData,
titlesData: titlesData,
borderData: borderData,
barGroups: barGroups,
gridData: const FlGridData(show: false),
),
),
);
}
BarTouchData get barTouchData => BarTouchData(
enabled: false,
touchTooltipData: BarTouchTooltipData(
//tooltipBgColor: Colors.transparent,
tooltipPadding: EdgeInsets.zero,
tooltipMargin: 8,
getTooltipItem:
(
BarChartGroupData group,
int groupIndex,
BarChartRodData rod,
int rodIndex,
) {
return BarTooltipItem(
rod.toY.round().toString(),
const TextStyle(color: Colors.cyan, fontWeight: FontWeight.bold),
);
},
),
);
Widget getTitles(double value, TitleMeta meta) {
List<String> dayMonListString = graphCtrl.getHeadDescription();
for (var i = 0; i < dayMonListString.length; i++) {
if (i == value.toInt()) {
graphCtrl.szBarTitle.value = dayMonListString[i];
}
}
return SideTitleWidget(
fitInside: SideTitleFitInsideData.fromTitleMeta(meta),
space: 4,
meta: meta,
child: Text(graphCtrl.szBarTitle.value, style: kBarTitleStyle),
);
}
FlTitlesData get titlesData => FlTitlesData(
show: true,
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 30,
getTitlesWidget: getTitles,
),
),
leftTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
);
FlBorderData get borderData => FlBorderData(show: false);
LinearGradient get _barsGradient => LinearGradient(
colors: [Colors.blue.shade400, Colors.red.shade300],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
);
List<BarChartGroupData> get barGroups => [
BarChartGroupData(
x: 0,
barRods: [BarChartRodData(toY: 8, gradient: _barsGradient)],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 1,
barRods: [BarChartRodData(toY: 10, gradient: _barsGradient)],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 2,
barRods: [BarChartRodData(toY: 14, gradient: _barsGradient)],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 3,
barRods: [BarChartRodData(toY: 15, gradient: _barsGradient)],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 4,
barRods: [BarChartRodData(toY: 13, gradient: _barsGradient)],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 5,
barRods: [BarChartRodData(toY: 10, gradient: _barsGradient)],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 6,
barRods: [BarChartRodData(toY: 16, gradient: _barsGradient)],
showingTooltipIndicators: [0],
),
];
}

View File

@ -1,43 +0,0 @@
import 'package:flutter/material.dart';
import '../../../utils/extensions/constants.dart';
class ChartDescription extends StatelessWidget {
final double mnWidth;
final Color backgroundColor;
final String szDescText;
final String szCurrentSumData;
const ChartDescription({
super.key,
required this.mnWidth,
required this.backgroundColor,
required this.szDescText,
required this.szCurrentSumData,
});
@override
Widget build(BuildContext context) {
return SizedBox(
width: mnWidth,
child: Row(
children: [
Container(
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(15),
),
width: 70,
height: 20,
child: Center(
child: Text(szCurrentSumData, style: kChartDescriptionFontStyle),
),
),
const SizedBox(width: 10),
Text(szDescText, style: kTextStyle),
],
),
);
}
}

View File

@ -1,49 +0,0 @@
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:get/get.dart';
import '../graph_controller.dart';
// 08.08.23 Mod. Line Chart with tree Lines
class LineChartLines extends GetView<GraphController> {
final Color firstLineColor;
final Color secondLineColor;
const LineChartLines({
super.key,
required this.firstLineColor,
required this.secondLineColor,
});
@override
Widget build(BuildContext context) {
final GraphController gCtrl = controller;
return AspectRatio(
aspectRatio: 3,
child: Obx(
() => LineChart(
LineChartData(
lineBarsData: [
LineChartBarData(
color: firstLineColor,
spots: gCtrl.pointsEuro
.map((point) => FlSpot(point.x, point.y))
.toList(),
isCurved: false,
dotData: const FlDotData(show: true),
),
LineChartBarData(
isStepLineChart: false,
color: secondLineColor,
spots: gCtrl.pointsGasoline
.map((point) => FlSpot(point.x, point.y))
.toList(),
isCurved: false,
dotData: const FlDotData(show: true),
),
],
),
),
),
);
}
}

View File

@ -1,36 +0,0 @@
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:get/get.dart';
import '../graph_controller.dart';
// 08.08.23 Mod. Line Chart with tree Lines
class LineChartSingleLine extends GetView<GraphController> {
final Color singleLineColor;
const LineChartSingleLine({super.key, required this.singleLineColor});
@override
Widget build(BuildContext context) {
final GraphController gCtrl = controller;
return AspectRatio(
aspectRatio: 3.55,
child: Obx(
() => LineChart(
LineChartData(
lineBarsData: [
LineChartBarData(
color: singleLineColor,
spots: gCtrl.pointsPerLiter
.map((point) => FlSpot(point.x, point.y))
.toList(),
isCurved: false,
dotData: const FlDotData(show: true),
),
],
),
),
),
);
}
}

View File

@ -1,46 +0,0 @@
import 'package:flutter/material.dart';
import '../../../utils/extensions/constants.dart';
import '../graph_controller.dart';
class MyListTileCard extends StatelessWidget {
const MyListTileCard({
super.key,
required this.graphCtrl,
required this.index,
});
final GraphController graphCtrl;
final int index;
@override
Widget build(BuildContext context) {
return Card(
shadowColor: Colors.grey.shade200,
child: ListTile(
title: Text(
'${graphCtrl.sumListData[index].szMonth}',
style: kTextStyle,
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Monatsausgaben: ${graphCtrl.sumListData[index].szSumme}',
style: kTextStyleSub,
),
Text(
'Monatsverbrauch: ${graphCtrl.sumListData[index].szVerbrauch} L',
style: kTextStyleSub,
),
Text(
'Tankungen: ${graphCtrl.sumListData[index].mnTankungen}',
style: kTextStyleSub,
),
],
),
),
);
}
}

View File

@ -1,232 +0,0 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite/models.dart' as models;
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import '../../data/repository/appwrite_repository.dart';
import '../../utils/extensions/static_helper.dart';
import '../tank/tank_view.dart';
class LoginController extends GetxController {
final AppwriteRepository _authRepository = AppwriteRepository();
final isVisible = false.obs;
//Form Key
final formKey = GlobalKey<FormState>();
bool isFormValid = false;
final _dataBox = GetStorage('MyUserStorage');
final emailController = TextEditingController();
final passwordController = TextEditingController();
final nameController = TextEditingController();
@override
void onInit() {
super.onInit();
print('LoginController initialized');
}
@override
void onReady() {
super.onReady();
// Initialize any necessary data or state here
var isSessionId = _dataBox.hasData('sessionId');
if (isSessionId) {
// If session ID exists, navigate to TankPage
print('Session ID found, navigating to TankPage');
goToTankPage();
} else {
// If no session ID, initialize the login controller
print('No session ID found, initializing LoginController');
}
// This method is called when the controller is ready
print('LoginController is ready');
}
@override
void onClose() {
// Clean up any resources or listeners here
emailController.dispose();
passwordController.dispose();
nameController.dispose();
// emailFocusNode.dispose();
// passwordFocusNode.dispose();
// nameFocusNode.dispose();
super.onClose();
}
void clearTextEditingController() {
emailController.clear();
passwordController.clear();
nameController.clear();
}
String? validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte geben Sie eine E-Mail-Adresse ein';
}
if (!GetUtils.isEmail(value)) {
return 'Bitte geben Sie eine gültige E-Mail-Adresse ein';
}
return null;
}
String? validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte geben Sie ein Passwort ein';
}
if (value.length < 8) {
return 'Das Passwort muss mindestens 8 Zeichen lang sein';
}
return null;
}
String? validateName(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte geben Sie Ihren Namen ein';
}
if (value.length < 3) {
return 'Der Name muss mindestens 3 Zeichen lang sein';
}
return null;
}
var message = 'NoMessage!';
var isError = false;
// Registrierung
Future<void> register() async {
isError = false;
message = 'NoMessage!';
isFormValid = formKey.currentState!.validate();
if (!isFormValid) {
print('Formular ist ungültig');
return;
} else {
print('Formular ist gültig');
formKey.currentState!.save();
try {
await _authRepository.signup({
'email': emailController.text,
'password': passwordController.text,
'name': nameController.text,
}).then((models.User userValue) {
// GetStorage data storage
isVisible(false);
print(
'User was stored and Loggedin: ${userValue.name}, ${userValue.$id}, ${userValue.email}',
);
// Store session ID in GetStorage
_dataBox.write('userId', userValue.$id);
_dataBox.write('userName', userValue.name);
_dataBox.write('userEmail', userValue.email);
// Go to TankPage
goToTankPage();
message = 'Sie wurden registriert und Angemeldet!!';
StaticHelper.getMySnackeBar('Erfolg', message, Colors.green);
}).catchError((error) {
if (error is AppwriteException) {
// Handle specific Appwrite exceptions
print('Appwrite Fehler: ${error.message}');
message = 'Appwrite Fehler: ${error.message}';
isError = true;
} else {
// Handle other types of errors
message = 'Allgemeiner Fehler: $error';
print('Allgemeiner Fehler: $error');
isError = true;
}
message = 'Fehler bei der Registrierung: $error';
print('Fehler bei der Registrierung: $error');
//Clear GetStorage session ID
StaticHelper.removeFromStorage();
isError = true;
});
} catch (e) {
message = 'Fehler bei Registrierung: $e';
print('Fehler bei Registrierung: $e');
//Clear GetStorage session ID
StaticHelper.removeFromStorage();
isError = true;
}
if (isError) StaticHelper.getMySnackeBar('Fehler', message, Colors.red);
}
}
Future<void> _getCurrentLoggedinUser() async {
await _authRepository.getCurrentUser.then((models.User userValue) {
// GetStorage data storage
print(
'User was stored and Loggedin: ${userValue.name}, ${userValue.$id}, ${userValue.email}',
);
// Store session ID in GetStorage
_dataBox.write('userId', userValue.$id);
_dataBox.write('userName', userValue.name);
_dataBox.write('userEmail', userValue.email);
}).catchError((error) {
print('Fehler beim Abrufen des Benutzers: $error');
});
}
// Login
Future<void> login() async {
message = 'NoMessage!';
isError = false;
isFormValid = formKey.currentState!.validate();
if (!isFormValid) {
print('Formular ist ungültig');
return;
} else {
print('Formular ist gültig');
formKey.currentState!.save();
try {
await _authRepository.login({
'email': emailController.text,
'password': passwordController.text,
}).then((models.Session session) {
// Store session ID in GetStorage
_dataBox.write('sessionId', session.$id);
print('Session ID stored: ${_dataBox.read('sessionId')}');
print(
'Erfolgreich eingeloggt: ${session.$id}\n${session.providerUid}',
);
_getCurrentLoggedinUser().then((_) {
// Go to TankPage
goToTankPage();
StaticHelper.getMySnackeBar(
'Erfolg', 'Sie wurden Angemeldet!!', Colors.green);
});
}).catchError((error) {
if (error is AppwriteException) {
// Handle specific Appwrite exceptions
isError = true;
message = 'Appwrite Fehler: ${error.message}';
print('Appwrite Fehler: ${error.message}');
} else {
// Handle other types of errors
print('Allgemeiner Fehler: $error');
isError = true;
message = 'Allgemeiner Fehler: $error';
}
print('Fehler beim Login: $error');
isError = true;
message = 'Fehler beim Login: $error';
_authRepository.logout();
});
} catch (e) {
print('Fehler beim Login: $e');
isError = true;
message = 'Fehler beim Login: $e';
_authRepository.logout();
}
if (isError) StaticHelper.getMySnackeBar('Fehler', message, Colors.red);
}
}
void goToTankPage() {
Get.offAndToNamed(TankPage.namedRoute, arguments: {'from': 'Input'});
}
}

View File

@ -1,162 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'login_controller.dart';
class LoginPage extends GetView<LoginController> {
static const namedRoute = '/login-page';
const LoginPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
alignment: Alignment.center,
width: double.infinity,
height: double.infinity,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
headerTextTankGuru(),
const SizedBox(height: 5),
headerTextDescription(),
const SizedBox(height: 10),
loadingImage(),
inputFields(),
],
),
),
),
),
);
}
//the structure of the login page
SizedBox loadingImage() {
return SizedBox(
width: 300,
height: 300,
child: ClipRRect(
borderRadius: BorderRadius.circular(40),
child: Image.asset('lib/images/gasolineGuru.jpg', fit: BoxFit.cover),
),
);
}
Text headerTextTankGuru() {
return Text(
'Tank GURU',
style: TextStyle(
fontSize: 35,
fontWeight: FontWeight.bold,
color: Colors.teal[600],
letterSpacing: 2,
),
);
}
Text headerTextDescription() {
return Text(
'Das ultimative Tanken',
style: TextStyle(fontSize: 20, color: Colors.grey[300]),
);
}
Widget inputFields() {
return Obx(
() => SizedBox(
width: 300,
child: Form(
key: controller.formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
children: [
SizedBox(height: 20),
TextFormField(
validator: (value) => controller.validateEmail(value),
keyboardType: TextInputType.emailAddress,
controller: controller.emailController,
decoration: InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(),
),
),
SizedBox(height: 20),
TextFormField(
validator: (value) => controller.validatePassword(value),
keyboardType: TextInputType.visiblePassword,
controller: controller.passwordController,
decoration: InputDecoration(
labelText: 'Password',
border: OutlineInputBorder(),
),
obscureText: true,
),
if (controller.isVisible.value) ...[
SizedBox(height: 20),
TextFormField(
validator: (value) => controller.validateName(value),
keyboardType: TextInputType.name,
controller: controller.nameController,
decoration: InputDecoration(
labelText: 'Name',
border: OutlineInputBorder(),
),
),
],
SizedBox(height: 20),
SizedBox(
width: 300,
child: ElevatedButton(
onPressed: () {
controller.isVisible.value == false
? controller.login()
: controller.register();
},
child: controller.isVisible.value == false
? Text('Login')
: Text('Registrieren'),
),
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Noch kein Konto? '),
GestureDetector(
onTap: () {
if (!controller.isVisible.value) {
controller.isVisible.value = true;
} else {
controller.isVisible.value = false;
}
},
child: controller.isVisible.value == false
? Text(
'Sign Up',
style: TextStyle(
color: Colors.teal,
fontWeight: FontWeight.bold,
decoration: TextDecoration.underline,
),
)
: Text(
'Sign In',
style: TextStyle(
color: Colors.teal,
fontWeight: FontWeight.bold,
decoration: TextDecoration.underline,
),
),
),
],
),
],
),
),
),
);
}
}

View File

@ -1,251 +0,0 @@
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
import '../../data/models/tank_model.dart';
import '../tanklist/tanklist_view.dart';
class PrintController extends GetxController {
final argunments = Get.arguments;
final List<dynamic> tankList = Get.arguments['tankList'] ?? [];
final String year = Get.arguments['year'] ?? 'NoYear';
final String summeLiter = Get.arguments['summeLiter'] ?? '0.0';
final String summePreis = Get.arguments['summePreis'] ?? '0.0';
Future<void> printPdfReport() async {
final doc = pw.Document();
final font = await PdfGoogleFonts.robotoRegular();
final List<AppWriteTankModel> tankungen =
tankList.map((e) => AppWriteTankModel.fromMap(e)).toList();
// Daten nach Monat gruppieren
final dFormat = DateFormat('MMMM yyyy', 'de');
final Map<String, List<AppWriteTankModel>> tankungenByMonth = {};
for (var tankung in tankungen) {
final month = dFormat.format(DateTime.parse(tankung.date));
if (!tankungenByMonth.containsKey(month)) {
tankungenByMonth[month] = [];
}
tankungenByMonth[month]!.add(tankung);
}
doc.addPage(
pw.Page(
pageFormat: PdfPageFormat.a4.copyWith(
marginBottom: 1.0 * PdfPageFormat.cm,
marginLeft: 1.0 * PdfPageFormat.cm,
marginRight: 1.0 * PdfPageFormat.cm,
marginTop: 1.0 * PdfPageFormat.cm),
build: (pw.Context context) {
return pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
//Header
// PDF-Design hier
pw.Text('Tankbericht $year',
style: pw.TextStyle(
fontSize: 24,
fontWeight: pw.FontWeight.bold,
color: PdfColors.blue900,
font: font)),
pw.SizedBox(height: 10),
pw.Text('Alle Tankungen im Überblick',
style: pw.TextStyle(
fontSize: 16, color: PdfColors.grey700, font: font)),
pw.Divider(color: PdfColors.grey400),
pw.SizedBox(height: 20),
// Data
// Dynamische Erstellung der monatlichen Abschnitte
...tankungenByMonth.entries.map((entry) {
final monthName = entry.key;
final monthlyData = entry.value;
// Monatliche Summen berechnen
final double monthlyLiters = monthlyData.fold(
0.0, (sum, item) => sum + double.parse(item.liters));
final double monthlyPrice = monthlyData.fold(
0.0,
(sum, item) =>
sum + double.parse(item.szSummePreis ?? '0.0'));
final double monthlyAvrLiterPrice =
monthlyPrice / monthlyLiters;
// Monatlicher Abschnitt
// Erstelle die Datenzeilen
final List<List<String>> tableData = monthlyData.map((item) {
var modDate = item.date.substring(5);
var modPreisPerLiter = item.pricePerLiter.padRight(5, '0');
return [
modDate,
item.location,
item.liters,
modPreisPerLiter,
item.szSummePreis ?? '0.0',
item.odometer
];
}).toList();
var monthAvrPricePerLiter = monthlyAvrLiterPrice.toStringAsFixed(3);
// Füge die Summenzeile hinzu
tableData.add([
'Summe',
'', // Leere Zelle für Ort
(monthlyLiters.toStringAsFixed(2)),
'$monthAvrPricePerLiter Ø', // Leere Zelle für Preis/L
(monthlyPrice.toStringAsFixed(2)),
''
]);
return pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
// Monatsüberschrift
pw.Text(
monthName,
style: pw.TextStyle(
fontWeight: pw.FontWeight.bold,
fontSize: 18,
font: font,
),
),
pw.SizedBox(height: 10),
// Tabelle für den jeweiligen Monat
// pw.TableHelper.fromTextArray(
// headers: [
// 'Datum',
// 'Ort',
// 'Menge (L)',
// 'Preis/L (€)',
// 'Summe (€)',
// 'KM-Stand'
// ],
// cellAlignment: pw.Alignment.centerLeft,
// border: pw.TableBorder.all(color: PdfColors.grey200),
// headerStyle: pw.TextStyle(
// fontWeight: pw.FontWeight.bold, font: font),
// data: tableData,
// cellStyle: pw.TextStyle(font: font),
// ),
// Manuelle Erstellung der Tabelle mit individueller Formatierung
pw.Table(
border: pw.TableBorder.all(color: PdfColors.grey200),
columnWidths: {
0: const pw.FlexColumnWidth(1.0), // Datum
1: const pw.FlexColumnWidth(4.0), // Ort
2: const pw.FlexColumnWidth(1.3), // Menge
3: const pw.FlexColumnWidth(1.3), // Preis/L
4: const pw.FlexColumnWidth(1.4), // Summe
5: const pw.FlexColumnWidth(1.3), // KM-Stand
},
children: [
// Kopfzeile mit grauem Hintergrund
pw.TableRow(
decoration:
const pw.BoxDecoration(color: PdfColors.grey200),
children: [
_buildHeaderCell('Datum', font),
_buildHeaderCell('Ort', font),
_buildHeaderCell('Menge(L)', font),
_buildHeaderCell('Preis/L(€)', font),
_buildHeaderCell('Summe(€)', font),
_buildHeaderCell('Km-Stand', font),
],
),
// Datenzeilen
...monthlyData.map((item) {
var modDate = item.date.substring(5);
var modPreisPerLiter =
item.pricePerLiter.padRight(5, '0');
return pw.TableRow(
children: [
_buildDataCell(modDate, font),
_buildDataCell(item.location, font),
_buildDataCell(item.liters, font),
_buildDataCell(modPreisPerLiter, font),
_buildDataCell(item.szSummePreis!, font),
_buildDataCell(item.odometer, font),
],
);
}),
// Summenzeile mit ANDERER grauem Hintergrund
pw.TableRow(
decoration:
const pw.BoxDecoration(color: PdfColors.grey300),
children: [
_buildDataCell('', font),
_buildDataCell('Gesamt Summe Monat', font),
_buildDataCell('${monthlyLiters.toStringAsFixed(2)} L', font),
_buildDataCell('$monthAvrPricePerLiter Ø', font),
_buildDataCell('${monthlyPrice.toStringAsFixed(2)}', font),
_buildDataCell('', font)
],
),
],
),
pw.SizedBox(height: 20),
],
);
}),
//footer
pw.Spacer(),
pw.Divider(color: PdfColors.grey400),
pw.Container(
alignment: pw.Alignment.centerRight,
child: pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.end,
children: [
pw.Text('Jahres-Gesamtmenge: $summeLiter L',
style: pw.TextStyle(
fontWeight: pw.FontWeight.bold,
fontSize: 16,
font: font)),
pw.Text('Jahres-Gesamtsumme: $summePreis',
style: pw.TextStyle(
fontWeight: pw.FontWeight.bold,
fontSize: 16,
color: PdfColors.blue700,
font: font)),
],
),
),
],
);
},
),
);
// Druckansicht öffnen
await Printing.layoutPdf(
onLayout: (PdfPageFormat format) async => doc.save(),
);
}
void goToTankListPage() async {
await Get.offAndToNamed(TanklistPage.namedRoute);
}
// Hilfs-Widgets für die Zellen
pw.Widget _buildHeaderCell(String text, pw.Font font) {
return pw.Container(
alignment: pw.Alignment.centerLeft,
padding: const pw.EdgeInsets.symmetric(vertical: 5, horizontal: 8),
child: pw.Text(
text,
style: pw.TextStyle(fontWeight: pw.FontWeight.bold, font: font),
),
);
}
pw.Widget _buildDataCell(String text, pw.Font font, {bool alignRight = false}) {
return pw.Container(
alignment: alignRight ? pw.Alignment.centerRight : pw.Alignment.centerLeft,
padding: const pw.EdgeInsets.symmetric(vertical: 5, horizontal: 8),
child: pw.Text(
text,
style: pw.TextStyle(font: font),
),
);
}
}

View File

@ -1,40 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import './print_controller.dart';
class PrintPage extends GetView<PrintController> {
static const namedRoute = '/print-pdf-page';
const PrintPage({super.key});
@override
Widget build(BuildContext context) {
var printCtrl = controller;
return PopScope(
canPop: false,
child: SafeArea(
child: Scaffold(
appBar: AppBar(
title: const Text('PDF-Bericht'),
centerTitle: true,
actions: [
IconButton(
icon: const Icon(Icons.list, color: Colors.white),
onPressed: () {
// Handle logout logic here
printCtrl.goToTankListPage();
},
),
],
),
body: Center(
child: ElevatedButton(
// Ruft die Controller-Methode auf
onPressed: () => printCtrl.printPdfReport(),
child: const Text('PDF erstellen & drucken'),
),
),
),
),
);
}
}

View File

@ -1,337 +0,0 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite/models.dart' as models;
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:intl/intl.dart';
import '../../utils/extensions/static_helper.dart';
import '../../data/repository/location_repository.dart';
import '../../data/repository/appwrite_repository.dart';
import '../login/login_view.dart';
import '../tanklist/tanklist_view.dart';
class TankController extends GetxController {
final _dataBox = GetStorage('MyUserStorage');
//AppWrite API-REST get Data
final AppwriteRepository _authRepository = AppwriteRepository();
// GEOLOCATING Services
final LocationRepository _locationRepository = LocationRepository();
// Rx-Variablen für die UI, um auf Änderungen zu reagieren
final circleAvatarUserChar = 'A'.obs;
final userNameToDisplay = 'Test User'.obs;
final Rx<Position?> currentPosition = Rx<Position?>(null);
final Rx<bool> isLoading = false.obs;
final Rx<String?> errorMessage = Rx<String?>(null);
//final rxOrtString = '?'.obs;
final rxSessionIdString = '?'.obs;
final rxSummePreisString = '0.00'.obs;
// TextEditingController für die Formulareingaben
final formKeyTank = GlobalKey<FormState>();
bool isFormValid = false;
DateTime? _selectedDateTime;
final dateController = TextEditingController();
final f = DateFormat('yyyy-MM-dd');
final kilometerStandEdittingController = TextEditingController();
final mengeController = TextEditingController();
final pricePerLiterController = TextEditingController();
final ortController = TextEditingController();
final FocusNode firstFocusNode = FocusNode(); // Deklariere den FocusNode
final isEditMode = false.obs;
String documentId = '';
// Methode für das ausgewählte Datum
Future<void> selectDateTime(BuildContext context) async {
// 1. Datum auswählen
final DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: _selectedDateTime ?? DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime(2101),
);
_selectedDateTime = pickedDate;
if (_selectedDateTime != null) {
dateController.text = _selectedDateTime!.toIso8601String().substring(
0,
10,
);
}
}
/// Methode zum Abrufen des Standorts.
Future<void> fetchCurrentLocation() async {
isLoading.value = true;
errorMessage.value = null;
try {
final Position position = await _locationRepository.getCurrentPosition();
currentPosition.value = position;
final double latitude = position.latitude;
final double longitude = position.longitude;
// Hier kannst du die Logik hinzufügen, um den Standort zu verwenden, z.B.
// den Standort in der UI anzuzeigen oder an einen Server zu senden.
var map = {'lat': latitude, 'lng': longitude};
//save to local Storage lat and long
_dataBox.write('lastLatitude', latitude);
_dataBox.write('lastLongitude', longitude);
var loc = await _locationRepository.getNearbyLocation(map);
ortController.text = loc;
// Print Standortinformationen in der Konsole
print('Nearby Location: $loc');
print('Current Position: Latitude: $latitude, Longitude: $longitude');
} catch (e) {
// Hier fängst du die Fehler aus dem Repository auf
errorMessage.value = e.toString();
} finally {
isLoading.value = false;
}
update();
}
void clearTextEditingController() {
formKeyTank.currentState!.reset();
// Den Fokus wieder auf das erste Feld legen
FocusScope.of(Get.context!).requestFocus(firstFocusNode);
// TextEditingController zurücksetzen
_selectedDateTime = null; // Datum zurücksetzen
dateController.clear();
kilometerStandEdittingController.clear();
mengeController.clear();
pricePerLiterController.clear();
ortController.clear();
}
String? validateKilometerStand(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte Kilometerstand eingeben';
}
if (!GetUtils.isNum(value)) {
return 'Bitte geben Sie eine gültige Zahl ein';
}
return null;
}
String? validateMenge(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte Menge eingeben';
}
if (!GetUtils.isNum(value)) {
return 'Bitte geben Sie eine gültige Zahl ein';
}
return null;
}
String? validatePricePerLiter(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte Preis pro Liter eingeben';
}
if (!GetUtils.isNum(value)) {
return 'Bitte geben Sie eine gültige Zahl ein';
}
return null;
}
String? validateOrt(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte Ort eingeben...';
}
return null;
}
//Go to Login Page
void logoutSessionAndGoToLoginPage() async {
// Handle logout logic here
print('Logout session and go to login page');
// Clear GetStorage session ID
StaticHelper.removeFromStorage();
print('Session ID removed from GetStorage');
await _authRepository.logout();
Get.offAndToNamed(LoginPage.namedRoute);
StaticHelper.getMySnackeBar(
'Logout', 'Sie wurden abgemeldet!', Colors.blue);
}
@override
void onInit() {
super.onInit();
handleInputOrUpdate();
}
void handleInputOrUpdate() {
var mapFromArguments = Get.arguments as Map<String, dynamic>?;
if (mapFromArguments != null && mapFromArguments['from'] != null) {
isEditMode.value = mapFromArguments['from'] == 'Input' ? true : false;
}
//bei true ein insert bei false ein update
if (isEditMode.value) {
fetchCurrentLocation();
} else {
// Im Editiermodus, keine Standortabfrage durchführen
print('Im Editiermodus, keine Standortabfrage durchführen');
// Den Fokus auf das erste Eingabefeld setzen
FocusScope.of(Get.context!).requestFocus(firstFocusNode);
print('TankController is in Edit Mode');
if (mapFromArguments != null && mapFromArguments['data'] != null) {
var dataMap = mapFromArguments['data'] as Map<String, dynamic>;
print('Data Map for Edit Mode: $dataMap');
// Setze die documentId für spätere Updates
documentId = dataMap['\$id'] ?? '';
// Setze die Werte in die TextEditingController
dateController.text = dataMap['date'] ?? '';
kilometerStandEdittingController.text = dataMap['odometer'] ?? '';
mengeController.text = dataMap['liters'] ?? '';
pricePerLiterController.text = dataMap['pricePerLiter'] ?? '';
ortController.text = dataMap['location'] ?? '';
// Berechne den Gesamtpreis
updateSumPrice();
}
}
}
@override
void onReady() async {
super.onReady();
if (_dataBox.hasData('sessionId')) {
rxSessionIdString(_dataBox.read('sessionId').toString());
}
await getCurrentLoggedinUser();
FocusScope.of(Get.context!).requestFocus(firstFocusNode);
print('TankController is ready');
}
Future<void> getCurrentLoggedinUser() async {
await _authRepository.getCurrentUser.then((models.User user) {
// Hier kannst du den Benutzernamen und das Avatar-Zeichen setzen
userNameToDisplay.value = user.name;
circleAvatarUserChar.value = user.name.substring(0, 1).toUpperCase();
}).catchError((error) {
print('Fehler beim Abrufen des Benutzers: $error');
});
}
@override
void onClose() {
dateController.dispose();
kilometerStandEdittingController.dispose();
mengeController.dispose();
pricePerLiterController.dispose();
ortController.dispose();
firstFocusNode.dispose(); // Dispose den FocusNode
}
void updateSumPrice() {
final double menge = double.tryParse(mengeController.text) ?? 0.0;
final double pricePerLiter =
double.tryParse(pricePerLiterController.text) ?? 0.0;
final double sumPrice = menge * pricePerLiter;
rxSummePreisString.value = sumPrice.toStringAsFixed(
2,
); // Formatieren auf 2 Dezimalstellen
}
void saveTankstopp() async {
bool isErrorBySaving = false;
String messageToUser = '';
isFormValid = formKeyTank.currentState!.validate();
if (!isFormValid) {
print('Formular ist ungültig');
messageToUser = 'Bitte überprüfen Sie Ihre Eingaben.';
Get.snackbar(
'Fehler',
messageToUser,
snackPosition: SnackPosition.BOTTOM,
duration: const Duration(seconds: 2),
);
return;
} else {
print('Formular ist gültig');
formKeyTank.currentState!.save();
try {
//false update a tank stop
if (isEditMode.value == false) {
await _authRepository.updateTankStop(documentId, {
'userId': _dataBox.read('userId'),
'date': f.format(DateTime.parse(dateController.text)),
'odometer': kilometerStandEdittingController.text,
'liters': mengeController.text,
'pricePerLiter': pricePerLiterController.text,
'location': ortController.text,
}).then((models.Document document) {
print('Tankstopp erfolgreich aktualisiert: ${document.data}');
messageToUser = 'Tankstopp erfolgreich aktualisiert!';
isErrorBySaving = false;
})
// Handle specific Appwrite exceptions
.catchError((error) {
isErrorBySaving = true;
if (error is AppwriteException) {
// Handle specific Appwrite exceptions
messageToUser = 'Appwrite Fehler: ${error.message}';
print('Appwrite Fehler: ${error.message}');
} else {
// Handle other types of errors
messageToUser = 'Allgemeiner Fehler: $error';
print('Allgemeiner Fehler: $error');
}
print('Fehler bei der speicherung: $error');
});
} else {
//true creating a tank stop
await _authRepository.createTankStop({
'userId': _dataBox.read('userId'),
'date': f.format(DateTime.parse(dateController.text)),
'odometer': kilometerStandEdittingController.text,
'liters': mengeController.text,
'pricePerLiter': pricePerLiterController.text,
'location': ortController.text,
}).then((models.Document document) {
print('Tankstopp erfolgreich gespeichert: ${document.data}');
messageToUser = 'Tankstopp erfolgreich gespeichert!';
isErrorBySaving = false;
})
// Handle specific Appwrite exceptions
.catchError((error) {
isErrorBySaving = true;
if (error is AppwriteException) {
// Handle specific Appwrite exceptions
messageToUser = 'Appwrite Fehler: ${error.message}';
print('Appwrite Fehler: ${error.message}');
} else {
// Handle other types of errors
messageToUser = 'Allgemeiner Fehler: $error';
print('Allgemeiner Fehler: $error');
}
print('Fehler bei der speicherung: $error');
});
// bei true ein insert
}
}
// Handle any other exceptions that might occur
catch (e) {
isErrorBySaving = true;
messageToUser = 'Fehler beim Speichern des Tankstopps: $e';
print('Fehler beim speichern: $e');
}
if (!isErrorBySaving) {
clearTextEditingController();
}
// Handle button press logic here
String title = isErrorBySaving ? 'Fehler' : 'Erfolg';
Get.snackbar(
title,
messageToUser,
backgroundColor: isErrorBySaving ? Colors.red : Colors.green,
snackPosition: SnackPosition.BOTTOM,
duration: const Duration(seconds: 4),
);
goToTankStopsView();
}
}
goToTankStopsView() async {
clearTextEditingController();
await Get.offAndToNamed(TanklistPage.namedRoute);
}
}

View File

@ -1,304 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import './tank_controller.dart';
class TankPage extends GetView<TankController> {
static const namedRoute = '/tank-stop-page';
const TankPage({super.key});
@override
Widget build(BuildContext context) {
var tankCtrl = controller;
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text(
'Tankstopp erfassen',
style: TextStyle(color: Colors.grey.shade300),
),
backgroundColor: Colors.transparent, // Mach die AppBar transparent
elevation: 0, // Entferne den Schatten unter der AppBar
centerTitle: true,
actions: [
IconButton(
icon: Icon(Icons.list, color: Colors.grey.shade300),
onPressed: () async {
// Handle logout logic here
controller.goToTankStopsView();
},
),
IconButton(
icon: Icon(Icons.logout, color: Colors.grey.shade300),
onPressed: () async {
// Handle logout logic here
controller.logoutSessionAndGoToLoginPage();
},
),
],
),
extendBodyBehindAppBar: true, // Erweitere den Body hinter die AppBar
body: Stack(
children: [
Container(
height: double.infinity,
width: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('lib/images/backgroundPitstopBlack.png'),
fit: BoxFit
.cover, // Skaliert das Bild, um den Container zu füllen
alignment: Alignment
.bottomCenter, // Richte das Bild am unteren Rand aus
),
),
),
Obx(
() => PopScope(
canPop: false,
child: SingleChildScrollView(
padding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top +
kToolbarHeight +
20,
left: 20,
right: 20,
bottom: 20,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircleAvatar(
backgroundColor: Colors.blue,
radius: 40,
child: Text(
controller.circleAvatarUserChar.value,
style: const TextStyle(
color: Colors.black,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 5),
Text(
controller.userNameToDisplay.value,
style: const TextStyle(
fontSize: 20,
backgroundColor: Colors.black87,
color: Colors.white,
fontWeight: FontWeight.bold,
letterSpacing: 3,
),
),
const SizedBox(height: 20),
inputFields(),
const SizedBox(height: 20),
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.black.withValues(alpha: 0.9),
),
child: Text.rich(
TextSpan(
text: 'Summe: ',
style: TextStyle(
fontSize: 18,
color: Colors.grey.shade300,
),
children: <TextSpan>[
TextSpan(
// Hier kommt der Wert als separater TextSpan
text: controller.rxSummePreisString.value,
// Doppelt so groß wie der Standardtext',
style: TextStyle(
fontSize: 30, // Doppelt so groß wie 18
color: Colors.blue, // Blaue Farbe
fontWeight: FontWeight
.bold, // Optional: Fetter Text, um ihn hervorzuheben
),
),
],
),
),
),
const SizedBox(height: 20),
SizedBox(
width: 350,
height: 50,
child: Obx(
() => ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue.withValues(
alpha: 0.9,
), // Button-Farbe
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
10,
), // Abgerundete Ecken
),
),
onPressed: () {
controller.saveTankstopp();
},
child: tankCtrl.isEditMode.value == true ? Text(
'Tankstop erfassen',
style:
TextStyle(color: Colors.white, fontSize: 20),
): Text(
'Tankstop updaten',
style: TextStyle(
color: Colors.white, fontSize: 20),
),
),
),
),
Container(
margin: EdgeInsets.only(top: 20, bottom: 50),
child: Text(
'Hinweis: Alle Felder sind Pflichtfelder.',
style: TextStyle(
fontSize: 16,
color: Colors.red.shade300,
),
),
),
],
),
),
),
),
],
),
),
);
}
Widget inputFields() {
return SizedBox(
width: 320,
child: Form(
key: controller.formKeyTank,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
children: [
TextFormField(
validator: (value) => controller.validateOrt(value),
focusNode: controller.firstFocusNode, // Setze den FocusNode
//onTap: () => controller.selectDateTime(Get.context!),
controller: controller.ortController,
decoration: InputDecoration(
labelText: 'Ort der Tankstelle',
labelStyle: const TextStyle(color: Colors.white, fontSize: 20),
errorStyle: const TextStyle(color: Colors.red, fontSize: 16),
filled: true,
fillColor: Colors.black.withValues(alpha: 0.9),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.white, width: 2),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none, // Entferne den Rand
),
),
style: const TextStyle(color: Colors.white),
),
SizedBox(height: 20),
TextFormField(
//focusNode: controller.firstFocusNode, // Setze den FocusNode
readOnly: true,
onTap: () => controller.selectDateTime(Get.context!),
keyboardType: TextInputType.text,
controller: controller.dateController,
decoration: InputDecoration(
labelText: 'Datum',
labelStyle: const TextStyle(color: Colors.white, fontSize: 20),
errorStyle: const TextStyle(color: Colors.red, fontSize: 16),
filled: true,
fillColor: Colors.black.withValues(alpha: 0.9),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.white, width: 2),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none, // Entferne den Rand
),
),
style: const TextStyle(color: Colors.white),
),
SizedBox(height: 20),
TextFormField(
validator: (value) => controller.validateKilometerStand(value),
keyboardType: TextInputType.number,
controller: controller.kilometerStandEdittingController,
decoration: InputDecoration(
labelText: 'Kilometerstand',
labelStyle: const TextStyle(color: Colors.white, fontSize: 20),
errorStyle: const TextStyle(color: Colors.red, fontSize: 16),
filled: true,
fillColor: Colors.black.withValues(alpha: 0.9),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.white, width: 2),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none, // Entferne den Rand
),
),
),
SizedBox(height: 20),
TextFormField(
validator: (value) => controller.validateMenge(value),
keyboardType: TextInputType.number,
controller: controller.mengeController,
decoration: InputDecoration(
labelText: 'Menge (in Litern)',
labelStyle: const TextStyle(color: Colors.white, fontSize: 20),
errorStyle: const TextStyle(color: Colors.red, fontSize: 16),
filled: true,
fillColor: Colors.black.withValues(alpha: 0.9),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.white, width: 2),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none, // Entferne den Rand
),
),
),
SizedBox(height: 20),
TextFormField(
onChanged: (value) {
// Update the sum price when the price per liter changes
controller.updateSumPrice();
},
validator: (value) => controller.validatePricePerLiter(value),
keyboardType: TextInputType.number,
controller: controller.pricePerLiterController,
decoration: InputDecoration(
labelText: 'Preis pro Liter',
labelStyle: const TextStyle(color: Colors.white, fontSize: 20),
errorStyle: const TextStyle(color: Colors.red, fontSize: 16),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.white, width: 2),
),
filled: true,
fillColor: Colors.black.withValues(alpha: 0.9),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
//borderSide: BorderSide.none, // Entferne den Rand
),
),
),
],
),
),
);
}
}

View File

@ -1,179 +0,0 @@
import 'package:appwrite/appwrite.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import '../login/login_view.dart';
import '../graph/graph_view.dart';
import '../../data/models/tank_model.dart';
import '../../data/repository/appwrite_repository.dart';
import '../../pages/tank/tank_view.dart';
import '../../pages/gaslist/gaslist_view.dart';
import '../print/print_view.dart';
class TanklistController extends GetxController {
final _dataBox = GetStorage('MyUserStorage');
final isloadingList = false.obs;
final rxTankListAlles = <AppWriteTankModel>[].obs;
final rxTankListActualYear = <AppWriteTankModel>[].obs;
final szRxUserId = 'NoUser'.obs;
//AppWrite API-REST get Data
final AppwriteRepository _authRepository = AppwriteRepository();
final szRxYear = DateTime.now().year.obs.toString().obs;
final szRxSummeYearLiter = '0.0'.obs;
final szRxSummePrice = '0.0'.obs;
@override
void onInit() {
szRxUserId(_dataBox.read('userId'));
super.onInit();
}
@override
void onReady() {
getTankList();
super.onReady();
}
@override
void onClose() {}
Future<void> getTankList() async {
isloadingList(true);
bool isErrorByLoading = false;
String message = '';
try {
await _authRepository
.listTankStops(szRxUserId.value)
.then((tankListData) {
if (tankListData.documents.isEmpty) {
isErrorByLoading = false;
message = 'Leere Liste keine Daten vorhanden';
isloadingList(false);
rxTankListAlles.clear();
rxTankListActualYear.clear();
szRxSummeYearLiter('0.0');
szRxSummePrice('0.0');
update();
return;
}
rxTankListAlles.clear();
var data = tankListData.toMap();
List d = data['documents'].toList();
rxTankListAlles.value =
d.map((e) => AppWriteTankModel.fromMap(e['data'])).toList();
rxTankListAlles.sort((a, b) {
final DateTime dateA = DateTime.parse(a.date);
final DateTime dateB = DateTime.parse(b.date);
return dateB.compareTo(dateA);
});
//Tank List per Actual year**********
rxTankListActualYear.clear();
rxTankListActualYear.value = rxTankListAlles
.where((tank) => tank.date.startsWith(szRxYear.value))
.toList();
// rxTankListActualYear.value = rxTankListAlles;
//Summe Liter aktuelles Jahr*********
szRxSummeYearLiter(
rxTankListActualYear.fold<double>(0.0, (previousValue, element) {
return previousValue + (double.tryParse(element.liters) ?? 0.0);
}).toStringAsFixed(2));
//Summe Preis aktuelles Jahr*********
szRxSummePrice(
rxTankListActualYear.fold<double>(0.0, (previousValue, element) {
return previousValue +
(double.tryParse(element.szSummePreis!) ?? 0.0);
}).toStringAsFixed(2));
message = 'Liste wurde erfolgreich geladen';
isErrorByLoading = false;
}).catchError((error) {
isErrorByLoading = true;
if (error is AppwriteException) {
message = error.message!;
} else {
message = 'Uuups da ist was schief gelaufen';
}
});
} catch (e) {
isErrorByLoading = true;
message = 'Fehler beim Laden der Tankliste';
print('Error fetching tank list: $e');
} finally {
if (!isErrorByLoading) {
isloadingList(false);
}
}
String title = isErrorByLoading ? 'Fehler' : 'Erfolg';
print('$title: $message');
update();
}
void goToUpdatePage(AppWriteTankModel item) {
var map = item.toMap();
print('Go to Update Page with data: $map');
// Go to Update Page
Get.offAndToNamed(TankPage.namedRoute,
arguments: {'from': 'Update', 'data': map});
}
void goToInputPage() {
Get.offAndToNamed(TankPage.namedRoute, arguments: {'from': 'Input'});
}
void logoutSessionAndGoToLoginPage() async {
// Handle logout logic here
print('Logout session and go to login page');
// Clear GetStorage session ID
_dataBox.remove('sessionId');
_dataBox.remove('userId');
_dataBox.remove('userName');
_dataBox.remove('userEmail');
print('Session ID removed from GetStorage');
await _authRepository.logout();
Get.offAndToNamed(LoginPage.namedRoute);
}
void goToChartView() {
Get.offAndToNamed(GraphPage.namedRoute);
}
void deleteTankStop(String documentId) async {
bool isErrorByLoading = false;
String message = '';
try {
await _authRepository.deleteTankStop(documentId).then((response) async {
await getTankList();
message = 'Tankstopp wurde erfolgreich gelöscht';
}).catchError((error) {
isErrorByLoading = true;
if (error is AppwriteException) {
message = error.message!;
} else {
message = 'Uuups da ist was schief gelaufen';
}
});
} catch (e) {
isErrorByLoading = true;
message = 'Fehler beim Löschen des Tankstopps';
print('Error deleting tank stop: $e');
}
String title = isErrorByLoading ? 'Fehler' : 'Erfolg';
print('$title: $message');
}
Future<void> goToGasView() async {
//Go to Gas Station List Page
await Get.offAndToNamed(GaslistPage.namedRoute);
}
void goToPrintView() {
List<Map<String, dynamic>> tankMap = rxTankListActualYear.map((e) => e.toMap()).toList();
Get.offAndToNamed(PrintPage.namedRoute, arguments: {
'tankList': tankMap,
'year': szRxYear.value,
'summeLiter': szRxSummeYearLiter.value,
'summePreis': szRxSummePrice.value,
});
}
}

View File

@ -1,169 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import './tanklist_controller.dart';
import './widgets/my_list_tile_item.dart';
class TanklistPage extends GetView<TanklistController> {
static const namedRoute = '/tank-stop-liste-page';
const TanklistPage({super.key});
@override
Widget build(BuildContext context) {
var tankListCtrl = controller;
return PopScope(
canPop: false,
child: SafeArea(
child: Scaffold(
appBar: AppBar(
shadowColor: Colors.grey,
title: Text('Tankstops'),
centerTitle: true,
//backgroundColor: Colors.grey.shade600,
actions: [
IconButton(
icon: Icon(Icons.add_chart, color: Colors.grey.shade300),
onPressed: () async {
// Handle go to Chart View
tankListCtrl.goToChartView();
},
),
IconButton(
icon: Icon(Icons.local_gas_station_sharp, color: Colors.grey.shade300),
onPressed: () async {
// Handle go to Chart View
tankListCtrl.goToGasView();
},
),
IconButton(
icon: Icon(Icons.print,
color: Colors.grey.shade300),
onPressed: () async {
// Handle go to Chart View
tankListCtrl.goToPrintView();
},
),
IconButton(
icon: Icon(Icons.logout, color: Colors.grey.shade300),
onPressed: () async {
// Handle logout logic here
tankListCtrl.logoutSessionAndGoToLoginPage();
},
),
],
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment
.end, // Positioniere die Buttons am unteren Ende
crossAxisAlignment: CrossAxisAlignment.end, // Richte sie rechts aus
mainAxisSize: MainAxisSize.min, // Nimm nur den benötigten Platz ein
children: [
FloatingActionButton(
onPressed: () => tankListCtrl.goToInputPage(),
backgroundColor: Colors.blue,
child: Icon(Icons.add),
),
],
),
body: Obx(() => tankListCtrl.isloadingList.value == false
? Padding(
padding: EdgeInsetsGeometry.only(left: 25, right: 25),
child: Column(
children: [
SizedBox(
child: Column(
children: [
Text(tankListCtrl.szRxYear.value,
style: TextStyle(
fontSize: 25, color: Colors.orange)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: [
Text('Jahresverbrauch',
style: TextStyle(fontSize: 14)),
Text(tankListCtrl.szRxSummeYearLiter.value,
style: TextStyle(
fontSize: 20,
color: Colors.orange)),
],
),
Column(
children: [
Text('Jahressumme',
style: TextStyle(fontSize: 14)),
Text(tankListCtrl.szRxSummePrice.value,
style: TextStyle(
fontSize: 20,
color: Colors.orange)),
],
),
],
),
],
),
),
Divider(
color: Colors.grey.shade200,
height: 0.0,
),
Expanded(
child: tankListCtrl.rxTankListActualYear.isNotEmpty ? ListView.builder(
padding: EdgeInsets.only(top: 8, bottom: 8),
physics: const BouncingScrollPhysics(),
itemBuilder: ((BuildContext context, int index) {
var item = tankListCtrl.rxTankListActualYear[index];
return Column(
children: [
Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.blue.withValues(
alpha: 0.35,
), // Die Farbe des Schattens
spreadRadius:
1, // Wie weit sich der Schatten ausbreitet
blurRadius:
1, // Wie stark der Schatten verschwommen ist
offset: const Offset(
0,
3,
), // Der Versatz des Schattens (x, y)
),
],
),
child: MyListTileItem(
listItem: item,
onPressedEdit: () {
tankListCtrl.goToUpdatePage(item);
},
onPressedDelete: () {
tankListCtrl.deleteTankStop(item.documentId);
},
),
),
SizedBox(height: 15),
],
);
}),
itemCount: tankListCtrl.rxTankListActualYear.length,
): Center(
child: Text('Keine Einträge für das aktuelle Jahr vorhanden',
style: TextStyle(
fontSize: 18, color: Colors.grey.shade600)),
),
),
],
),
)
: Center(
child: CircularProgressIndicator(
color: Colors.blue,
),
)),
),
),
);
}
}

View File

@ -1,131 +0,0 @@
import 'package:flutter/material.dart';
import '../../../data/models/tank_model.dart';
class MyListTileItem extends StatelessWidget {
const MyListTileItem(
{super.key, required this.listItem, required this.onPressedEdit, required this.onPressedDelete});
final AppWriteTankModel listItem;
final void Function()? onPressedEdit;
final void Function()? onPressedDelete;
@override
Widget build(BuildContext context) {
return _myListItem(context);
}
Widget _myListItem(BuildContext context) {
var textColor = Colors.orange.shade400;
return Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Wrap(
alignment: WrapAlignment.spaceBetween,
children: [
Row(
children: [
Icon(Icons.date_range),
SizedBox(width: 10),
Text(
listItem.date,
style: TextStyle(color: textColor, fontSize: 25),
),
],
),
Row(
children: [
Image.asset('lib/icons/kilometer.png'),
SizedBox(width: 10),
Text(
'${listItem.odometer} km',
style: TextStyle(color: textColor, fontSize: 25),
),
],
),
],
),
Divider(thickness: 3, color: Colors.black),
Row(
children: [
Icon(Icons.local_gas_station),
SizedBox(width: 10),
Text(
'${listItem.liters} L',
style: TextStyle(color: textColor, fontSize: 25),
),
],
),
Divider(thickness: 1, color: Colors.black),
Row(
children: [
Icon(Icons.euro),
SizedBox(width: 10),
Text(
'${listItem.pricePerLiter} €/L ',
style: TextStyle(color: textColor, fontSize: 25),
),
],
),
Divider(thickness: 1, color: Colors.black),
Row(
children: [
Icon(Icons.price_change),
SizedBox(width: 10),
Text('${listItem.szSummePreis}',
style: TextStyle(color: textColor, fontSize: 25)),
],
),
Divider(thickness: 1, color: Colors.black),
Wrap(
children: [
Icon(Icons.pin_drop),
SizedBox(width: 10),
SizedBox(
width: 250,
child: Text(
listItem.location,
style: TextStyle(color: textColor, fontSize: 16),
),
),
],
),
Divider(thickness: 1, color: Colors.black),
Wrap(
spacing: 10,
children: [
ElevatedButton.icon(
onPressed: onPressedEdit,
label: Text(
'Edit',
style: TextStyle(color: Colors.grey.shade200),
),
icon: const Icon(Icons.edit),
style: ElevatedButton.styleFrom(
backgroundColor: const Color.fromARGB(255, 3, 71, 128),
foregroundColor: Colors.grey.shade200,
shadowColor: Colors.white,
),
),
ElevatedButton.icon(
onPressed: onPressedDelete,
label: Text(
'Delete',
style: TextStyle(color: Colors.grey.shade200),
),
icon: const Icon(Icons.delete),
style: ElevatedButton.styleFrom(
backgroundColor: const Color.fromARGB(255, 128, 3, 45),
foregroundColor: Colors.grey.shade200,
shadowColor: Colors.white,
),
),
],
),
],
),
);
}
}

View File

@ -1,6 +1,6 @@
import 'dart:math';
import '../../utils/extensions/colors.dart';
import 'package:appwrite_flutter_starter_kit/utils/extensions/colors.dart';
import 'package:flutter/material.dart';
/// Background color for gradients, blur, etc.

View File

@ -1,8 +1,8 @@
import '../../data/models/log.dart';
import '../../data/models/project_info.dart';
import '../../ui/components/responsive_layout.dart';
import '../../ui/components/single_wrap.dart';
import '../../utils/extensions/colors.dart';
import 'package:appwrite_flutter_starter_kit/data/models/log.dart';
import 'package:appwrite_flutter_starter_kit/data/models/project_info.dart';
import 'package:appwrite_flutter_starter_kit/ui/components/responsive_layout.dart';
import 'package:appwrite_flutter_starter_kit/ui/components/single_wrap.dart';
import 'package:appwrite_flutter_starter_kit/utils/extensions/colors.dart';
import 'package:flutter/material.dart';
class CollapsibleBottomSheet extends StatefulWidget {
@ -235,8 +235,8 @@ class ProjectSection extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Column(
children: [
Wrap(
alignment: WrapAlignment.spaceBetween,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ProjectRow(title: "Endpoint", value: projectInfo.endpoint),
ProjectRow(title: "Project ID", value: projectInfo.projectId),
@ -491,7 +491,7 @@ class LogsTableRow extends StatelessWidget {
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: Text(
response.length >= 50 ? response.substring(0, 50) : response,
response.length > 50 ? response.substring(0, 50) : response,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(

View File

@ -1,4 +1,4 @@
import '../../utils/extensions/build_context.dart';
import 'package:appwrite_flutter_starter_kit/utils/extensions/build_context.dart';
import 'package:flutter/material.dart';
/// A widget that animates a connection line with a checkmark in the middle.
@ -15,7 +15,7 @@ class ConnectionLine extends StatelessWidget {
return SizedBox(
width: context.widthFactor(
mobileFactor: 0.25,
largeScreenFactor: 0.1,
largeScreenFactor: 0.125,
),
child: Flex(
direction: Axis.horizontal,

View File

@ -1,4 +1,4 @@
import '../../data/models/status.dart';
import 'package:appwrite_flutter_starter_kit/data/models/status.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

View File

@ -1,94 +1,60 @@
import '../../ui/components/responsive_layout.dart';
import '../../utils/extensions/build_context.dart';
import 'package:appwrite_flutter_starter_kit/utils/extensions/build_context.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
const cardWidgets = [
GeneralInfoCard(
title: "Edit your app",
link: null,
subtitle: HighlightedText(),
),
GeneralInfoCard(
title: "Head to Appwrite Cloud",
link: "https://cloud.appwrite.io",
subtitle: Text(
"Start managing your project from the Appwrite console",
style: TextStyle(fontSize: 14, color: Color(0xFF56565C)),
),
),
GeneralInfoCard(
title: "Explore docs",
link: "https://appwrite.io/docs",
subtitle: Text(
"Discover the full power of Appwrite by diving into our documentation",
style: TextStyle(fontSize: 14, color: Color(0xFF56565C)),
),
),
];
/// A widget that contains a list of informational cards displayed vertically.
class GettingStartedCards extends StatelessWidget {
const GettingStartedCards({super.key});
@override
Widget build(BuildContext context) {
return ResponsiveLayout(
smallDeviceLayout: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
GeneralInfoCard(
title: "Edit your app",
link: null,
subtitle: const HighlightedText(),
return Padding(
padding: const EdgeInsets.all(16.0),
child: context.isLargeScreen
? Wrap(
spacing: 16,
runSpacing: 16,
alignment: WrapAlignment.center,
children: cardWidgets
.map((card) => SizedBox(
width: 350,
child: card,
))
.toList(),
)
: Column(
mainAxisSize: MainAxisSize.min,
children: cardWidgets
.map((card) => Padding(
padding: const EdgeInsets.only(bottom: 16),
child: card,
))
.toList(),
),
GeneralInfoCard(
title: "Head to Appwrite Cloud",
link: "https://cloud.appwrite.io",
subtitle: const Text(
"Start managing your project from the Appwrite console",
style: TextStyle(
fontSize: 14,
color: Color(0xFF56565C),
),
),
),
GeneralInfoCard(
title: "Explore docs",
link: "https://appwrite.io/docs",
subtitle: const Text(
"Discover the full power of Appwrite by diving into our documentation",
style: TextStyle(
fontSize: 14,
color: Color(0xFF56565C),
),
),
),
],
),
),
largeDeviceLayout: Padding(
padding: EdgeInsets.symmetric(
horizontal: context.isExtraWideScreen ? 64 : 16.0, vertical: 16.0),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
spacing: 16,
children: [
Flexible(
child: GeneralInfoCard(
title: "Edit your app",
link: null,
subtitle: const HighlightedText(),
),
),
Flexible(
child: GeneralInfoCard(
title: "Head to Appwrite Cloud",
link: "https://cloud.appwrite.io",
subtitle: const Text(
"Start managing your project from the Appwrite console",
style: TextStyle(
fontSize: 14,
color: Color(0xFF56565C),
),
),
),
),
Flexible(
child: GeneralInfoCard(
title: "Explore docs",
link: "https://appwrite.io/docs",
subtitle: const Text(
"Discover the full power of Appwrite by diving into our documentation",
style: TextStyle(
fontSize: 14,
color: Color(0xFF56565C),
),
),
),
),
],
),
),
);
}
}
@ -115,12 +81,9 @@ class GeneralInfoCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
final double cardWidth = context.isExtraWideScreen
? constraints.maxWidth.clamp(0, 350)
: constraints.maxWidth;
return SizedBox(
width: cardWidth,
// `1` because we already have padding on sides.
width: constraints.maxWidth * (context.isExtraWideScreen ? 0.55 : 1),
child: Card(
elevation: 0,
shape: RoundedRectangleBorder(

View File

@ -1,6 +1,6 @@
import '../../data/models/status.dart';
import '../../ui/icons/appwrite.dart';
import '../../utils/extensions/build_context.dart';
import 'package:appwrite_flutter_starter_kit/data/models/status.dart';
import 'package:appwrite_flutter_starter_kit/ui/icons/appwrite.dart';
import 'package:appwrite_flutter_starter_kit/utils/extensions/build_context.dart';
import 'package:flutter/material.dart';
import 'connection_line.dart';
@ -19,19 +19,24 @@ class TopPlatformView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
PlatformIcon(
size: context.isExtraWideScreen ? 142 : 100,
child: FlutterLogo(size: context.isExtraWideScreen ? 56 : 40),
),
ConnectionLine(show: status == Status.success),
PlatformIcon(
size: context.isExtraWideScreen ? 142 : 100,
child: AppwriteIcon(size: context.isExtraWideScreen ? 56 : 40),
),
],
return Padding(
// web has extra padding on top.
padding:
context.isLargeScreen ? EdgeInsets.only(top: 85) : EdgeInsets.zero,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
PlatformIcon(
size: context.isLargeScreen ? 185 : 100,
child: FlutterLogo(size: context.isLargeScreen ? 100 : 40),
),
ConnectionLine(show: status == Status.success),
PlatformIcon(
size: context.isLargeScreen ? 185 : 100,
child: AppwriteIcon(size: context.isLargeScreen ? 100 : 40),
),
],
),
);
}
}
@ -58,7 +63,7 @@ class PlatformIcon extends StatelessWidget {
height: size,
decoration: BoxDecoration(
color: const Color(0xFFFAFAFD),
borderRadius: BorderRadius.circular(context.isExtraWideScreen ? size * 0.2 : 24),
borderRadius: BorderRadius.circular(context.isLargeScreen ? 44 : 24),
border: Border.all(color: const Color(0x0A19191C), width: 1),
boxShadow: [
BoxShadow(
@ -72,10 +77,9 @@ class PlatformIcon extends StatelessWidget {
child: Container(
width: size * 0.86,
height: size * 0.86,
margin: context.isExtraWideScreen ? EdgeInsets.all(8) : null,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(context.isExtraWideScreen ? size * 0.2: 16),
borderRadius: BorderRadius.circular(context.isLargeScreen ? 32 : 16),
border: Border.all(color: const Color(0xFFFAFAFB), width: 1),
boxShadow: [
BoxShadow(

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
class AppwriteIcon extends StatelessWidget {
final double size; // Desired width, height scales accordingly
final double size;
final Color color;
const AppwriteIcon({

View File

@ -3,11 +3,7 @@ import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:window_manager/window_manager.dart';
import 'package:intl/date_symbol_data_local.dart';
import './extensions/http_overrides.dart';
/// A utility class for initializing the Flutter application.
///
@ -23,11 +19,6 @@ class AppInitializer {
_ensureInitialized();
await _setupWindowDimensions();
await _setupDeviceOrientation();
await _setupDateFormating();
//dotENV initial
await dotenv.load(fileName: '.env');
//Overrides initial
HttpOverrides.global = MyHttpOverrides();
}
/// Ensures that Flutter bindings are initialized.
@ -60,8 +51,4 @@ class AppInitializer {
overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top],
);
}
// Initialisiert die Lokalisierungsdaten für eine bestimmte Sprache
static Future<void> _setupDateFormating() async {
await initializeDateFormatting('de_DE', null);
}
}

View File

@ -1,29 +0,0 @@
import 'package:flutter/material.dart';
var kTextStyle = TextStyle(fontSize: 20, color: Colors.grey.shade100);
var kTextStyleSub = TextStyle(fontSize: 16, color: Colors.grey.shade400);
var kColorEuroChart = Colors.red.shade500;
var kColorBenzinChart = Colors.yellow.shade500;
var kColorPerLiterChart = Colors.blueGrey.shade300;
var kChartDescriptionFontStyle = TextStyle(
color: Colors.grey.shade900,
fontWeight: FontWeight.bold,
fontSize: 16,
);
var kBarTitleStyle = TextStyle(
color: Colors.blue.shade900,
fontWeight: FontWeight.bold,
fontSize: 14,
);
var kInputDecorationDropDownMenueYear = const InputDecoration(
prefixIcon: Icon(Icons.date_range),
hintText: 'Jahresauswahl',
filled: true,
fillColor: Colors.black,
errorStyle: TextStyle(color: Colors.yellow),
);

View File

@ -1,9 +0,0 @@
import 'dart:io';
class MyHttpOverrides extends HttpOverrides{
@override
HttpClient createHttpClient(SecurityContext? context){
return super.createHttpClient(context)
..badCertificateCallback = (X509Certificate cert, String host, int port)=> true;
}
}

View File

@ -1,21 +0,0 @@
import 'package:get/get.dart';
import '../../pages/gaslist/gaslist_controller.dart';
import '../../pages/graph/graph_controller.dart';
import '../../pages/login/login_controller.dart';
import '../../pages/tank/tank_controller.dart';
import '../../pages/tanklist/tanklist_controller.dart';
import '../../pages/print/print_controller.dart';
class SampleBindings extends Bindings {
@override
void dependencies() {
// Define your dependencies here
Get.lazyPut<LoginController>(() => LoginController());
Get.lazyPut<TankController>(() => TankController());
Get.lazyPut<TanklistController>(() => TanklistController());
Get.lazyPut<GraphController>(() => GraphController());
Get.lazyPut<GaslistController>(() => GaslistController());
Get.lazyPut<PrintController>(() => PrintController());
}
}

View File

@ -1,53 +0,0 @@
import 'package:get/get.dart';
import '../../pages/graph/graph_view.dart';
import '../../pages/login/login_view.dart';
import '../../pages/print/print_view.dart';
import '../../pages/tank/tank_view.dart';
import '../../pages/tanklist/tanklist_view.dart';
import '../../pages/gaslist/gaslist_view.dart';
import './sample_bindings.dart';
class SampleRouts {
static final sampleBindings = SampleBindings();
static List<GetPage<dynamic>> samplePages = [
GetPage(
name: LoginPage.namedRoute,
page: () => const LoginPage(),
binding: sampleBindings,
),
GetPage(
name: TankPage.namedRoute,
page: () => const TankPage(),
binding: sampleBindings,
),
GetPage(
name: TanklistPage.namedRoute,
page: () => const TanklistPage(),
binding: sampleBindings,
),
GetPage(
name: GraphPage.namedRoute,
page: () => const GraphPage(),
binding: sampleBindings,
),
GetPage(
name: GaslistPage.namedRoute,
page: () => const GaslistPage(),
binding: sampleBindings,
),
GetPage(
name: PrintPage.namedRoute,
page: () => const PrintPage(),
binding: sampleBindings,
),
// GetPage(
// name: MapPage.namedRoute,
// page: () => const MapPage(),
// binding: SampleBindings(),
// ),
];
}

View File

@ -1,89 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import '../../data/models/tank_model.dart';
class StaticHelper {
static double sumMonatEuro = 0.0;
static double sumMonatLiter = 0.0;
static List staticSearchList = [];
static GetStorage dataBox = GetStorage('MyUserStorage');
static List listMonth = [
{'month': 'Jänner', 'value': '01'},
{'month': 'Februar', 'value': '02'},
{'month': 'März', 'value': '03'},
{'month': 'April', 'value': '04'},
{'month': 'Mai', 'value': '05'},
{'month': 'Juni', 'value': '06'},
{'month': 'Juli', 'value': '07'},
{'month': 'August', 'value': '08'},
{'month': 'September', 'value': '09'},
{'month': 'Oktober', 'value': '10'},
{'month': 'November', 'value': '11'},
{'month': 'Dezember', 'value': '12'},
];
static List staticListGetDaysInBetween(
List<AppWriteTankModel> list,
String monthValue,
int year,
) {
List<AppWriteTankModel> searchList = [];
List<DateTime> days = [];
var dateYear = year;
var auswahlMonat = int.parse(monthValue);
var startDate = DateTime(dateYear, auswahlMonat, 1);
var endDate = DateTime(dateYear, auswahlMonat + 1, 0);
//List of Days
for (int i = 0; i <= endDate.difference(startDate).inDays; i++) {
days.add(DateTime(startDate.year, startDate.month, startDate.day + i));
}
sumMonatEuro = 0.0;
sumMonatLiter = 0.0;
int entryCounter = 0;
for (var day in days) {
for (AppWriteTankModel model in list) {
int milliSecDate = (DateTime.parse(model.date)).microsecondsSinceEpoch;
if (milliSecDate == day.microsecondsSinceEpoch) {
entryCounter = entryCounter + 1;
model.mnIndexCount = entryCounter;
searchList.add(model);
var mnEuroGesamt =
double.parse(model.liters) * double.parse(model.pricePerLiter);
sumMonatEuro += mnEuroGesamt;
sumMonatLiter += double.parse(model.liters);
}
}
}
searchList.sort((a, b) {
final DateTime dateA = DateTime.parse(a.date);
final DateTime dateB = DateTime.parse(b.date);
return dateB.compareTo(dateA);
});
return staticSearchList = searchList;
}
static getMySnackeBar(String title, String message, Color backgroundColor) {
Get.snackbar(
title,
message,
backgroundColor: backgroundColor,
snackPosition: SnackPosition.BOTTOM,
duration: const Duration(seconds: 4),
);
}
static removeFromStorage() {
dataBox.remove('sessionId');
dataBox.remove('userId');
dataBox.remove('userName');
dataBox.remove('userEmail');
}
static bool hasData() {
return dataBox.hasData('sessionId');
}
}

View File

@ -7,7 +7,6 @@
#include "generated_plugin_registrant.h"
#include <desktop_webview_window/desktop_webview_window_plugin.h>
#include <printing/printing_plugin.h>
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
#include <window_manager/window_manager_plugin.h>
@ -17,9 +16,6 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWebviewWindowPlugin");
desktop_webview_window_plugin_register_with_registrar(desktop_webview_window_registrar);
g_autoptr(FlPluginRegistrar) printing_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "PrintingPlugin");
printing_plugin_register_with_registrar(printing_registrar);
g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin");
screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar);

View File

@ -4,7 +4,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
desktop_webview_window
printing
screen_retriever_linux
url_launcher_linux
window_manager

View File

@ -8,10 +8,8 @@ import Foundation
import desktop_webview_window
import device_info_plus
import flutter_web_auth_2
import geolocator_apple
import package_info_plus
import path_provider_foundation
import printing
import screen_retriever_macos
import url_launcher_macos
import window_manager
@ -21,10 +19,8 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin"))
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))

View File

@ -67,7 +67,7 @@
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* AppwriteStarterKit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tankguru_flutter_app_appwrite.app; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10ED2044A3C60003C045 /* AppwriteStarterKit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = appwrite_flutter_starter_kit.app; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };

View File

@ -2,14 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to your location to find nearby gas stations and services.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to your location to track your position even when the app is in the background.</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>

View File

@ -41,22 +41,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.11.0"
barcode:
dependency: transitive
description:
name: barcode
sha256: "7b6729c37e3b7f34233e2318d866e8c48ddb46c1f7ad01ff7bb2a8de1da2b9f4"
url: "https://pub.dev"
source: hosted
version: "2.2.9"
bidi:
dependency: transitive
description:
name: bidi
sha256: "77f475165e94b261745cf1032c751e2032b8ed92ccb2bf5716036db79320637d"
url: "https://pub.dev"
source: hosted
version: "2.0.13"
characters:
dependency: transitive
description:
@ -153,14 +137,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.2"
equatable:
dependency: transitive
description:
name: equatable
sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7"
url: "https://pub.dev"
source: hosted
version: "2.0.7"
ffi:
dependency: transitive
description:
@ -177,37 +153,13 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.1"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev"
source: hosted
version: "1.1.1"
fl_chart:
dependency: "direct main"
description:
name: fl_chart
sha256: "577aeac8ca414c25333334d7c4bb246775234c0e44b38b10a82b559dd4d764e7"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_dotenv:
dependency: "direct main"
description:
name: flutter_dotenv
sha256: b7c7be5cd9f6ef7a78429cabd2774d3c4af50e79cb2b7593e3d5d763ef95c61b
url: "https://pub.dev"
source: hosted
version: "5.2.1"
flutter_launcher_icons:
dependency: "direct main"
dependency: "direct dev"
description:
name: flutter_launcher_icons
sha256: bfa04787c85d80ecb3f8777bde5fc10c3de809240c48fa061a2c2bf15ea5211c
@ -251,70 +203,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
geolocator:
dependency: "direct main"
description:
name: geolocator
sha256: f62bcd90459e63210bbf9c35deb6a51c521f992a78de19a1fe5c11704f9530e2
url: "https://pub.dev"
source: hosted
version: "13.0.4"
geolocator_android:
dependency: transitive
description:
name: geolocator_android
sha256: fcb1760a50d7500deca37c9a666785c047139b5f9ee15aa5469fae7dbbe3170d
url: "https://pub.dev"
source: hosted
version: "4.6.2"
geolocator_apple:
dependency: transitive
description:
name: geolocator_apple
sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22
url: "https://pub.dev"
source: hosted
version: "2.3.13"
geolocator_platform_interface:
dependency: transitive
description:
name: geolocator_platform_interface
sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67"
url: "https://pub.dev"
source: hosted
version: "4.2.6"
geolocator_web:
dependency: transitive
description:
name: geolocator_web
sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172
url: "https://pub.dev"
source: hosted
version: "4.1.3"
geolocator_windows:
dependency: transitive
description:
name: geolocator_windows
sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6"
url: "https://pub.dev"
source: hosted
version: "0.2.5"
get:
dependency: "direct main"
description:
name: get
sha256: c79eeb4339f1f3deffd9ec912f8a923834bec55f7b49c9e882b8fef2c139d425
url: "https://pub.dev"
source: hosted
version: "4.7.2"
get_storage:
dependency: "direct main"
description:
name: get_storage
sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
html:
dependency: transitive
description:
@ -324,13 +212,13 @@ packages:
source: hosted
version: "0.15.5"
http:
dependency: "direct main"
dependency: transitive
description:
name: http
sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.5.0"
version: "1.3.0"
http_parser:
dependency: transitive
description:
@ -363,14 +251,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.9.0"
latlong2:
dependency: "direct main"
description:
name: latlong2
sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
url: "https://pub.dev"
source: hosted
version: "0.9.1"
lints:
dependency: transitive
description:
@ -419,14 +299,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.0"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
path_provider:
dependency: transitive
description:
@ -475,22 +347,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.0"
pdf:
dependency: "direct main"
description:
name: pdf
sha256: "28eacad99bffcce2e05bba24e50153890ad0255294f4dd78a17075a2ba5c8416"
url: "https://pub.dev"
source: hosted
version: "3.11.3"
pdf_widget_wrapper:
dependency: transitive
description:
name: pdf_widget_wrapper
sha256: c930860d987213a3d58c7ec3b7ecf8085c3897f773e8dc23da9cae60a5d6d0f5
url: "https://pub.dev"
source: hosted
version: "1.0.4"
petitparser:
dependency: transitive
description:
@ -523,22 +379,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.1"
printing:
dependency: "direct main"
description:
name: printing
sha256: "482cd5a5196008f984bb43ed0e47cbfdca7373490b62f3b27b3299275bf22a93"
url: "https://pub.dev"
source: hosted
version: "5.14.2"
qr:
dependency: transitive
description:
name: qr
sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
screen_retriever:
dependency: transitive
description:
@ -592,14 +432,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.0"
sprintf:
dependency: transitive
description:
name: sprintf
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
stream_channel:
dependency: transitive
description:
@ -704,22 +536,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.4"
uuid:
dependency: transitive
description:
name: uuid
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
url: "https://pub.dev"
source: hosted
version: "4.5.1"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
version: "2.1.4"
web:
dependency: transitive
description:
@ -801,5 +625,5 @@ packages:
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.8.0-0 <4.0.0"
flutter: ">=3.27.4"
dart: ">=3.7.0-0 <4.0.0"
flutter: ">=3.27.0"

Some files were not shown because too many files have changed in this diff Show More