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