update
This commit is contained in:
parent
d21554cddc
commit
b13b385cb7
10 changed files with 84 additions and 70 deletions
|
@ -41,8 +41,7 @@ android {
|
|||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "com.example.cdb_ui"
|
||||
applicationId "de.hydrar.red.cdb"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||
minSdkVersion flutter.minSdkVersion
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<application
|
||||
android:label="cdb_ui"
|
||||
android:label="CDB"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
|
|
63
lib/api.dart
63
lib/api.dart
|
@ -6,7 +6,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|||
// todo : api errors
|
||||
|
||||
class API {
|
||||
late SharedPreferences pref;
|
||||
SharedPreferences? pref;
|
||||
static final API _instance = API._internal();
|
||||
|
||||
// cache
|
||||
|
@ -41,16 +41,24 @@ class API {
|
|||
|
||||
Future<void> init() async {
|
||||
pref = await SharedPreferences.getInstance();
|
||||
instance = pref.getString("instance") ?? "";
|
||||
instance = pref!.getString("instance") ?? "";
|
||||
}
|
||||
|
||||
bool isInit() {
|
||||
return pref.containsKey("token") && pref.containsKey("instance");
|
||||
if (pref == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return pref!.containsKey("token") && pref!.containsKey("instance");
|
||||
}
|
||||
|
||||
bool isPrefetched() {
|
||||
return items != null && locations != null && flowInfos != null;
|
||||
}
|
||||
|
||||
void save(String instance, String token) {
|
||||
pref.setString("instance", instance);
|
||||
pref.setString("token", token);
|
||||
pref!.setString("instance", instance);
|
||||
pref!.setString("token", token);
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
|
@ -60,7 +68,7 @@ class API {
|
|||
var resp = await http.get(Uri.parse(url), headers: <String, String>{
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
'Token': pref.getString("token")!
|
||||
'Token': pref!.getString("token")!
|
||||
});
|
||||
|
||||
return utf8.decode(resp.bodyBytes);
|
||||
|
@ -71,7 +79,7 @@ class API {
|
|||
headers: <String, String>{
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
'Token': pref.getString("token")!
|
||||
'Token': pref!.getString("token")!
|
||||
},
|
||||
body: jsonEncode(data));
|
||||
|
||||
|
@ -163,7 +171,7 @@ class API {
|
|||
}
|
||||
|
||||
// /supply
|
||||
Future<String> supplyItem(String item, String variant, String price,
|
||||
Future<String> supplyItem(String item, String variant, double price,
|
||||
String? origin, String? location, String? note) async {
|
||||
if (origin!.isEmpty) {
|
||||
origin = null;
|
||||
|
@ -214,7 +222,7 @@ class API {
|
|||
}
|
||||
|
||||
// /item/<item_id>/<variant_id>/price_history?<origin>
|
||||
Future<List<Price>> getPriceHistory(String item, String variant,
|
||||
Future<List<double>> getPriceHistory(String item, String variant,
|
||||
{String? origin}) async {
|
||||
var url = "$instance/item/$item/$variant/price_history";
|
||||
|
||||
|
@ -224,10 +232,10 @@ class API {
|
|||
|
||||
var resp = jsonDecode(await getRequest(url)) as List<dynamic>;
|
||||
|
||||
return resp.map((x) => Price(x)).toList();
|
||||
return resp.map((x) => x as double).toList();
|
||||
}
|
||||
|
||||
Future<Price> getLatestPrice(String item, String variant,
|
||||
Future<double> getLatestPrice(String item, String variant,
|
||||
{String? origin}) async {
|
||||
var url = "$instance/item/$item/$variant/price_latest";
|
||||
|
||||
|
@ -237,7 +245,7 @@ class API {
|
|||
|
||||
var resp = jsonDecode(await getRequest(url)) as Map<String, dynamic>;
|
||||
|
||||
return Price(resp);
|
||||
return resp as double;
|
||||
}
|
||||
|
||||
// Flows
|
||||
|
@ -386,31 +394,11 @@ class ItemVariant {
|
|||
}
|
||||
}
|
||||
|
||||
class Price {
|
||||
late double value;
|
||||
late String currency;
|
||||
|
||||
Price(Map<String, dynamic> json) {
|
||||
value = json["value"];
|
||||
currency = json["currency"];
|
||||
}
|
||||
|
||||
Price.fromString(String value) {
|
||||
var priceSplit = value.split(" ");
|
||||
this.value = double.parse(priceSplit[0]);
|
||||
currency = priceSplit[1];
|
||||
}
|
||||
|
||||
String format() {
|
||||
return "${value.toStringAsFixed(2)} $currency";
|
||||
}
|
||||
}
|
||||
|
||||
class Transaction {
|
||||
late String uuid;
|
||||
late String item;
|
||||
late String variant;
|
||||
late Price price;
|
||||
late double price;
|
||||
String? origin;
|
||||
late int timestamp;
|
||||
ConsumeInfo? consumed;
|
||||
|
@ -422,7 +410,7 @@ class Transaction {
|
|||
uuid = json["uuid"];
|
||||
item = json["item"];
|
||||
variant = json["variant"];
|
||||
price = Price(json["price"]);
|
||||
price = json["price"];
|
||||
origin = json["origin"];
|
||||
timestamp = json["timestamp"];
|
||||
expired = json["expired"];
|
||||
|
@ -431,12 +419,11 @@ class Transaction {
|
|||
location = json["location"] != null ? Location(json["location"]) : null;
|
||||
}
|
||||
|
||||
Transaction.inMemory(String itemID, String variantID, String price,
|
||||
Transaction.inMemory(String itemID, String variantID, this.price,
|
||||
String? origin, Location? location, String? note) {
|
||||
uuid = "";
|
||||
item = itemID;
|
||||
variant = variantID;
|
||||
this.price = Price.fromString(price);
|
||||
origin = origin;
|
||||
timestamp = 0;
|
||||
consumed = null;
|
||||
|
@ -448,12 +435,12 @@ class Transaction {
|
|||
|
||||
class ConsumeInfo {
|
||||
late String destination;
|
||||
late Price price;
|
||||
late double price;
|
||||
late int timestamp;
|
||||
|
||||
ConsumeInfo(Map<String, dynamic> json) {
|
||||
destination = json["destination"];
|
||||
price = Price(json["price"]);
|
||||
price = json["price"];
|
||||
timestamp = json["timestamp"];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,27 +7,49 @@ import 'package:cdb_ui/pages/stats.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
await API().init();
|
||||
if (API().isInit()) {
|
||||
await API().prefetch();
|
||||
}
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
class MyApp extends StatefulWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
State<MyApp> createState() => _MyAppState();
|
||||
}
|
||||
|
||||
class _MyAppState extends State<MyApp> {
|
||||
bool init = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
() async {
|
||||
await API().init();
|
||||
if (API().isInit()) {
|
||||
await API().prefetch();
|
||||
setState(() {
|
||||
init = true;
|
||||
});
|
||||
}
|
||||
}();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'CDB',
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: Colors.deepPurple, brightness: Brightness.dark),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: API().isInit() ? const MyHomePage() : const SetupPage(),
|
||||
);
|
||||
title: 'CDB',
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: Colors.deepPurple, brightness: Brightness.dark),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: API().isInit()
|
||||
? (API().isPrefetched()
|
||||
? const MyHomePage()
|
||||
: const Scaffold(
|
||||
body: CircularProgressIndicator(),
|
||||
))
|
||||
: const SetupPage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import 'dart:js_interop_unsafe';
|
||||
|
||||
import 'package:cdb_ui/api.dart' as API;
|
||||
import 'package:cdb_ui/api.dart';
|
||||
import 'package:cdb_ui/pages/supply.dart';
|
||||
|
|
|
@ -24,6 +24,7 @@ class StatsPage extends StatelessWidget {
|
|||
// global origin / destinations
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text("Home"),),
|
||||
body: FutureBuilder(
|
||||
future: _fetchData(),
|
||||
builder: (context, snapshot) {
|
||||
|
|
|
@ -53,7 +53,7 @@ class _SupplyPageState extends State<SupplyPage> {
|
|||
var t = SupplyForm(
|
||||
itemID: widget.item.id,
|
||||
variant: variant,
|
||||
price: "${_priceController.text} €",
|
||||
price: double.parse(_priceController.text),
|
||||
origin: _selectedOrigin,
|
||||
location: _selectedLocation,
|
||||
note: _noteController.text);
|
||||
|
@ -66,8 +66,13 @@ class _SupplyPageState extends State<SupplyPage> {
|
|||
}
|
||||
|
||||
API()
|
||||
.supplyItem(widget.item.id, variant, "${_priceController.text} €",
|
||||
_selectedOrigin, _selectedLocation, _noteController.text)
|
||||
.supplyItem(
|
||||
widget.item.id,
|
||||
variant,
|
||||
double.parse(_priceController.text),
|
||||
_selectedOrigin,
|
||||
_selectedLocation,
|
||||
_noteController.text)
|
||||
.then((_) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Item added successfully!')),
|
||||
|
@ -138,7 +143,7 @@ class _SupplyPageState extends State<SupplyPage> {
|
|||
? await API()
|
||||
.getLatestPrice(widget.item.id, variant,
|
||||
origin: selection)
|
||||
.then((x) => x.value.toStringAsFixed(2))
|
||||
.then((x) => x.toStringAsFixed(2))
|
||||
: _priceController.text;
|
||||
setState(() {
|
||||
_priceController.text = price;
|
||||
|
@ -293,7 +298,7 @@ class AutocompletedTextField extends StatelessWidget {
|
|||
class SupplyForm {
|
||||
final String itemID;
|
||||
final String variant;
|
||||
final String price;
|
||||
final double price;
|
||||
final String? origin;
|
||||
final String? location;
|
||||
final String note;
|
||||
|
|
|
@ -165,7 +165,7 @@ class _TransactionPageState extends State<TransactionPage> {
|
|||
|
||||
if (transaction.expired) const Text("Transaction is Expired!"),
|
||||
|
||||
IconText(Icons.money, transaction.price.format(),
|
||||
IconText(Icons.money, transaction.price.toStringAsFixed(2),
|
||||
color: Colors.green),
|
||||
|
||||
if (transaction.origin != null)
|
||||
|
@ -181,7 +181,8 @@ class _TransactionPageState extends State<TransactionPage> {
|
|||
Text("Consumed on: ${tsFormat(transaction.consumed!.timestamp)}"),
|
||||
IconText(Icons.store, transaction.consumed!.destination,
|
||||
color: Colors.blue),
|
||||
IconText(Icons.money, transaction.consumed!.price.format(),
|
||||
IconText(
|
||||
Icons.money, transaction.consumed!.price.toStringAsFixed(2),
|
||||
color: Colors.green),
|
||||
]
|
||||
|
||||
|
@ -286,8 +287,7 @@ class TransactionCard extends StatelessWidget {
|
|||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
IconText(Icons.money,
|
||||
"${t.price.value.toStringAsFixed(2)} ${t.price.currency}",
|
||||
IconText(Icons.money, "${t.price.toStringAsFixed(2)} €",
|
||||
color: Colors.green),
|
||||
if (t.origin != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
|
@ -328,6 +328,7 @@ class IconText extends StatelessWidget {
|
|||
Text(
|
||||
text,
|
||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
overflow: TextOverflow.fade,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
@ -124,10 +124,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
|
||||
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.2"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -417,10 +417,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1"
|
||||
version: "1.1.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: cdb_ui
|
||||
description: A new Flutter project.
|
||||
description: Economic Database.
|
||||
# The following line prevents the package from being accidentally published to
|
||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
|
|
Loading…
Reference in a new issue