[storage] refactor to based and main storage [BasedScreen] store storage context as well (will probably create some main dao in future)
This commit is contained in:
parent
1100114040
commit
07c92443ce
16 changed files with 151 additions and 122 deletions
|
@ -14,10 +14,12 @@ class ApiClient {
|
||||||
|
|
||||||
ApiClient({
|
ApiClient({
|
||||||
required this.baseUrl,
|
required this.baseUrl,
|
||||||
}) {
|
});
|
||||||
() async {
|
|
||||||
await loadToken();
|
static Future<ApiClient> create({required String baseUrl}) async {
|
||||||
}();
|
var client = ApiClient(baseUrl: baseUrl);
|
||||||
|
client.loadToken();
|
||||||
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadToken() async {
|
Future<void> loadToken() async {
|
||||||
|
|
1
lib/client/based.dart
Normal file
1
lib/client/based.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
import 'package:fooder/client.dart';
|
|
@ -1,10 +1,14 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:fooder/screens/login.dart';
|
import 'package:fooder/screens/login.dart';
|
||||||
import 'package:fooder/client.dart';
|
import 'package:fooder/client.dart';
|
||||||
|
import 'package:fooder/storage.dart';
|
||||||
import 'package:fooder/theme.dart';
|
import 'package:fooder/theme.dart';
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({super.key});
|
final Storage storage;
|
||||||
|
final ApiClient apiClient;
|
||||||
|
|
||||||
|
const MyApp({required this.storage, required this.apiClient, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -15,14 +19,18 @@ class MyApp extends StatelessWidget {
|
||||||
themeMode: ThemeMode.system,
|
themeMode: ThemeMode.system,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
home: LoginScreen(
|
home: LoginScreen(
|
||||||
apiClient: ApiClient(
|
apiClient: apiClient,
|
||||||
baseUrl: 'https://fooderapi.domandoman.xyz/api',
|
storage: storage,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() async {
|
||||||
runApp(const MyApp());
|
var storage = await Storage.create();
|
||||||
|
var apiClient = await ApiClient.create(
|
||||||
|
baseUrl: 'https://fooderapi.domandoman.xyz/api',
|
||||||
|
);
|
||||||
|
|
||||||
|
runApp(MyApp(storage: storage, apiClient: apiClient));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ class Product {
|
||||||
final double carb;
|
final double carb;
|
||||||
final double fat;
|
final double fat;
|
||||||
final double fiber;
|
final double fiber;
|
||||||
|
final int usageCountCached;
|
||||||
final String? barcode;
|
final String? barcode;
|
||||||
|
|
||||||
Product(
|
Product(
|
||||||
|
@ -16,6 +17,7 @@ class Product {
|
||||||
required this.carb,
|
required this.carb,
|
||||||
required this.fat,
|
required this.fat,
|
||||||
required this.fiber,
|
required this.fiber,
|
||||||
|
this.usageCountCached = 0,
|
||||||
this.barcode});
|
this.barcode});
|
||||||
|
|
||||||
Product.fromJson(Map<String, dynamic> map)
|
Product.fromJson(Map<String, dynamic> map)
|
||||||
|
@ -26,6 +28,7 @@ class Product {
|
||||||
carb = map['carb'] as double,
|
carb = map['carb'] as double,
|
||||||
fat = map['fat'] as double,
|
fat = map['fat'] as double,
|
||||||
fiber = map['fiber'] as double,
|
fiber = map['fiber'] as double,
|
||||||
|
usageCountCached = map['usage_count_cached'] as int,
|
||||||
barcode = map['barcode'] as String?;
|
barcode = map['barcode'] as String?;
|
||||||
|
|
||||||
Map<String, Object?> toMap() {
|
Map<String, Object?> toMap() {
|
||||||
|
@ -38,6 +41,7 @@ class Product {
|
||||||
'fat': fat,
|
'fat': fat,
|
||||||
'fiber': fiber,
|
'fiber': fiber,
|
||||||
'barcode': barcode,
|
'barcode': barcode,
|
||||||
|
'usage_count_cached': usageCountCached,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,16 @@ import 'package:fooder/components/text.dart';
|
||||||
import 'package:fooder/components/dropdown.dart';
|
import 'package:fooder/components/dropdown.dart';
|
||||||
import 'package:fooder/components/floating_action_button.dart';
|
import 'package:fooder/components/floating_action_button.dart';
|
||||||
import 'package:fooder/screens/add_product.dart';
|
import 'package:fooder/screens/add_product.dart';
|
||||||
import 'package:fooder/storage/base.dart';
|
|
||||||
import 'package:simple_barcode_scanner/simple_barcode_scanner.dart';
|
import 'package:simple_barcode_scanner/simple_barcode_scanner.dart';
|
||||||
|
|
||||||
class AddEntryScreen extends BasedScreen {
|
class AddEntryScreen extends BasedScreen {
|
||||||
final Diary diary;
|
final Diary diary;
|
||||||
|
|
||||||
const AddEntryScreen(
|
const AddEntryScreen(
|
||||||
{super.key, required super.apiClient, required this.diary});
|
{super.key,
|
||||||
|
required super.apiClient,
|
||||||
|
required super.storage,
|
||||||
|
required this.diary});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AddEntryScreen> createState() => _AddEntryScreen();
|
State<AddEntryScreen> createState() => _AddEntryScreen();
|
||||||
|
@ -27,6 +29,7 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
final productNameController = TextEditingController();
|
final productNameController = TextEditingController();
|
||||||
Meal? meal;
|
Meal? meal;
|
||||||
List<Product> products = [];
|
List<Product> products = [];
|
||||||
|
Diary get diary => widget.diary;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
@ -45,35 +48,18 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
setState(() {
|
setState(() {
|
||||||
meal = widget.diary.meals[0];
|
meal = diary.meals[0];
|
||||||
});
|
});
|
||||||
_getProducts().then((value) => null);
|
_getProducts().then((value) => null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _getProducts() async {
|
Future<void> _getProducts() async {
|
||||||
if (storage != null) {
|
var productsMap = await apiClient.getProducts(productNameController.text);
|
||||||
var storagePorducts = await storage!.product.list();
|
|
||||||
|
|
||||||
if (storagePorducts.length > 5) {
|
|
||||||
print("Using local storage");
|
|
||||||
setState(() {
|
|
||||||
products = storagePorducts;
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print("No local storage");
|
|
||||||
}
|
|
||||||
|
|
||||||
var productsMap =
|
|
||||||
await widget.apiClient.getProducts(productNameController.text);
|
|
||||||
|
|
||||||
var parsedProducts = (productsMap['products'] as List<dynamic>)
|
var parsedProducts = (productsMap['products'] as List<dynamic>)
|
||||||
.map((e) => Product.fromJson(e as Map<String, dynamic>))
|
.map((e) => Product.fromJson(e as Map<String, dynamic>))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
await storage!.product.bulkInsert(parsedProducts);
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
products = parsedProducts;
|
products = parsedProducts;
|
||||||
});
|
});
|
||||||
|
@ -113,7 +99,7 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await widget.apiClient.addEntry(
|
await apiClient.addEntry(
|
||||||
grams: grams,
|
grams: grams,
|
||||||
productId: products[0].id,
|
productId: products[0].id,
|
||||||
mealId: meal!.id,
|
mealId: meal!.id,
|
||||||
|
@ -131,7 +117,7 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
|
|
||||||
if (res is String) {
|
if (res is String) {
|
||||||
try {
|
try {
|
||||||
var productMap = await widget.apiClient.getProductByBarcode(res);
|
var productMap = await apiClient.getProductByBarcode(res);
|
||||||
|
|
||||||
var product = Product.fromJson(productMap);
|
var product = Product.fromJson(productMap);
|
||||||
|
|
||||||
|
@ -168,7 +154,7 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
items: <DropdownMenuItem<Meal>>[
|
items: <DropdownMenuItem<Meal>>[
|
||||||
for (var meal in widget.diary.meals)
|
for (var meal in diary.meals)
|
||||||
DropdownMenuItem<Meal>(
|
DropdownMenuItem<Meal>(
|
||||||
value: meal,
|
value: meal,
|
||||||
child: Text(meal.name),
|
child: Text(meal.name),
|
||||||
|
@ -199,7 +185,8 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => AddProductScreen(
|
builder: (context) => AddProductScreen(
|
||||||
apiClient: widget.apiClient,
|
apiClient: apiClient,
|
||||||
|
storage: storage,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).then((product) {
|
).then((product) {
|
||||||
|
|
|
@ -10,7 +10,10 @@ class AddMealScreen extends BasedScreen {
|
||||||
final Diary diary;
|
final Diary diary;
|
||||||
|
|
||||||
const AddMealScreen(
|
const AddMealScreen(
|
||||||
{super.key, required super.apiClient, required this.diary});
|
{super.key,
|
||||||
|
required super.apiClient,
|
||||||
|
required super.storage,
|
||||||
|
required this.diary});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AddMealScreen> createState() => _AddMealScreen();
|
State<AddMealScreen> createState() => _AddMealScreen();
|
||||||
|
@ -22,10 +25,10 @@ class _AddMealScreen extends BasedState<AddMealScreen> {
|
||||||
bool nameChanged = false;
|
bool nameChanged = false;
|
||||||
List<Preset> presets = [];
|
List<Preset> presets = [];
|
||||||
Preset? selectedPreset;
|
Preset? selectedPreset;
|
||||||
|
Diary get diary => widget.diary;
|
||||||
|
|
||||||
Future<void> _getPresets() async {
|
Future<void> _getPresets() async {
|
||||||
var presetsMap =
|
var presetsMap = await apiClient.getPresets(presetNameController.text);
|
||||||
await widget.apiClient.getPresets(presetNameController.text);
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
presets = (presetsMap['presets'] as List<dynamic>)
|
presets = (presetsMap['presets'] as List<dynamic>)
|
||||||
|
@ -39,7 +42,7 @@ class _AddMealScreen extends BasedState<AddMealScreen> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
setState(() {
|
setState(() {
|
||||||
nameController.text = "Meal ${widget.diary.meals.length + 1}";
|
nameController.text = "Meal ${diary.meals.length + 1}";
|
||||||
});
|
});
|
||||||
_getPresets();
|
_getPresets();
|
||||||
}
|
}
|
||||||
|
@ -57,15 +60,15 @@ class _AddMealScreen extends BasedState<AddMealScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _addMeal() async {
|
Future<void> _addMeal() async {
|
||||||
await widget.apiClient.addMeal(
|
await apiClient.addMeal(
|
||||||
name: nameController.text,
|
name: nameController.text,
|
||||||
diaryId: widget.diary.id,
|
diaryId: diary.id,
|
||||||
);
|
);
|
||||||
popMeDaddy();
|
popMeDaddy();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _deletePreset(Preset preset) async {
|
Future<void> _deletePreset(Preset preset) async {
|
||||||
widget.apiClient.deletePreset(preset.id);
|
apiClient.deletePreset(preset.id);
|
||||||
setState(() {
|
setState(() {
|
||||||
presets.remove(preset);
|
presets.remove(preset);
|
||||||
});
|
});
|
||||||
|
@ -103,9 +106,9 @@ class _AddMealScreen extends BasedState<AddMealScreen> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await widget.apiClient.addMealFromPreset(
|
await apiClient.addMealFromPreset(
|
||||||
name: nameChanged ? nameController.text : selectedPreset!.name,
|
name: nameChanged ? nameController.text : selectedPreset!.name,
|
||||||
diaryId: widget.diary.id,
|
diaryId: diary.id,
|
||||||
presetId: selectedPreset!.id,
|
presetId: selectedPreset!.id,
|
||||||
);
|
);
|
||||||
popMeDaddy();
|
popMeDaddy();
|
||||||
|
|
|
@ -7,7 +7,8 @@ import 'package:fooder/components/text.dart';
|
||||||
import 'package:fooder/components/floating_action_button.dart';
|
import 'package:fooder/components/floating_action_button.dart';
|
||||||
|
|
||||||
class AddProductScreen extends BasedScreen {
|
class AddProductScreen extends BasedScreen {
|
||||||
const AddProductScreen({super.key, required super.apiClient});
|
const AddProductScreen(
|
||||||
|
{super.key, required super.apiClient, required super.storage});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AddProductScreen> createState() => _AddProductScreen();
|
State<AddProductScreen> createState() => _AddProductScreen();
|
||||||
|
@ -61,7 +62,7 @@ class _AddProductScreen extends BasedState<AddProductScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var productJson = await widget.apiClient.addProduct(
|
var productJson = await apiClient.addProduct(
|
||||||
carb: carb,
|
carb: carb,
|
||||||
fat: fat,
|
fat: fat,
|
||||||
protein: protein,
|
protein: protein,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:fooder/client.dart';
|
import 'package:fooder/client.dart';
|
||||||
|
import 'package:fooder/storage.dart';
|
||||||
import 'package:fooder/components/app_bar.dart';
|
import 'package:fooder/components/app_bar.dart';
|
||||||
import 'package:fooder/components/navigation_bar.dart';
|
import 'package:fooder/components/navigation_bar.dart';
|
||||||
import 'package:fooder/screens/login.dart';
|
import 'package:fooder/screens/login.dart';
|
||||||
import 'package:fooder/screens/main.dart';
|
import 'package:fooder/screens/main.dart';
|
||||||
import 'package:fooder/storage/base.dart';
|
|
||||||
|
|
||||||
TextStyle logoStyle(context) {
|
TextStyle logoStyle(context) {
|
||||||
return Theme.of(context).textTheme.labelLarge!.copyWith(
|
return Theme.of(context).textTheme.labelLarge!.copyWith(
|
||||||
|
@ -14,34 +14,27 @@ TextStyle logoStyle(context) {
|
||||||
|
|
||||||
abstract class BasedScreen extends StatefulWidget {
|
abstract class BasedScreen extends StatefulWidget {
|
||||||
final ApiClient apiClient;
|
final ApiClient apiClient;
|
||||||
final Storage? storage;
|
final Storage storage;
|
||||||
|
|
||||||
const BasedScreen({super.key, required this.apiClient, this.storage});
|
const BasedScreen(
|
||||||
|
{super.key, required this.apiClient, required this.storage});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class BasedState<T extends BasedScreen> extends State<T> {
|
abstract class BasedState<T extends BasedScreen> extends State<T> {
|
||||||
Storage? storage;
|
ApiClient get apiClient => widget.apiClient;
|
||||||
|
Storage get storage => widget.storage;
|
||||||
|
|
||||||
@override
|
void logout() async {
|
||||||
void initState() {
|
await apiClient.logout();
|
||||||
super.initState();
|
backToLogin();
|
||||||
_asyncInitState().then((value) => null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _asyncInitState() async {
|
void backToLogin() {
|
||||||
if (widget.storage != null) {
|
|
||||||
this.storage = widget.storage;
|
|
||||||
} else {
|
|
||||||
this.storage = await Storage.create();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _logout() async {
|
|
||||||
await widget.apiClient.logout();
|
|
||||||
Navigator.pushReplacement(
|
Navigator.pushReplacement(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => LoginScreen(apiClient: widget.apiClient),
|
builder: (context) =>
|
||||||
|
LoginScreen(apiClient: apiClient, storage: storage),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +43,8 @@ abstract class BasedState<T extends BasedScreen> extends State<T> {
|
||||||
Navigator.pushReplacement(
|
Navigator.pushReplacement(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => MainScreen(apiClient: widget.apiClient),
|
builder: (context) =>
|
||||||
|
MainScreen(apiClient: apiClient, storage: storage),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +57,7 @@ abstract class BasedState<T extends BasedScreen> extends State<T> {
|
||||||
Icons.logout,
|
Icons.logout,
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
onPressed: _logout,
|
onPressed: logout,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,7 +13,10 @@ class EditEntryScreen extends BasedScreen {
|
||||||
final Entry entry;
|
final Entry entry;
|
||||||
|
|
||||||
const EditEntryScreen(
|
const EditEntryScreen(
|
||||||
{super.key, required super.apiClient, required this.entry});
|
{super.key,
|
||||||
|
required super.apiClient,
|
||||||
|
required super.storage,
|
||||||
|
required this.entry});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<EditEntryScreen> createState() => _EditEntryScreen();
|
State<EditEntryScreen> createState() => _EditEntryScreen();
|
||||||
|
@ -23,6 +26,7 @@ class _EditEntryScreen extends BasedState<EditEntryScreen> {
|
||||||
final gramsController = TextEditingController();
|
final gramsController = TextEditingController();
|
||||||
final productNameController = TextEditingController();
|
final productNameController = TextEditingController();
|
||||||
List<Product> products = [];
|
List<Product> products = [];
|
||||||
|
Entry get entry => entry;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
@ -39,15 +43,14 @@ class _EditEntryScreen extends BasedState<EditEntryScreen> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
setState(() {
|
setState(() {
|
||||||
gramsController.text = widget.entry.grams.toString();
|
gramsController.text = entry.grams.toString();
|
||||||
productNameController.text = widget.entry.product.name;
|
productNameController.text = entry.product.name;
|
||||||
products = [widget.entry.product];
|
products = [entry.product];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _getProducts() async {
|
Future<void> _getProducts() async {
|
||||||
var productsMap =
|
var productsMap = await apiClient.getProducts(productNameController.text);
|
||||||
await widget.apiClient.getProducts(productNameController.text);
|
|
||||||
setState(() {
|
setState(() {
|
||||||
products = (productsMap['products'] as List<dynamic>)
|
products = (productsMap['products'] as List<dynamic>)
|
||||||
.map((e) => Product.fromJson(e as Map<String, dynamic>))
|
.map((e) => Product.fromJson(e as Map<String, dynamic>))
|
||||||
|
@ -75,17 +78,17 @@ class _EditEntryScreen extends BasedState<EditEntryScreen> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await widget.apiClient.updateEntry(
|
await apiClient.updateEntry(
|
||||||
widget.entry.id,
|
entry.id,
|
||||||
grams: grams,
|
grams: grams,
|
||||||
productId: products[0].id,
|
productId: products[0].id,
|
||||||
mealId: widget.entry.mealId,
|
mealId: entry.mealId,
|
||||||
);
|
);
|
||||||
popMeDaddy();
|
popMeDaddy();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _deleteEntry() async {
|
Future<void> _deleteEntry() async {
|
||||||
await widget.apiClient.deleteEntry(widget.entry.id);
|
await apiClient.deleteEntry(widget.entry.id);
|
||||||
popMeDaddy();
|
popMeDaddy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +102,7 @@ class _EditEntryScreen extends BasedState<EditEntryScreen> {
|
||||||
|
|
||||||
if (res is String) {
|
if (res is String) {
|
||||||
try {
|
try {
|
||||||
var productMap = await widget.apiClient.getProductByBarcode(res);
|
var productMap = await apiClient.getProductByBarcode(res);
|
||||||
|
|
||||||
var product = Product.fromJson(productMap);
|
var product = Product.fromJson(productMap);
|
||||||
|
|
||||||
|
@ -144,7 +147,8 @@ class _EditEntryScreen extends BasedState<EditEntryScreen> {
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => AddProductScreen(
|
builder: (context) => AddProductScreen(
|
||||||
apiClient: widget.apiClient,
|
apiClient: apiClient,
|
||||||
|
storage: storage,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).then((product) {
|
).then((product) {
|
||||||
|
|
|
@ -7,7 +7,8 @@ import 'package:fooder/components/text.dart';
|
||||||
import 'package:fooder/components/button.dart';
|
import 'package:fooder/components/button.dart';
|
||||||
|
|
||||||
class LoginScreen extends BasedScreen {
|
class LoginScreen extends BasedScreen {
|
||||||
const LoginScreen({super.key, required super.apiClient});
|
const LoginScreen(
|
||||||
|
{super.key, required super.apiClient, required super.storage});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<LoginScreen> createState() => _LoginScreen();
|
State<LoginScreen> createState() => _LoginScreen();
|
||||||
|
@ -28,7 +29,8 @@ class _LoginScreen extends BasedState<LoginScreen> {
|
||||||
Navigator.pushReplacement(
|
Navigator.pushReplacement(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => MainScreen(apiClient: widget.apiClient),
|
builder: (context) =>
|
||||||
|
MainScreen(apiClient: apiClient, storage: storage),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -36,7 +38,7 @@ class _LoginScreen extends BasedState<LoginScreen> {
|
||||||
// login client when button pressed
|
// login client when button pressed
|
||||||
Future<void> _login() async {
|
Future<void> _login() async {
|
||||||
try {
|
try {
|
||||||
await widget.apiClient.login(
|
await apiClient.login(
|
||||||
usernameController.text,
|
usernameController.text,
|
||||||
passwordController.text,
|
passwordController.text,
|
||||||
);
|
);
|
||||||
|
@ -62,14 +64,14 @@ class _LoginScreen extends BasedState<LoginScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _asyncInitState() async {
|
Future<void> _asyncInitState() async {
|
||||||
await widget.apiClient.loadToken();
|
await apiClient.loadToken();
|
||||||
|
|
||||||
if (widget.apiClient.refreshToken == null) {
|
if (apiClient.refreshToken == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await widget.apiClient.refresh();
|
await apiClient.refresh();
|
||||||
showText("Welcome back!");
|
showText("Welcome back!");
|
||||||
popMeDaddy();
|
popMeDaddy();
|
||||||
} on Exception catch (_) {
|
} on Exception catch (_) {
|
||||||
|
@ -120,8 +122,10 @@ class _LoginScreen extends BasedState<LoginScreen> {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) => RegisterScreen(
|
||||||
RegisterScreen(apiClient: widget.apiClient),
|
apiClient: apiClient,
|
||||||
|
storage: storage,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,10 +8,10 @@ import 'package:fooder/widgets/meal.dart';
|
||||||
import 'package:fooder/components/sliver.dart';
|
import 'package:fooder/components/sliver.dart';
|
||||||
import 'package:fooder/components/date_picker.dart';
|
import 'package:fooder/components/date_picker.dart';
|
||||||
import 'package:fooder/components/floating_action_button.dart';
|
import 'package:fooder/components/floating_action_button.dart';
|
||||||
import 'package:fooder/storage/base.dart';
|
|
||||||
|
|
||||||
class MainScreen extends BasedScreen {
|
class MainScreen extends BasedScreen {
|
||||||
const MainScreen({super.key, required super.apiClient});
|
const MainScreen(
|
||||||
|
{super.key, required super.apiClient, required super.storage});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MainScreen> createState() => _MainScreen();
|
State<MainScreen> createState() => _MainScreen();
|
||||||
|
@ -28,7 +28,7 @@ class _MainScreen extends BasedState<MainScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _asyncInitState() async {
|
Future<void> _asyncInitState() async {
|
||||||
var diaryMap = await widget.apiClient.getDiary(date: date);
|
var diaryMap = await apiClient.getDiary(date: date);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
diary = Diary.fromJson(diaryMap);
|
diary = Diary.fromJson(diaryMap);
|
||||||
|
@ -52,8 +52,8 @@ class _MainScreen extends BasedState<MainScreen> {
|
||||||
await Navigator.push(
|
await Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) => AddEntryScreen(
|
||||||
AddEntryScreen(apiClient: widget.apiClient, diary: diary!),
|
apiClient: apiClient, diary: diary!, storage: storage),
|
||||||
),
|
),
|
||||||
).then((_) => _asyncInitState());
|
).then((_) => _asyncInitState());
|
||||||
}
|
}
|
||||||
|
@ -67,8 +67,9 @@ class _MainScreen extends BasedState<MainScreen> {
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => AddMealScreen(
|
builder: (context) => AddMealScreen(
|
||||||
apiClient: widget.apiClient,
|
apiClient: apiClient,
|
||||||
diary: diary!,
|
diary: diary!,
|
||||||
|
storage: storage,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).then((_) => _asyncInitState());
|
).then((_) => _asyncInitState());
|
||||||
|
@ -90,13 +91,14 @@ class _MainScreen extends BasedState<MainScreen> {
|
||||||
[
|
[
|
||||||
SummaryWidget(
|
SummaryWidget(
|
||||||
diary: diary!,
|
diary: diary!,
|
||||||
apiClient: widget.apiClient,
|
apiClient: apiClient,
|
||||||
refreshParent: _asyncInitState,
|
refreshParent: _asyncInitState,
|
||||||
),
|
),
|
||||||
for (var (i, meal) in diary!.meals.indexed)
|
for (var (i, meal) in diary!.meals.indexed)
|
||||||
MealWidget(
|
MealWidget(
|
||||||
|
apiClient: apiClient,
|
||||||
|
storage: storage,
|
||||||
meal: meal,
|
meal: meal,
|
||||||
apiClient: widget.apiClient,
|
|
||||||
refreshParent: _asyncInitState,
|
refreshParent: _asyncInitState,
|
||||||
initiallyExpanded: i == 0,
|
initiallyExpanded: i == 0,
|
||||||
showText: showText,
|
showText: showText,
|
||||||
|
|
|
@ -5,7 +5,8 @@ import 'package:fooder/components/text.dart';
|
||||||
import 'package:fooder/components/button.dart';
|
import 'package:fooder/components/button.dart';
|
||||||
|
|
||||||
class RegisterScreen extends BasedScreen {
|
class RegisterScreen extends BasedScreen {
|
||||||
const RegisterScreen({super.key, required super.apiClient});
|
const RegisterScreen(
|
||||||
|
{super.key, required super.apiClient, required super.storage});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<RegisterScreen> createState() => _RegisterScreen();
|
State<RegisterScreen> createState() => _RegisterScreen();
|
||||||
|
@ -49,7 +50,7 @@ class _RegisterScreen extends BasedState<RegisterScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await widget.apiClient.register(
|
await apiClient.register(
|
||||||
usernameController.text,
|
usernameController.text,
|
||||||
passwordController.text,
|
passwordController.text,
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,23 +9,23 @@ class Storage {
|
||||||
Database db;
|
Database db;
|
||||||
ProductStorage product;
|
ProductStorage product;
|
||||||
|
|
||||||
|
static const String path = "storage.db";
|
||||||
|
|
||||||
Storage({required this.db, required this.product});
|
Storage({required this.db, required this.product});
|
||||||
|
|
||||||
static Future<Storage> create() async {
|
static Future<Storage> create() async {
|
||||||
var db = await database();
|
|
||||||
return Storage(db: db, product: ProductStorage(db: db));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<void> createTables(Database db, int version) async {
|
|
||||||
await ProductStorage.createTable(db, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<Database> database({String path = "storage.db"}) async {
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
return openDatabase(
|
var db = await openDatabase(
|
||||||
join(await getDatabasesPath(), path),
|
join(await getDatabasesPath(), path),
|
||||||
onCreate: createTables,
|
onCreate: createTables,
|
||||||
version: 1,
|
version: 1,
|
||||||
);
|
);
|
||||||
|
return Storage(db: db, product: ProductStorage(db: db));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> createTables(Database db, int version) async {
|
||||||
|
var batch = db.batch();
|
||||||
|
await ProductStorage.createTable(batch);
|
||||||
|
await batch.commit(noResult: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
11
lib/storage/based.dart
Normal file
11
lib/storage/based.dart
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:sqflite/sqflite.dart';
|
||||||
|
|
||||||
|
abstract class StorageBased {
|
||||||
|
Database db;
|
||||||
|
|
||||||
|
StorageBased({required this.db});
|
||||||
|
|
||||||
|
static Future<void> createTable(Batch batch) async {}
|
||||||
|
}
|
|
@ -2,29 +2,32 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:sqflite/sqflite.dart';
|
import 'package:sqflite/sqflite.dart';
|
||||||
import 'package:fooder/models/product.dart';
|
import 'package:fooder/models/product.dart';
|
||||||
|
import 'package:fooder/storage/based.dart';
|
||||||
|
|
||||||
class ProductStorage {
|
class ProductStorage extends StorageBased {
|
||||||
Database db;
|
ProductStorage({required super.db});
|
||||||
|
|
||||||
ProductStorage({required this.db});
|
static Future<void> createTable(Batch batch) async {
|
||||||
|
batch.execute('''
|
||||||
static Future<void> createTable(Database db, int version) async {
|
|
||||||
await db.execute('''
|
|
||||||
CREATE TABLE product(
|
CREATE TABLE product(
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER,
|
||||||
name TEXT NOT NULL,
|
name TEXT,
|
||||||
barcode TEXT,
|
barcode TEXT,
|
||||||
calories NOT NULL,
|
calories REAL,
|
||||||
protein REAL NOT NULL,
|
protein REAL,
|
||||||
carb REAL NOT NULL,
|
carb REAL,
|
||||||
fat REAL NOT NULL,
|
fat REAL,
|
||||||
fiber REAL NOT NULL
|
fiber REAL,
|
||||||
|
usage_count_cached INTEGER
|
||||||
)
|
)
|
||||||
''');
|
''');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Product>> list() async {
|
Future<List<Product>> list({String? name, String? barcode}) async {
|
||||||
var result = await db.query('product');
|
var result = await db.query('product',
|
||||||
|
where: 'name LIKE ? AND barcode LIKE ?',
|
||||||
|
whereArgs: ['%$name%', '%$barcode%'],
|
||||||
|
orderBy: 'usage_count_cached DESC');
|
||||||
return result.map((e) => Product.fromJson(e)).toList();
|
return result.map((e) => Product.fromJson(e)).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:fooder/widgets/entry.dart';
|
||||||
import 'package:fooder/widgets/macro.dart';
|
import 'package:fooder/widgets/macro.dart';
|
||||||
import 'package:fooder/screens/edit_entry.dart';
|
import 'package:fooder/screens/edit_entry.dart';
|
||||||
import 'package:fooder/client.dart';
|
import 'package:fooder/client.dart';
|
||||||
|
import 'package:fooder/storage.dart';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
|
||||||
class MealHeader extends StatelessWidget {
|
class MealHeader extends StatelessWidget {
|
||||||
|
@ -38,6 +39,7 @@ class MealWidget extends StatelessWidget {
|
||||||
|
|
||||||
final Meal meal;
|
final Meal meal;
|
||||||
final ApiClient apiClient;
|
final ApiClient apiClient;
|
||||||
|
final Storage storage;
|
||||||
final Function() refreshParent;
|
final Function() refreshParent;
|
||||||
final Function(String) showText;
|
final Function(String) showText;
|
||||||
final bool initiallyExpanded;
|
final bool initiallyExpanded;
|
||||||
|
@ -49,6 +51,7 @@ class MealWidget extends StatelessWidget {
|
||||||
required this.refreshParent,
|
required this.refreshParent,
|
||||||
required this.initiallyExpanded,
|
required this.initiallyExpanded,
|
||||||
required this.showText,
|
required this.showText,
|
||||||
|
required this.storage,
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<void> saveMeal(context) async {
|
Future<void> saveMeal(context) async {
|
||||||
|
@ -124,6 +127,7 @@ class MealWidget extends StatelessWidget {
|
||||||
builder: (context) => EditEntryScreen(
|
builder: (context) => EditEntryScreen(
|
||||||
apiClient: apiClient,
|
apiClient: apiClient,
|
||||||
entry: entry,
|
entry: entry,
|
||||||
|
storage: storage,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).then((_) => refreshParent());
|
).then((_) => refreshParent());
|
||||||
|
|
Loading…
Reference in a new issue