correções do pr

This commit is contained in:
jantunesmessias 2025-02-25 17:13:09 -03:00
parent aa1bd55818
commit a7f1ea418b
9 changed files with 237 additions and 121 deletions

View File

@ -1,6 +1,5 @@
import 'dart:convert';
import 'dart:core';
import 'dart:developer';
import 'dart:io';
import 'dart:typed_data';

View File

@ -164,13 +164,14 @@ class _DocumentViewerScreenState extends ScreenState<DocumentViewerScreen> {
super.initState();
}
backAction() => widget.bloc.events.unselectDocument();
@override
Widget build(BuildContext context) {
final String title = widget.doc.$1.description;
final theme = FlutterFlowTheme.of(context);
final locale = FFLocalizations.of(context);
backAction() => widget.bloc.events.unselectDocument();
infoAction() => DetailsComponentWidget(
buttons: [],
statusHashMap: [
@ -225,6 +226,7 @@ class _DocumentViewerScreenState extends ScreenState<DocumentViewerScreen> {
return ReadView(
title: widget.doc.$1.description,
url: widget.doc.$2.toString(),
onError: backAction,
);
}
}
@ -330,14 +332,16 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
Widget itemFooterBuilder<T extends Category>(
Future<List<T?>> Function() fetchData) =>
Builder(builder: (context) {
CategoryComponent categoryItemBuilder<T>(T? item) {
return CategoryComponent(category: item! as Category);
CategoryComponent categoryItemBuilder<T>(T? item, bool isSelected) {
return CategoryComponent(
category: item! as Category, isSelected: isSelected);
}
return EnhancedCarouselView<T>(
dataProvider: fetchData,
itemBuilder: categoryItemBuilder,
filter: filterByCategory<T>,
showIndicator: true,
);
});
@ -654,8 +658,14 @@ class DocumentComponent extends StatelessComponent {
final description = document.description;
final title = document.category.title;
const double size = 20;
final date = ValidatorUtil.toLocalDateTime(
'yyyy-MM-dd',
document.updatedAt,
);
return InkWell(
return Tooltip(
message: description,
child: InkWell(
onTap: () => onPressed(document, context),
enableFeedback: true,
overlayColor: WidgetStateProperty.all<Color>(primaryColor),
@ -682,14 +692,14 @@ class DocumentComponent extends StatelessComponent {
overflow: TextOverflow.ellipsis,
),
),
AutoText(
ValidatorUtil.toLocalDateTime(
'yyyy-MM-dd',
document.updatedAt,
),
Tooltip(
message: date,
child: AutoText(
date,
style: textStyleMinor,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
@ -714,6 +724,7 @@ class DocumentComponent extends StatelessComponent {
.addToEnd(space),
),
),
),
);
},
),
@ -732,16 +743,19 @@ class DocumentComponent extends StatelessComponent {
class CategoryComponent extends StatelessComponent {
final Category category;
final bool isSelected;
const CategoryComponent({
super.key,
required this.category,
this.isSelected = false,
});
@override
Widget build(BuildContext context) {
final backgroundTheme = FlutterFlowTheme.of(context).primaryBackground;
final textTheme = FlutterFlowTheme.of(context).primaryText;
final color = isSelected ? category.color.highlight : category.color;
return ColoredBox(
color: backgroundTheme,
child: Padding(
@ -751,7 +765,7 @@ class CategoryComponent extends StatelessComponent {
Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: category.color,
color: color,
shape: BoxShape.circle,
),
child: Icon(

View File

@ -34,20 +34,13 @@ class LocalsRemoteDataSourceImpl implements LocalsRemoteDataSource {
try {
final GetLocalsCall callback = FreAccessWSGlobal.getLocalsCall;
var response = await callback.call();
final bool? isError = response.jsonBody['error'];
if (response.jsonBody == null) return;
final bool? isError = response.jsonBody['error'];
if (isError == true) {
LocalUtil.handleError(context, response.jsonBody['error_msg']);
return;
}
if (response.jsonBody == null) {
// final String errorMsg = FFLocalizations.of(context).getVariableText(
// enText: 'Verify your connection',
// ptText: 'Verifique sua conexão',
// );
// await DialogUtil.error(context, errorMsg).whenComplete(() async => await selectLocal(context, response));
return;
}
final List<dynamic> locals = response.jsonBody['locais'] ?? [];
final bool isEmpty = locals.isEmpty;

View File

@ -12,3 +12,4 @@ export 'utils/string_util.dart';
export 'utils/text_util.dart';
export 'utils/validator_util.dart';
export 'utils/webview_util.dart';
export 'utils/color_util.dart';

View File

@ -0,0 +1,48 @@
import 'dart:ui';
import 'package:flutter/material.dart';
class ColorUtil {
static Color getContrastColor(Color a, Color b) {
double luminance(Color color) {
return (0.299 * color.r + 0.587 * color.g + 0.114 * color.b) / 255;
}
double contrastRatio(Color a, Color b) {
final lumA = luminance(a) + 0.05;
final lumB = luminance(b) + 0.05;
return lumA > lumB ? lumA / lumB : lumB / lumA;
}
if (contrastRatio(a, b) < 4.5) {
// Find a color with higher contrast within the same hue
final hsv = HSVColor.fromColor(a);
double hue = hsv.hue;
double saturation = hsv.saturation;
double brightness = hsv.value;
// Increase brightness to ensure higher contrast
brightness = brightness > 0.5 ? brightness - 0.5 : brightness + 0.5;
return HSVColor.fromAHSV(1.0, hue, saturation, brightness).toColor();
}
return b;
}
static Color getSelfContrastColor(Color color) {
final hsv = HSVColor.fromColor(color);
double hue = hsv.hue;
double saturation = hsv.saturation;
double brightness = hsv.value;
// Increase brightness to ensure higher contrast
brightness = brightness > 0.5 ? brightness - 0.5 : brightness + 0.5;
return HSVColor.fromAHSV(1.0, hue, saturation, brightness).toColor();
}
}
extension ColorUtilExtension on Color {
Color get highlight => ColorUtil.getSelfContrastColor(this);
}

View File

@ -1,4 +1,6 @@
/// [Base]
library;
export 'widgets/page.dart';
export 'widgets/component.dart';
export 'widgets/screen.dart';

View File

@ -2,29 +2,40 @@ import 'package:flutter/material.dart';
import 'package:hub/flutter_flow/index.dart';
import 'package:hub/shared/utils.dart';
class EnhancedCarouselView<T> extends StatelessWidget {
class EnhancedCarouselView<T> extends StatefulWidget {
final Future<List<T?>> Function() dataProvider;
final void Function(T, BuildContext) filter;
final Widget Function<T>(T? item) itemBuilder;
final Widget Function<T>(T? item, bool isSelected) itemBuilder;
final bool showIndicator;
const EnhancedCarouselView({
super.key,
required this.dataProvider,
required this.filter,
required this.itemBuilder,
this.showIndicator = false,
});
@override
_EnhancedCarouselViewState<T> createState() =>
_EnhancedCarouselViewState<T>();
}
class _EnhancedCarouselViewState<T> extends State<EnhancedCarouselView<T>> {
T? selectedCategory;
@override
Widget build(BuildContext context) {
final theme = FlutterFlowTheme.of(context);
final backgroundColor = theme.primary;
final overlayColor = WidgetStateProperty.all(Colors.transparent);
return Column(
return Stack(
children: [
Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
spacing: 20,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(15, 0, 50, 0),
@ -40,11 +51,13 @@ class EnhancedCarouselView<T> extends StatelessWidget {
),
),
FutureBuilder<List<T?>>(
future: dataProvider(),
future: widget.dataProvider(),
builder: (context, snapshot) {
if (!snapshot.hasData) return SizedBox();
final items =
snapshot.data!.map((item) => itemBuilder(item)).toList();
final items = snapshot.data!
.map((item) =>
widget.itemBuilder(item, item == selectedCategory))
.toList();
return SizedBox(
height: 130, // Set a specific height
child: CarouselView(
@ -61,11 +74,34 @@ class EnhancedCarouselView<T> extends StatelessWidget {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
onTap: (index) => filter(snapshot.data![index] as T, context),
onTap: (index) {
setState(() {
if (selectedCategory == snapshot.data![index])
selectedCategory = null;
else
selectedCategory = snapshot.data![index] as T;
});
widget.filter(snapshot.data![index] as T, context);
},
children: items,
),
);
}),
},
),
],
),
if (widget.showIndicator)
Positioned(
left: 0,
top: 50,
child: Icon(Icons.arrow_left, size: 30, color: Colors.grey),
),
if (widget.showIndicator)
Positioned(
right: 0,
top: 50,
child: Icon(Icons.arrow_right, size: 30, color: Colors.grey),
),
],
);
}

View File

@ -1,6 +1,7 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:hub/flutter_flow/index.dart';
import 'package:rx_bloc/rx_bloc.dart';
import 'package:rx_bloc_list/rx_bloc_list.dart';
import 'package:rxdart/rxdart.dart';
@ -211,6 +212,10 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
@override
Widget build(BuildContext context) {
final String defaultMessage = FFLocalizations.of(context).getVariableText(
ptText: 'Nenhum item encontrado',
enText: 'No items found',
);
final header = StreamBuilder<List<HeaderType>>(
stream: bloc.states.headerItems.cast<List<HeaderType>>(),
builder: (context, headerSnapshot) {
@ -250,7 +255,9 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
} else if (bodySnapshot.hasError) {
return EnhancedErrorWidget(error: bodySnapshot.error);
} else if (!bodySnapshot.hasData || bodySnapshot.data!.isEmpty) {
return const SizedBox.shrink();
return Center(
child: Text(defaultMessage),
);
} else {
return ListView.builder(
itemCount: bodySnapshot.data?.length ?? 0,

View File

@ -1,7 +1,7 @@
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:hub/features/backend/index.dart';
// Removed unnecessary import
import 'package:hub/flutter_flow/index.dart';
import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/widgets.dart';
@ -32,9 +32,11 @@ abstract interface class Viewer extends StatelessComponent {
class ReadView extends StatefulWidget {
final String url;
final String title;
final VoidCallback onError;
const ReadView({
super.key,
required this.onError,
required this.url,
required this.title,
});
@ -50,8 +52,12 @@ class ReadViewState extends State<ReadView> {
final Future<DocumentType> document = DocumentType.openFile(file.path);
return ReadViewController(document: document);
} catch (e) {
logError('Erro ao baixar o PDF', e);
return Future.error(e);
final message = FFLocalizations.of(context).getVariableText(
ptText: 'Erro ao baixar o PDF',
enText: 'Error downloading PDF',
);
return Future.error(message);
}
}
@ -68,14 +74,19 @@ class ReadViewState extends State<ReadView> {
throw Exception('Falha ao baixar o PDF');
}
} catch (e) {
logError('Erro ao baixar o PDF', e);
final message = FFLocalizations.of(context).getVariableText(
ptText: 'Erro ao baixar o PDF',
enText: 'Error downloading PDF',
);
await throwError(message, e);
rethrow;
}
}
void logError(String message, dynamic error) {
Future<void> throwError(String message, dynamic error) async {
log('$message: $error');
DialogUtil.error(context, message);
await DialogUtil.error(context, message)
.whenComplete(() => widget.onError());
}
@override
@ -104,7 +115,7 @@ class ReadViewState extends State<ReadView> {
);
}
void onShare() async {
Future<void> onShare() async {
try {
final Uri uri = Uri.parse(widget.url);
final response = await http.get(uri);
@ -113,10 +124,15 @@ class ReadViewState extends State<ReadView> {
name: '${widget.title}.pdf', mimeType: 'application/pdf');
await Share.shareXFiles([xfile], text: 'Confira este PDF!');
} else {
throw Exception('Erro ao compartilhar o arquivo: ${response.statusCode}');
throw Exception(
'Erro ao compartilhar o arquivo: ${response.statusCode}');
}
} catch (e) {
logError('Erro ao compartilhar o arquivo', e);
final message = FFLocalizations.of(context).getVariableText(
ptText: 'Erro ao compartilhar o arquivo',
enText: 'Error sharing file',
);
await throwError(message, e);
}
}