added cache for categories

This commit is contained in:
Patrick Alvin Alcala 2025-03-20 13:10:39 +08:00
parent 753c730588
commit 1aa7410e2e
14 changed files with 195 additions and 63 deletions

View file

@ -0,0 +1,17 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pharmacy_mobile/blocs/caches/categorylist/categorylist_cache_event.dart';
import 'package:pharmacy_mobile/blocs/caches/categorylist/categorylist_cache_state.dart';
class CategoryListBloc extends Bloc<CategoryListCacheEvent, CategoryListCacheState> {
CategoryListBloc() : super(CategoryListCacheState([])) {
on<CategoryListCacheSet>((event, emit) {
emit(CategoryListCacheState(event.value));
});
on<CategoryListCacheGet>((event, emit) {
emit(state);
});
on<CategoryListCacheCheck>((event, emit) {
emit(state);
});
}
}

View file

@ -0,0 +1,10 @@
abstract class CategoryListCacheEvent {}
class CategoryListCacheSet extends CategoryListCacheEvent {
final List value;
CategoryListCacheSet(this.value);
}
class CategoryListCacheGet extends CategoryListCacheEvent {}
class CategoryListCacheCheck extends CategoryListCacheEvent {}

View file

@ -0,0 +1,5 @@
class CategoryListCacheState {
final List value;
CategoryListCacheState(this.value);
}

View file

@ -0,0 +1,14 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pharmacy_mobile/blocs/caches/categorylist/categorylist_cache_bloc.dart';
import 'package:pharmacy_mobile/blocs/caches/categorylist/categorylist_cache_event.dart';
Future<List> cacheGetCategoryList(BuildContext context) async {
try {
final categoryListCache = context.read<CategoryListBloc>();
categoryListCache.add(CategoryListCacheGet());
return categoryListCache.state.value;
} catch (e) {
return [];
}
}

View file

@ -0,0 +1,14 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pharmacy_mobile/blocs/caches/categorylist/categorylist_cache_bloc.dart';
import 'package:pharmacy_mobile/blocs/caches/categorylist/categorylist_cache_event.dart';
Future<bool> cacheSetCategoryList(BuildContext context, List value) async {
try {
final categoryListCache = context.read<CategoryListBloc>();
categoryListCache.add(CategoryListCacheSet(value));
return true;
} catch (e) {
return false;
}
}

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:pharmacy_mobile/auth/auth_gate.dart'; import 'package:pharmacy_mobile/auth/auth_gate.dart';
import 'package:pharmacy_mobile/blocs/caches/categorylist/categorylist_cache_bloc.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_bloc.dart'; import 'package:pharmacy_mobile/blocs/guest/guest_bloc.dart';
import 'package:pharmacy_mobile/blocs/user/user_bloc.dart'; import 'package:pharmacy_mobile/blocs/user/user_bloc.dart';
import 'package:pharmacy_mobile/pages/add_category_page.dart'; import 'package:pharmacy_mobile/pages/add_category_page.dart';
@ -124,6 +125,9 @@ class MyApp extends StatelessWidget {
BlocProvider( BlocProvider(
create: (context) => UserBloc(), create: (context) => UserBloc(),
), ),
BlocProvider(
create: (context) => CategoryListBloc(),
),
], ],
child: MaterialApp.router( child: MaterialApp.router(
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,

View file

@ -1,6 +1,7 @@
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart'; import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:pharmacy_mobile/blocs/caches/categorylist/functions/cache_getcategorylist.dart';
import 'package:pharmacy_mobile/functions/checkexisting_function.dart'; import 'package:pharmacy_mobile/functions/checkexisting_function.dart';
import 'package:pharmacy_mobile/tables/ref_categories.dart'; import 'package:pharmacy_mobile/tables/ref_categories.dart';
import 'package:pharmacy_mobile/tables/ref_generic_names.dart'; import 'package:pharmacy_mobile/tables/ref_generic_names.dart';
@ -28,7 +29,8 @@ class _AddGenericsPageState extends State<AddGenericsPage> {
final _nameController = TextEditingController(); final _nameController = TextEditingController();
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
bool _isLoading = false; late bool _isLoading = false;
late final List _categoryListCache = [];
late List _categoryList = []; late List _categoryList = [];
late String _selectedCategory = ''; late String _selectedCategory = '';
@ -52,22 +54,34 @@ class _AddGenericsPageState extends State<AddGenericsPage> {
} }
} }
void autoRun() async { Future<void> _getCategory() async {
if (await InternetConnectionChecker.instance.hasConnection) { final categoryListCache = await cacheGetCategoryList(context);
_getList();
} else {
if (mounted) {
showNotification(context, 'Error: No Internet Connection', false);
WidgetsBinding.instance.addPostFrameCallback((_) { if (categoryListCache.isNotEmpty) {
if (mounted) { setState(() {
context.push('/main'); _categoryList = categoryListCache;
} });
}); } else {
if (await InternetConnectionChecker.instance.hasConnection) {
_getList();
} else {
if (mounted) {
showNotification(context, 'Error: No Internet Connection', false);
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
context.push('/main');
}
});
}
} }
} }
} }
void autoRun() async {
_getCategory();
}
void _updateCategory(dynamic category) { void _updateCategory(dynamic category) {
_selectedCategory = category; _selectedCategory = category;
} }

