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) {
|
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(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: EnhancedListView<Document, Search, Category, Query>(
|
child: EnhancedListView<Document, SearchField, Category, Query>(
|
||||||
key: model.vehicleScreenManager,
|
key: model.vehicleScreenManager,
|
||||||
headerBuilder: model.itemHeaderBuilder<Search>,
|
controller: controller,
|
||||||
headerItems: model.generateHeaderItems<Search>,
|
repository: repository,
|
||||||
bodyBuilder: model.itemBodyBuilder<Document>,
|
|
||||||
bodyItems: model.generateBodyItems<Document, Query>,
|
|
||||||
footerBuilder: model.itemFooterBuilder<Category>,
|
|
||||||
footerItems: model.generateFooterItems<Category>,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
] //
|
] //
|
||||||
|
@ -235,7 +242,7 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
|
||||||
final DocumentPageBlocType bloc;
|
final DocumentPageBlocType bloc;
|
||||||
DocumentModel(this.bloc);
|
DocumentModel(this.bloc);
|
||||||
|
|
||||||
late EnhancedListViewKey<Document, Search, Category, Query>
|
late EnhancedListViewKey<Document, SearchField, Category, Query>
|
||||||
vehicleScreenManager;
|
vehicleScreenManager;
|
||||||
late DocumentKey vehicleScreenViewer;
|
late DocumentKey vehicleScreenViewer;
|
||||||
late PagingController<int, Document> _pagingController;
|
late PagingController<int, Document> _pagingController;
|
||||||
|
@ -247,7 +254,7 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
|
||||||
@override
|
@override
|
||||||
void initState(BuildContext context) {
|
void initState(BuildContext context) {
|
||||||
vehicleScreenManager =
|
vehicleScreenManager =
|
||||||
EnhancedListViewKey<Document, Search, Category, Query>();
|
EnhancedListViewKey<Document, SearchField, Category, Query>();
|
||||||
vehicleScreenViewer = DocumentKey();
|
vehicleScreenViewer = DocumentKey();
|
||||||
_pagingController = PagingController<int, Document>(firstPageKey: 1);
|
_pagingController = PagingController<int, Document>(firstPageKey: 1);
|
||||||
|
|
||||||
|
@ -388,7 +395,7 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
|
||||||
|
|
||||||
/// [Header]
|
/// [Header]
|
||||||
|
|
||||||
Widget itemHeaderBuilder<T extends Search>(
|
Widget itemHeaderBuilder<T extends SearchField>(
|
||||||
Future<List<T?>> Function() generateHeaderItems) {
|
Future<List<T?>> Function() generateHeaderItems) {
|
||||||
return Builder(builder: (context) {
|
return Builder(builder: (context) {
|
||||||
final theme = FlutterFlowTheme.of(context);
|
final theme = FlutterFlowTheme.of(context);
|
||||||
|
@ -462,8 +469,8 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<T?>> generateHeaderItems<T extends Search>() async {
|
Future<List<T?>> generateHeaderItems<T extends SearchField>() async {
|
||||||
final Search item = Search();
|
final SearchField item = SearchField();
|
||||||
return [item] as List<T?>;
|
return [item] as List<T?>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,8 +544,8 @@ class DocumentPageBloc extends $DocumentPageBloc {
|
||||||
|
|
||||||
abstract interface class Archive extends Entity {}
|
abstract interface class Archive extends Entity {}
|
||||||
|
|
||||||
interface class Search extends Archive {
|
interface class SearchField extends Archive {
|
||||||
Search();
|
SearchField();
|
||||||
}
|
}
|
||||||
|
|
||||||
interface class Document extends Archive {
|
interface class Document extends Archive {
|
||||||
|
|
|
@ -5,17 +5,19 @@ part of 'widgets.dart';
|
||||||
typedef EnhancedListViewKey<BodyType, HeaderType, FooterType, QueryType>
|
typedef EnhancedListViewKey<BodyType, HeaderType, FooterType, QueryType>
|
||||||
= GlobalKey<
|
= GlobalKey<
|
||||||
EnhancedListViewState<BodyType, HeaderType, FooterType, QueryType>>;
|
EnhancedListViewState<BodyType, HeaderType, FooterType, QueryType>>;
|
||||||
typedef PaginatedListViewHeaderBuilder<HeaderType> = Widget Function(
|
typedef HeaderTileBuilder<HeaderType> = Widget Function(
|
||||||
Future<List<HeaderType?>> Function() headerItems);
|
Future<List<HeaderType?>> Function() headerItems);
|
||||||
typedef PaginatedListViewBodyBuilder<BodyType> = Widget Function(
|
typedef BodyTileBuilder<BodyType> = Widget Function(
|
||||||
BuildContext context, BodyType item, int index);
|
BuildContext context, BodyType item, int index);
|
||||||
typedef PaginatedListViewFooterBuilder<FooterType> = Widget Function(
|
typedef FooterTileBuilder<FooterType> = Widget Function(
|
||||||
Future<List<FooterType?>> Function() footerItems);
|
Future<List<FooterType?>> Function() footerItems);
|
||||||
typedef Query<QueryType> = QueryType?;
|
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);
|
Function(int page, int pageSize, QueryType query);
|
||||||
typedef HeaderItemsBuilder<HeaderType> = Future<List<HeaderType?>> Function();
|
typedef HeaderRetrievalUseCase<HeaderType> = Future<List<HeaderType?>>
|
||||||
typedef FooterItemsBuilder<FooterType> = Future<List<FooterType?>> Function();
|
Function();
|
||||||
|
typedef FooterRetrievalUseCase<FooterType> = Future<List<FooterType?>>
|
||||||
|
Function();
|
||||||
|
|
||||||
/// [Extensions] ----------------------------------------------------
|
/// [Extensions] ----------------------------------------------------
|
||||||
extension PaginatedListMergeExtensions<T>
|
extension PaginatedListMergeExtensions<T>
|
||||||
|
@ -54,20 +56,20 @@ extension StreamStartWithExtension<T> on Stream<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension QueryBlocStreamExtensions<T> on Stream<bool> {
|
extension QueryBlocStreamExtensions<T> on Stream<bool> {
|
||||||
Stream<Result<EnhancedPaginatedList<T>>> fetchData(
|
// Stream<Result<EnhancedPaginatedList<T>>> fetchData(
|
||||||
EnhancedListViewRepository<T> repository,
|
// EnhancedListViewRepository<T> repository,
|
||||||
PaginatedListViewBodyBuilder<T> builder,
|
// PaginatedListViewBodyBuilder<T> builder,
|
||||||
BehaviorSubject<EnhancedPaginatedList<T>> paginatedList,
|
// BehaviorSubject<EnhancedPaginatedList<T>> paginatedList,
|
||||||
) =>
|
// ) =>
|
||||||
switchMap((reset) {
|
// switchMap((reset) {
|
||||||
if (reset) {
|
// if (reset) {
|
||||||
paginatedList.add(paginatedList.value.resetAll());
|
// paginatedList.add(paginatedList.value.resetAll());
|
||||||
}
|
// }
|
||||||
final nextPage = paginatedList.value.currentPage + 1;
|
// final nextPage = paginatedList.value.currentPage + 1;
|
||||||
return repository
|
// return repository
|
||||||
.fetchPage(nextPage, paginatedList.value.pageSize, builder)
|
// .fetchPage(nextPage, paginatedList.value.pageSize, builder)
|
||||||
.asResultStream();
|
// .asResultStream();
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [Interfaces] ----------------------------------------------------
|
/// [Interfaces] ----------------------------------------------------
|
||||||
|
@ -167,21 +169,15 @@ mixin EnhancedListViewMixin<BodyType, HeaderType, FooterType, QueryType> {
|
||||||
|
|
||||||
class EnhancedListView<BodyType, HeaderType, FooterType, QueryType>
|
class EnhancedListView<BodyType, HeaderType, FooterType, QueryType>
|
||||||
extends EnhancedListViewBase<BodyType, HeaderType, FooterType, QueryType> {
|
extends EnhancedListViewBase<BodyType, HeaderType, FooterType, QueryType> {
|
||||||
final BodyItemsBuilder<BodyType, QueryType?> bodyItems;
|
final EnhancedListViewRepository<BodyType, HeaderType, FooterType, QueryType>
|
||||||
final PaginatedListViewBodyBuilder<BodyType> bodyBuilder;
|
repository;
|
||||||
final HeaderItemsBuilder<HeaderType>? headerItems;
|
final EnhancedListViewController<BodyType, HeaderType, FooterType, QueryType>
|
||||||
final PaginatedListViewHeaderBuilder<HeaderType>? headerBuilder;
|
controller;
|
||||||
final FooterItemsBuilder<FooterType>? footerItems;
|
|
||||||
final PaginatedListViewFooterBuilder<FooterType>? footerBuilder;
|
|
||||||
|
|
||||||
const EnhancedListView({
|
const EnhancedListView({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.bodyItems,
|
required this.repository,
|
||||||
required this.bodyBuilder,
|
required this.controller,
|
||||||
this.headerItems,
|
|
||||||
this.headerBuilder,
|
|
||||||
this.footerItems,
|
|
||||||
this.footerBuilder,
|
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -198,9 +194,9 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
bloc = EnhancedListViewBloc<ItemType, HeaderType, FooterType, QueryType>(
|
bloc = EnhancedListViewBloc<ItemType, HeaderType, FooterType, QueryType>(
|
||||||
bodyItemsBuilder: widget.bodyItems,
|
bodyItemsBuilder: widget.repository.fetchBody,
|
||||||
headerItemsBuilder: widget.headerItems ?? () async => [],
|
headerItemsBuilder: widget.repository.fetchHeader ?? () async => [],
|
||||||
footerItemsBuilder: widget.footerItems ?? () async => [],
|
footerItemsBuilder: widget.repository.fetchFooter ?? () async => [],
|
||||||
);
|
);
|
||||||
bloc.events.loadBodyItems();
|
bloc.events.loadBodyItems();
|
||||||
bloc.events.loadHeaderItems();
|
bloc.events.loadHeaderItems();
|
||||||
|
@ -219,7 +215,8 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
|
||||||
} else if (!headerSnapshot.hasData || headerSnapshot.data!.isEmpty) {
|
} else if (!headerSnapshot.hasData || headerSnapshot.data!.isEmpty) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
} else {
|
} 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) {
|
} else if (!footerSnapshot.hasData || footerSnapshot.data!.isEmpty) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
} else {
|
} 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(
|
return ListView.builder(
|
||||||
itemCount: bodySnapshot.data?.length ?? 0,
|
itemCount: bodySnapshot.data?.length ?? 0,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return widget.bodyBuilder(
|
return widget.controller
|
||||||
context, bodySnapshot.data![index], index);
|
.bodyBuilder(context, bodySnapshot.data![index], index);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -262,9 +260,9 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
if (widget.headerBuilder != null) header,
|
if (widget.controller.headerBuilder != null) header,
|
||||||
body,
|
body,
|
||||||
if (widget.footerBuilder != null) footer,
|
if (widget.controller.footerBuilder != null) footer,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -340,15 +338,47 @@ class AuthorizationError implements Exception {
|
||||||
AuthorizationError(this.message);
|
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] ----------------------------------------------------
|
/// [Blocs] ----------------------------------------------------
|
||||||
|
|
||||||
Stream<bool> get loadingState => Stream<bool>.empty();
|
Stream<bool> get loadingState => Stream<bool>.empty();
|
||||||
Stream<Exception> get errorState => Stream<Exception>.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,
|
abstract class EnhancedListViewEvents<BodyType, HeaderType, FooterType,
|
||||||
QueryType> {
|
QueryType> {
|
||||||
void loadBodyItems({bool reset = false, dynamic query = null});
|
void loadBodyItems({bool reset = false, dynamic query = null});
|
||||||
|
@ -390,9 +420,9 @@ class EnhancedListViewBloc<BodyType, HeaderType, FooterType, QueryType>
|
||||||
.addTo(_compositeSubscription);
|
.addTo(_compositeSubscription);
|
||||||
}
|
}
|
||||||
|
|
||||||
final BodyItemsBuilder<BodyType, QueryType?> bodyItemsBuilder;
|
final BodyRetrievalUseCase<BodyType, QueryType?> bodyItemsBuilder;
|
||||||
final HeaderItemsBuilder<HeaderType> headerItemsBuilder;
|
final HeaderRetrievalUseCase<HeaderType> headerItemsBuilder;
|
||||||
final FooterItemsBuilder<FooterType> footerItemsBuilder;
|
final FooterRetrievalUseCase<FooterType> footerItemsBuilder;
|
||||||
|
|
||||||
final _bodyItems = BehaviorSubject<List<BodyType>>.seeded([]);
|
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