WIP
This commit is contained in:
parent
23a6b6d1d9
commit
8b8950a992
Binary file not shown.
|
@ -118,18 +118,25 @@ class DocumentManagerScreen extends StatelessScreen {
|
|||
}
|
||||
|
||||
Widget buildBody(BuildContext context) {
|
||||
final SizedBox space = SizedBox(height: 30);
|
||||
const SizedBox space = SizedBox(height: 10);
|
||||
final controller = EnhancedListViewController(
|
||||
headerBuilder: model.itemHeaderBuilder<SearchField>,
|
||||
bodyBuilder: model.itemBodyBuilder<Document>,
|
||||
footerBuilder: model.itemFooterBuilder<Category>,
|
||||
);
|
||||
final repository = EnhancedListViewRepository(
|
||||
fetchHeader: model.generateHeaderItems<SearchField>,
|
||||
fetchBody: model.generateBodyItems<Document, Query>,
|
||||
fetchFooter: model.generateFooterItems<Category>,
|
||||
);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: EnhancedListView<Document, Search, Category, Query>(
|
||||
child: EnhancedListView<Document, SearchField, Category, Query>(
|
||||
key: model.vehicleScreenManager,
|
||||
headerBuilder: model.itemHeaderBuilder<Search>,
|
||||
headerItems: model.generateHeaderItems<Search>,
|
||||
bodyBuilder: model.itemBodyBuilder<Document>,
|
||||
bodyItems: model.generateBodyItems<Document, Query>,
|
||||
footerBuilder: model.itemFooterBuilder<Category>,
|
||||
footerItems: model.generateFooterItems<Category>,
|
||||
controller: controller,
|
||||
repository: repository,
|
||||
),
|
||||
),
|
||||
] //
|
||||
|
@ -235,7 +242,7 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
|
|||
final DocumentPageBlocType bloc;
|
||||
DocumentModel(this.bloc);
|
||||
|
||||
late EnhancedListViewKey<Document, Search, Category, Query>
|
||||
late EnhancedListViewKey<Document, SearchField, Category, Query>
|
||||
vehicleScreenManager;
|
||||
late DocumentKey vehicleScreenViewer;
|
||||
late PagingController<int, Document> _pagingController;
|
||||
|
@ -247,7 +254,7 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
|
|||
@override
|
||||
void initState(BuildContext context) {
|
||||
vehicleScreenManager =
|
||||
EnhancedListViewKey<Document, Search, Category, Query>();
|
||||
EnhancedListViewKey<Document, SearchField, Category, Query>();
|
||||
vehicleScreenViewer = DocumentKey();
|
||||
_pagingController = PagingController<int, Document>(firstPageKey: 1);
|
||||
|
||||
|
@ -388,7 +395,7 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
|
|||
|
||||
/// [Header]
|
||||
|
||||
Widget itemHeaderBuilder<T extends Search>(
|
||||
Widget itemHeaderBuilder<T extends SearchField>(
|
||||
Future<List<T?>> Function() generateHeaderItems) {
|
||||
return Builder(builder: (context) {
|
||||
final theme = FlutterFlowTheme.of(context);
|
||||
|
@ -462,8 +469,8 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
|
|||
});
|
||||
}
|
||||
|
||||
Future<List<T?>> generateHeaderItems<T extends Search>() async {
|
||||
final Search item = Search();
|
||||
Future<List<T?>> generateHeaderItems<T extends SearchField>() async {
|
||||
final SearchField item = SearchField();
|
||||
return [item] as List<T?>;
|
||||
}
|
||||
|
||||
|
@ -537,8 +544,8 @@ class DocumentPageBloc extends $DocumentPageBloc {
|
|||
|
||||
abstract interface class Archive extends Entity {}
|
||||
|
||||
interface class Search extends Archive {
|
||||
Search();
|
||||
interface class SearchField extends Archive {
|
||||
SearchField();
|
||||
}
|
||||
|
||||
interface class Document extends Archive {
|
||||
|
|
|
@ -5,17 +5,19 @@ part of 'widgets.dart';
|
|||
typedef EnhancedListViewKey<BodyType, HeaderType, FooterType, QueryType>
|
||||
= GlobalKey<
|
||||
EnhancedListViewState<BodyType, HeaderType, FooterType, QueryType>>;
|
||||
typedef PaginatedListViewHeaderBuilder<HeaderType> = Widget Function(
|
||||
typedef HeaderTileBuilder<HeaderType> = Widget Function(
|
||||
Future<List<HeaderType?>> Function() headerItems);
|
||||
typedef PaginatedListViewBodyBuilder<BodyType> = Widget Function(
|
||||
typedef BodyTileBuilder<BodyType> = Widget Function(
|
||||
BuildContext context, BodyType item, int index);
|
||||
typedef PaginatedListViewFooterBuilder<FooterType> = Widget Function(
|
||||
typedef FooterTileBuilder<FooterType> = Widget Function(
|
||||
Future<List<FooterType?>> Function() footerItems);
|
||||
typedef Query<QueryType> = QueryType?;
|
||||
typedef BodyItemsBuilder<BodyType, QueryType> = Future<List<BodyType?>>
|
||||
typedef BodyRetrievalUseCase<BodyType, QueryType> = Future<List<BodyType?>>
|
||||
Function(int page, int pageSize, QueryType query);
|
||||
typedef HeaderItemsBuilder<HeaderType> = Future<List<HeaderType?>> Function();
|
||||
typedef FooterItemsBuilder<FooterType> = Future<List<FooterType?>> Function();
|
||||
typedef HeaderRetrievalUseCase<HeaderType> = Future<List<HeaderType?>>
|
||||
Function();
|
||||
typedef FooterRetrievalUseCase<FooterType> = Future<List<FooterType?>>
|
||||
Function();
|
||||
|
||||
/// [Extensions] ----------------------------------------------------
|
||||
extension PaginatedListMergeExtensions<T>
|
||||
|
@ -54,20 +56,20 @@ extension StreamStartWithExtension<T> on Stream<T> {
|
|||
}
|
||||
|
||||
extension QueryBlocStreamExtensions<T> on Stream<bool> {
|
||||
Stream<Result<EnhancedPaginatedList<T>>> fetchData(
|
||||
EnhancedListViewRepository<T> repository,
|
||||
PaginatedListViewBodyBuilder<T> builder,
|
||||
BehaviorSubject<EnhancedPaginatedList<T>> 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();
|
||||
});
|
||||
// Stream<Result<EnhancedPaginatedList<T>>> fetchData(
|
||||
// EnhancedListViewRepository<T> repository,
|
||||
// PaginatedListViewBodyBuilder<T> builder,
|
||||
// BehaviorSubject<EnhancedPaginatedList<T>> 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();
|
||||
// });
|
||||
}
|
||||
|
||||
/// [Interfaces] ----------------------------------------------------
|
||||
|
@ -167,21 +169,15 @@ mixin EnhancedListViewMixin<BodyType, HeaderType, FooterType, QueryType> {
|
|||
|
||||
class EnhancedListView<BodyType, HeaderType, FooterType, QueryType>
|
||||
extends EnhancedListViewBase<BodyType, HeaderType, FooterType, QueryType> {
|
||||
final BodyItemsBuilder<BodyType, QueryType?> bodyItems;
|
||||
final PaginatedListViewBodyBuilder<BodyType> bodyBuilder;
|
||||
final HeaderItemsBuilder<HeaderType>? headerItems;
|
||||
final PaginatedListViewHeaderBuilder<HeaderType>? headerBuilder;
|
||||
final FooterItemsBuilder<FooterType>? footerItems;
|
||||
final PaginatedListViewFooterBuilder<FooterType>? footerBuilder;
|
||||
final EnhancedListViewRepository<BodyType, HeaderType, FooterType, QueryType>
|
||||
repository;
|
||||
final EnhancedListViewController<BodyType, HeaderType, FooterType, QueryType>
|
||||
controller;
|
||||
|
||||
const EnhancedListView({
|
||||
Key? key,
|
||||
required this.bodyItems,
|
||||
required this.bodyBuilder,
|
||||
this.headerItems,
|
||||
this.headerBuilder,
|
||||
this.footerItems,
|
||||
this.footerBuilder,
|
||||
required this.repository,
|
||||
required this.controller,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
|
@ -198,9 +194,9 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
|
|||
super.initState();
|
||||
|
||||
bloc = EnhancedListViewBloc<ItemType, HeaderType, FooterType, QueryType>(
|
||||
bodyItemsBuilder: widget.bodyItems,
|
||||
headerItemsBuilder: widget.headerItems ?? () async => [],
|
||||
footerItemsBuilder: widget.footerItems ?? () async => [],
|
||||
bodyItemsBuilder: widget.repository.fetchBody,
|
||||
headerItemsBuilder: widget.repository.fetchHeader ?? () async => [],
|
||||
footerItemsBuilder: widget.repository.fetchFooter ?? () async => [],
|
||||
);
|
||||
bloc.events.loadBodyItems();
|
||||
bloc.events.loadHeaderItems();
|
||||
|
@ -219,7 +215,8 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
|
|||
} else if (!headerSnapshot.hasData || headerSnapshot.data!.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
} else {
|
||||
return widget.headerBuilder!(() async => headerSnapshot.data!);
|
||||
return widget
|
||||
.controller.headerBuilder!(() async => headerSnapshot.data!);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
@ -233,7 +230,8 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
|
|||
} else if (!footerSnapshot.hasData || footerSnapshot.data!.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
} else {
|
||||
return widget.footerBuilder!(() async => footerSnapshot.data!);
|
||||
return widget
|
||||
.controller.footerBuilder!(() async => footerSnapshot.data!);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
@ -251,8 +249,8 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
|
|||
return ListView.builder(
|
||||
itemCount: bodySnapshot.data?.length ?? 0,
|
||||
itemBuilder: (context, index) {
|
||||
return widget.bodyBuilder(
|
||||
context, bodySnapshot.data![index], index);
|
||||
return widget.controller
|
||||
.bodyBuilder(context, bodySnapshot.data![index], index);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -262,9 +260,9 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
|
|||
|
||||
return Column(
|
||||
children: [
|
||||
if (widget.headerBuilder != null) header,
|
||||
if (widget.controller.headerBuilder != null) header,
|
||||
body,
|
||||
if (widget.footerBuilder != null) footer,
|
||||
if (widget.controller.footerBuilder != null) footer,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -340,15 +338,47 @@ class AuthorizationError implements Exception {
|
|||
AuthorizationError(this.message);
|
||||
}
|
||||
|
||||
/// [Repositories] ----------------------------------------------------
|
||||
|
||||
class EnhancedListViewRepository<BodyType, HeaderType, FooterType, QueryType> {
|
||||
final BodyRetrievalUseCase<BodyType, QueryType?> fetchBody;
|
||||
final HeaderRetrievalUseCase<HeaderType>? fetchHeader;
|
||||
final FooterRetrievalUseCase<FooterType>? fetchFooter;
|
||||
|
||||
const EnhancedListViewRepository({
|
||||
required this.fetchBody,
|
||||
this.fetchHeader,
|
||||
this.fetchFooter,
|
||||
});
|
||||
}
|
||||
|
||||
// class HeaderRepository<HeaderType, QueryType> {}
|
||||
// class BodyRepository<BodyType, QueryType> {}
|
||||
// class FooterRepository<FooterType, QueryType> {}
|
||||
|
||||
/// [Controllers] ----------------------------------------------------
|
||||
|
||||
class EnhancedListViewController<BodyType, HeaderType, FooterType, QueryType> {
|
||||
final BodyTileBuilder<BodyType> bodyBuilder;
|
||||
final HeaderTileBuilder<HeaderType>? headerBuilder;
|
||||
final FooterTileBuilder<FooterType>? footerBuilder;
|
||||
|
||||
const EnhancedListViewController({
|
||||
required this.bodyBuilder,
|
||||
this.headerBuilder,
|
||||
this.footerBuilder,
|
||||
});
|
||||
}
|
||||
|
||||
// class HeaderController<HeaderType, QueryType> {}
|
||||
// class BodyController<BodyType, QueryType> {}
|
||||
// class FooterController<FooterType, QueryType> {}
|
||||
|
||||
/// [Blocs] ----------------------------------------------------
|
||||
|
||||
Stream<bool> get loadingState => Stream<bool>.empty();
|
||||
Stream<Exception> get errorState => Stream<Exception>.empty();
|
||||
|
||||
abstract class EnhancedListViewRepository<T> {
|
||||
Future<EnhancedPaginatedList<T>> fetchPage(
|
||||
int page, int pageSize, PaginatedListViewBodyBuilder<T> builder);
|
||||
}
|
||||
|
||||
abstract class EnhancedListViewEvents<BodyType, HeaderType, FooterType,
|
||||
QueryType> {
|
||||
void loadBodyItems({bool reset = false, dynamic query = null});
|
||||
|
@ -390,9 +420,9 @@ class EnhancedListViewBloc<BodyType, HeaderType, FooterType, QueryType>
|
|||
.addTo(_compositeSubscription);
|
||||
}
|
||||
|
||||
final BodyItemsBuilder<BodyType, QueryType?> bodyItemsBuilder;
|
||||
final HeaderItemsBuilder<HeaderType> headerItemsBuilder;
|
||||
final FooterItemsBuilder<FooterType> footerItemsBuilder;
|
||||
final BodyRetrievalUseCase<BodyType, QueryType?> bodyItemsBuilder;
|
||||
final HeaderRetrievalUseCase<HeaderType> headerItemsBuilder;
|
||||
final FooterRetrievalUseCase<FooterType> footerItemsBuilder;
|
||||
|
||||
final _bodyItems = BehaviorSubject<List<BodyType>>.seeded([]);
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class EnhancedSearchView extends StatelessWidget {
|
||||
const EnhancedSearchView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = FlutterFlowTheme.of(context);
|
||||
final locale = FFLocalizations.of(context);
|
||||
TextEditingController editingController = TextEditingController();
|
||||
return TextFormField(
|
||||
controller: editingController,
|
||||
onChanged: (value) => EasyDebounce.debounce(
|
||||
'_model.keyTextFieldTextController',
|
||||
const Duration(milliseconds: 500),
|
||||
() => filterBySearchBar(Document.fromDesc(value), context),
|
||||
),
|
||||
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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue