Initial commit
This commit is contained in:
10
lib/controllers/home_controller.dart
Normal file
10
lib/controllers/home_controller.dart
Normal file
@@ -0,0 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class HomeController extends GetxController {
|
||||
|
||||
void loadFilaments() {}
|
||||
|
||||
void downloadFilaments() {}
|
||||
|
||||
void restoreFilaments() {}
|
||||
}
|
||||
153
lib/helpers/filament_repository.dart
Normal file
153
lib/helpers/filament_repository.dart
Normal file
@@ -0,0 +1,153 @@
|
||||
import 'dart:convert';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import '../model/filament_model.dart';
|
||||
|
||||
class FilamentRepository extends GetxService {
|
||||
static FilamentRepository get to => Get.find();
|
||||
|
||||
final GetStorage _storage = GetStorage();
|
||||
static const String _storageKey = 'filaments';
|
||||
|
||||
Future<FilamentRepository> init() async {
|
||||
await GetStorage.init();
|
||||
return this;
|
||||
}
|
||||
|
||||
// Create - Füge ein neues Filament hinzu
|
||||
Future<bool> createFilament(FilamentModel filament) async {
|
||||
try {
|
||||
final filaments = getAllFilaments();
|
||||
filaments.add(filament);
|
||||
await _storage.write(
|
||||
_storageKey,
|
||||
filaments.map((f) => f.toJson()).toList(),
|
||||
);
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error creating filament: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Read - Alle Filamente abrufen
|
||||
List<FilamentModel> getAllFilaments() {
|
||||
try {
|
||||
final data = _storage.read(_storageKey);
|
||||
if (data == null) return [];
|
||||
|
||||
return (data as List)
|
||||
.map((json) => FilamentModel.fromJson(json))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
print('Error reading filaments: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Read - Einzelnes Filament nach ID
|
||||
FilamentModel? getFilamentById(String id) {
|
||||
try {
|
||||
final filaments = getAllFilaments();
|
||||
return filaments.firstWhereOrNull((f) => f.id == id);
|
||||
} catch (e) {
|
||||
print('Error getting filament by id: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Update - Aktualisiere ein Filament
|
||||
Future<bool> updateFilament(FilamentModel filament) async {
|
||||
try {
|
||||
final filaments = getAllFilaments();
|
||||
final index = filaments.indexWhere((f) => f.id == filament.id);
|
||||
|
||||
if (index == -1) return false;
|
||||
|
||||
filaments[index] = filament;
|
||||
await _storage.write(
|
||||
_storageKey,
|
||||
filaments.map((f) => f.toJson()).toList(),
|
||||
);
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error updating filament: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete - Lösche ein Filament
|
||||
Future<bool> deleteFilament(String id) async {
|
||||
try {
|
||||
final filaments = getAllFilaments();
|
||||
filaments.removeWhere((f) => f.id == id);
|
||||
await _storage.write(
|
||||
_storageKey,
|
||||
filaments.map((f) => f.toJson()).toList(),
|
||||
);
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error deleting filament: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete All - Lösche alle Filamente
|
||||
Future<bool> deleteAllFilaments() async {
|
||||
try {
|
||||
await _storage.remove(_storageKey);
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error deleting all filaments: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Backup - Exportiere als JSON String
|
||||
String exportToJson() {
|
||||
try {
|
||||
final filaments = getAllFilaments();
|
||||
return jsonEncode(filaments.map((f) => f.toJson()).toList());
|
||||
} catch (e) {
|
||||
print('Error exporting to JSON: $e');
|
||||
return '[]';
|
||||
}
|
||||
}
|
||||
|
||||
// Restore - Importiere von JSON String
|
||||
Future<bool> importFromJson(String jsonString) async {
|
||||
try {
|
||||
final List<dynamic> data = jsonDecode(jsonString);
|
||||
final filaments = data
|
||||
.map((json) => FilamentModel.fromJson(json))
|
||||
.toList();
|
||||
await _storage.write(
|
||||
_storageKey,
|
||||
filaments.map((f) => f.toJson()).toList(),
|
||||
);
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error importing from JSON: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Zähle alle Filamente
|
||||
int getCount() {
|
||||
return getAllFilaments().length;
|
||||
}
|
||||
|
||||
// Suche Filamente nach Name
|
||||
List<FilamentModel> searchByName(String query) {
|
||||
final filaments = getAllFilaments();
|
||||
return filaments
|
||||
.where((f) => f.name.toLowerCase().contains(query.toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Filtere nach Typ (z.B. PLA, ABS, PETG)
|
||||
List<FilamentModel> filterByType(String type) {
|
||||
final filaments = getAllFilaments();
|
||||
return filaments.where((f) => f.type == type).toList();
|
||||
}
|
||||
}
|
||||
14
lib/helpers/sample_bindings.dart
Normal file
14
lib/helpers/sample_bindings.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../controllers/home_controller.dart';
|
||||
|
||||
|
||||
|
||||
class SampleBindings extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
// Define your dependencies here no permanent Binding
|
||||
Get.lazyPut<HomeController>(() => HomeController());
|
||||
}
|
||||
|
||||
}
|
||||
19
lib/helpers/sample_routes.dart
Normal file
19
lib/helpers/sample_routes.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:get/get.dart';
|
||||
import '../pages/home_view.dart';
|
||||
import 'sample_bindings.dart';
|
||||
|
||||
|
||||
|
||||
|
||||
class SampleRouts {
|
||||
static final sampleBindings = SampleBindings();
|
||||
static List<GetPage<dynamic>> samplePages = [
|
||||
GetPage(
|
||||
name: HomePage.namedRoute,
|
||||
page: () => const HomePage(),
|
||||
binding: sampleBindings,
|
||||
),
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
28
lib/main.dart
Normal file
28
lib/main.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'helpers/filament_repository.dart';
|
||||
import 'helpers/sample_bindings.dart';
|
||||
import 'helpers/sample_routes.dart';
|
||||
import 'pages/home_view.dart';
|
||||
|
||||
void main() async {
|
||||
await Get.putAsync(() => FilamentRepository().init());
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetMaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Flutter Demo',
|
||||
theme: ThemeData(colorScheme: .fromSeed(seedColor: Colors.deepPurple)),
|
||||
initialBinding: SampleBindings(),
|
||||
initialRoute: HomePage.namedRoute,
|
||||
getPages: SampleRouts.samplePages,
|
||||
);
|
||||
}
|
||||
}
|
||||
82
lib/model/filament_model.dart
Normal file
82
lib/model/filament_model.dart
Normal file
@@ -0,0 +1,82 @@
|
||||
|
||||
|
||||
class FilamentModel {
|
||||
final String id;
|
||||
final String name;
|
||||
final String type; // PLA, ABS, PETG, etc.
|
||||
final String color;
|
||||
final double weight; // in Gramm
|
||||
final double price; // Preis
|
||||
final String? manufacturer;
|
||||
final DateTime? purchaseDate;
|
||||
final String? notes;
|
||||
|
||||
FilamentModel({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.type,
|
||||
required this.color,
|
||||
required this.weight,
|
||||
required this.price,
|
||||
this.manufacturer,
|
||||
this.purchaseDate,
|
||||
this.notes,
|
||||
});
|
||||
|
||||
// JSON Serialisierung
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'type': type,
|
||||
'color': color,
|
||||
'weight': weight,
|
||||
'price': price,
|
||||
'manufacturer': manufacturer,
|
||||
'purchaseDate': purchaseDate?.toIso8601String(),
|
||||
'notes': notes,
|
||||
};
|
||||
}
|
||||
|
||||
// JSON Deserialisierung
|
||||
factory FilamentModel.fromJson(Map<String, dynamic> json) {
|
||||
return FilamentModel(
|
||||
id: json['id'] as String,
|
||||
name: json['name'] as String,
|
||||
type: json['type'] as String,
|
||||
color: json['color'] as String,
|
||||
weight: (json['weight'] as num).toDouble(),
|
||||
price: (json['price'] as num).toDouble(),
|
||||
manufacturer: json['manufacturer'] as String?,
|
||||
purchaseDate: json['purchaseDate'] != null
|
||||
? DateTime.parse(json['purchaseDate'] as String)
|
||||
: null,
|
||||
notes: json['notes'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
// CopyWith für Updates
|
||||
FilamentModel copyWith({
|
||||
String? id,
|
||||
String? name,
|
||||
String? type,
|
||||
String? color,
|
||||
double? weight,
|
||||
double? price,
|
||||
String? manufacturer,
|
||||
DateTime? purchaseDate,
|
||||
String? notes,
|
||||
}) {
|
||||
return FilamentModel(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
type: type ?? this.type,
|
||||
color: color ?? this.color,
|
||||
weight: weight ?? this.weight,
|
||||
price: price ?? this.price,
|
||||
manufacturer: manufacturer ?? this.manufacturer,
|
||||
purchaseDate: purchaseDate ?? this.purchaseDate,
|
||||
notes: notes ?? this.notes,
|
||||
);
|
||||
}
|
||||
}
|
||||
156
lib/pages/home_view.dart
Normal file
156
lib/pages/home_view.dart
Normal file
@@ -0,0 +1,156 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../controllers/home_controller.dart';
|
||||
import '../widgets/info_item.dart';
|
||||
import '../widgets/primary_button.dart';
|
||||
import '../widgets/secondary_button.dart';
|
||||
|
||||
class HomePage extends GetView<HomeController> {
|
||||
static const String namedRoute = '/home-page';
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var homeCtrl = controller;
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Colors.blue.shade50, Colors.purple.shade50],
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24.0,
|
||||
vertical: 32.0,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Header & Image
|
||||
Hero(
|
||||
tag: 'filament_image',
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withAlpha(25),
|
||||
blurRadius: 20,
|
||||
offset: Offset(0, 10),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Image.asset(
|
||||
'assets/images/fillament_pla_home.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Text(
|
||||
'Filament Verwaltung',
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headlineLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.deepPurple.shade700,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
Text(
|
||||
'Verwalte deine Filamente einfach und übersichtlich',
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
color: Colors.grey.shade700,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
|
||||
// Info Card
|
||||
Card(
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
children: [
|
||||
buildInfoItem(
|
||||
icon: Icons.storage_rounded,
|
||||
text: 'Lokale Speicherung auf diesem Gerät',
|
||||
color: Colors.blue,
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
buildInfoItem(
|
||||
icon: Icons.list_alt_rounded,
|
||||
text: 'Filament laden → zur Liste',
|
||||
color: Colors.green,
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
buildInfoItem(
|
||||
icon: Icons.cloud_download_rounded,
|
||||
text: 'Backup → Download als JSON',
|
||||
color: Colors.orange,
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
buildInfoItem(
|
||||
icon: Icons.cloud_upload_rounded,
|
||||
text: 'Wiederherstellen → Upload JSON',
|
||||
color: Colors.purple,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
|
||||
// Action Buttons
|
||||
buildPrimaryButton(
|
||||
context: context,
|
||||
icon: Icons.inventory_2_rounded,
|
||||
label: 'Filamente laden',
|
||||
onPressed: () => homeCtrl.loadFilaments(),
|
||||
color: Colors.deepPurple,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: buildSecondaryButton(
|
||||
context: context,
|
||||
icon: Icons.save_alt_rounded,
|
||||
label: 'Backup',
|
||||
onPressed: () => homeCtrl.downloadFilaments(),
|
||||
color: Colors.blue,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: buildSecondaryButton(
|
||||
context: context,
|
||||
icon: Icons.restore_rounded,
|
||||
label: 'Wiederherstellen',
|
||||
onPressed: () => homeCtrl.restoreFilaments(),
|
||||
color: Colors.teal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
28
lib/widgets/info_item.dart
Normal file
28
lib/widgets/info_item.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Widget buildInfoItem({
|
||||
required IconData icon,
|
||||
required String text,
|
||||
required Color color,
|
||||
}) {
|
||||
return Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withAlpha(25),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Icon(icon, color: color, size: 20),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey.shade700),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
32
lib/widgets/primary_button.dart
Normal file
32
lib/widgets/primary_button.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Widget buildPrimaryButton({
|
||||
required BuildContext context,
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required VoidCallback onPressed,
|
||||
required Color color,
|
||||
}) {
|
||||
return ElevatedButton(
|
||||
onPressed: onPressed,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: color,
|
||||
foregroundColor: Colors.white,
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
elevation: 4,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon),
|
||||
SizedBox(width: 12),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
34
lib/widgets/secondary_button.dart
Normal file
34
lib/widgets/secondary_button.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Widget buildSecondaryButton({
|
||||
required BuildContext context,
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required VoidCallback onPressed,
|
||||
required Color color,
|
||||
}) {
|
||||
return ElevatedButton(
|
||||
onPressed: onPressed,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.white,
|
||||
foregroundColor: color,
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
side: BorderSide(color: color.withOpacity(0.3)),
|
||||
),
|
||||
elevation: 2,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(icon, size: 28),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user