WIP
This commit is contained in:
parent
ed66fc86a2
commit
263013930e
|
@ -5,6 +5,7 @@ import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:http/http.dart';
|
||||||
import 'package:hub/features/documents/index.dart' as doc;
|
import 'package:hub/features/documents/index.dart' as doc;
|
||||||
import 'package:hub/features/notification/index.dart';
|
import 'package:hub/features/notification/index.dart';
|
||||||
import 'package:hub/features/storage/index.dart';
|
import 'package:hub/features/storage/index.dart';
|
||||||
|
@ -79,6 +80,23 @@ class FreAccessWSGlobal extends Api {
|
||||||
static GetDocuments getDocuments = GetDocuments();
|
static GetDocuments getDocuments = GetDocuments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GetPDF extends Endpoint {
|
||||||
|
Future<Uri> call(final int id) async {
|
||||||
|
final String baseUrl = FreAccessWSGlobal.getBaseUrl();
|
||||||
|
final String devUUID =
|
||||||
|
(await StorageHelper().get(ProfileStorageKey.devUUID.key)) ?? '';
|
||||||
|
final String userUUID =
|
||||||
|
(await StorageHelper().get(ProfileStorageKey.userUUID.key)) ?? '';
|
||||||
|
final String cliUUID =
|
||||||
|
(await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? '';
|
||||||
|
const String atividade = 'visualizarDocumento';
|
||||||
|
const String callname = 'getDocumento.php';
|
||||||
|
|
||||||
|
return Uri.parse(
|
||||||
|
"$baseUrl/$callname?devUUID=$devUUID&userUUID=$userUUID&cliID=$cliUUID&atividade=$atividade&documentId=$id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class GetCategories extends Endpoint {
|
class GetCategories extends Endpoint {
|
||||||
@override
|
@override
|
||||||
Future<ApiCallResponse> call() async {
|
Future<ApiCallResponse> call() async {
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
part of 'index.dart';
|
||||||
|
|
||||||
|
abstract interface class Archive extends Entity {}
|
|
@ -0,0 +1,68 @@
|
||||||
|
part of 'index.dart';
|
||||||
|
|
||||||
|
interface class Category extends Archive {
|
||||||
|
final int id;
|
||||||
|
final Color color;
|
||||||
|
final String title;
|
||||||
|
|
||||||
|
Category({
|
||||||
|
required this.id,
|
||||||
|
required this.color,
|
||||||
|
required this.title,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Category.fromDesc(String desc) {
|
||||||
|
return Category(
|
||||||
|
id: 0,
|
||||||
|
color: Colors.transparent,
|
||||||
|
title: desc,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Color isSelected() => Colors.black;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CategoryItem extends StatelessComponent {
|
||||||
|
final Category category;
|
||||||
|
|
||||||
|
const CategoryItem({
|
||||||
|
super.key,
|
||||||
|
required this.category,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final backgroundTheme = FlutterFlowTheme.of(context).primaryBackground;
|
||||||
|
return ColoredBox(
|
||||||
|
color: backgroundTheme,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: category.color,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.folder,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 40,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
category.title,
|
||||||
|
style: TextStyle(
|
||||||
|
color: category.color,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +1,6 @@
|
||||||
part of 'index.dart';
|
part of 'index.dart';
|
||||||
|
|
||||||
abstract interface class DocumentEntity extends Entity {}
|
interface class Document extends Archive {
|
||||||
|
|
||||||
interface class Category extends DocumentEntity {
|
|
||||||
final int id;
|
|
||||||
final Color color;
|
|
||||||
final String title;
|
|
||||||
|
|
||||||
Category({
|
|
||||||
required this.id,
|
|
||||||
required this.color,
|
|
||||||
required this.title,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory Category.fromDesc(String desc) {
|
|
||||||
return Category(
|
|
||||||
id: 0,
|
|
||||||
color: Colors.transparent,
|
|
||||||
title: desc,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Color isSelected() => Colors.black;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface class Document extends DocumentEntity {
|
|
||||||
final int id;
|
final int id;
|
||||||
final String description;
|
final String description;
|
||||||
final String type;
|
final String type;
|
||||||
|
@ -57,10 +33,16 @@ interface class Document extends DocumentEntity {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class DocumentItem extends StatelessWidget {
|
// ignore: must_be_immutable
|
||||||
|
class DocumentItem extends StatelessComponent {
|
||||||
final Document document;
|
final Document document;
|
||||||
|
void Function(Document, BuildContext) onPressed;
|
||||||
|
|
||||||
const DocumentItem({super.key, required this.document});
|
DocumentItem({
|
||||||
|
super.key,
|
||||||
|
required this.document,
|
||||||
|
required this.onPressed,
|
||||||
|
});
|
||||||
|
|
||||||
Tooltip _buildTooltip(String text, Color color, BuildContext context,
|
Tooltip _buildTooltip(String text, Color color, BuildContext context,
|
||||||
BoxConstraints constraints) {
|
BoxConstraints constraints) {
|
||||||
|
@ -106,16 +88,6 @@ class DocumentItem extends StatelessWidget {
|
||||||
fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
);
|
);
|
||||||
final Map<String, dynamic> extra = <String, dynamic>{
|
|
||||||
'document': document,
|
|
||||||
kTransitionInfoKey: const TransitionInfo(
|
|
||||||
hasTransition: true,
|
|
||||||
transitionType: PageTransitionType.rightToLeft,
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
Future<Object?> onTap() =>
|
|
||||||
context.push('/documentViewerScreen', extra: extra);
|
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
|
@ -126,7 +98,7 @@ class DocumentItem extends StatelessWidget {
|
||||||
: MediaQuery.of(context).size.height * 2;
|
: MediaQuery.of(context).size.height * 2;
|
||||||
|
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: onTap,
|
onTap: () => onPressed(document, context),
|
||||||
enableFeedback: true,
|
enableFeedback: true,
|
||||||
overlayColor: WidgetStateProperty.all<Color>(primaryColor),
|
overlayColor: WidgetStateProperty.all<Color>(primaryColor),
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
@ -189,4 +161,13 @@ class DocumentItem extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DocumentItem copyWith({
|
||||||
|
Document? document,
|
||||||
|
}) {
|
||||||
|
return DocumentItem(
|
||||||
|
document: document ?? this.document,
|
||||||
|
onPressed: onPressed,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,24 +2,41 @@ part of 'index.dart';
|
||||||
|
|
||||||
class DocumentManagerScreen extends StatelessScreen {
|
class DocumentManagerScreen extends StatelessScreen {
|
||||||
final DocumentPageModel model;
|
final DocumentPageModel model;
|
||||||
|
final DocumentPageState state;
|
||||||
|
|
||||||
const DocumentManagerScreen({
|
const DocumentManagerScreen({
|
||||||
super.key,
|
super.key,
|
||||||
required this.model,
|
required this.model,
|
||||||
|
required this.state,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final SizedBox space = SizedBox(height: 30);
|
final String title = FFLocalizations.of(context).getVariableText(
|
||||||
|
enText: 'Documents',
|
||||||
|
ptText: 'Documentos',
|
||||||
|
);
|
||||||
|
final theme = FlutterFlowTheme.of(context);
|
||||||
|
action() => Navigator.pop(context);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: theme.primaryBackground,
|
||||||
|
appBar: buildAppBar(title, context, action),
|
||||||
|
body: buildBody(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildBody(BuildContext context) {
|
||||||
|
final SizedBox space = SizedBox(height: 30);
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: RemoteSearchView<Document>(
|
child: EnhancedRemoteListView<Document, Category>(
|
||||||
key: model.searchKey,
|
key: model.managerKey,
|
||||||
pagingController: model._pagingController,
|
pagingController: model._pagingController,
|
||||||
headerBuilder: model.listHeaderBuilder,
|
headerBuilder: model.listHeaderBuilder,
|
||||||
bodyBuilder: model.listBodyBuilder,
|
headerItems: model.generateCategories,
|
||||||
|
bodyBuilder: model.documentItemBuilder,
|
||||||
dataProvider: model.generateDocuments,
|
dataProvider: model.generateDocuments,
|
||||||
onFetchError: model.onFetchError,
|
onFetchError: model.onFetchError,
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
part of 'index.dart';
|
||||||
|
|
||||||
|
/// -----------------------------------------------
|
||||||
|
/// [DocumentPageBloc]
|
||||||
|
/// -----------------------------------------------
|
||||||
|
|
||||||
|
class DocumentPageBloc extends Bloc<DocumentPageEvent, DocumentPageState> {
|
||||||
|
final DocumentPageModel model;
|
||||||
|
|
||||||
|
DocumentPageBloc._(this.model, DocumentPageState initialState)
|
||||||
|
: super(initialState) {
|
||||||
|
on<SelectDocumentEvent>(_selectDocument);
|
||||||
|
on<UnselectDocumentEvent>(_unselectDocument);
|
||||||
|
on<SelectCategoryEvent>(_selectCategory);
|
||||||
|
on<UnselectCategoryEvent>(_unselectCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DocumentPageBloc create(DocumentPageModel model) {
|
||||||
|
final initialState = DocumentPageState(
|
||||||
|
categories: [],
|
||||||
|
documents: [],
|
||||||
|
);
|
||||||
|
return DocumentPageBloc._(model, initialState);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _selectCategory(
|
||||||
|
SelectCategoryEvent event, Emitter<DocumentPageState> emit) async {
|
||||||
|
print('select: ${event.query}');
|
||||||
|
final docs = await model.generateDocuments(state.page, event.query);
|
||||||
|
final bool isSelected = !state.isCategorySelected;
|
||||||
|
|
||||||
|
emit(state.copyWith(
|
||||||
|
isCategorySelected: isSelected,
|
||||||
|
documents: isSelected ? docs.$2 : state.documents,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _unselectCategory(
|
||||||
|
UnselectCategoryEvent event, Emitter<DocumentPageState> emit) async {
|
||||||
|
emit(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _selectDocument(
|
||||||
|
SelectDocumentEvent event, Emitter<DocumentPageState> emit) async {
|
||||||
|
print('-> select');
|
||||||
|
emit(state.copyWith(
|
||||||
|
uri: await GetPDF().call(event.document.id),
|
||||||
|
currentDocument: event.document,
|
||||||
|
isDocumentSelected: true,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _unselectDocument(
|
||||||
|
UnselectDocumentEvent event, Emitter<DocumentPageState> emit) async {
|
||||||
|
final docs = await model.generateDocuments(state.page, state.query);
|
||||||
|
final cats = await model.generateCategories();
|
||||||
|
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
currentDocument: null,
|
||||||
|
isDocumentSelected: false,
|
||||||
|
documents: docs.$2,
|
||||||
|
categories: cats,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// -----------------------------------------------
|
||||||
|
/// [DocumentPageEvent]
|
||||||
|
/// -----------------------------------------------
|
||||||
|
|
||||||
|
abstract class DocumentPageEvent {}
|
||||||
|
|
||||||
|
class SelectDocumentEvent extends DocumentPageEvent {
|
||||||
|
final Document document;
|
||||||
|
SelectDocumentEvent(
|
||||||
|
this.document,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnselectDocumentEvent extends DocumentPageEvent {}
|
||||||
|
|
||||||
|
class UnselectCategoryEvent extends DocumentPageEvent {}
|
||||||
|
|
||||||
|
class SelectCategoryEvent extends DocumentPageEvent {
|
||||||
|
final Query query;
|
||||||
|
SelectCategoryEvent(this.query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// -----------------------------------------------
|
||||||
|
/// [DocumentPageState]
|
||||||
|
/// -----------------------------------------------
|
||||||
|
|
||||||
|
class DocumentPageState {
|
||||||
|
final bool isCategorySelected;
|
||||||
|
final bool isDocumentSelected;
|
||||||
|
final Document? currentDocument;
|
||||||
|
final Category? currentCategory;
|
||||||
|
final Uri? uri;
|
||||||
|
final int? count;
|
||||||
|
final dynamic page;
|
||||||
|
final Query? query;
|
||||||
|
final List<Document?> documents;
|
||||||
|
final List<Category?> categories;
|
||||||
|
|
||||||
|
const DocumentPageState({
|
||||||
|
this.query,
|
||||||
|
this.count,
|
||||||
|
this.page,
|
||||||
|
this.uri,
|
||||||
|
required this.documents,
|
||||||
|
this.currentDocument,
|
||||||
|
this.isCategorySelected = false,
|
||||||
|
required this.categories,
|
||||||
|
this.currentCategory,
|
||||||
|
this.isDocumentSelected = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
DocumentPageState copyWith({
|
||||||
|
Uri? uri,
|
||||||
|
Query? query,
|
||||||
|
int? count,
|
||||||
|
dynamic page,
|
||||||
|
List<Document?>? documents,
|
||||||
|
Document? currentDocument,
|
||||||
|
bool? isDocumentSelected,
|
||||||
|
List<Category?>? categories,
|
||||||
|
Category? currentCategory,
|
||||||
|
bool? isCategorySelected,
|
||||||
|
}) {
|
||||||
|
return DocumentPageState(
|
||||||
|
uri: uri ?? this.uri,
|
||||||
|
query: query ?? this.query,
|
||||||
|
count: count ?? this.count,
|
||||||
|
page: page ?? this.page,
|
||||||
|
//
|
||||||
|
documents: documents ?? this.documents,
|
||||||
|
currentDocument: currentDocument ?? this.currentDocument,
|
||||||
|
isDocumentSelected: isDocumentSelected ?? this.isDocumentSelected,
|
||||||
|
//
|
||||||
|
categories: categories ?? this.categories,
|
||||||
|
currentCategory: currentCategory ?? this.currentCategory,
|
||||||
|
isCategorySelected: isCategorySelected ?? this.isCategorySelected,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,59 +1,80 @@
|
||||||
part of 'index.dart';
|
part of 'index.dart';
|
||||||
|
|
||||||
class DocumentPageModel extends FlutterFlowModel<DocumentPage> {
|
class DocumentPageModel extends FlutterFlowModel<DocumentPage> {
|
||||||
@override
|
DocumentPageModel();
|
||||||
void dispose() {}
|
|
||||||
|
late final GlobalKey<State<FutureBuilder>> pageKey;
|
||||||
|
late final SearchKey managerKey;
|
||||||
|
late final DocumentKey viewerKey;
|
||||||
|
late final PagingController<int, Document> _pagingController;
|
||||||
|
|
||||||
|
/// ------------
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState(BuildContext context) {}
|
void initState(BuildContext context) {
|
||||||
|
pageKey = GlobalKey<State<FutureBuilder>>();
|
||||||
|
managerKey = SearchKey();
|
||||||
|
viewerKey = DocumentKey();
|
||||||
|
|
||||||
final SearchKey searchKey = SearchKey();
|
_pagingController = PagingController<int, Document>(firstPageKey: 1);
|
||||||
final DocumentKey docKey = DocumentKey();
|
}
|
||||||
|
|
||||||
final PagingController<int, Document> _pagingController =
|
@override
|
||||||
PagingController<int, Document>(firstPageKey: 1);
|
void dispose() {
|
||||||
int count = 0;
|
_pagingController.dispose();
|
||||||
final dynamic page = 1;
|
// isCategorySelected = false;
|
||||||
|
// isDocumentSelected = false;
|
||||||
|
}
|
||||||
|
|
||||||
Query query = Document.fromDesc('');
|
/// ------------
|
||||||
|
|
||||||
late Document currentDocument;
|
/// [onView]
|
||||||
bool isCategorySelected = false;
|
void onView(Document document, BuildContext context) async {
|
||||||
late Category currentCategory;
|
context.read<DocumentPageBloc>().add(SelectDocumentEvent(document));
|
||||||
|
}
|
||||||
|
|
||||||
List<Document?> documents = [];
|
/// [documentItemBuilder]
|
||||||
List<Category?> categories = [];
|
DocumentItem documentItemBuilder<T extends Document>(
|
||||||
|
BuildContext context, T item, int index) {
|
||||||
|
return DocumentItem(
|
||||||
|
document: item,
|
||||||
|
onPressed: onView,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// [listBodyBuilder]
|
CategoryItem categoryItemBuilder<T>(T? item) {
|
||||||
Widget listBodyBuilder<T>(BuildContext context, Document item, int index) {
|
return CategoryItem(category: item! as Category);
|
||||||
return DocumentItem(document: item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [listHeaderBuilder]
|
/// [listHeaderBuilder]
|
||||||
Widget listHeaderBuilder(BuildContext context) => Column(
|
Widget listHeaderBuilder<T>(Future<List<T?>> Function() gen) =>
|
||||||
mainAxisSize: MainAxisSize.max,
|
Builder(builder: (context) {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Padding(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
padding: const EdgeInsets.fromLTRB(15, 0, 50, 0),
|
children: [
|
||||||
child: Text(
|
Padding(
|
||||||
'Últimos Documentos',
|
padding: const EdgeInsets.fromLTRB(15, 0, 50, 0),
|
||||||
style: TextStyle(
|
child: Text(
|
||||||
color: FlutterFlowTheme.of(context).primaryText,
|
'Últimos Documentos',
|
||||||
fontSize: LimitedFontSizeUtil.getHeaderFontSize(context),
|
style: TextStyle(
|
||||||
|
color: FlutterFlowTheme.of(context).primaryText,
|
||||||
|
fontSize: LimitedFontSizeUtil.getHeaderFontSize(context),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
EnhancedCarouselView<T>(
|
||||||
CategoryCarousel<Category>(
|
generateItems: gen,
|
||||||
categories: categories,
|
itemBuilder: categoryItemBuilder,
|
||||||
filter: filterByCategory,
|
filter: filter<T>,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
/// [generateDocuments]
|
/// [generateDocuments]
|
||||||
Future<(bool, List<Document?>)> generateDocuments(
|
Future<(bool, List<Document?>?)> generateDocuments(
|
||||||
pageKey, Query query) async {
|
pageKey, Query query) async {
|
||||||
final List<Document?> error = [null];
|
final List<Document?> error = [null];
|
||||||
print('Query: ${query is Document}');
|
print('Query: ${query is Document}');
|
||||||
|
@ -103,9 +124,8 @@ class DocumentPageModel extends FlutterFlowModel<DocumentPage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [generateCategories]
|
/// [generateCategories]
|
||||||
Future<List<Category?>> generateCategories(List<Document?> documents) async {
|
Future<List<Category?>> generateCategories() async {
|
||||||
final List<Category?> error = [null];
|
final List<Category?> error = [null];
|
||||||
if (documents == []) return error;
|
|
||||||
|
|
||||||
final GetCategories getCategories = FreAccessWSGlobal.getCategories;
|
final GetCategories getCategories = FreAccessWSGlobal.getCategories;
|
||||||
final ApiCallResponse newItems = await getCategories.call();
|
final ApiCallResponse newItems = await getCategories.call();
|
||||||
|
@ -130,26 +150,32 @@ class DocumentPageModel extends FlutterFlowModel<DocumentPage> {
|
||||||
return cats;
|
return cats;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filterByCategory(Category query) {
|
/// [filter]
|
||||||
final state = searchKey.currentState;
|
void filter<T>(T query, BuildContext context) {
|
||||||
|
context
|
||||||
if (state != null) {
|
.read<DocumentPageBloc>()
|
||||||
log('filterByCategories: ');
|
.add(SelectCategoryEvent(query as Archive?));
|
||||||
|
|
||||||
state.safeSetState(() {
|
|
||||||
if (isCategorySelected) {
|
|
||||||
state.filter(null);
|
|
||||||
isCategorySelected = false;
|
|
||||||
} else {
|
|
||||||
state.filter(query);
|
|
||||||
isCategorySelected = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// {
|
||||||
|
// log('filterByCategories: ');
|
||||||
|
// final state = managerKey.currentState;
|
||||||
|
|
||||||
|
// if (state != null) {
|
||||||
|
// // safeSetState(() {
|
||||||
|
// // if (isCategorySelected) {
|
||||||
|
// // filter(null);
|
||||||
|
// // isCategorySelected = false;
|
||||||
|
// // } else {
|
||||||
|
// // filter(query);
|
||||||
|
// // isCategorySelected = true;
|
||||||
|
// // }
|
||||||
|
// // });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// [onFetchError]
|
||||||
void onFetchError(Object e, StackTrace s) {
|
void onFetchError(Object e, StackTrace s) {
|
||||||
DialogUtil.errorDefault(docKey.currentContext!);
|
DialogUtil.errorDefault(viewerKey.currentContext!);
|
||||||
LogUtil.requestAPIFailed(
|
LogUtil.requestAPIFailed(
|
||||||
"proccessRequest.php", "", "Consulta de Veículo", e, s);
|
"proccessRequest.php", "", "Consulta de Veículo", e, s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,44 +11,34 @@ class DocumentPage extends StatefulPage {
|
||||||
|
|
||||||
class FREDocumentPageState<T extends DocumentPage>
|
class FREDocumentPageState<T extends DocumentPage>
|
||||||
extends PageState<DocumentPage> {
|
extends PageState<DocumentPage> {
|
||||||
DocumentPageModel model = DocumentPageModel();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) => buildBody(context);
|
||||||
final String title = FFLocalizations.of(context).getVariableText(
|
DocumentPageModel model = DocumentPageModel();
|
||||||
enText: 'Documents',
|
|
||||||
ptText: 'Documentos',
|
|
||||||
);
|
|
||||||
final theme = FlutterFlowTheme.of(context);
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: theme.primaryBackground,
|
|
||||||
appBar: buildAppBar(title, context),
|
|
||||||
body: buildBody(context),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
model.initState(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildBody(BuildContext context) {
|
Widget buildBody(BuildContext context) {
|
||||||
return FutureBuilder<void>(
|
return BlocProvider<DocumentPageBloc>(
|
||||||
future: initAsync(),
|
create: (context) => DocumentPageBloc.create(model),
|
||||||
builder: (context, snapshot) {
|
child: BlocBuilder<DocumentPageBloc, DocumentPageState>(
|
||||||
return DocumentManagerScreen(model: model);
|
builder: (context, state) {
|
||||||
},
|
print('Bloc -> ${state.isCategorySelected}');
|
||||||
);
|
|
||||||
// return DocumentViewScreen(document: documents.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> initAsync() async {
|
if (state.isDocumentSelected)
|
||||||
final documents = await model.generateDocuments(model.page, model.query);
|
return DocumentViewScreen(
|
||||||
final categories = await model.generateCategories(model.documents);
|
doc: state.currentDocument!,
|
||||||
model.documents = documents.$2;
|
uri: state.uri!,
|
||||||
model.categories = categories;
|
);
|
||||||
log('-> generateDocuments: $documents');
|
else
|
||||||
log('-> generateCategories: $categories');
|
return DocumentManagerScreen(
|
||||||
|
model: model,
|
||||||
|
state: state,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,43 +3,52 @@ part of 'index.dart';
|
||||||
class DocumentViewScreen extends StatefulScreen {
|
class DocumentViewScreen extends StatefulScreen {
|
||||||
const DocumentViewScreen({
|
const DocumentViewScreen({
|
||||||
super.key,
|
super.key,
|
||||||
required this.document,
|
required this.doc,
|
||||||
|
required this.uri,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Document document;
|
final Document doc;
|
||||||
|
final Uri uri;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DocumentViewScreen> createState() => _DocumentViewScreenState();
|
ScreenState<DocumentViewScreen> createState() => _DocumentViewScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DocumentViewScreenState extends State<DocumentViewScreen> {
|
class _DocumentViewScreenState extends ScreenState<DocumentViewScreen> {
|
||||||
final PDFViewerKey _viewerKey = PDFViewerKey();
|
final PDFViewerKey _viewerKey = PDFViewerKey();
|
||||||
|
|
||||||
|
void onShare() async {
|
||||||
|
final response = await http.get(widget.uri);
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final XFile xfile = XFile.fromData(response.bodyBytes,
|
||||||
|
name: '${widget.doc.description}.pdf', mimeType: 'application/pdf');
|
||||||
|
await Share.shareXFiles([xfile], text: 'Confira este PDF!');
|
||||||
|
} else {
|
||||||
|
print('Erro ao baixar o arquivo: ${response.statusCode}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final Uri url = Uri.parse(
|
action() => context.read<DocumentPageBloc>().add(UnselectDocumentEvent());
|
||||||
'https://cdn.syncfusion.com/content/PDFViewer/flutter-succinctly.pdf');
|
|
||||||
|
|
||||||
void onPressed() async {
|
final String title = widget.doc.description;
|
||||||
final response = await http.get(url);
|
final theme = FlutterFlowTheme.of(context);
|
||||||
if (response.statusCode == 200) {
|
return Scaffold(
|
||||||
final XFile xfile = XFile.fromData(response.bodyBytes,
|
backgroundColor: theme.primaryBackground,
|
||||||
name:
|
appBar: buildAppBar(title, context, action),
|
||||||
'${widget.document.description}_${widget.document.category.title}.pdf',
|
body: buildBody(context),
|
||||||
mimeType: 'application/pdf');
|
);
|
||||||
await Share.shareXFiles([xfile], text: 'Confira este PDF!');
|
}
|
||||||
} else {
|
|
||||||
print('Erro ao baixar o arquivo: ${response.statusCode}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Widget buildBody(BuildContext context) {
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(10),
|
padding: EdgeInsets.all(10),
|
||||||
child: FREViewerPDF(
|
child: FREViewerPDF(
|
||||||
search: _viewerKey,
|
search: _viewerKey,
|
||||||
src: url.toString(),
|
src: widget.uri.toString(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
|
@ -51,7 +60,7 @@ class _DocumentViewScreenState extends State<DocumentViewScreen> {
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
onPressed: onPressed,
|
onPressed: onShare,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:developer';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:hub/features/backend/index.dart';
|
import 'package:hub/features/backend/index.dart';
|
||||||
|
@ -19,3 +20,6 @@ part 'document_page_widget.dart';
|
||||||
part 'document_viewer_screen.dart';
|
part 'document_viewer_screen.dart';
|
||||||
part 'document_page_model.dart';
|
part 'document_page_model.dart';
|
||||||
part 'document_item_component.dart';
|
part 'document_item_component.dart';
|
||||||
|
part 'document_page_bloc.dart';
|
||||||
|
part 'category_item_component.dart';
|
||||||
|
part 'archive_item_component.dart';
|
||||||
|
|
|
@ -310,11 +310,12 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) {
|
||||||
name: 'documentViewerScreen',
|
name: 'documentViewerScreen',
|
||||||
path: '/documentViewerScreen',
|
path: '/documentViewerScreen',
|
||||||
builder: (context, params) {
|
builder: (context, params) {
|
||||||
final Document document =
|
final Document doc = params.getParam('doc', ParamType.Function);
|
||||||
params.getParam('document', ParamType.Function);
|
final Uri uri = params.getParam('uri', ParamType.Function);
|
||||||
return DocumentViewScreen(
|
return DocumentViewScreen(
|
||||||
key: UniqueKey(),
|
key: UniqueKey(),
|
||||||
document: document,
|
doc: doc,
|
||||||
|
uri: uri,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -6,25 +6,30 @@ import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
extension PagedListViewExtension<PageKeyType, ItemType>
|
extension PagedListViewExtension<PageKeyType, ItemType>
|
||||||
on PagedSliverList<PageKeyType, ItemType> {}
|
on PagedSliverList<PageKeyType, ItemType> {}
|
||||||
|
|
||||||
|
typedef PaginatedListViewHeaderBuilder<T> = Widget Function<T>(
|
||||||
|
Future<List<T?>> Function() gen);
|
||||||
|
typedef PaginatedListViewBodyBuilder<T> = Widget Function(BuildContext, T, int);
|
||||||
|
|
||||||
mixin Pageable<T extends StatefulWidget> on State<T> {
|
mixin Pageable<T extends StatefulWidget> on State<T> {
|
||||||
Expanded buildPaginatedListView<PageKeyType, ItemType>(
|
Expanded buildPaginatedListView<PageKeyType, BodyType, HeaderType>(
|
||||||
String noDataFound,
|
String noDataFound,
|
||||||
PagingController<PageKeyType, ItemType> pg,
|
PagingController<PageKeyType, BodyType> pg,
|
||||||
Widget Function(BuildContext) headerBuilder,
|
Future<List<HeaderType?>> Function() headerItems,
|
||||||
Widget Function(BuildContext, ItemType, int) bodyBuilder) {
|
PaginatedListViewHeaderBuilder<BodyType> headerBuilder,
|
||||||
|
PaginatedListViewBodyBuilder<BodyType> bodyBuilder) {
|
||||||
final theme = FlutterFlowTheme.of(context);
|
final theme = FlutterFlowTheme.of(context);
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: RefreshIndicator(
|
child: RefreshIndicator(
|
||||||
backgroundColor: theme.primaryBackground,
|
backgroundColor: theme.primaryBackground,
|
||||||
color: theme.primary,
|
color: theme.primary,
|
||||||
onRefresh: () async => pg.refresh(),
|
onRefresh: () async => pg.refresh(),
|
||||||
child: PagedListView<PageKeyType, ItemType>(
|
child: PagedListView<PageKeyType, BodyType>(
|
||||||
pagingController: pg,
|
pagingController: pg,
|
||||||
builderDelegate: PagedChildBuilderDelegate<ItemType>(
|
builderDelegate: PagedChildBuilderDelegate<BodyType>(
|
||||||
animateTransitions: true,
|
animateTransitions: true,
|
||||||
itemBuilder: (context, item, int index) {
|
itemBuilder: (context, item, int index) {
|
||||||
return Column(children: [
|
return Column(children: [
|
||||||
if (index == 0) headerBuilder(context),
|
if (index == 0) headerBuilder(headerItems),
|
||||||
bodyBuilder(context, item, index),
|
bodyBuilder(context, item, index),
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
@ -33,7 +38,8 @@ mixin Pageable<T extends StatefulWidget> on State<T> {
|
||||||
firstPageProgressIndicatorBuilder: (context) =>
|
firstPageProgressIndicatorBuilder: (context) =>
|
||||||
buildLoadingIndicator(context),
|
buildLoadingIndicator(context),
|
||||||
noItemsFoundIndicatorBuilder: (context) =>
|
noItemsFoundIndicatorBuilder: (context) =>
|
||||||
buildNoDataFound(context, noDataFound, headerBuilder),
|
buildNoDataFound<HeaderType>(
|
||||||
|
context, noDataFound, headerItems, headerBuilder),
|
||||||
firstPageErrorIndicatorBuilder: (context) => const Placeholder(),
|
firstPageErrorIndicatorBuilder: (context) => const Placeholder(),
|
||||||
newPageErrorIndicatorBuilder: (context) => const Placeholder(),
|
newPageErrorIndicatorBuilder: (context) => const Placeholder(),
|
||||||
),
|
),
|
||||||
|
@ -92,16 +98,17 @@ mixin Pageable<T extends StatefulWidget> on State<T> {
|
||||||
showSnackbar(context, message, true);
|
showSnackbar(context, message, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildNoDataFound(
|
Widget buildNoDataFound<T>(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
String title,
|
String title,
|
||||||
Widget Function(BuildContext) headerBuilder,
|
Future<List<T?>> Function() items,
|
||||||
|
Widget Function<T>(Future<List<T?>> Function() items) headerBuilder,
|
||||||
) {
|
) {
|
||||||
final headerFontSize = LimitedFontSizeUtil.getHeaderFontSize(context);
|
final headerFontSize = LimitedFontSizeUtil.getHeaderFontSize(context);
|
||||||
// final bodyFontSize = LimitedFontSizeUtil.getBodyFontSize(context);
|
// final bodyFontSize = LimitedFontSizeUtil.getBodyFontSize(context);
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
headerBuilder(context),
|
headerBuilder(items),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
|
@ -20,3 +20,5 @@ abstract class StatefulComponent<T> extends StatefulWidget
|
||||||
implements ComponentWidget<T> {
|
implements ComponentWidget<T> {
|
||||||
const StatefulComponent({super.key});
|
const StatefulComponent({super.key});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class ComponentState<T extends StatefulComponent> extends State<T> {}
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
part of 'widgets.dart';
|
part of 'widgets.dart';
|
||||||
|
|
||||||
mixin MixinPage {
|
mixin Template {
|
||||||
PreferredSizeWidget buildAppBar(String title, BuildContext context) {
|
PreferredSizeWidget buildAppBar(
|
||||||
|
String title,
|
||||||
|
BuildContext context,
|
||||||
|
dynamic Function()? backAction,
|
||||||
|
) {
|
||||||
|
final theme = FlutterFlowTheme.of(context);
|
||||||
return AppBar(
|
return AppBar(
|
||||||
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
|
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
|
@ -17,14 +22,15 @@ mixin MixinPage {
|
||||||
FlutterFlowTheme.of(context).headlineMediumFamily),
|
FlutterFlowTheme.of(context).headlineMediumFamily),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
leading: _backButton(context, FlutterFlowTheme.of(context)),
|
leading: _backButton(context, theme, backAction),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
elevation: 0.0,
|
elevation: 0.0,
|
||||||
actions: [],
|
actions: [],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _backButton(BuildContext context, FlutterFlowTheme theme) {
|
Widget _backButton(BuildContext context, FlutterFlowTheme theme,
|
||||||
|
dynamic Function()? onPressed) {
|
||||||
return FlutterFlowIconButton(
|
return FlutterFlowIconButton(
|
||||||
key: ValueKey<String>('BackNavigationAppBar'),
|
key: ValueKey<String>('BackNavigationAppBar'),
|
||||||
borderColor: Colors.transparent,
|
borderColor: Colors.transparent,
|
||||||
|
@ -36,7 +42,7 @@ mixin MixinPage {
|
||||||
color: theme.primaryText,
|
color: theme.primaryText,
|
||||||
size: 30.0,
|
size: 30.0,
|
||||||
),
|
),
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: onPressed,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +58,7 @@ abstract class ModelPage<T> extends ModelWidget implements PageWidget<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class StatelessPage<T> extends StatelessWidget
|
abstract class StatelessPage<T> extends StatelessWidget
|
||||||
|
with Template
|
||||||
implements PageWidget<T> {
|
implements PageWidget<T> {
|
||||||
const StatelessPage({super.key});
|
const StatelessPage({super.key});
|
||||||
}
|
}
|
||||||
|
@ -61,4 +68,4 @@ abstract class StatefulPage<T> extends StatefulWidget implements PageWidget<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class PageState<T extends StatefulPage> extends State<T>
|
abstract class PageState<T extends StatefulPage> extends State<T>
|
||||||
with MixinPage {}
|
with Template {}
|
||||||
|
|
|
@ -9,6 +9,7 @@ abstract class ModelScreen<T> extends ModelWidget implements ScreenWidget<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class StatelessScreen<T> extends StatelessWidget
|
abstract class StatelessScreen<T> extends StatelessWidget
|
||||||
|
with Template
|
||||||
implements ScreenWidget<T> {
|
implements ScreenWidget<T> {
|
||||||
const StatelessScreen({super.key});
|
const StatelessScreen({super.key});
|
||||||
}
|
}
|
||||||
|
@ -17,3 +18,6 @@ abstract class StatefulScreen<T> extends StatefulWidget
|
||||||
implements ScreenWidget<T> {
|
implements ScreenWidget<T> {
|
||||||
const StatefulScreen({super.key});
|
const StatefulScreen({super.key});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class ScreenState<T extends StatefulScreen> extends State<T>
|
||||||
|
with Template {}
|
||||||
|
|
|
@ -1,59 +1,32 @@
|
||||||
part of '../widgets.dart';
|
part of '../widgets.dart';
|
||||||
|
|
||||||
class CategoryCarousel<T> extends StatelessWidget {
|
class EnhancedCarouselView<T> extends StatelessWidget {
|
||||||
final List<T?> categories;
|
final Future<List<T?>> Function() generateItems;
|
||||||
final void Function(T) filter;
|
final void Function(T, BuildContext) filter;
|
||||||
|
final Widget Function<T>(T? item) itemBuilder;
|
||||||
|
|
||||||
const CategoryCarousel({
|
const EnhancedCarouselView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.categories,
|
required this.generateItems,
|
||||||
required this.filter,
|
required this.filter,
|
||||||
|
required this.itemBuilder,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final backgroundTheme = FlutterFlowTheme.of(context).primaryBackground;
|
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 120,
|
height: 120,
|
||||||
child: CarouselView(
|
child: FutureBuilder<List<T?>>(
|
||||||
itemExtent: 100,
|
future: generateItems(),
|
||||||
onTap: (index) => filter(categories[index] as T),
|
builder: (context, snapshot) {
|
||||||
children: categories.map((category) {
|
if (!snapshot.hasData) return SizedBox();
|
||||||
category as Category?;
|
return CarouselView(
|
||||||
return ColoredBox(
|
itemExtent: 100,
|
||||||
color: backgroundTheme,
|
onTap: (index) => filter(snapshot.data![index] as T, context),
|
||||||
child: Padding(
|
children:
|
||||||
padding: const EdgeInsets.all(8.0),
|
snapshot.data!.map((item) => itemBuilder(item)).toList(),
|
||||||
child: Column(
|
);
|
||||||
children: [
|
}),
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: category!.color,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
Icons.folder,
|
|
||||||
color: Colors.white,
|
|
||||||
size: 40,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
category.title,
|
|
||||||
style: TextStyle(
|
|
||||||
color: category.color,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +1,32 @@
|
||||||
part of '../widgets.dart';
|
part of '../widgets.dart';
|
||||||
|
|
||||||
typedef SearchKey = GlobalKey<RemoteSearchViewState>;
|
typedef SearchKey = GlobalKey<EnhancedRemoteListViewState>;
|
||||||
|
|
||||||
typedef Query<X extends DocumentEntity> = X?;
|
typedef Query<X extends Archive> = X?;
|
||||||
|
|
||||||
/// -----------------------------------------------
|
/// -----------------------------------------------
|
||||||
/// [SearchView]
|
/// [EnhancedListView]
|
||||||
/// -----------------------------------------------
|
/// -----------------------------------------------
|
||||||
|
|
||||||
class SearchView<T> extends StatefulComponent {
|
abstract interface class EnhancedListView<T> extends StatefulWidget {
|
||||||
const SearchView({super.key});
|
const EnhancedListView({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
State<SearchView> createState() => _SearchViewState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SearchViewState<T> extends State<SearchView> {
|
abstract interface class EnhancedListViewState<T>
|
||||||
@override
|
extends State<EnhancedListView> {}
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const Placeholder();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// -----------------------------------------------
|
/// -----------------------------------------------
|
||||||
/// [LocalSearchView]
|
/// [EnhancedLocalListView]
|
||||||
/// -----------------------------------------------
|
/// -----------------------------------------------
|
||||||
|
|
||||||
class LocalSearchView<T> extends SearchView<T> {
|
class EnhancedLocalListView<T> extends EnhancedListView<T> {
|
||||||
final List<T> list;
|
final List<T> list;
|
||||||
final Widget Function(T) itemBuilder;
|
final Widget Function(T) itemBuilder;
|
||||||
final bool Function(T, String) filter;
|
final bool Function(T, String) filter;
|
||||||
final Widget header;
|
final Widget header;
|
||||||
final List<T> Function(String)? onSearch;
|
final List<T> Function(String)? onSearch;
|
||||||
|
|
||||||
LocalSearchView({
|
EnhancedLocalListView({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.list,
|
required this.list,
|
||||||
required this.itemBuilder,
|
required this.itemBuilder,
|
||||||
|
@ -49,10 +42,11 @@ class LocalSearchView<T> extends SearchView<T> {
|
||||||
// return documents.where((documents) => filter(documents, query)).toList();
|
// return documents.where((documents) => filter(documents, query)).toList();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
LocalSearchViewState<T> createState() => LocalSearchViewState<T>();
|
EnhancedLocalListViewState<T> createState() =>
|
||||||
|
EnhancedLocalListViewState<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
class LocalSearchViewState<T> extends State<LocalSearchView<T>> {
|
class EnhancedLocalListViewState<T> extends State<EnhancedLocalListView<T>> {
|
||||||
TextEditingController editingController = TextEditingController();
|
TextEditingController editingController = TextEditingController();
|
||||||
late List<T> filteredItems;
|
late List<T> filteredItems;
|
||||||
|
|
||||||
|
@ -141,22 +135,25 @@ class LocalSearchViewState<T> extends State<LocalSearchView<T>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// -----------------------------------------------
|
/// -----------------------------------------------
|
||||||
/// [RemoteSearchView]
|
/// [EnhancedRemoteListView]
|
||||||
/// -----------------------------------------------
|
/// -----------------------------------------------
|
||||||
|
|
||||||
class RemoteSearchView<T> extends SearchView<T> {
|
// ignore: must_be_immutable
|
||||||
|
class EnhancedRemoteListView<T, Y> extends EnhancedListView<T> {
|
||||||
final Widget Function(BuildContext, T, int) bodyBuilder;
|
final Widget Function(BuildContext, T, int) bodyBuilder;
|
||||||
Widget Function(BuildContext) headerBuilder;
|
final Future<List<Y?>> Function() headerItems;
|
||||||
|
Widget Function<T>(Future<List<T?>> Function() gen) headerBuilder;
|
||||||
final PagingController<int, T> pagingController;
|
final PagingController<int, T> pagingController;
|
||||||
final Future<(bool, List<T?>)> Function(int pageKey, Query query)
|
final Future<(bool, List<T?>?)> Function(int pageKey, Query query)
|
||||||
dataProvider;
|
dataProvider;
|
||||||
|
|
||||||
final void Function(Object, StackTrace) onFetchError;
|
final void Function(Object, StackTrace) onFetchError;
|
||||||
|
|
||||||
RemoteSearchView({
|
EnhancedRemoteListView({
|
||||||
Key? key,
|
Key? key,
|
||||||
// required this.fetchItems,
|
// required this.fetchItems,
|
||||||
required this.bodyBuilder,
|
required this.bodyBuilder,
|
||||||
|
required this.headerItems,
|
||||||
required this.headerBuilder,
|
required this.headerBuilder,
|
||||||
required this.pagingController,
|
required this.pagingController,
|
||||||
required this.dataProvider,
|
required this.dataProvider,
|
||||||
|
@ -164,11 +161,12 @@ class RemoteSearchView<T> extends SearchView<T> {
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
RemoteSearchViewState<T> createState() => RemoteSearchViewState<T>();
|
EnhancedRemoteListViewState<T, Y> createState() =>
|
||||||
|
EnhancedRemoteListViewState<T, Y>();
|
||||||
}
|
}
|
||||||
|
|
||||||
class RemoteSearchViewState<T> extends State<RemoteSearchView<T>>
|
class EnhancedRemoteListViewState<T, Y>
|
||||||
with Pageable {
|
extends State<EnhancedRemoteListView<T, Y>> with Pageable {
|
||||||
TextEditingController editingController = TextEditingController();
|
TextEditingController editingController = TextEditingController();
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
Query query = Document.fromDesc('');
|
Query query = Document.fromDesc('');
|
||||||
|
@ -246,9 +244,10 @@ class RemoteSearchViewState<T> extends State<RemoteSearchView<T>>
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
buildPaginatedListView<int, T>(
|
buildPaginatedListView<int, T, Y>(
|
||||||
noDataFound,
|
noDataFound,
|
||||||
widget.pagingController,
|
widget.pagingController,
|
||||||
|
widget.headerItems,
|
||||||
widget.headerBuilder,
|
widget.headerBuilder,
|
||||||
widget.bodyBuilder,
|
widget.bodyBuilder,
|
||||||
),
|
),
|
|
@ -17,7 +17,7 @@ part 'model.dart';
|
||||||
part 'entity.dart';
|
part 'entity.dart';
|
||||||
|
|
||||||
/// [View]'s
|
/// [View]'s
|
||||||
part 'view/search_view.dart';
|
part 'view/list_view.dart';
|
||||||
part 'view/carousel_view.dart';
|
part 'view/carousel_view.dart';
|
||||||
|
|
||||||
/// [Viewer]
|
/// [Viewer]
|
||||||
|
|
Loading…
Reference in New Issue