View file

@ -3,7 +3,7 @@ import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart'; import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:pharmacy_mobile/functions/checkexisting_function.dart'; import 'package:pharmacy_mobile/functions/checkexisting_function.dart';
import 'package:pharmacy_mobile/tables/ref_manufactorers.dart'; import 'package:pharmacy_mobile/tables/ref_manufacturers.dart';
import 'package:pharmacy_mobile/widgets/buttonwithprogress_widget.dart'; import 'package:pharmacy_mobile/widgets/buttonwithprogress_widget.dart';
import 'package:pharmacy_mobile/widgets/form_border_widget2.dart'; import 'package:pharmacy_mobile/widgets/form_border_widget2.dart';
import 'package:pharmacy_mobile/widgets/input_form_widget.dart'; import 'package:pharmacy_mobile/widgets/input_form_widget.dart';
@ -16,33 +16,33 @@ class AddManufacturerPage extends StatefulWidget {
const AddManufacturerPage({super.key}); const AddManufacturerPage({super.key});
@override @override
State<AddManufacturerPage> createState() => _AddManufactorerPageState(); State<AddManufacturerPage> createState() => _AddManufacturerPageState();
} }
class _AddManufactorerPageState extends State<AddManufacturerPage> { class _AddManufacturerPageState extends State<AddManufacturerPage> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _nameController = TextEditingController(); final _nameController = TextEditingController();
final _addressController = TextEditingController(); final _addressController = TextEditingController();
final _refManufactorers = RefManufactorers(); final _refManufacturers = RefManufacturers();
late bool _isLoading = false; late bool _isLoading = false;
void _saveManufactorer() async { void _saveManufacturer() async {
setState(() => _isLoading = true); setState(() => _isLoading = true);
try { try {
if (await InternetConnectionChecker.instance.hasConnection) { if (await InternetConnectionChecker.instance.hasConnection) {
final existing = await checkExisting(_refManufactorers, _nameController); final existing = await checkExisting(_refManufacturers, _nameController);
if (existing && mounted) { if (existing && mounted) {
showNotification(context, 'Manufactorer already listed', false); showNotification(context, 'Manufacturer already listed', false);
return; return;
} }
final post = await _refManufactorers.postManufactorer(_nameController.text, _addressController.text); final post = await _refManufacturers.postManufacturer(_nameController.text, _addressController.text);
if (post && mounted) { if (post && mounted) {
showNotification(context, 'Manufactorer added to list', true); showNotification(context, 'Manufacturer added to list', true);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) { if (mounted) {
@ -103,12 +103,12 @@ class _AddManufactorerPageState extends State<AddManufacturerPage> {
// if (_isLoading) // if (_isLoading)
// const Center(child: CircularProgressIndicator(color: Colors.white)) // const Center(child: CircularProgressIndicator(color: Colors.white))
// else // else
// ButtonWidget(text: 'Save Manufactorer', onPressed: _saveManufactorer) // ButtonWidget(text: 'Save Manufacturer', onPressed: _saveManufacturer)
ButtonWithProgressWidget( ButtonWithProgressWidget(
trigger: _isLoading, trigger: _isLoading,
progressText: 'Adding Manufacturer', progressText: 'Adding Manufacturer',
buttonText: 'Save', buttonText: 'Save',
onPressed: _saveManufactorer) onPressed: _saveManufacturer)
], ],
))) )))
], ],

View file

@ -7,7 +7,7 @@ import 'package:pharmacy_mobile/functions/barcode_scan_function.dart';
import 'package:pharmacy_mobile/functions/checkresult_function.dart'; import 'package:pharmacy_mobile/functions/checkresult_function.dart';
import 'package:pharmacy_mobile/tables/ref_categories.dart'; import 'package:pharmacy_mobile/tables/ref_categories.dart';
import 'package:pharmacy_mobile/tables/ref_generic_names.dart'; import 'package:pharmacy_mobile/tables/ref_generic_names.dart';
import 'package:pharmacy_mobile/tables/ref_manufactorers.dart'; import 'package:pharmacy_mobile/tables/ref_manufacturers.dart';
import 'package:pharmacy_mobile/tables/ref_medicines.dart'; import 'package:pharmacy_mobile/tables/ref_medicines.dart';
import 'package:pharmacy_mobile/tables/ref_types.dart'; import 'package:pharmacy_mobile/tables/ref_types.dart';
import 'package:pharmacy_mobile/tables/storage.dart'; import 'package:pharmacy_mobile/tables/storage.dart';
@ -39,7 +39,7 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
final _refGenericNames = RefGenericNames(); final _refGenericNames = RefGenericNames();
final _refCategories = RefCategories(); final _refCategories = RefCategories();
final _refTypes = RefTypes(); final _refTypes = RefTypes();
final _refManufactorer = RefManufactorers(); final _refManufacturer = RefManufacturers();
final _refMedicines = RefMedicines(); final _refMedicines = RefMedicines();
final _storage = Storage(); final _storage = Storage();
final _nameController = TextEditingController(); final _nameController = TextEditingController();
@ -51,8 +51,8 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
late String _selectedCategory = ''; late String _selectedCategory = '';
late List _typeList = []; late List _typeList = [];
late String _selectedType = ''; late String _selectedType = '';
late List _manufactorerList = []; late List _manufacturerList = [];
late String _selectedManufactorer = ''; late String _selectedManufacturer = '';
late String uuid = ''; late String uuid = '';
late bool imageUploaded = false; late bool imageUploaded = false;
late String imageUrl = ''; late String imageUrl = '';
@ -71,10 +71,10 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
}); });
} }
Future<void> _getManufactorer() async { Future<void> _getManufacturer() async {
_manufactorerList = await _refManufactorer.getList(); _manufacturerList = await _refManufacturer.getList();
setState(() { setState(() {
checkResult(context, _manufactorerList, 'Manufactorer'); checkResult(context, _manufacturerList, 'Manufacturer');
}); });
} }
@ -82,7 +82,7 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
if (await InternetConnectionChecker.instance.hasConnection) { if (await InternetConnectionChecker.instance.hasConnection) {
await _getGenerics(); await _getGenerics();
await _getTypes(); await _getTypes();
await _getManufactorer(); await _getManufacturer();
// final sample = await _refMedicines.getList2(); // final sample = await _refMedicines.getList2();
} else { } else {
@ -110,8 +110,8 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
_selectedType = type; _selectedType = type;
} }
void _updateManufactorer(dynamic manufactorer) { void _updateManufacturer(dynamic manufacturer) {
_selectedManufactorer = manufactorer; _selectedManufacturer = manufacturer;
} }
Future<void> _scanBarcode() async { Future<void> _scanBarcode() async {
@ -142,10 +142,10 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
final medName = _nameController.text; final medName = _nameController.text;
final medGenericUUID = await _refGenericNames.getUUID(_selectedGeneric); final medGenericUUID = await _refGenericNames.getUUID(_selectedGeneric);
final medTypeUUID = await _refTypes.getUUID(_selectedType); final medTypeUUID = await _refTypes.getUUID(_selectedType);
final medManufactorerUUID = await _refManufactorer.getUUID(_selectedManufactorer); final medManufacturerUUID = await _refManufacturer.getUUID(_selectedManufacturer);
await _refMedicines.postMedicine( await _refMedicines.postMedicine(
uuid, medName, medManufactorerUUID, medGenericUUID, medTypeUUID, encrpytedBarcode); uuid, medName, medManufacturerUUID, medGenericUUID, medTypeUUID, encrpytedBarcode);
} else { } else {
if (mounted) { if (mounted) {
showNotification(context, 'Error: No Internet Connection', false); showNotification(context, 'Error: No Internet Connection', false);
@ -177,13 +177,19 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
uploaded = await _storage.uploadImage(context, storageName, webpImage, '$imageName.webp'); uploaded = await _storage.uploadImage(context, storageName, webpImage, '$imageName.webp');
} }
setState(() { if (!uploaded) {
if (!uploaded) { if (mounted) {
if (mounted) { showNotification(context, 'Image Upload failed, try again.', false);
showNotification(context, 'Image Upload failed, try again.', false); return;
}
} }
}); }
if (imageName.isNotEmpty) {
final url = await _getImageUrl('$imageName.webp');
setState(() {
imageUrl = url;
});
}
} }
Future<Uint8List> _webpConvert(Uint8List file) async { Future<Uint8List> _webpConvert(Uint8List file) async {
@ -197,6 +203,11 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
return result; return result;
} }
Future<String> _getImageUrl(String imageName) async {
final image = await _storage.getImageURL('ref_medicines_images', imageName);
return image;
}
@override @override
void initState() { void initState() {
autoRun(); autoRun();
@ -213,8 +224,8 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
_selectedCategory = ''; _selectedCategory = '';
_typeList = []; _typeList = [];
_selectedType = ''; _selectedType = '';
_manufactorerList = []; _manufacturerList = [];
_selectedManufactorer = ''; _selectedManufacturer = '';
super.dispose(); super.dispose();
} }
@ -265,10 +276,10 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
), ),
const Gap(16), const Gap(16),
DropDownWidget( DropDownWidget(
label: 'Manufactorer', label: 'Manufacturer',
list: _manufactorerList, list: _manufacturerList,
listTitle: 'manufactorer_name', listTitle: 'manufacturer_name',
onChanged: _updateManufactorer, onChanged: _updateManufacturer,
), ),
const Gap(16), const Gap(16),
InputFormWidget(label: 'Barcode', controller: _barcodeController), InputFormWidget(label: 'Barcode', controller: _barcodeController),

