From 2487801ee1f9bf08b113e6917724cf40c35ab5d2 Mon Sep 17 00:00:00 2001 From: jantunesmessias Date: Mon, 17 Feb 2025 11:55:18 -0300 Subject: [PATCH] WIP --- .../documents/document_page_bloc.dart | 16 +- .../documents/document_page_model.dart | 120 ++-- .../documents/document_screen_manager.dart | 16 +- lib/shared/widgets/carousel_view.dart | 2 +- lib/shared/widgets/enhanced_list_view.dart | 637 ++++++++++++++++++ lib/shared/widgets/list_view.dart | 594 ++++++++-------- lib/shared/widgets/widgets.dart | 7 +- pubspec.yaml | 154 +++-- 8 files changed, 1108 insertions(+), 438 deletions(-) create mode 100644 lib/shared/widgets/enhanced_list_view.dart diff --git a/lib/features/documents/document_page_bloc.dart b/lib/features/documents/document_page_bloc.dart index 3a20209f..a0d75b62 100644 --- a/lib/features/documents/document_page_bloc.dart +++ b/lib/features/documents/document_page_bloc.dart @@ -21,6 +21,7 @@ class DocumentPageBloc extends Bloc { Future _filterCategoryEvent( FilterCategoryEvent event, Emitter emit) async { + log('generateDocuments -> ${state.isCategorySelected}'); state.isCategorySelected ? _unselectCategory(event, emit) : _selectCategory(event, emit); @@ -32,8 +33,12 @@ class DocumentPageBloc extends Bloc { isCategorySelected: true, )); - final s = model.managerKey.currentState!; - state.isCategorySelected ? s.filter(event.query) : s.filter(event.query); + final listViewState = model.enhancedListViewKey.currentState!; + listViewState.safeSetState(() async { + return await listViewState.filterItems(event.query); + }); + + // state.isCategorySelected ? s.filter(event.query) : s.filter(event.query); } Future _unselectCategory( @@ -42,9 +47,10 @@ class DocumentPageBloc extends Bloc { isCategorySelected: false, )); - final s = model.managerKey.currentState!; - final Query q = Document.fromDesc(''); - s.filter(q); + final listViewState = model.enhancedListViewKey.currentState!; + listViewState.safeSetState(() async { + return await listViewState.filterItems(null); + }); } Future _selectDocument( diff --git a/lib/features/documents/document_page_model.dart b/lib/features/documents/document_page_model.dart index 482bfb3d..8501e39b 100644 --- a/lib/features/documents/document_page_model.dart +++ b/lib/features/documents/document_page_model.dart @@ -4,7 +4,8 @@ class DocumentPageModel extends FlutterFlowModel { DocumentPageModel(); late final GlobalKey> pageKey; - late final SearchKey managerKey; + late final EnhancedRemoteListViewKey + enhancedListViewKey; late final DocumentKey viewerKey; late final PagingController _pagingController; @@ -13,7 +14,7 @@ class DocumentPageModel extends FlutterFlowModel { @override void initState(BuildContext context) { pageKey = GlobalKey>(); - managerKey = SearchKey(); + enhancedListViewKey = EnhancedRemoteListViewKey(); viewerKey = DocumentKey(); _pagingController = PagingController(firstPageKey: 1); @@ -33,8 +34,8 @@ class DocumentPageModel extends FlutterFlowModel { context.read().add(SelectDocumentEvent(document)); } - /// [documentItemBuilder] - DocumentItem documentItemBuilder( + /// [itemBodyBuilder] + DocumentItem itemBodyBuilder( BuildContext context, T item, int index) { print('ItemBuilder -> $index'); return DocumentItem( @@ -47,8 +48,8 @@ class DocumentPageModel extends FlutterFlowModel { return CategoryItem(category: item! as Category); } - /// [listHeaderBuilder] - Widget listHeaderBuilder(Future> Function() gen) => + /// [itemHeaderBuilder] + Widget itemHeaderBuilder(Future> Function() gen) => Builder(builder: (context) { return Column( mainAxisSize: MainAxisSize.max, @@ -75,81 +76,64 @@ class DocumentPageModel extends FlutterFlowModel { ); }); - /// [generateDocuments] - Future<(bool, List?)> generateDocuments( - pageKey, Query query) async { - final List error = [null]; + /// [generateBodyItems] + Future> generateBodyItems( + int pageKey, int pageSize, dynamic query) async { + log('generateDocuments: $query'); + + final List error = [null]; print('Query: ${query is Document}'); final GetDocuments getDocuments = FreAccessWSGlobal.getDocuments; final ApiCallResponse newItems = await getDocuments.call(pageKey, query); - if (newItems.jsonBody == null) return (false, error); - if (newItems.jsonBody['error'] == true) return (false, error); - - final List list = newItems.jsonBody['value']['list']; - - late final List docs = []; - - for (var item in list) { - log('-> generateDocuments: $item'); - final String description = item['description']; - final String type = item['type']; - final String category = item['category']['description']; - final String color = item['category']['color']; - final String person = item['person'] ?? ''; - final String property = item['property'] ?? ''; - final String createdAt = item['createdAt']; - final String updatedAt = item['updatedAt']; - final int categoryId = item['category']['id']; - final int documentId = item['id']; - - final doc = Document( - id: documentId, - description: description, - type: type, - category: Category( - id: categoryId, - color: color.toColor(), - title: category, - ), - person: person, - property: property, - createdAt: createdAt, - updatedAt: updatedAt, - ); - - docs.add(doc); + if (newItems.jsonBody == null || newItems.jsonBody['error'] == true) { + return error; } - return (true, docs); - // listViewKey.currentState!.count = newItems.jsonBody['value']['count'] ?? 0; + final List list = newItems.jsonBody['value']['list']; + final List docs = list.map((item) { + log('-> generateDocuments: $item'); + return Document( + id: item['id'], + description: item['description'], + type: item['type'], + category: Category( + id: item['category']['id'], + color: item['category']['color'].toColor(), + title: item['category']['description'], + ), + person: item['person'] ?? '', + property: item['property'] ?? '', + createdAt: item['createdAt'], + updatedAt: item['updatedAt'], + ); + }).toList(); + + return docs as List; } - /// [generateCategories] - Future> generateCategories() async { - final List error = [null]; + /// [generateHeaderItems] + Future> generateHeaderItems() async { + final List error = [null]; final GetCategories getCategories = FreAccessWSGlobal.getCategories; final ApiCallResponse newItems = await getCategories.call(); - if (newItems.jsonBody['error'] == true) return error; - if (newItems.jsonBody == null) return error; - final list = newItems.jsonBody['value'] as List; - late final List cats = []; - for (var item in list) { - final String color = item['color']; - final String title = item['description']; - final int id = item['id']; - - final cat = Category( - id: id, - color: color.toColor(), - title: title, - ); - cats.add(cat); + if (newItems.jsonBody == null || newItems.jsonBody['error'] == true) { + return error; } - log('cats: $cats'); - return cats; + + final List list = newItems.jsonBody['value']; + final List categories = list.map((item) { + return Category( + id: item['id'], + color: item['color'].toColor(), + title: item['description'], + ); + }).toList(); + + log('categories: $categories'); + return categories as List; } /// [filter] diff --git a/lib/features/documents/document_screen_manager.dart b/lib/features/documents/document_screen_manager.dart index 3374cb1b..1db102dd 100644 --- a/lib/features/documents/document_screen_manager.dart +++ b/lib/features/documents/document_screen_manager.dart @@ -31,14 +31,14 @@ class DocumentManagerScreen extends StatelessScreen { return Column( children: [ Expanded( - child: EnhancedRemoteListView( - key: model.managerKey, - pagingController: model._pagingController, - headerBuilder: model.listHeaderBuilder, - headerItems: model.generateCategories, - bodyBuilder: model.documentItemBuilder, - dataProvider: model.generateDocuments, - onFetchError: model.onFetchError, + child: EnhancedListView.remote( + key: model.enhancedListViewKey, + headerBuilder: model.itemHeaderBuilder, + headerItems: model.generateHeaderItems, + bodyBuilder: model.itemBodyBuilder, + bodyItems: model.generateBodyItems, + footerBuilder: null, + footerItems: null, ), ), ] // diff --git a/lib/shared/widgets/carousel_view.dart b/lib/shared/widgets/carousel_view.dart index 402a2567..cce63a45 100644 --- a/lib/shared/widgets/carousel_view.dart +++ b/lib/shared/widgets/carousel_view.dart @@ -1,4 +1,4 @@ -part of '../widgets.dart'; +part of 'widgets.dart'; class EnhancedCarouselView extends StatelessWidget { final Future> Function() generateItems; diff --git a/lib/shared/widgets/enhanced_list_view.dart b/lib/shared/widgets/enhanced_list_view.dart new file mode 100644 index 00000000..5ba1828e --- /dev/null +++ b/lib/shared/widgets/enhanced_list_view.dart @@ -0,0 +1,637 @@ +part of 'widgets.dart'; + +/// [TypeDefs] + +typedef EnhancedRemoteListViewKey + = GlobalKey>; +typedef EnhancedLocalListViewKey + = GlobalKey>; + +typedef PaginatedListViewHeaderBuilder = Widget Function( + Future> Function() headerItems); +typedef PaginatedListViewBodyBuilder = Widget Function( + BuildContext context, T item, int index); +typedef PaginatedListViewFooterBuilder = Widget Function( + Future> Function() footerItems); + +typedef Query = T?; + +typedef BodyItemsBuilder = Future> Function( + int page, int pageSize, Query query); +typedef HeaderItemsBuilder = Future> Function(); +typedef FooterItemsBuilder = Future> Function(); + +/// [Extensions] +extension PaginatedListMergeExtensions + on Stream>> { + Stream> mergeWithPaginatedList( + BehaviorSubject> currentList) { + return map( + (result) { + final current = currentList.value; + if (result is ResultSuccess>) { + final newPaginated = result.data; + return current.items.isEmpty + ? newPaginated + : current.copyWith( + list: [...current.items, ...newPaginated.items], + currentPage: newPaginated.currentPage, + totalCount: newPaginated.totalCount, + error: newPaginated.error, + ); + } else if (result is ResultError>) { + return current.copyWith(error: result.error); + } else { + return current; + } + }, + ); + } +} + +extension PublishSubjectExtensions on PublishSubject { + Stream startWith(T initial) => Rx.concat([Stream.value(initial), this]); +} + +extension StreamStartWithExtension on Stream { + Stream startWith(T initial) => Rx.concat([Stream.value(initial), this]); +} + +extension QueryBlocStreamExtensions on Stream { + Stream>> fetchData( + EnhancedListViewRepository repository, + PaginatedListViewBodyBuilder builder, + BehaviorSubject> paginatedList, + ) => + switchMap((reset) { + if (reset) { + paginatedList.add(paginatedList.value.resetAll()); + } + final nextPage = paginatedList.value.currentPage + 1; + return repository + .fetchPage(nextPage, paginatedList.value.pageSize, builder) + .asResultStream(); + }); +} + +/// [Widgets] + +/// [EnhancedListView] + +interface class EnhancedPaginatedList extends PaginatedList { + @override + final Exception? error; + final bool isInitialized; + @override + final bool isLoading; + final List items; + @override + final int pageSize; + @override + final int? totalCount; + final int currentPage; + + EnhancedPaginatedList({ + required this.items, + required this.pageSize, + this.currentPage = 0, + this.totalCount, + required this.error, + required this.isInitialized, + required this.isLoading, + }) : super( + error: error, + isInitialized: isInitialized, + isLoading: isLoading, + list: items, + pageSize: pageSize, + totalCount: totalCount, + ); + + EnhancedPaginatedList resetAll() => EnhancedPaginatedList( + error: null, + isInitialized: false, + isLoading: false, + items: const [], + pageSize: pageSize, + totalCount: null, + currentPage: 0, + ); + + @override + EnhancedPaginatedList copyWith({ + List? list, + bool? isLoading, + int? totalCount, + Exception? error, + int? pageSize, + bool? isInitialized, + int? currentPage, + }) => + EnhancedPaginatedList( + error: error ?? this.error, + isInitialized: isInitialized ?? this.isInitialized, + isLoading: isLoading ?? this.isLoading, + items: list ?? this.items, + pageSize: pageSize ?? this.pageSize, + totalCount: totalCount ?? this.totalCount, + currentPage: currentPage ?? this.currentPage, + ); + + @override + int get itemCount => items.length; + + @override + T? getItem(int index) => index < items.length ? items[index] : null; + + Future awaitLoad() async => Future.value(); +} + +abstract interface class EnhancedListViewBase extends StatefulWidget { + const EnhancedListViewBase({super.key}); +} + +abstract interface class EnhancedListViewBaseState + extends State {} + +class EnhancedListView { + static EnhancedRemoteListView + remote({ + required Key? key, + required BodyItemsBuilder bodyItems, + required PaginatedListViewBodyBuilder bodyBuilder, + HeaderItemsBuilder? headerItems, + PaginatedListViewHeaderBuilder? headerBuilder, + FooterItemsBuilder? footerItems, + PaginatedListViewFooterBuilder? footerBuilder, + }) { + return EnhancedRemoteListView( + key: key, + bodyItems: bodyItems, + bodyBuilder: bodyBuilder, + headerItems: headerItems, + headerBuilder: headerBuilder, + footerItems: footerItems, + footerBuilder: footerBuilder, + ); + } + + static EnhancedLocalListView local({ + required Key? key, + required List list, + required Widget Function(T) itemBuilder, + required bool Function(T, String) filter, + List Function(String)? onSearch, + Widget? header, + }) { + return EnhancedLocalListView( + key: key, + list: list, + itemBuilder: itemBuilder, + filter: filter, + onSearch: onSearch, + header: header, + ); + } +} + +/// [EnhancedLocalListView] + +class EnhancedLocalListView extends EnhancedListViewBase { + final List list; + final Widget Function(T) itemBuilder; + final bool Function(T, String) filter; + final Widget header; + final List Function(String)? onSearch; + + EnhancedLocalListView({ + Key? key, + required this.list, + required this.itemBuilder, + required this.filter, + List Function(String)? onSearch, + Widget? header, + }) : header = header ?? const SizedBox.shrink(), + onSearch = onSearch ?? + ((String query) => + list.where((documents) => filter(documents, query)).toList()), + super(key: key); + + @override + EnhancedLocalListViewState createState() => + EnhancedLocalListViewState(); +} + +class EnhancedLocalListViewState + extends State> { + TextEditingController editingController = TextEditingController(); + late List filteredItems; + + @override + void initState() { + filteredItems = widget.list; + super.initState(); + } + + @override + Widget build(BuildContext context) { + void filter(value) { + setState(() { + filteredItems = widget.onSearch!(value); + }); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: ListView.builder( + shrinkWrap: true, + itemCount: filteredItems.length + 1, + itemBuilder: (context, index) { + if (index == 0) return widget.header; + return widget.itemBuilder(filteredItems[index - 1]); + }, + ), + ), + Padding( + padding: const EdgeInsets.all(30.0), + child: TextFormField( + controller: editingController, + onChanged: filter, + cursorColor: Colors.black, + cursorWidth: 2.0, + cursorRadius: Radius.circular(2.0), + style: TextStyle( + color: Colors.black, + fontSize: 16.0, + ), + keyboardType: TextInputType.text, + textInputAction: TextInputAction.search, + autocorrect: true, + textCapitalization: TextCapitalization.sentences, + decoration: InputDecoration( + prefixIcon: Icon(Icons.search, color: Colors.black), + labelText: 'Pesquisar', + labelStyle: TextStyle( + color: Colors.black, + fontSize: 16.0, + ), + hintText: 'Digite sua pesquisa', + hintStyle: TextStyle( + color: Colors.grey, + fontSize: 14.0, + ), + filled: true, + fillColor: Colors.white, + contentPadding: + EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(15.0)), + borderSide: BorderSide(color: Colors.black), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(15.0)), + borderSide: BorderSide(color: Colors.blue), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(15.0)), + borderSide: BorderSide(color: Colors.red), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(15.0)), + borderSide: BorderSide(color: Colors.red, width: 2.0), + ), + ), + ), + ), + ], + ); + } +} + +/// [EnhancedRemoteListView] + +class EnhancedRemoteListView + extends EnhancedListViewBase { + final BodyItemsBuilder bodyItems; + final PaginatedListViewBodyBuilder bodyBuilder; + final HeaderItemsBuilder? headerItems; + final PaginatedListViewHeaderBuilder? headerBuilder; + final FooterItemsBuilder? footerItems; + final PaginatedListViewFooterBuilder? footerBuilder; + + const EnhancedRemoteListView({ + Key? key, + required this.bodyItems, + required this.bodyBuilder, + this.headerItems, + this.headerBuilder, + this.footerItems, + this.footerBuilder, + }) : super(key: key); + + @override + EnhancedRemoteListViewState createState() => + EnhancedRemoteListViewState(); +} + +class EnhancedRemoteListViewState + extends State> { + final ScrollController _scrollController = ScrollController(); + bool _isLoadingMore = false; + List _items = []; + int _currentPage = 1; + Query query; + + @override + void initState() { + super.initState(); + _scrollController.addListener(_onScroll); + _loadInitialItems(); + } + + void _onScroll() { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent && + !_isLoadingMore) { + _loadMoreItems(); + } + } + + Future _loadInitialItems() async { + final newItems = await widget.bodyItems(1, 10, query); + setState(() { + _items = newItems; + }); + } + + Future _loadMoreItems() async { + setState(() { + _isLoadingMore = true; + }); + final newItems = await widget.bodyItems(_currentPage + 1, 10, query); + setState(() { + _isLoadingMore = false; + if (newItems.isNotEmpty) { + _items.addAll(newItems); + _currentPage++; + } + }); + } + + Future filterItems(Query newQuery) async { + log('filterItems: $newQuery'); + setState(() { + query = newQuery; + _items = []; + _currentPage = 1; + }); + await _loadInitialItems(); + } + + @override + Widget build(BuildContext context) { + log('key: ${widget.key}'); + return ListView.builder( + controller: _scrollController, + itemCount: _items.length + + (widget.headerItems != null ? 1 : 0) + + (widget.footerItems != null ? 1 : 0) + + (_isLoadingMore ? 1 : 0), + itemBuilder: (context, index) { + if (widget.headerItems != null && index == 0) { + return FutureBuilder>( + future: widget.headerItems!(), + builder: (context, headerSnapshot) { + if (headerSnapshot.connectionState == ConnectionState.waiting) { + return const EnhancedProgressIndicator(); + } else if (headerSnapshot.hasError) { + return EnhancedErrorWidget(error: headerSnapshot.error); + } else { + return widget + .headerBuilder!(() => Future.value(headerSnapshot.data)); + } + }, + ); + } + if (widget.footerItems != null && + index == _items.length + (widget.headerItems != null ? 1 : 0)) { + return FutureBuilder>( + future: widget.footerItems!(), + builder: (context, footerSnapshot) { + if (footerSnapshot.connectionState == ConnectionState.waiting) { + return const EnhancedProgressIndicator(); + } else if (footerSnapshot.hasError) { + return EnhancedErrorWidget( + error: footerSnapshot.error as Exception); + } else { + return widget + .footerBuilder!(() => Future.value(footerSnapshot.data)); + } + }, + ); + } + if (_isLoadingMore && + index == + _items.length + + (widget.headerItems != null ? 1 : 0) + + (widget.footerItems != null ? 1 : 0)) { + return const EnhancedProgressIndicator(); + } + final item = _items[index - (widget.headerItems != null ? 1 : 0)]; + return widget.bodyBuilder(context, item as ItemType, index); + }, + ); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } +} + +/// [Utils] + +class EnhancedListTile extends StatelessWidget { + const EnhancedListTile( + {required this.leading, required this.title, super.key}); + + final T leading; + final T title; + + @override + Widget build(BuildContext context) { + return Card( + child: ListTile( + leading: leading, + title: title, + ), + ); + } +} + +class EnhancedErrorWidget extends StatelessWidget { + final Object? error; + const EnhancedErrorWidget({required this.error, super.key}); + + @override + Widget build(BuildContext context) { + log('error: $error'); + return Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + error.toString(), + style: const TextStyle(color: Colors.red), + ), + ); + } +} + +class EnhancedProgressIndicator extends StatelessWidget { + const EnhancedProgressIndicator({super.key}); + + @override + Widget build(BuildContext context) => const Center( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 12), + child: CircularProgressIndicator(), + ), + ); +} + +class NetworkError implements Exception { + final String message; + NetworkError(this.message); +} + +class ParsingError implements Exception { + final String message; + ParsingError(this.message); +} + +class AuthorizationError implements Exception { + final String message; + AuthorizationError(this.message); +} + +/// [State Managment] +Stream get loadingState => Stream.empty(); +Stream get errorState => Stream.empty(); + +abstract class EnhancedListViewRepository { + Future> fetchPage( + int page, int pageSize, PaginatedListViewBodyBuilder builder); +} + +abstract class EnhancedListViewBlocStates { + Stream get isLoading; + Stream get errors; + Stream> get paginatedList; + + @RxBlocIgnoreState() + Future get refreshDone; +} + +abstract class EnhancedListViewEvents { + void loadPage({bool reset = false}); +} + +abstract class EnhancedListViewBlocType extends RxBlocTypeBase { + EnhancedListViewEvents get events; + EnhancedListViewBlocStates get states; +} + +abstract class $EnhancedListViewBloc extends RxBlocBase + implements + EnhancedListViewEvents, + EnhancedListViewBlocStates, + EnhancedListViewBlocType { + final _compositeSubscription = CompositeSubscription(); + + final _$loadPageEvent = PublishSubject(); + + late final Stream _isLoadingState = _mapToIsLoadingState(); + late final Stream _errorsState = _mapToErrorsState(); + late final Stream> _paginatedListState = + _mapToPaginatedListState(); + + @override + void loadPage({bool reset = false}) => _$loadPageEvent.add(reset); + + @override + Stream get isLoading => _isLoadingState; + @override + Stream get errors => _errorsState; + @override + Stream> get paginatedList => _paginatedListState; + + Stream _mapToIsLoadingState(); + Stream _mapToErrorsState(); + Stream> _mapToPaginatedListState(); + + @override + EnhancedListViewEvents get events => this; + @override + EnhancedListViewBlocStates get states => this; + + @override + void dispose() { + _$loadPageEvent.close(); + _compositeSubscription.dispose(); + super.dispose(); + } +} + +class EnhancedListViewBloc extends $EnhancedListViewBloc { + EnhancedListViewBloc({ + required EnhancedListViewRepository repository, + required PaginatedListViewBodyBuilder builder, + required T item, + int initialPageSize = 50, + }) { + _$loadPageEvent + .startWith(true) + .fetchData( + repository, + (context, item, index) => builder(context, item, index), + _paginatedList, + ) + .setResultStateHandler(this) + .mergeWithPaginatedList(_paginatedList) + .bind(_paginatedList) + .addTo(_compositeSubscription); + } + + final _paginatedList = BehaviorSubject>.seeded( + EnhancedPaginatedList( + items: [], + pageSize: 1, + currentPage: 1, + error: Exception(), + isInitialized: true, + isLoading: false, + totalCount: 0, + ), + ); + + @override + Future get refreshDone async => _paginatedList.value.awaitLoad(); + + @override + Stream> _mapToPaginatedListState() => _paginatedList; + @override + Stream _mapToErrorsState() => + errorState.map((error) => error.toString()); + @override + Stream _mapToIsLoadingState() => loadingState; + + @override + void dispose() { + _paginatedList.close(); + super.dispose(); + } +} diff --git a/lib/shared/widgets/list_view.dart b/lib/shared/widgets/list_view.dart index 17a72c6a..7304de9f 100644 --- a/lib/shared/widgets/list_view.dart +++ b/lib/shared/widgets/list_view.dart @@ -1,325 +1,325 @@ -part of '../widgets.dart'; +part of 'widgets.dart'; -typedef SearchKey = GlobalKey; +// typedef SearchKey = GlobalKey; -typedef Query = X?; +// typedef Query = X?; -/// ----------------------------------------------- -/// [EnhancedListView] -/// ----------------------------------------------- +// /// ----------------------------------------------- +// /// [EnhancedListView] +// /// ----------------------------------------------- -abstract interface class EnhancedListView extends StatefulWidget { - const EnhancedListView({super.key}); -} +// abstract interface class EnhancedListView extends StatefulWidget { +// const EnhancedListView({super.key}); +// } -abstract interface class EnhancedListViewState - extends State {} +// abstract interface class EnhancedListViewState +// extends State {} -/// ----------------------------------------------- -/// [EnhancedLocalListView] -/// ----------------------------------------------- +// /// ----------------------------------------------- +// /// [EnhancedLocalListView] +// /// ----------------------------------------------- -class EnhancedLocalListView extends EnhancedListView { - final List list; - final Widget Function(T) itemBuilder; - final bool Function(T, String) filter; - final Widget header; - final List Function(String)? onSearch; +// class EnhancedLocalListView extends EnhancedListView { +// final List list; +// final Widget Function(T) itemBuilder; +// final bool Function(T, String) filter; +// final Widget header; +// final List Function(String)? onSearch; - EnhancedLocalListView({ - Key? key, - required this.list, - required this.itemBuilder, - required this.filter, - List Function(String)? onSearch, - Widget? header, - }) : header = header ?? const SizedBox.shrink(), - onSearch = onSearch ?? - ((String query) => - list.where((documents) => filter(documents, query)).toList()), - super(key: key); +// EnhancedLocalListView({ +// Key? key, +// required this.list, +// required this.itemBuilder, +// required this.filter, +// List Function(String)? onSearch, +// Widget? header, +// }) : header = header ?? const SizedBox.shrink(), +// onSearch = onSearch ?? +// ((String query) => +// list.where((documents) => filter(documents, query)).toList()), +// super(key: key); - // return documents.where((documents) => filter(documents, query)).toList(); +// // return documents.where((documents) => filter(documents, query)).toList(); - @override - EnhancedLocalListViewState createState() => - EnhancedLocalListViewState(); -} +// @override +// EnhancedLocalListViewState createState() => +// EnhancedLocalListViewState(); +// } -class EnhancedLocalListViewState extends State> { - TextEditingController editingController = TextEditingController(); - late List filteredItems; +// class EnhancedLocalListViewState extends State> { +// TextEditingController editingController = TextEditingController(); +// late List filteredItems; - @override - void initState() { - filteredItems = widget.list; - super.initState(); - } +// @override +// void initState() { +// filteredItems = widget.list; +// super.initState(); +// } - @override - Widget build(BuildContext context) { - void filter(value) { - safeSetState(() { - filteredItems = widget.onSearch!(value); - }); - } +// @override +// Widget build(BuildContext context) { +// void filter(value) { +// safeSetState(() { +// filteredItems = widget.onSearch!(value); +// }); +// } - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - Expanded( - child: ListView.builder( - shrinkWrap: true, - itemCount: filteredItems.length + 1, - itemBuilder: (context, index) { - if (index == 0) return widget.header; - return widget.itemBuilder(filteredItems[index - 1]); - }, - ), - ), - Padding( - padding: const EdgeInsets.all(30.0), - child: TextFormField( - controller: editingController, - onChanged: filter, - cursorColor: Colors.black, - cursorWidth: 2.0, - cursorRadius: Radius.circular(2.0), - style: TextStyle( - color: Colors.black, - fontSize: 16.0, - ), - keyboardType: TextInputType.text, - textInputAction: TextInputAction.search, - autocorrect: true, - textCapitalization: TextCapitalization.sentences, - decoration: InputDecoration( - prefixIcon: Icon(Icons.search, color: Colors.black), - labelText: 'Pesquisar', - labelStyle: TextStyle( - color: Colors.black, - fontSize: 16.0, - ), - hintText: 'Digite sua pesquisa', - hintStyle: TextStyle( - color: Colors.grey, - fontSize: 14.0, - ), - filled: true, - fillColor: Colors.white, - contentPadding: - EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(15.0)), - borderSide: BorderSide(color: Colors.black), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(15.0)), - borderSide: BorderSide(color: Colors.blue), - ), - errorBorder: OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(15.0)), - borderSide: BorderSide(color: Colors.red), - ), - focusedErrorBorder: OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(15.0)), - borderSide: BorderSide(color: Colors.red, width: 2.0), - ), - ), - )), - ], - ); - } -} +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisAlignment: MainAxisAlignment.center, +// mainAxisSize: MainAxisSize.max, +// children: [ +// Expanded( +// child: ListView.builder( +// shrinkWrap: true, +// itemCount: filteredItems.length + 1, +// itemBuilder: (context, index) { +// if (index == 0) return widget.header; +// return widget.itemBuilder(filteredItems[index - 1]); +// }, +// ), +// ), +// Padding( +// padding: const EdgeInsets.all(30.0), +// child: TextFormField( +// controller: editingController, +// onChanged: filter, +// cursorColor: Colors.black, +// cursorWidth: 2.0, +// cursorRadius: Radius.circular(2.0), +// style: TextStyle( +// color: Colors.black, +// fontSize: 16.0, +// ), +// keyboardType: TextInputType.text, +// textInputAction: TextInputAction.search, +// autocorrect: true, +// textCapitalization: TextCapitalization.sentences, +// decoration: InputDecoration( +// prefixIcon: Icon(Icons.search, color: Colors.black), +// labelText: 'Pesquisar', +// labelStyle: TextStyle( +// color: Colors.black, +// fontSize: 16.0, +// ), +// hintText: 'Digite sua pesquisa', +// hintStyle: TextStyle( +// color: Colors.grey, +// fontSize: 14.0, +// ), +// filled: true, +// fillColor: Colors.white, +// contentPadding: +// EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), +// enabledBorder: OutlineInputBorder( +// borderRadius: BorderRadius.all(Radius.circular(15.0)), +// borderSide: BorderSide(color: Colors.black), +// ), +// focusedBorder: OutlineInputBorder( +// borderRadius: BorderRadius.all(Radius.circular(15.0)), +// borderSide: BorderSide(color: Colors.blue), +// ), +// errorBorder: OutlineInputBorder( +// borderRadius: BorderRadius.all(Radius.circular(15.0)), +// borderSide: BorderSide(color: Colors.red), +// ), +// focusedErrorBorder: OutlineInputBorder( +// borderRadius: BorderRadius.all(Radius.circular(15.0)), +// borderSide: BorderSide(color: Colors.red, width: 2.0), +// ), +// ), +// )), +// ], +// ); +// } +// } -/// ----------------------------------------------- -/// [EnhancedRemoteListView] -/// ----------------------------------------------- +// /// ----------------------------------------------- +// /// [EnhancedRemoteListView] +// /// ----------------------------------------------- -// ignore: must_be_immutable -class EnhancedRemoteListView extends EnhancedListView { - final Widget Function(BuildContext, T, int) bodyBuilder; - final Future> Function() headerItems; - Widget Function(Future> Function() gen) headerBuilder; - final PagingController pagingController; - final Future<(bool, List?)> Function(int pageKey, Query query) - dataProvider; +// // ignore: must_be_immutable +// class EnhancedRemoteListView extends EnhancedListView { +// final Widget Function(BuildContext, T, int) bodyBuilder; +// final Future> Function() headerItems; +// Widget Function(Future> Function() gen) headerBuilder; +// final PagingController pagingController; +// final Future<(bool, List?)> Function(int pageKey, Query query) +// dataProvider; - final void Function(Object, StackTrace) onFetchError; +// final void Function(Object, StackTrace) onFetchError; - EnhancedRemoteListView({ - Key? key, - // required this.fetchItems, - required this.bodyBuilder, - required this.headerItems, - required this.headerBuilder, - required this.pagingController, - required this.dataProvider, - required this.onFetchError, - }) : super(key: key); +// EnhancedRemoteListView({ +// Key? key, +// // required this.fetchItems, +// required this.bodyBuilder, +// required this.headerItems, +// required this.headerBuilder, +// required this.pagingController, +// required this.dataProvider, +// required this.onFetchError, +// }) : super(key: key); - @override - EnhancedRemoteListViewState createState() => - EnhancedRemoteListViewState(); -} +// @override +// EnhancedRemoteListViewState createState() => +// EnhancedRemoteListViewState(); +// } -class EnhancedRemoteListViewState - extends State> with Pageable { - TextEditingController editingController = TextEditingController(); - bool isLoading = false; - Query query = Document.fromDesc(''); +// class EnhancedRemoteListViewState +// extends State> with Pageable { +// TextEditingController editingController = TextEditingController(); +// bool isLoading = false; +// Query query = Document.fromDesc(''); - @override - void initState() { - widget.pagingController.addPageRequestListener( - (page) => fetchPage( - dataProvider: () async => await widget.dataProvider(page, query), - onDataUnavailable: () => showNoMoreDataSnackBar(context), - onDataAvailable: (data) => - widget.pagingController.appendLastPage(data), - onFetchError: (e, s) => widget.onFetchError), - ); - widget.pagingController.addStatusListener(_showError); +// @override +// void initState() { +// widget.pagingController.addPageRequestListener( +// (page) => fetchPage( +// dataProvider: () async => await widget.dataProvider(page, query), +// onDataUnavailable: () => showNoMoreDataSnackBar(context), +// onDataAvailable: (data) => +// widget.pagingController.appendLastPage(data), +// onFetchError: (e, s) => widget.onFetchError), +// ); +// widget.pagingController.addStatusListener(_showError); - super.initState(); - } +// super.initState(); +// } - Future _showError(PagingStatus status) async { - if (status == PagingStatus.subsequentPageError) { - final message = FFLocalizations.of(context).getVariableText( - enText: 'Something went wrong while fetching a new page.', - ptText: 'Algo deu errado ao buscar uma nova página.', - ); - final retry = FFLocalizations.of(context).getVariableText( - enText: 'Retry', - ptText: 'Recarregar', - ); +// Future _showError(PagingStatus status) async { +// if (status == PagingStatus.subsequentPageError) { +// final message = FFLocalizations.of(context).getVariableText( +// enText: 'Something went wrong while fetching a new page.', +// ptText: 'Algo deu errado ao buscar uma nova página.', +// ); +// final retry = FFLocalizations.of(context).getVariableText( +// enText: 'Retry', +// ptText: 'Recarregar', +// ); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(message), - action: SnackBarAction( - label: retry, - onPressed: () => widget.pagingController.retryLastFailedRequest(), - ), - ), - ); - } - } +// ScaffoldMessenger.of(context).showSnackBar( +// SnackBar( +// content: Text(message), +// action: SnackBarAction( +// label: retry, +// onPressed: () => widget.pagingController.retryLastFailedRequest(), +// ), +// ), +// ); +// } +// } - void filter(Query data) async { - if (data is Category) { - safeSetState(() => query = Category( - id: data.id, - color: data.color, - title: data.title, - )); - widget.pagingController.refresh(); - } else if (data is Document) { - log('filter: ${data.description}'); +// void filter(Query data) async { +// if (data is Category) { +// safeSetState(() => query = Category( +// id: data.id, +// color: data.color, +// title: data.title, +// )); +// widget.pagingController.refresh(); +// } else if (data is Document) { +// log('filter: ${data.description}'); - safeSetState(() => query = data); - widget.pagingController.refresh(); - } else { - safeSetState(() { - query = Document.fromDesc(''); - }); - widget.pagingController.refresh(); - } - } +// safeSetState(() => query = data); +// widget.pagingController.refresh(); +// } else { +// safeSetState(() { +// query = Document.fromDesc(''); +// }); +// widget.pagingController.refresh(); +// } +// } - @override - Widget build(BuildContext context) { - final noDataFound = FFLocalizations.of(context).getVariableText( - ptText: "Nenhum item encontrado!", - enText: "No item found", - ); - final theme = FlutterFlowTheme.of(context); - final locale = FFLocalizations.of(context); +// @override +// Widget build(BuildContext context) { +// final noDataFound = FFLocalizations.of(context).getVariableText( +// ptText: "Nenhum item encontrado!", +// enText: "No item found", +// ); +// final theme = FlutterFlowTheme.of(context); +// final locale = FFLocalizations.of(context); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - buildPaginatedListView( - noDataFound, - widget.pagingController, - widget.headerItems, - widget.headerBuilder, - widget.bodyBuilder, - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: TextFormField( - controller: editingController, - onChanged: (value) => EasyDebounce.debounce( - '_model.keyTextFieldTextController', - const Duration(milliseconds: 500), - () => filter(Document.fromDesc(value)), - ), - cursorColor: theme.primaryText, - showCursor: false, - cursorWidth: 2.0, - cursorRadius: Radius.circular(100), - style: TextStyle( - color: theme.primaryText, - fontSize: 16.0, - decorationColor: Colors.amber, - ), - keyboardType: TextInputType.text, - textInputAction: TextInputAction.search, - autocorrect: true, - textCapitalization: TextCapitalization.sentences, - decoration: InputDecoration( - prefixIcon: Icon(Icons.search, color: theme.primary), - labelText: locale.getVariableText( - ptText: 'Pesquisar', - enText: 'Search', - ), - labelStyle: TextStyle( - color: theme.primaryText, - fontSize: 16.0, - ), - hintText: locale.getVariableText( - ptText: 'Digite sua pesquisa', - enText: 'Enter your search', - ), - hintStyle: TextStyle( - color: theme.accent2, - fontSize: 14.0, - ), - filled: true, - fillColor: Colors.transparent, - helperStyle: TextStyle( - color: theme.primaryText, - decorationColor: theme.primaryText, - ), - focusColor: theme.primaryText, - contentPadding: - EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), - enabledBorder: UnderlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(15.0)), - borderSide: BorderSide(color: theme.primaryText), - ), - focusedBorder: UnderlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(15.0)), - borderSide: BorderSide(color: theme.primaryText), - ), - errorBorder: UnderlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(15.0)), - borderSide: BorderSide(color: theme.primaryText), - ), - focusedErrorBorder: UnderlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(15.0)), - borderSide: BorderSide(color: theme.primaryText, width: 2.0), - ), - ), - ), - ), - ], - ); - } -} +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisAlignment: MainAxisAlignment.center, +// mainAxisSize: MainAxisSize.max, +// children: [ +// buildPaginatedListView( +// noDataFound, +// widget.pagingController, +// widget.headerItems, +// widget.headerBuilder, +// widget.bodyBuilder, +// ), +// Padding( +// padding: const EdgeInsets.all(8.0), +// child: TextFormField( +// controller: editingController, +// onChanged: (value) => EasyDebounce.debounce( +// '_model.keyTextFieldTextController', +// const Duration(milliseconds: 500), +// () => filter(Document.fromDesc(value)), +// ), +// cursorColor: theme.primaryText, +// showCursor: false, +// cursorWidth: 2.0, +// cursorRadius: Radius.circular(100), +// style: TextStyle( +// color: theme.primaryText, +// fontSize: 16.0, +// decorationColor: Colors.amber, +// ), +// keyboardType: TextInputType.text, +// textInputAction: TextInputAction.search, +// autocorrect: true, +// textCapitalization: TextCapitalization.sentences, +// decoration: InputDecoration( +// prefixIcon: Icon(Icons.search, color: theme.primary), +// labelText: locale.getVariableText( +// ptText: 'Pesquisar', +// enText: 'Search', +// ), +// labelStyle: TextStyle( +// color: theme.primaryText, +// fontSize: 16.0, +// ), +// hintText: locale.getVariableText( +// ptText: 'Digite sua pesquisa', +// enText: 'Enter your search', +// ), +// hintStyle: TextStyle( +// color: theme.accent2, +// fontSize: 14.0, +// ), +// filled: true, +// fillColor: Colors.transparent, +// helperStyle: TextStyle( +// color: theme.primaryText, +// decorationColor: theme.primaryText, +// ), +// focusColor: theme.primaryText, +// contentPadding: +// EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), +// enabledBorder: UnderlineInputBorder( +// borderRadius: BorderRadius.all(Radius.circular(15.0)), +// borderSide: BorderSide(color: theme.primaryText), +// ), +// focusedBorder: UnderlineInputBorder( +// borderRadius: BorderRadius.all(Radius.circular(15.0)), +// borderSide: BorderSide(color: theme.primaryText), +// ), +// errorBorder: UnderlineInputBorder( +// borderRadius: BorderRadius.all(Radius.circular(15.0)), +// borderSide: BorderSide(color: theme.primaryText), +// ), +// focusedErrorBorder: UnderlineInputBorder( +// borderRadius: BorderRadius.all(Radius.circular(15.0)), +// borderSide: BorderSide(color: theme.primaryText, width: 2.0), +// ), +// ), +// ), +// ), +// ], +// ); +// } +// } diff --git a/lib/shared/widgets/widgets.dart b/lib/shared/widgets/widgets.dart index 0edd1805..c09aeccf 100644 --- a/lib/shared/widgets/widgets.dart +++ b/lib/shared/widgets/widgets.dart @@ -9,12 +9,15 @@ import 'package:http/http.dart' as http; import 'package:hub/features/documents/index.dart'; import 'package:hub/flutter_flow/index.dart'; import 'package:hub/shared/mixins/pegeable_mixin.dart'; -import 'package:hub/shared/utils/index.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; import 'package:path_provider/path_provider.dart'; import 'package:pdfx/pdfx.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:rx_bloc_list/rx_bloc_list.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:rx_bloc/rx_bloc.dart'; +/// [Base] part 'page.dart'; part 'component.dart'; part 'screen.dart'; @@ -25,5 +28,7 @@ part 'entity.dart'; part 'list_view.dart'; part 'carousel_view.dart'; part 'read_view.dart'; +part 'enhanced_list_view.dart'; +/// [Component]'s part 'text.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 799c3b86..7283c1df 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,77 +1,102 @@ +# Informações básicas do projeto name: hub -description: A new Flutter project. - -publish_to: "none" +description: . # Descrição do projeto (adicione mais detalhes se necessário) +publish_to: "none" # Destino de publicação +# Versão do aplicativo version: 1.3.5+24 +# Restrições de versão do SDK Dart environment: - sdk: ">=3.0.0 <4.0.0" + sdk: ">=3.5.0-0.0.dev <4.0.0" +# Dependências do aplicativo dependencies: + # Dependências essenciais do Flutter flutter: sdk: flutter flutter_localizations: sdk: flutter - pdfx: ^2.8.0 - auto_size_text: ^3.0.0 + + # Gerenciamento de Estado + provider: 6.1.2 + flutter_bloc: ^9.0.0 + flutter_riverpod: ^2.5.1 + rx_bloc: ^6.0.1 + flutter_rx_bloc: ^7.0.0 + rx_bloc_list: ^5.0.1 + rxdart: ^0.28.0 + rx_bloc_test: ^5.0.0 + bloc_test: ^10.0.0 + bloc_concurrency: ^0.3.0 + hydrated_bloc: ^10.0.0 + + # Programação Funcional + dart_either: ^2.0.0 + result_dart: ^2.0.0 + fpdart: ^1.1.1 + + # Pacotes de UI + auto_size_text: 3.0.0 barcode_widget: ^2.0.4 + infinite_scroll_pagination: ^4.1.0 cached_network_image: ^3.4.0 - firebase_core: ^3.4.0 flutter_inappwebview: ^6.0.0 webview_flutter: ^4.8.0 - rxdart: ^0.28.0 - collection: ^1.18.0 - app_links: ^6.3.2 - # crop_your_image: 1.1.0 - csv: 6.0.0 - device_info_plus: ^10.1.2 #11.2.2 + flutter_spinkit: 5.2.1 + flutter_staggered_grid_view: 0.7.0 + flutter_svg: ^2.0.15 + font_awesome_flutter: ^10.8.0 + google_fonts: 6.2.1 + material_symbols_icons: ^4.2784.0 + fluttertoast: ^8.2.8 + cupertino_icons: ^1.0.0 + qr_flutter: ^4.1.0 + percent_indicator: ^4.2.3 + page_transition: ^2.2.1 + share_plus: ^10.1.4 + pdfx: ^2.8.0 + dropdown_button2: ^2.3.9 + + # Firebase + firebase_core: ^3.4.0 firebase_messaging: ^15.1.0 - dropdown_button2: 2.3.9 + firebase_analytics: ^11.3.0 + firebase_crashlytics: ^4.0.1 + + # Utilidades + app_links: ^6.3.3 + collection: ^1.18.0 + csv: 6.0.0 + device_info_plus: ^10.1.2 easy_debounce: 2.0.3 equatable: ^2.0.6 file_picker: ^8.0.7 - # flutter_expandable_fab: ^2.1.0 - firebase_analytics: ^11.3.0 flutter_animate: ^4.5.2 - # flutter_cache_manager: ^3.4.1 - # flutter_plugin_android_lifecycle: ^2.0.23 - share_plus: ^10.1.4 - # connectivity_plus: ^6.0.5 flutter_secure_storage: ^10.0.0-beta.2 flutter_secure_storage_linux: ^2.0.0 flutter_secure_storage_macos: ^4.0.0 flutter_secure_storage_platform_interface: ^2.0.1 flutter_secure_storage_web: ^2.0.0 flutter_secure_storage_windows: ^4.0.0 - flutter_spinkit: 5.2.1 - flutter_staggered_grid_view: 0.7.0 - flutter_svg: ^2.0.15 - font_awesome_flutter: ^10.8.0 from_css_color: 2.0.0 go_router: ^14.3.0 - google_fonts: 6.2.1 - http: 1.3.0 + http: ^1.3.0 image_picker: 1.1.2 image_picker_android: ^0.8.12+15 image_picker_for_web: ^3.0.5 - persistent_bottom_nav_bar: ^6.2.1 image_picker_ios: ^0.8.12+1 image_picker_platform_interface: ^2.10.1 local_auth: ^2.2.0 intl: ^0.19.0 - # camera: ^0.11.0+2 json_path: ^0.7.4 mime_type: ^1.0.1 - page_transition: ^2.2.1 path_provider: ^2.1.4 path_provider_android: ^2.2.12 google_mlkit_face_detection: ^0.12.0 path_provider_foundation: ^2.4.1 path_provider_platform_interface: 2.1.2 - percent_indicator: ^4.2.3 plugin_platform_interface: 2.1.8 - provider: 6.1.2 shared_preferences: ^2.3.2 shared_preferences_android: ^2.3.3 shared_preferences_foundation: ^2.5.3 @@ -85,69 +110,80 @@ dependencies: url_launcher_android: ^6.3.12 url_launcher_ios: ^6.3.1 url_launcher_platform_interface: 2.3.2 - infinite_scroll_pagination: ^4.1.0 - # video_player: 2.8.7 - # video_player_android: 2.5.0 - # video_player_avfoundation: 2.6.1 - # video_player_platform_interface: 6.2.2 - # video_player_web: 2.3.1 - material_symbols_icons: ^4.2784.0 - fluttertoast: ^8.2.8 - cupertino_icons: ^1.0.0 - flutter_bloc: ^9.0.0 - flutter_riverpod: ^2.5.1 - qr_flutter: ^4.1.0 permission_handler: ^11.3.1 - firebase_crashlytics: ^4.0.1 awesome_notifications: ^0.10.0 app_tracking_transparency: ^2.0.6 - # dio: ^5.7.0 - # crypto: ^3.0.5 freezed_annotation: ^2.4.4 package_info_plus: ^8.1.1 - # json_annotation: ^4.9.0 + sliver_tools: ^0.2.12 + json_annotation: ^4.9.0 + # Dependências a partir de repositório Git (pacotes personalizados) + # base: + # git: + # url: 'git@github.com:FRE-Informatica/flutter-freaccess-base.git' + # path: 'packages/base' + # components: + # git: + # url: 'git@github.com:FRE-Informatica/flutter-freaccess-base.git' + # path: 'packages/components' + # templates: + # git: + # url: 'git@github.com:FRE-Informatica/flutter-freaccess-base.git' + # path: 'packages/templates' + # theme: + # git: + # url: 'git@github.com:FRE-Informatica/flutter-freaccess-base.git' + # path: 'packages/theme' + +# Substituição de versões específicas de pacotes, se necessário dependency_overrides: - http: 1.3.0 + http: ^1.3.0 uuid: ^4.0.0 win32: 5.5.1 +# Dependências para desenvolvimento e testes dev_dependencies: + bloc_lint: ^0.1.0 + rx_bloc_generator: ^8.0.1 flutter_launcher_icons: ^0.14.1 flutter_lints: ^5.0.0 image: ^4.3.0 lints: ^5.0.0 - # build_runner: ^2.4.13 mockito: ^5.4.4 integration_test: sdk: flutter flutter_test: sdk: flutter - build_runner: ^2.4.13 - freezed: ^2.5.7 - json_serializable: ^6.9.0 + build_runner: ^2.4.14 + freezed: ^3.0.0-0.0.dev + json_serializable: ^6.9.4 test: ^1.25.7 patrol: ^3.13.2 patrol_finders: ^2.6.0 +# Configuração do flutter_launcher_icons flutter_launcher_icons: - android: "launcher_icon" - ios: true + android: "launcher_icon" # Nome da pasta/ícone para Android + ios: true # Geração de ícones para iOS web: - generate: true + generate: true # Geração de ícones para Web image_path: "assets/images/app_launcher_icon.svg" adaptive_icon_background: "assets/images/adaptive_background_icon.svg" adaptive_icon_foreground: "assets/images/adaptive_foreground_icon.svg" +# Configurações específicas do Flutter flutter: - uses-material-design: true + uses-material-design: true # Habilita o uso do Material Design + # Definição de assets (imagens, fontes, etc.) assets: - assets/fonts/ - assets/images/ - assets/images/dark/ - assets/images/light/ - - assets/files/ + +# Configuração de fontes customizadas fonts: - family: "SF Pro" fonts: @@ -160,13 +196,15 @@ fonts: - family: Icons fonts: - asset: assets/fonts/icons.ttf + - family: Menu fonts: - asset: assets/fonts/menu.ttf +# Configuração do Patrol (ferramenta para testes de integração) patrol: app_name: FRE ACCESS HUB android: package_name: com.freaccess.hub ios: - bundle_id: br.com.freaccess.hub \ No newline at end of file + bundle_id: br.com.freaccess.hub