Initial Release: SAVEXSTATE Vault V1 - Cyber Orange Edition
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:firebase_storage/firebase_storage.dart';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'dart:typed_data';
|
||||
|
||||
class AdminArtifactScreen extends StatefulWidget {
|
||||
const AdminArtifactScreen({super.key});
|
||||
|
||||
@override
|
||||
State<AdminArtifactScreen> createState() => _AdminArtifactScreenState();
|
||||
}
|
||||
|
||||
class _AdminArtifactScreenState extends State<AdminArtifactScreen> {
|
||||
final _titleController = TextEditingController();
|
||||
final _descController = TextEditingController();
|
||||
final _priceController = TextEditingController();
|
||||
final _stockController = TextEditingController();
|
||||
final _urlController = TextEditingController(); // FOR EXTERNAL STORE LINK
|
||||
|
||||
Uint8List? _fileBytes;
|
||||
String? _fileName;
|
||||
bool _isUploading = false;
|
||||
|
||||
Future<void> _pickImage() async {
|
||||
final result = await FilePicker.platform.pickFiles(type: FileType.image, withData: true);
|
||||
if (result != null) {
|
||||
setState(() {
|
||||
_fileBytes = result.files.first.bytes;
|
||||
_fileName = result.files.first.name;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _upload() async {
|
||||
if (_fileBytes == null || _titleController.text.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("MISSING_DATA")));
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() => _isUploading = true);
|
||||
|
||||
try {
|
||||
// 1. Upload to Storage
|
||||
final path = 'artifacts/${DateTime.now().millisecondsSinceEpoch}_$_fileName';
|
||||
final task = await FirebaseStorage.instance.ref().child(path).putData(_fileBytes!);
|
||||
final url = await task.ref.getDownloadURL();
|
||||
|
||||
// 2. Save Document to Firestore
|
||||
await FirebaseFirestore.instance.collection('artifacts').add({
|
||||
'title': _titleController.text.trim(),
|
||||
'description': _descController.text.trim(),
|
||||
'price': _priceController.text.trim(),
|
||||
'stock': _stockController.text.trim(),
|
||||
'purchaseUrl': _urlController.text.trim(), // LINK TO STORE
|
||||
'imageUrl': url,
|
||||
'serial': "SS-${DateTime.now().millisecondsSinceEpoch.toString().substring(8)}",
|
||||
'createdAt': FieldValue.serverTimestamp(),
|
||||
});
|
||||
|
||||
if (!mounted) return;
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("SYSTEM_ERROR: $e")));
|
||||
} finally {
|
||||
setState(() => _isUploading = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text("REGISTER_ARTIFACT")),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
children: [
|
||||
// Preview selected image
|
||||
Container(
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(border: Border.all(color: const Color(0xFF00FF00))),
|
||||
child: _fileBytes == null
|
||||
? const Center(child: Text("NO_IMAGE_LOADED"))
|
||||
: Image.memory(_fileBytes!, fit: BoxFit.cover),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
OutlinedButton(onPressed: _pickImage, child: const Text("[ SELECT_ASSET_IMAGE ]")),
|
||||
|
||||
const SizedBox(height: 30),
|
||||
TextField(controller: _titleController, decoration: const InputDecoration(labelText: "ASSET_NAME")),
|
||||
const SizedBox(height: 15),
|
||||
TextField(controller: _descController, maxLines: 3, decoration: const InputDecoration(labelText: "TECHNICAL_SPECS")),
|
||||
const SizedBox(height: 15),
|
||||
TextField(controller: _urlController, decoration: const InputDecoration(labelText: "PURCHASE_GATEWAY_URL")),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: TextField(controller: _priceController, decoration: const InputDecoration(labelText: "VALUE_\$"))),
|
||||
const SizedBox(width: 15),
|
||||
Expanded(child: TextField(controller: _stockController, decoration: const InputDecoration(labelText: "UNITS_AVAIL"))),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 50),
|
||||
_isUploading
|
||||
? const CircularProgressIndicator(color: Color(0xFF00FF00))
|
||||
: ElevatedButton(onPressed: _upload, child: const Text("[ EXECUTE_REGISTRATION ]")),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user