View file

@ -31,7 +31,7 @@ class _CustomerSearchPageState extends State<CustomerSearchPage> {
// late final List _medicinesList = []; // late final List _medicinesList = [];
Future<void> _getURL() async { Future<void> _getURL() async {
final image = await _storage.getPublicURL('ref_medicines_images', 'a3e430fe-86c1-4d46-9c6a-aed2dae57fef.webp'); final image = await _storage.getImageURL('ref_medicines_images', 'a3e430fe-86c1-4d46-9c6a-aed2dae57fef.webp');
setState(() { setState(() {
imageUrl = image; imageUrl = image;
}); });

View file

@ -3,6 +3,9 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:pharmacy_mobile/auth/auth_service.dart'; import 'package:pharmacy_mobile/auth/auth_service.dart';
import 'package:pharmacy_mobile/blocs/caches/categorylist/functions/cache_getcategorylist.dart';
import 'package:pharmacy_mobile/blocs/caches/categorylist/functions/cache_setcategorylist.dart';
import 'package:pharmacy_mobile/tables/ref_categories.dart';
import 'package:pharmacy_mobile/widgets/buttonwithprogress_widget.dart'; import 'package:pharmacy_mobile/widgets/buttonwithprogress_widget.dart';
import 'package:pharmacy_mobile/widgets/menu_widget.dart'; import 'package:pharmacy_mobile/widgets/menu_widget.dart';
import 'package:pharmacy_mobile/widgets/page_background_widget.dart'; import 'package:pharmacy_mobile/widgets/page_background_widget.dart';
@ -20,6 +23,7 @@ class MainPage extends StatefulWidget {
class _MainPageState extends State<MainPage> { class _MainPageState extends State<MainPage> {
final _authService = AuthService(); final _authService = AuthService();
final _refCategories = RefCategories();
late bool _isLoading = false; late bool _isLoading = false;
@ -45,6 +49,50 @@ class _MainPageState extends State<MainPage> {
} }
} }
// void _getList() async {
// _categoryList = await _refCategories.getList();
// if (_categoryList.isEmpty) {
// if (mounted) {
// showNotification(context, 'Error: No Categories Found', false);
// WidgetsBinding.instance.addPostFrameCallback((_) {
// if (mounted) {
// context.push('/main');
// }
// });
// }
// } else {
// setState(() => {});
// }
// }
Future<void> _getCategoryListCache() async {
final categoryList = await _refCategories.getList();
if (categoryList.isNotEmpty) {
// ignore: use_build_context_synchronously
final setCache = await cacheSetCategoryList(context, categoryList);
if (!setCache) {
// ignore: use_build_context_synchronously
showNotification(context, 'Caching failed', false);
} else {
print('Caching Success');
}
}
}
void autoRun() async {
await _getCategoryListCache();
}
@override
void initState() {
autoRun();
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PopScope( return PopScope(

View file

@ -1,12 +1,7 @@
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart'; import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:pharmacy_mobile/auth/auth_service.dart'; import 'package:pharmacy_mobile/auth/auth_service.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_bloc.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_event.dart';
import 'package:pharmacy_mobile/widgets/buttonwithprogress_widget.dart'; import 'package:pharmacy_mobile/widgets/buttonwithprogress_widget.dart';
import 'package:pharmacy_mobile/widgets/glossy_container_widget.dart'; import 'package:pharmacy_mobile/widgets/glossy_container_widget.dart';
import 'package:pharmacy_mobile/widgets/input_form_widget.dart'; import 'package:pharmacy_mobile/widgets/input_form_widget.dart';

View file

@ -1,15 +1,15 @@
import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
class RefManufactorers { class RefManufacturers {
final SupabaseClient _supabase = Supabase.instance.client; final SupabaseClient _supabase = Supabase.instance.client;
Future<List> getList() async { Future<List> getList() async {
try { try {
final data = await _supabase final data = await _supabase
.from('ref_manufactorers') .from('ref_manufacturers')
.select('manufactorer_name') .select('manufacturer_name')
.order('manufactorer_name', ascending: true); .order('manufacturer_name', ascending: true);
return data.toList(); return data.toList();
} catch (e) { } catch (e) {
return []; return [];
@ -19,20 +19,20 @@ class RefManufactorers {
Future<String> getUUID(String name) async { Future<String> getUUID(String name) async {
try { try {
final data = final data =
await _supabase.from('ref_manufactorers').select('ref_manufactorers_uuid').eq('manufactorer_name', name); await _supabase.from('ref_manufacturers').select('ref_manufacturers_uuid').eq('manufacturer_name', name);
return data.first['ref_manufactorers_uuid'].toString(); return data.first['ref_manufacturers_uuid'].toString();
} catch (e) { } catch (e) {
return ''; return '';
} }
} }
Future<bool> postManufactorer(String name, String address) async { Future<bool> postManufacturer(String name, String address) async {
try { try {
final genericUUID = Uuid().v4(); final genericUUID = Uuid().v4();
await _supabase await _supabase
.from('ref_manufactorers') .from('ref_manufacturers')
.insert({'ref_manufactorers_uuid': genericUUID, 'manufactorer_name': name, 'manufactorer_address': address}); .insert({'ref_manufacturers_uuid': genericUUID, 'manufacturer_name': name, 'manufacturer_address': address});
return true; return true;
} catch (e) { } catch (e) {
return false; return false;

View file

@ -36,7 +36,7 @@ class Storage {
} }
} }
Future<String> getPublicURL(String storage, String name) async { Future<String> getImageURL(String storage, String name) async {
try { try {
final String file = _supabase.storage.from(storage).getPublicUrl(name); final String file = _supabase.storage.from(storage).getPublicUrl(name);
return file; return file;