Merge branch 'main' into fix/fd-787

This commit is contained in:
J. A. Messias 2024-09-12 17:13:27 -03:00
commit 6b9fad6591
32 changed files with 3171 additions and 61 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -348,7 +348,6 @@ Future<bool> checkLocals({
Future<void> showShare(payload) async { Future<void> showShare(payload) async {
for (var i = 0; i < payload['convites'].length; i++) { for (var i = 0; i < payload['convites'].length; i++) {
log('ADD');
await Share.share(''' await Share.share('''
Olá, \*${payload['convites'][i]['VTE_NOME']}\*! Você foi convidado para \*${AppState().local}\*. Olá, \*${payload['convites'][i]['VTE_NOME']}\*! Você foi convidado para \*${AppState().local}\*.

View File

@ -160,6 +160,9 @@ class AppState extends ChangeNotifier {
await _safeInitAsync(() async { await _safeInitAsync(() async {
_whatsapp = await secureStorage.getBool('whatsapp') ?? _whatsapp; _whatsapp = await secureStorage.getBool('whatsapp') ?? _whatsapp;
}); });
await _safeInitAsync(() async {
_pets = await secureStorage.getBool('pets') ?? _pets;
});
await _safeInitAsync(() async { await _safeInitAsync(() async {
_haveLocal = await secureStorage.getBool('ff_have_local') ?? _haveLocal; _haveLocal = await secureStorage.getBool('ff_have_local') ?? _haveLocal;
}); });
@ -188,6 +191,17 @@ class AppState extends ChangeNotifier {
secureStorage.delete(key: 'ff_request_os_notification'); secureStorage.delete(key: 'ff_request_os_notification');
} }
bool _pets = false;
bool get pets => _pets;
set pets(bool value) {
_pets = value;
secureStorage.setBool('pets', value);
}
void deletePets() {
secureStorage.delete(key: 'pets');
}
bool _whatsapp = false; bool _whatsapp = false;
bool get whatsapp => _whatsapp; bool get whatsapp => _whatsapp;

View File

@ -49,8 +49,223 @@ class PhpGroup {
static DeleteAccount deleteAccount = DeleteAccount(); static DeleteAccount deleteAccount = DeleteAccount();
static CancelaVisita cancelaVisita = CancelaVisita(); static CancelaVisita cancelaVisita = CancelaVisita();
static BuscaEnconcomendas buscaEnconcomendas = BuscaEnconcomendas(); static BuscaEnconcomendas buscaEnconcomendas = BuscaEnconcomendas();
static RegisterPet registerPet = RegisterPet();
static DeletePet deletePet = DeletePet();
static UpdatePet updatePet = UpdatePet();
static GetPets getPets = GetPets();
static GetPetPhoto getPetPhoto = GetPetPhoto();
} }
class DeletePet {
Future<ApiCallResponse> call({
String? devUUID = '',
String? userUUID = '',
String? cliID = '',
String? atividade = 'excluirPet',
int? petID = 0,
}) async {
final baseUrl = PhpGroup.getBaseUrl();
return ApiManager.instance.makeApiCall(
callName: 'deletePet',
apiUrl: '$baseUrl/processRequest.php',
callType: ApiCallType.POST,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
params: {
'devUUID': devUUID,
'userUUID': userUUID,
'cliID': cliID,
'atividade': atividade,
'petId': petID,
},
bodyType: BodyType.X_WWW_FORM_URL_ENCODED,
returnBody: true,
encodeBodyUtf8: false,
decodeUtf8: false,
cache: false,
isStreamingApi: false,
alwaysAllowBody: false,
);
}
}
class UpdatePet {
Future<ApiCallResponse> call({
String? devUUID = '',
String? userUUID = '',
String? cliID = '',
String? atividade = 'atualizarPet',
int? petID = 0,
String? image = '',
String? name = '',
String? species = '',
String? breed = '',
String? color = '',
String? birthdayDate = '',
String? gender = '',
String? size = '',
String? notes = '',
}) async {
final baseUrl = PhpGroup.getBaseUrl();
return ApiManager.instance.makeApiCall(
callName: 'updatePet',
apiUrl: '$baseUrl/processRequest.php',
callType: ApiCallType.POST,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
params: {
'devUUID': devUUID,
'userUUID': userUUID,
'cliID': cliID,
'atividade': atividade,
'id': petID,
'image': image,
'name': name,
'species': species,
'breed': breed,
'color': color,
'birthdayDate': ValidatorUtil.toISO8601USA('dd/MM/yyyy', birthdayDate!),
'gender': gender,
'size': size,
'notes': notes,
},
bodyType: BodyType.X_WWW_FORM_URL_ENCODED,
returnBody: true,
encodeBodyUtf8: false,
decodeUtf8: false,
cache: false,
isStreamingApi: false,
alwaysAllowBody: false,
);
}
}
class GetPets {
Future<ApiCallResponse> call({
String? devUUID = '',
String? userUUID = '',
String? cliID = '',
String? atividade = 'consultaPets',
int? page = 0,
int? pageSize = 0,
}) async {
final baseUrl = PhpGroup.getBaseUrl();
return ApiManager.instance.makeApiCall(
callName: 'getPets',
apiUrl: '$baseUrl/processRequest.php',
callType: ApiCallType.POST,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
params: {
'devUUID': devUUID,
'userUUID': userUUID,
'cliID': cliID,
'atividade': atividade,
'page': page,
'pageSize': pageSize,
},
bodyType: BodyType.X_WWW_FORM_URL_ENCODED,
returnBody: true,
encodeBodyUtf8: false,
decodeUtf8: false,
cache: false,
alwaysAllowBody: false,
);
}
}
class GetPetPhoto {
Future<ApiCallResponse> call({
String? devUUID = '',
String? userUUID = '',
String? cliID = '',
String? atividade = 'consultaFotoPet',
int? petId = 0,
}) async {
final baseUrl = PhpGroup.getBaseUrl();
return ApiManager.instance.makeApiCall(
callName: 'getPetPhoto',
apiUrl: '$baseUrl/getImage.php',
callType: ApiCallType.POST,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
params: {
'devUUID': devUUID,
'userUUID': userUUID,
'atividade': atividade,
'cliID': cliID,
'petId': petId,
},
bodyType: BodyType.BLOB,
returnBody: true,
encodeBodyUtf8: false,
decodeUtf8: false,
cache: false,
isStreamingApi: false,
);
}
}
class RegisterPet {
Future<ApiCallResponse> call({
String? devUUID = '',
String? userUUID = '',
String? cliID = '',
String? atividade = 'cadastrarPet',
String? image = '',
String? name = '',
String? species = '',
String? breed = '',
String? color = '',
String? birthdayDate = '',
String? gender = '',
String? size = '',
String? notes = '',
}) async {
final baseUrl = PhpGroup.getBaseUrl();
return ApiManager.instance.makeApiCall(
callName: 'registerPet',
apiUrl: '$baseUrl/processRequest.php',
callType: ApiCallType.POST,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
params: {
'devUUID': devUUID,
'userUUID': userUUID,
'cliID': cliID,
'atividade': atividade,
'image': image,
'name': name,
'species': species,
'breed': breed,
if (color != '') 'color': color,
if (birthdayDate != '')
'birthdayDate':
ValidatorUtil.toISO8601USA('dd/MM/yyyy', birthdayDate!),
'gender': gender,
'size': size,
if (notes != '') 'notes': notes,
},
bodyType: BodyType.X_WWW_FORM_URL_ENCODED,
returnBody: true,
encodeBodyUtf8: false,
decodeUtf8: false,
cache: false,
isStreamingApi: false,
alwaysAllowBody: false,
);
}
}
class BuscaEnconcomendas { class BuscaEnconcomendas {
Future<ApiCallResponse> call({ Future<ApiCallResponse> call({
@ -58,7 +273,6 @@ class BuscaEnconcomendas {
String? userUUID = '', String? userUUID = '',
String? cliID = '', String? cliID = '',
String? atividade = '', String? atividade = '',
String? page = '', String? page = '',
String? pageSize = '', String? pageSize = '',
String? adresseeType = '', String? adresseeType = '',
@ -78,7 +292,6 @@ class BuscaEnconcomendas {
'userUUID': userUUID, 'userUUID': userUUID,
'atividade': atividade, 'atividade': atividade,
'cliID': cliID, 'cliID': cliID,
'page': page, 'page': page,
'pageSize': pageSize, 'pageSize': pageSize,
'adresseeType': adresseeType, 'adresseeType': adresseeType,

View File

@ -29,6 +29,7 @@ enum BodyType {
TEXT, TEXT,
X_WWW_FORM_URL_ENCODED, X_WWW_FORM_URL_ENCODED,
MULTIPART, MULTIPART,
BLOB,
} }
class ApiCallOptions extends Equatable { class ApiCallOptions extends Equatable {
@ -133,13 +134,18 @@ class ApiCallResponse {
http.Response response, http.Response response,
bool returnBody, bool returnBody,
bool decodeUtf8, bool decodeUtf8,
BodyType? bodyType,
) { ) {
dynamic jsonBody; dynamic jsonBody;
try { try {
if (bodyType == BodyType.BLOB) {
jsonBody = response.bodyBytes; // Armazenar os bytes diretamente
} else {
final responseBody = decodeUtf8 && returnBody final responseBody = decodeUtf8 && returnBody
? const Utf8Decoder().convert(response.bodyBytes) ? const Utf8Decoder().convert(response.bodyBytes)
: response.body; : response.body;
jsonBody = returnBody ? json.decode(responseBody) : null; jsonBody = returnBody ? json.decode(responseBody) : null;
}
} catch (_) {} } catch (_) {}
return ApiCallResponse( return ApiCallResponse(
jsonBody, jsonBody,
@ -194,6 +200,7 @@ class ApiManager {
bool decodeUtf8, bool decodeUtf8,
bool isStreamingApi, { bool isStreamingApi, {
http.Client? client, http.Client? client,
BodyType? bodyType, // Adicionado para verificar o tipo de corpo
}) async { }) async {
if (params.isNotEmpty) { if (params.isNotEmpty) {
final specifier = final specifier =
@ -218,7 +225,8 @@ class ApiManager {
: (client != null ? client.delete : http.delete); : (client != null ? client.delete : http.delete);
final response = final response =
await makeRequest(Uri.parse(apiUrl), headers: toStringMap(headers)); await makeRequest(Uri.parse(apiUrl), headers: toStringMap(headers));
return ApiCallResponse.fromHttpResponse(response, returnBody, decodeUtf8); return ApiCallResponse.fromHttpResponse(
response, returnBody, decodeUtf8, bodyType); // Passar bodyType
} }
static Future<ApiCallResponse> requestWithBody( static Future<ApiCallResponse> requestWithBody(
@ -259,7 +267,7 @@ class ApiManager {
if (bodyType == BodyType.MULTIPART) { if (bodyType == BodyType.MULTIPART) {
return multipartRequest(type, apiUrl, headers, params, returnBody, return multipartRequest(type, apiUrl, headers, params, returnBody,
decodeUtf8, alwaysAllowBody); decodeUtf8, alwaysAllowBody, bodyType);
} }
final requestFn = { final requestFn = {
@ -270,7 +278,8 @@ class ApiManager {
}[type]!; }[type]!;
final response = await requestFn(Uri.parse(apiUrl), final response = await requestFn(Uri.parse(apiUrl),
headers: toStringMap(headers), body: postBody); headers: toStringMap(headers), body: postBody);
return ApiCallResponse.fromHttpResponse(response, returnBody, decodeUtf8); return ApiCallResponse.fromHttpResponse(
response, returnBody, decodeUtf8, bodyType);
} }
static Future<ApiCallResponse> multipartRequest( static Future<ApiCallResponse> multipartRequest(
@ -281,6 +290,7 @@ class ApiManager {
bool returnBody, bool returnBody,
bool decodeUtf8, bool decodeUtf8,
bool alwaysAllowBody, bool alwaysAllowBody,
BodyType? bodyType,
) async { ) async {
assert( assert(
{ApiCallType.POST, ApiCallType.PUT, ApiCallType.PATCH}.contains(type) || {ApiCallType.POST, ApiCallType.PUT, ApiCallType.PATCH}.contains(type) ||
@ -321,7 +331,8 @@ class ApiManager {
nonFileParams.forEach((key, value) => request.fields[key] = value); nonFileParams.forEach((key, value) => request.fields[key] = value);
final response = await http.Response.fromStream(await request.send()); final response = await http.Response.fromStream(await request.send());
return ApiCallResponse.fromHttpResponse(response, returnBody, decodeUtf8); return ApiCallResponse.fromHttpResponse(
response, returnBody, decodeUtf8, bodyType);
} }
static MediaType? _getMediaType(String? filename) { static MediaType? _getMediaType(String? filename) {
@ -362,6 +373,10 @@ class ApiManager {
contentType = 'multipart/form-data'; contentType = 'multipart/form-data';
postBody = params; postBody = params;
break; break;
case BodyType.BLOB:
contentType = 'application/octet-stream';
postBody = body;
break;
case BodyType.NONE: case BodyType.NONE:
case null: case null:
break; break;
@ -513,8 +528,8 @@ class ApiManager {
log('API Call: $callName'); log('API Call: $callName');
log('URL: $apiUrl'); log('URL: $apiUrl');
log('Headers: $headers'); log('Headers: $headers');
log('Params$params'); log('Params: $params');
log('Response${result.jsonBody}'); log('Response: ${result.jsonBody}');
return result; return result;
} }
} }

View File

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/flutter_flow/flutter_flow_icon_button.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
class AppBarUtil extends StatelessWidget implements PreferredSizeWidget {
final String title;
final VoidCallback? onBackButtonPressed;
final Widget? actionButton;
const AppBarUtil({
Key? key,
required this.title,
this.onBackButtonPressed,
this.actionButton,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
automaticallyImplyLeading: false,
forceMaterialTransparency: true,
elevation: 0.0,
leading: FlutterFlowIconButton(
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,
buttonSize: 60.0,
icon: Icon(
Icons.keyboard_arrow_left,
color: FlutterFlowTheme.of(context).primaryText,
size: 30.0,
),
onPressed: onBackButtonPressed ?? () => Navigator.of(context).pop(),
),
title: Text(
title,
style: FlutterFlowTheme.of(context).headlineMedium.override(
fontFamily: 'Nunito',
color: FlutterFlowTheme.of(context).primaryText,
fontSize: 15.0,
letterSpacing: 0.0,
fontWeight: FontWeight.bold,
useGoogleFonts: GoogleFonts.asMap().containsKey('Nunito'),
),
),
actions: [
if (actionButton != null) actionButton!,
],
centerTitle: true,
);
}
@override
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
}

View File

@ -0,0 +1,273 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
class CustomDatePickerUtil extends StatefulWidget {
TextEditingController? controller;
final FocusNode? focusNode;
final String hintText;
final String dateFormat;
final String locale;
final DateTime? initialDate;
final DateTime firstDate;
final DateTime? lastDate;
final bool timePicker;
final FormFieldValidator<String>? validator;
CustomDatePickerUtil({
Key? key,
this.controller,
this.focusNode,
required this.hintText,
required this.dateFormat,
required this.locale,
required this.timePicker,
this.initialDate,
required this.firstDate,
this.lastDate,
this.validator,
}) : super(key: key);
@override
_CustomDatePickerState createState() => _CustomDatePickerState();
}
class _CustomDatePickerState extends State<CustomDatePickerUtil> {
DateTime? _selectedDate;
TimeOfDay? _selectedTime;
@override
void initState() {
super.initState();
_selectedDate = widget.initialDate;
}
@override
void dispose() {
super.dispose();
}
_selectDate(BuildContext context) async {
final pickedDate = await showDatePicker(
context: context,
initialDate: getCurrentTimestamp,
firstDate: widget.firstDate,
lastDate: widget.lastDate ?? DateTime(2100),
builder: (context, child) {
return wrapInMaterialDatePickerTheme(
context,
child!,
headerBackgroundColor: FlutterFlowTheme.of(context).primary,
headerForegroundColor: FlutterFlowTheme.of(context).info,
headerTextStyle: FlutterFlowTheme.of(context).headlineLarge.override(
fontFamily: FlutterFlowTheme.of(context).headlineLargeFamily,
fontSize: 32.0,
letterSpacing: 0.0,
fontWeight: FontWeight.w600,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).headlineLargeFamily),
),
pickerBackgroundColor: FlutterFlowTheme.of(context).primaryBackground,
pickerForegroundColor: FlutterFlowTheme.of(context).primaryText,
selectedDateTimeBackgroundColor: FlutterFlowTheme.of(context).primary,
selectedDateTimeForegroundColor: FlutterFlowTheme.of(context).info,
actionButtonForegroundColor: FlutterFlowTheme.of(context).primaryText,
iconSize: 24.0,
);
},
);
if (pickedDate != null) {
if (widget.timePicker == true) {
final TimeOfDay? pickedTime = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(_selectedDate ?? DateTime.now()),
builder: (context, child) {
return wrapInMaterialTimePickerTheme(
context,
child!,
headerBackgroundColor: FlutterFlowTheme.of(context).primary,
headerForegroundColor: FlutterFlowTheme.of(context).info,
headerTextStyle:
FlutterFlowTheme.of(context).headlineLarge.override(
fontFamily:
FlutterFlowTheme.of(context).headlineLargeFamily,
fontSize: 32.0,
letterSpacing: 0.0,
fontWeight: FontWeight.w600,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).headlineLargeFamily),
),
pickerBackgroundColor:
FlutterFlowTheme.of(context).primaryBackground,
pickerForegroundColor: FlutterFlowTheme.of(context).info,
selectedDateTimeBackgroundColor:
FlutterFlowTheme.of(context).primary,
selectedDateTimeForegroundColor:
FlutterFlowTheme.of(context).info,
pickerDialForegroundColor:
FlutterFlowTheme.of(context).primaryText,
actionButtonForegroundColor:
FlutterFlowTheme.of(context).primaryText,
iconSize: 24.0,
);
},
);
if (pickedTime != null) {
setState(() {
_selectedDate = DateTime(
pickedDate.year,
pickedDate.month,
pickedDate.day,
pickedTime.hour,
pickedTime.minute,
);
widget.controller?.text = dateTimeFormat(
widget.dateFormat,
_selectedDate,
locale: widget.locale,
);
widget.controller?.selection = TextSelection.collapsed(
offset: widget.controller!.text.length,
);
});
}
} else {
setState(() {
_selectedDate = DateTime(
pickedDate.year,
pickedDate.month,
pickedDate.day,
);
widget.controller = TextEditingController(
text: dateTimeFormat(
widget.dateFormat,
_selectedDate,
locale: widget.locale,
));
widget.controller?.selection = TextSelection.collapsed(
offset: widget.controller!.text.length,
);
});
}
}
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(
width: MediaQuery.of(context).size.width,
height: 60.0,
child: Stack(
children: [
Padding(
padding:
const EdgeInsetsDirectional.fromSTEB(24.0, 0.0, 24.0, 0.0),
child: TextFormField(
controller: widget.controller,
focusNode: widget.focusNode,
readOnly: true,
autovalidateMode: AutovalidateMode.onUserInteraction,
autofocus: false,
obscureText: false,
decoration: InputDecoration(
isDense: true,
labelStyle: FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily:
FlutterFlowTheme.of(context).labelMediumFamily,
color: FlutterFlowTheme.of(context).primaryText,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).labelMediumFamily),
),
hintText: widget.hintText,
hintStyle: FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily:
FlutterFlowTheme.of(context).labelMediumFamily,
color: FlutterFlowTheme.of(context).primaryText,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).labelMediumFamily),
lineHeight: 1.0,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).customColor6,
width: 0.5,
),
borderRadius: BorderRadius.circular(10.0),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).primary,
width: 0.5,
),
borderRadius: BorderRadius.circular(10.0),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).error,
width: 0.5,
),
borderRadius: BorderRadius.circular(10.0),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).error,
width: 0.5,
),
borderRadius: BorderRadius.circular(10.0),
),
suffixIcon: Icon(
Icons.date_range,
color: FlutterFlowTheme.of(context).accent1,
),
),
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily:
FlutterFlowTheme.of(context).bodyMediumFamily,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).bodyMediumFamily),
lineHeight: 1.8,
),
textAlign: TextAlign.start,
validator: widget.validator,
),
),
Padding(
padding:
const EdgeInsetsDirectional.fromSTEB(24.0, 0.0, 24.0, 0.0),
child: InkWell(
splashColor: Colors.transparent,
focusColor: Colors.transparent,
hoverColor: Colors.transparent,
highlightColor: Colors.transparent,
onTap: () => _selectDate(context),
child: Container(
width: double.infinity,
height: 80.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
),
),
),
),
],
),
),
],
);
}
}

View File

@ -0,0 +1,142 @@
import 'package:easy_debounce/easy_debounce.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/components/atomic_components/shared_components_atoms/tabview.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
class CustomInputUtil extends StatefulWidget {
final TextEditingController? controller;
final String? labelText;
final String? hintText;
final bool? obscureText;
final IconData? suffixIcon;
final bool autoFocus;
FocusNode? focusNode;
final TextInputAction textInputAction;
final TextInputType keyboardType;
final int maxLength;
final String? Function(String?)? validator;
final bool haveMaxLength;
final void Function(String)? onChanged;
CustomInputUtil(
{Key? key,
this.controller,
required this.labelText,
required this.hintText,
required this.suffixIcon,
this.autoFocus = false,
required this.focusNode,
this.onChanged,
this.textInputAction = TextInputAction.next,
this.keyboardType = TextInputType.text,
this.maxLength = 80,
this.validator,
this.obscureText,
required this.haveMaxLength})
: super(key: key);
@override
State<CustomInputUtil> createState() => _CustomInputUtilState();
}
class _CustomInputUtilState extends State<CustomInputUtil> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsetsDirectional.fromSTEB(24.0, 0.0, 24.0, 10.0),
child: Column(
children: [
TextFormField(
controller: widget.controller,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: widget.validator,
autofocus: widget.autoFocus,
focusNode: widget.focusNode,
onChanged: (_) => EasyDebounce.debounce(
'${widget.controller}',
const Duration(milliseconds: 500),
() => setState(() {}),
),
textInputAction: widget.textInputAction,
obscureText: false,
decoration: InputDecoration(
isDense: true,
labelText: widget.labelText,
labelStyle: FlutterFlowTheme.of(context).labelMedium.override(
fontFamily: FlutterFlowTheme.of(context).labelMediumFamily,
color: FlutterFlowTheme.of(context).primaryText,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).labelMediumFamily,
),
),
hintText: widget.hintText,
hintStyle: FlutterFlowTheme.of(context).labelMedium.override(
fontFamily: FlutterFlowTheme.of(context).labelMediumFamily,
color: FlutterFlowTheme.of(context).primaryText,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).labelMediumFamily,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).customColor6,
width: 0.5,
),
borderRadius: BorderRadius.circular(10.0),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).primary,
width: 0.5,
),
borderRadius: BorderRadius.circular(10.0),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).error,
width: 0.5,
),
borderRadius: BorderRadius.circular(10.0),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).error,
width: 0.5,
),
borderRadius: BorderRadius.circular(10.0),
),
suffixIcon: Icon(
widget.suffixIcon,
color: FlutterFlowTheme.of(context).accent1,
),
),
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily,
color: FlutterFlowTheme.of(context).primaryText,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).bodyMediumFamily,
),
),
maxLines: null,
maxLength: widget.haveMaxLength ? widget.maxLength : null,
keyboardType: widget.keyboardType,
inputFormatters: [
LengthLimitingTextInputFormatter(widget.maxLength),
],
),
],
),
);
}
}

View File

@ -0,0 +1,140 @@
import 'dart:developer';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/components/organism_components/message_well_component/message_well_component_widget.dart';
import 'package:hub/flutter_flow/flutter_flow_drop_down.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
import 'package:hub/flutter_flow/form_field_controller.dart';
class CustomSelect extends StatefulWidget {
final List<String> options;
final List<String> optionsLabel;
final String hintText;
final bool isMultiSelect;
FormFieldController<String> controller;
dynamic Function(String?)? changed;
String? dropDownValue;
bool isRequired;
CustomSelect({
Key? key,
required this.options,
required this.optionsLabel,
required this.hintText,
required this.controller,
required this.changed,
this.isRequired = false,
this.dropDownValue,
this.isMultiSelect = false,
}) : super(key: key);
@override
_CustomSelectState createState() => _CustomSelectState();
}
class _CustomSelectState extends State<CustomSelect> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsetsDirectional.fromSTEB(0, 0.0, 0, 10.0),
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(
24.0, 0.0, 24.0, 0.0),
child: Container(
width: 100.0,
height: 48.0,
decoration: const BoxDecoration(),
child: FlutterFlowDropDown<String>(
fillColor: FlutterFlowTheme.of(context).primaryBackground,
controller: widget.controller ??=
FormFieldController<String>(
widget.dropDownValue ??= ''),
options: widget.options,
optionLabels: widget.optionsLabel,
onChanged: widget.changed,
isMultiSelect: false,
width: double.infinity,
height: double.infinity,
textStyle: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily:
FlutterFlowTheme.of(context).bodyMediumFamily,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).bodyMediumFamily),
),
hintText: widget.hintText,
icon: Icon(
Icons.keyboard_arrow_down_rounded,
color: FlutterFlowTheme.of(context).accent1,
size: 24.0,
),
elevation: 2.0,
borderColor: FlutterFlowTheme.of(context).customColor6,
borderWidth: 0.5,
borderRadius: 10.0,
margin: const EdgeInsetsDirectional.fromSTEB(
12.0, 0.0, 16.0, 0.0),
hidesUnderline: true,
isOverButton: true,
isSearchable: false,
),
),
),
),
],
),
if (widget.isRequired)
if (widget.dropDownValue == null || widget.dropDownValue == '')
Padding(
padding:
const EdgeInsetsDirectional.fromSTEB(24.0, 0.0, 24.0, 0.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding:
const EdgeInsetsDirectional.only(top: 5, start: 15),
child: Text(
FFLocalizations.of(context).getVariableText(
enText: 'This field is required',
ptText: 'Este campo é obrigatório',
),
style: FlutterFlowTheme.of(context)
.bodySmall
.override(
fontFamily: FlutterFlowTheme.of(context)
.bodySmallFamily,
color:
FlutterFlowTheme.of(context).customColor6,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context)
.bodySmallFamily),
)),
),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,178 @@
import 'dart:developer';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
import 'package:hub/flutter_flow/upload_data.dart';
import 'package:hub/flutter_flow/uploaded_file.dart';
class MediaUploadButtonUtil extends StatefulWidget {
final Function(FFUploadedFile) onUploadComplete;
bool isUploading;
final String labelText;
FFUploadedFile? uploadedFiles;
MediaUploadButtonUtil(
{Key? key,
required this.onUploadComplete,
required this.isUploading,
required this.labelText,
this.uploadedFiles})
: super(key: key);
@override
State<MediaUploadButtonUtil> createState() => _MediaUploadButtonUtilState();
}
class _MediaUploadButtonUtilState extends State<MediaUploadButtonUtil> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsetsDirectional.fromSTEB(24.0, 0.0, 24.0, 0.0),
child: Builder(
builder: (context) {
if (widget.uploadedFiles != null &&
widget.uploadedFiles!.bytes!.isNotEmpty) {
{
return InkWell(
splashColor: Colors.transparent,
focusColor: Colors.transparent,
hoverColor: Colors.transparent,
highlightColor: Colors.transparent,
onTap: () async {
setState(() {
widget.isUploading = false;
widget.uploadedFiles =
FFUploadedFile(bytes: Uint8List.fromList([]));
widget.onUploadComplete(widget.uploadedFiles!);
});
},
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.memory(
widget.uploadedFiles!.bytes ?? Uint8List.fromList([]),
width: 300.0,
height: 200.0,
fit: BoxFit.cover,
),
),
);
}
} else {
return Stack(
children: [
Align(
alignment: const AlignmentDirectional(0.0, 0.0),
child: FFButtonWidget(
onPressed: () async {
final selectedMedia =
await selectMediaWithSourceBottomSheet(
context: context,
imageQuality: 100,
allowPhoto: true,
includeDimensions: true,
);
if (selectedMedia != null) {
setState(() => widget.isUploading = true);
var selectedUploadedFiles = <FFUploadedFile>[];
try {
showUploadMessage(
context,
'Uploading file...',
showLoading: true,
);
selectedUploadedFiles = selectedMedia
.map((m) => FFUploadedFile(
name: m.storagePath.split('/').last,
bytes: m.bytes,
height: m.dimensions?.height,
width: m.dimensions?.width,
// blurHash: m.blurHash,
))
.toList();
} finally {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
widget.isUploading = false;
}
if (selectedUploadedFiles.length ==
selectedMedia.length) {
setState(() {
widget.uploadedFiles = selectedUploadedFiles.first;
});
widget.onUploadComplete(widget.uploadedFiles!);
showUploadMessage(context, 'Success!');
} else {
setState(() {});
showUploadMessage(context, 'Failed to upload data');
return;
}
}
},
text: '',
icon: Icon(
Icons.photo_camera,
color: FlutterFlowTheme.of(context).accent1,
size: 30.0,
),
options: FFButtonOptions(
width: double.infinity,
height: 120.0,
padding: const EdgeInsetsDirectional.fromSTEB(
0.0, 0.0, 0.0, 20.0),
iconPadding: const EdgeInsetsDirectional.fromSTEB(
14.0, 0.0, 0.0, 20.0),
color: FlutterFlowTheme.of(context).primaryBackground,
textStyle: FlutterFlowTheme.of(context)
.titleSmall
.override(
fontFamily:
FlutterFlowTheme.of(context).titleSmallFamily,
color: FlutterFlowTheme.of(context).primaryText,
fontSize: 16.0,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).titleSmallFamily),
),
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).accent1,
width: 0.2,
),
borderRadius: BorderRadius.circular(8.0),
),
),
),
Align(
alignment: const AlignmentDirectional(0.0, 0.0),
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(
10.0, 65.0, 10.0, 0.0),
child: Text(
widget.labelText,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily:
FlutterFlowTheme.of(context).bodyMediumFamily,
color: FlutterFlowTheme.of(context).primaryText,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).bodyMediumFamily),
),
),
),
),
],
);
}
},
),
);
}
}

View File

@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
import 'package:hub/flutter_flow/internationalization.dart';
import 'package:json_path/fun_sdk.dart';
class SubmitButtonUtil extends StatelessWidget {
final String labelText;
Future Function()? onPressed;
SubmitButtonUtil({
required this.labelText,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
return FFButtonWidget(
onPressed: onPressed,
text: labelText,
options: FFButtonOptions(
width: 250.0,
height: 36.0,
disabledColor: FlutterFlowTheme.of(context).customColor5,
padding: const EdgeInsetsDirectional.fromSTEB(80.0, 0.0, 80.0, 0.0),
iconPadding: const EdgeInsetsDirectional.fromSTEB(0.0, 0.0, 0.0, 0.0),
color: FlutterFlowTheme.of(context).primary,
textStyle: FlutterFlowTheme.of(context).titleSmall.override(
fontFamily: FlutterFlowTheme.of(context).titleSmallFamily,
color: FlutterFlowTheme.of(context).info,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap()
.containsKey(FlutterFlowTheme.of(context).titleSmallFamily),
),
borderSide: const BorderSide(
color: Colors.transparent,
width: 30.0,
),
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(15.0),
bottomRight: Radius.circular(15.0),
topLeft: Radius.circular(15.0),
topRight: Radius.circular(15.0),
),
),
);
}
}

View File

@ -0,0 +1,79 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
class TabViewUtil extends StatelessWidget {
final BuildContext context;
final dynamic model;
String labelTab1;
String labelTab2;
final TabController controller;
final Function(bool) onEditingChanged;
Widget widget1;
Widget widget2;
TabViewUtil({
super.key,
required this.onEditingChanged,
required this.context,
required this.model,
required this.labelTab1,
required this.labelTab2,
required this.controller,
required this.widget1,
required this.widget2,
});
@override
Widget build(BuildContext context) {
return SafeArea(
top: true,
child: Column(
children: [
Align(
alignment: const Alignment(0.0, 0),
child: TabBar(
labelColor: FlutterFlowTheme.of(context).primaryText,
unselectedLabelColor: FlutterFlowTheme.of(context).primaryText,
labelStyle: FlutterFlowTheme.of(context).titleMedium.override(
fontFamily: FlutterFlowTheme.of(context).titleMediumFamily,
fontSize: 13.0,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).titleMediumFamily),
),
unselectedLabelStyle: const TextStyle(),
indicatorColor: FlutterFlowTheme.of(context).primary,
padding: const EdgeInsets.all(4.0),
tabs: [
Tab(
text: labelTab1,
),
Tab(
text: labelTab2,
),
],
controller: controller,
onTap: (i) async {
if (i == 1) onEditingChanged(false);
[() async {}, () async {}][i]();
},
),
),
Expanded(
child: TabBarView(
controller: controller,
children: [
widget1,
widget2,
],
),
),
// Adicione o conteúdo do TabBarView aqui
],
),
);
}
}

View File

@ -356,4 +356,22 @@ class MenuComponentModel extends FlutterFlowModel<MenuComponentWidget> {
}, },
); );
} }
Future petsAction(BuildContext context) async {
bool isPet = AppState().pets;
if (isPet) {
context.push(
'/petsPage',
extra: <String, dynamic>{
kTransitionInfoKey: const TransitionInfo(
hasTransition: true,
transitionType: PageTransitionType.scale,
alignment: Alignment.bottomCenter,
),
},
);
} else {
DialogUnavailable.unavailableFeature(context);
}
}
} }

View File

@ -89,6 +89,17 @@ class _MenuComponentWidgetState extends State<MenuComponentWidget> {
ptText: 'QRCode\nde Acesso', ptText: 'QRCode\nde Acesso',
), ),
), ),
MenuButtonWidget(
icon: Icons.pets,
action: () async {
await _model.petsAction(context);
setState(() {});
},
title: FFLocalizations.of(context).getVariableText(
enText: 'Pets\nRegister',
ptText: 'Cadastro\nde Pet',
),
),
MenuButtonWidget( MenuButtonWidget(
icon: Icons.people, icon: Icons.people,
action: () async { action: () async {
@ -213,6 +224,17 @@ class _MenuComponentWidgetState extends State<MenuComponentWidget> {
ptText: 'QRCode\nde Acesso', ptText: 'QRCode\nde Acesso',
), ),
), ),
MenuButtonWidget(
icon: Icons.pets,
action: () async {
await _model.petsAction(context);
setState(() {});
},
title: FFLocalizations.of(context).getVariableText(
enText: 'Pets\nRegister',
ptText: 'Cadastrar\nPet',
),
),
MenuButtonWidget( MenuButtonWidget(
icon: Icons.transfer_within_a_station_outlined, icon: Icons.transfer_within_a_station_outlined,
action: () async { action: () async {
@ -338,6 +360,17 @@ class _MenuComponentWidgetState extends State<MenuComponentWidget> {
ptText: 'Encomendas', ptText: 'Encomendas',
), ),
), ),
MenuButtonWidget(
icon: Icons.pets,
action: () async {
await _model.petsAction(context);
setState(() {});
},
title: FFLocalizations.of(context).getVariableText(
enText: 'Pets\nRegister',
ptText: 'Cadastrar\nPet',
),
),
MenuCardItem( MenuCardItem(
icon: Icons.event_available, icon: Icons.event_available,
action: () async { action: () async {
@ -452,6 +485,17 @@ class _MenuComponentWidgetState extends State<MenuComponentWidget> {
ptText: 'QRCode de Acesso', ptText: 'QRCode de Acesso',
), ),
), ),
MenuCardItem(
icon: Icons.pets,
action: () async {
await _model.petsAction(context);
setState(() {});
},
title: FFLocalizations.of(context).getVariableText(
enText: 'Pets Register',
ptText: 'Cadastro de Pet',
),
),
MenuCardItem( MenuCardItem(
icon: Icons.transfer_within_a_station_outlined, icon: Icons.transfer_within_a_station_outlined,
action: () async { action: () async {

View File

@ -1,5 +1,8 @@
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hub/actions/actions.dart'; import 'package:hub/actions/actions.dart';
import 'package:hub/backend/api_requests/api_calls.dart';
import 'package:hub/components/templates_components/details_component/details_component_widget.dart'; import 'package:hub/components/templates_components/details_component/details_component_widget.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart'; import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart'; import 'package:hub/flutter_flow/flutter_flow_util.dart';
@ -8,15 +11,14 @@ import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/shared/utils/validator_util.dart'; import 'package:hub/shared/utils/validator_util.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
Widget buildDetails( Widget buildVisitDetails(
dynamic visitaWrapItem, dynamic item,
BuildContext context, BuildContext context,
Future<dynamic> Function(BuildContext, int, int, String, String)? Future<dynamic> Function(BuildContext, int, int, String, String)?
changeStatusAction) { changeStatusAction) {
return DetailsComponentWidget( return DetailsComponentWidget(
buttons: [ buttons: [
if (getStatus(visitaWrapItem['VAW_STATUS']) == if (getStatus(item['VAW_STATUS']) == status.active) // REJECT ACTION
status.active) // REJECT ACTION
FFButtonWidget( FFButtonWidget(
text: FFLocalizations.of(context).getVariableText( text: FFLocalizations.of(context).getVariableText(
ptText: 'Cancelar', ptText: 'Cancelar',
@ -37,10 +39,10 @@ Widget buildDetails(
await changeStatusAction await changeStatusAction
?.call( ?.call(
context, context,
int.parse(visitaWrapItem['VAW_DESTINO']), int.parse(item['VAW_DESTINO']),
int.parse(visitaWrapItem['VAW_ID']), int.parse(item['VAW_ID']),
visitaWrapItem['VAW_CHAVE'] ?? '', item['VAW_CHAVE'] ?? '',
visitaWrapItem['VTE_DOCUMENTO'] ?? '', item['VTE_DOCUMENTO'] ?? '',
) )
.then((value) { .then((value) {
// Navigator.pop(context, value); // Navigator.pop(context, value);
@ -93,8 +95,7 @@ Widget buildDetails(
// borderRadius: 12, // borderRadius: 12,
), ),
), ),
if (getStatus(visitaWrapItem['VAW_STATUS']) != if (getStatus(item['VAW_STATUS']) != status.active) // RECALL ACTION
status.active) // RECALL ACTION
FFButtonWidget( FFButtonWidget(
text: FFLocalizations.of(context).getVariableText( text: FFLocalizations.of(context).getVariableText(
ptText: 'Reagendar', ptText: 'Reagendar',
@ -106,10 +107,10 @@ Widget buildDetails(
context.pop(); context.pop();
context.pushNamed('scheduleCompleteVisitPage', extra: { context.pushNamed('scheduleCompleteVisitPage', extra: {
'dropdownValue1': visitaWrapItem['MOT_DESCRICAO'], 'dropdownValue1': item['MOT_DESCRICAO'],
'dropdownValue2': visitaWrapItem['NAC_DESCRICAO'], 'dropdownValue2': item['NAC_DESCRICAO'],
'visitorJsonList': [visitaWrapItem], 'visitorJsonList': [item],
'visitorStrList': visitaWrapItem['VTE_DOCUMENTO'], 'visitorStrList': item['VTE_DOCUMENTO'],
}); });
}, },
options: FFButtonOptions( options: FFButtonOptions(
@ -127,8 +128,7 @@ Widget buildDetails(
// borderRadius: 12, // borderRadius: 12,
), ),
), ),
if (getStatus(visitaWrapItem['VAW_STATUS']) == if (getStatus(item['VAW_STATUS']) == status.active) // SHARE ACTION
status.active) // SHARE ACTION
FFButtonWidget( FFButtonWidget(
text: FFLocalizations.of(context).getVariableText( text: FFLocalizations.of(context).getVariableText(
ptText: 'Compartilhar', ptText: 'Compartilhar',
@ -137,13 +137,13 @@ Widget buildDetails(
icon: const Icon(Icons.share), icon: const Icon(Icons.share),
onPressed: () async { onPressed: () async {
Share.share(''' Share.share('''
Olá, \*${visitaWrapItem['VTE_NOME']}\*! Você foi convidado para \*${AppState().local}\*. Olá, \*${item['VTE_NOME']}\*! Você foi convidado para \*${AppState().local}\*.
\*Validade do Convite\*: \*Validade do Convite\*:
- Início: ${visitaWrapItem['VAW_DTINICIO']} - Início: ${item['VAW_DTINICIO']}
- Fim: ${visitaWrapItem['VAW_DTFIM']} - Fim: ${item['VAW_DTFIM']}
URL do Convite: https://visita.freaccess.com.br/${visitaWrapItem['VAW_ID']}/${AppState().cliUUID}/${visitaWrapItem['VAW_CHAVE']} URL do Convite: https://visita.freaccess.com.br/${item['VAW_ID']}/${AppState().cliUUID}/${item['VAW_CHAVE']}
'''); ''');
}, },
options: FFButtonOptions( options: FFButtonOptions(
@ -164,59 +164,57 @@ URL do Convite: https://visita.freaccess.com.br/${visitaWrapItem['VAW_ID']}/${Ap
], ],
labelsHashMap: Map<String, String>.from({ labelsHashMap: Map<String, String>.from({
'${FFLocalizations.of(context).getVariableText(ptText: "Nome", enText: "Name")}:': '${FFLocalizations.of(context).getVariableText(ptText: "Nome", enText: "Name")}:':
visitaWrapItem['VTE_NOME'] ?? '', item['VTE_NOME'] ?? '',
'${FFLocalizations.of(context).getVariableText(ptText: "Inicio", enText: "Start")}:': '${FFLocalizations.of(context).getVariableText(ptText: "Inicio", enText: "Start")}:':
visitaWrapItem['VAW_DTINICIO'] != '' && item['VAW_DTINICIO'] != '' && item['VAW_DTINICIO'] != null
visitaWrapItem['VAW_DTINICIO'] != null
? ValidatorUtil.toLocalDateTime( ? ValidatorUtil.toLocalDateTime(
'yyyy-MM-dd HH:mm:ss', visitaWrapItem['VAW_DTINICIO']) 'yyyy-MM-dd HH:mm:ss', item['VAW_DTINICIO'])
: '', : '',
'${FFLocalizations.of(context).getVariableText(ptText: "Fim", enText: "End")}:': '${FFLocalizations.of(context).getVariableText(ptText: "Fim", enText: "End")}:':
visitaWrapItem['VAW_DTFIM'] != '' && item['VAW_DTFIM'] != '' && item['VAW_DTFIM'] != null
visitaWrapItem['VAW_DTFIM'] != null
? ValidatorUtil.toLocalDateTime( ? ValidatorUtil.toLocalDateTime(
'yyyy-MM-dd HH:mm:ss', visitaWrapItem['VAW_DTFIM']) 'yyyy-MM-dd HH:mm:ss', item['VAW_DTFIM'])
: '', : '',
}), }),
imagePath: imagePath:
'https://freaccess.com.br/freaccess/getImage.php?cliID=${AppState().cliUUID}&atividade=getFoto&Documento=${visitaWrapItem['VTE_DOCUMENTO'] ?? ''}&tipo=E', 'https://freaccess.com.br/freaccess/getImage.php?cliID=${AppState().cliUUID}&atividade=getFoto&Documento=${item['VTE_DOCUMENTO'] ?? ''}&tipo=E',
statusHashMap: [ statusHashMap: [
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.active) if (getStatus(item['VAW_STATUS']) == status.active)
Map<String, Color>.from({ Map<String, Color>.from({
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(
ptText: 'Ativo', ptText: 'Ativo',
enText: 'Active', enText: 'Active',
): FlutterFlowTheme.of(context).warning, ): FlutterFlowTheme.of(context).warning,
}), }),
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.unknown) if (getStatus(item['VAW_STATUS']) == status.unknown)
Map<String, Color>.from({ Map<String, Color>.from({
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(
ptText: 'Pendente', ptText: 'Pendente',
enText: 'Pending', enText: 'Pending',
): FlutterFlowTheme.of(context).alternate, ): FlutterFlowTheme.of(context).alternate,
}), }),
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.canceled) if (getStatus(item['VAW_STATUS']) == status.canceled)
Map<String, Color>.from({ Map<String, Color>.from({
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(
ptText: 'Cancelado', ptText: 'Cancelado',
enText: 'Canceled', enText: 'Canceled',
): FlutterFlowTheme.of(context).error, ): FlutterFlowTheme.of(context).error,
}), }),
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.finished) if (getStatus(item['VAW_STATUS']) == status.finished)
Map<String, Color>.from({ Map<String, Color>.from({
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(
ptText: 'Finalizado', ptText: 'Finalizado',
enText: 'Finished', enText: 'Finished',
): FlutterFlowTheme.of(context).success, ): FlutterFlowTheme.of(context).success,
}), }),
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.blocked) if (getStatus(item['VAW_STATUS']) == status.blocked)
Map<String, Color>.from({ Map<String, Color>.from({
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(
ptText: 'Bloqueado', ptText: 'Bloqueado',
enText: 'Blocked', enText: 'Blocked',
): FlutterFlowTheme.of(context).error, ): FlutterFlowTheme.of(context).error,
}), }),
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.inactive) if (getStatus(item['VAW_STATUS']) == status.inactive)
Map<String, Color>.from({ Map<String, Color>.from({
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(
ptText: 'Inativo', ptText: 'Inativo',
@ -226,3 +224,178 @@ URL do Convite: https://visita.freaccess.com.br/${visitaWrapItem['VAW_ID']}/${Ap
], ],
); );
} }
Widget buildPetDetails(
dynamic item,
BuildContext context,
Future<dynamic> Function(BuildContext, int, int, String, String)?
changeStatusAction) {
return DetailsComponentWidget(
buttons: [
// EDIT ACTION
FFButtonWidget(
text: FFLocalizations.of(context).getVariableText(
ptText: 'Editar',
enText: 'Edit',
),
icon: const Icon(Icons.edit),
onPressed: () async {
context.pop();
context.pop();
context.pushNamed('petsPage', extra: {
'pet': item,
});
},
options: FFButtonOptions(
width: 130,
height: 40,
color: FlutterFlowTheme.of(context).primaryBackground,
elevation: 0,
textStyle: TextStyle(
color: FlutterFlowTheme.of(context).primaryText,
),
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).primaryBackground,
width: 1,
),
// borderRadius: 12,
),
),
// DELETE ACTION
FFButtonWidget(
text: FFLocalizations.of(context).getVariableText(
ptText: 'Excluir',
enText: 'Delete',
),
icon: const Icon(Icons.close),
onPressed: () async {
showAlertDialog(
context,
FFLocalizations.of(context).getVariableText(
ptText: 'Excluir Pet',
enText: 'Delete Pet',
),
FFLocalizations.of(context).getVariableText(
ptText: 'Você tem certeza que deseja excluir esse pet?',
enText: 'Are you sure you want to delete this pet?',
), () async {
int id = item['id'];
await PhpGroup.deletePet
.call(
userUUID: AppState().userUUID,
devUUID: AppState().devUUID,
cliID: AppState().cliUUID,
petID: id,
)
.then((value) {
// Navigator.pop(context, value);
context.pop(value);
context.pop(value);
if (value == false) {
showSnackbar(
context,
FFLocalizations.of(context).getVariableText(
ptText: 'Erro ao excluir pet',
enText: 'Error deleting pet',
),
true,
);
} else if (value == true) {
showSnackbar(
context,
FFLocalizations.of(context).getVariableText(
enText: 'Success deleting pet',
ptText: 'Succeso ao excluir pet',
),
false,
);
}
}).catchError((err, stack) {
context.pop();
showSnackbar(
context,
FFLocalizations.of(context).getVariableText(
enText: 'Error deleting pet',
ptText: 'Erro ao excluir pet',
),
true,
);
});
});
},
options: FFButtonOptions(
width: 130,
height: 40,
color: FlutterFlowTheme.of(context).primaryBackground,
elevation: 0,
textStyle: TextStyle(
color: FlutterFlowTheme.of(context).primaryText,
),
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).primaryBackground,
width: 1,
),
// borderRadius: 12,
),
),
],
// 'MIN', 'PEQ', 'MED', 'GRA', 'GIG'
labelsHashMap: Map<String, String>.from({
if (item['species'] != null && item['species'] != '')
'${FFLocalizations.of(context).getVariableText(ptText: "Espécie", enText: "Species")}:':
item['species'].toString().toUpperCase(),
if (item['breed'] != null && item['breed'] != '')
'${FFLocalizations.of(context).getVariableText(ptText: "Raça", enText: "Breed")}:':
item['breed'].toString().toUpperCase(),
if (item['color'] != null && item['color'] != '')
'${FFLocalizations.of(context).getVariableText(ptText: "Cor", enText: "Color")}:':
item['color'].toString().toUpperCase(),
if (item['birthdayDate'] != null && item['birthdayDate'] != '')
'${FFLocalizations.of(context).getVariableText(ptText: "Data de Nascimento", enText: "Date of Birth")}:':
ValidatorUtil.formatDateTimePicker(item['birthdayDate']),
if (item['gender'] != null && item['gender'] != '')
'${FFLocalizations.of(context).getVariableText(ptText: "Gênero", enText: "Gender")}:':
item['gender'] == 'MAC'
? FFLocalizations.of(context)
.getVariableText(ptText: 'MACHO', enText: 'MALE')
: FFLocalizations.of(context)
.getVariableText(enText: 'FEMALE', ptText: 'FÊMEA'),
if (item['size'] != null && item['size'] != '')
'${FFLocalizations.of(context).getVariableText(ptText: "Porte", enText: "Size")}:':
item['size'] == 'MIN'
? FFLocalizations.of(context)
.getVariableText(ptText: 'MINI', enText: 'MINI')
: item['size'] == 'PEQ'
? FFLocalizations.of(context)
.getVariableText(ptText: 'PEQUENO', enText: 'SMALL')
: item['size'] == 'MED'
? FFLocalizations.of(context)
.getVariableText(ptText: 'MÉDIO', enText: 'MEDIUM')
: item['size'] == 'GRD'
? FFLocalizations.of(context).getVariableText(
ptText: 'GRANDE', enText: 'LARGE')
: item['size'] == 'GIG'
? FFLocalizations.of(context).getVariableText(
ptText: 'GIGANTE', enText: 'GIANT')
: '',
if (item['notes'] != null && item['notes'] != '')
'${FFLocalizations.of(context).getVariableText(ptText: "Observação", enText: "Notes")}:':
item['notes'] ?? '',
}),
imagePath:
'https://freaccess.com.br/freaccess/getImage.php?devUUID=${AppState().devUUID}&userUUID=${AppState().userUUID}&cliID=${AppState().cliUUID}&atividade=consultaFotoPet&petId=${item['id'] ?? ''}',
statusHashMap: [
if (item['gender'] == "MAC")
Map<String, Color>.from({
item['name']: Color(0xFF094CB0),
}),
if (item['gender'] == "FEM")
Map<String, Color>.from({
item['name']: Color(0xFFE463E7),
}),
],
);
}

View File

@ -5,7 +5,6 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
const kThemeModeKey = '__theme_mode__'; const kThemeModeKey = '__theme_mode__';
SharedPreferences? _prefs; SharedPreferences? _prefs;

View File

@ -6,6 +6,7 @@ import 'package:hub/pages/delivery_schedule_page/delivery_schedule_widget.dart';
import 'package:hub/pages/fast_pass_page/fast_pass_page_widget.dart'; import 'package:hub/pages/fast_pass_page/fast_pass_page_widget.dart';
import 'package:hub/pages/message_history_page/message_history_page_widget.dart'; import 'package:hub/pages/message_history_page/message_history_page_widget.dart';
import 'package:hub/pages/package_order_page/package_order_page.dart'; import 'package:hub/pages/package_order_page/package_order_page.dart';
import 'package:hub/pages/pets_page/pets_page_widget.dart';
import 'package:hub/pages/provisional_schedule_page/provisional_schedule_widget.dart'; import 'package:hub/pages/provisional_schedule_page/provisional_schedule_widget.dart';
import 'package:hub/pages/reception_page/reception_page_widget.dart'; import 'package:hub/pages/reception_page/reception_page_widget.dart';
import 'package:hub/pages/reservation_page/reservation_page_widget.dart'; import 'package:hub/pages/reservation_page/reservation_page_widget.dart';
@ -201,6 +202,20 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) => GoRouter(
path: '/reservation', path: '/reservation',
builder: (context, params) => ReservationPageWidget(), builder: (context, params) => ReservationPageWidget(),
), ),
FFRoute(
name: 'petsPage',
path: '/petsPage',
builder: (context, params) {
final pet = params.getParam(
'pet',
ParamType.JSON,
);
return PetsPageWidget(
pet: pet,
);
},
),
// FFRoute( // FFRoute(
// name: 'settingsPage', // name: 'settingsPage',
// path: '/settingsPage', // path: '/settingsPage',

View File

@ -1,10 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer'; import 'dart:developer';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:hub/backend/notifications/notification_service.dart';
import 'package:hub/shared/utils/log_util.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
@ -38,6 +34,79 @@ class _HomePageWidgetState extends State<HomePageWidget> {
LocalProfileComponentWidget(showBottomSheet: showModalSelectLocal); LocalProfileComponentWidget(showBottomSheet: showModalSelectLocal);
} }
Future<void> processData() async {
try {
var response = await PhpGroup.getDadosCall.call(
devUUID: AppState().devUUID,
userUUID: AppState().userUUID,
cliUUID: AppState().cliUUID,
atividade: 'getDados',
);
final error = response.jsonBody['error'];
final errorMsg = response.jsonBody['error_msg'];
if (error == false) {
log(response.jsonBody.toString());
AppState().whatsapp = response.jsonBody['whatsapp'] ?? false;
AppState().provisional = response.jsonBody['provisional'] ?? false;
AppState().pets = response.jsonBody['pet'] ?? false;
AppState().name = response.jsonBody['visitado']['VDO_NOME'];
safeSetState(() {});
return;
}
DialogUtil.warningDefault(context).whenComplete(() => processLocals());
safeSetState(() {});
return;
} catch (e, s) {
DialogUtil.warningDefault(context).whenComplete(() => processLocals());
}
}
Future<void> processLocals() async {
try {
var response = await PhpGroup.getLocalsCall.call(
devUUID: AppState().devUUID,
userUUID: AppState().userUUID,
);
List<dynamic> locals = response.jsonBody['locais'] ?? [];
final activeLocals =
locals.where((local) => local['CLU_STATUS'] == 'A').toList();
if (activeLocals.isEmpty || AppState().cliUUID.isEmpty) {
await showModalSelectLocal();
} else {
await processData();
}
} catch (e) {
await showModalSelectLocal();
}
}
Future<void> showModalSelectLocal() async {
await showModalBottomSheet(
isScrollControlled: true,
backgroundColor: Colors.transparent,
enableDrag: false,
isDismissible: false,
context: context,
builder: (context) => Padding(
padding: MediaQuery.viewInsetsOf(context),
child: const BottomArrowLinkedLocalsComponentWidget(),
),
).then((_) async {
_model.updatePage(() => safeSetState(() {
_localProfileComponentWidget = LocalProfileComponentWidget(
showBottomSheet: showModalSelectLocal);
}));
await processData();
});
}
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();

View File

@ -240,7 +240,6 @@ class _LiberationHistoryWidgetState extends State<LiberationHistoryWidget> {
id: liberationHistoryItem['VTE_ID'].toString(), id: liberationHistoryItem['VTE_ID'].toString(),
) )
.then((value) { .then((value) {
log('test: $value');
if (value) { if (value) {
showSnackbar( showSnackbar(
context, context,

View File

@ -0,0 +1,259 @@
import 'package:flutter/material.dart';
import 'package:hub/actions/actions.dart';
import 'package:hub/backend/api_requests/api_calls.dart';
import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.dart';
import 'package:hub/components/templates_components/details_component/details_component_action.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/pages/schedule_complete_visit_page/schedule_complete_visit_page_model.dart';
import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/log_util.dart';
import 'package:hub/shared/utils/validator_util.dart';
class PetsHistoryScreen extends StatefulWidget {
PetsHistoryScreen({Key? key}) : super(key: key);
@override
_PetsHistoryScreenState createState() => _PetsHistoryScreenState();
}
class _PetsHistoryScreenState extends State<PetsHistoryScreen>
with TickerProviderStateMixin {
late ScrollController _scrollController;
int _pageNumber = 1;
final int _pageSize = 10;
bool _hasData = false;
bool _loading = false;
late Future<void> _petsFuture;
List<dynamic> _petsWrap = [];
@override
void initState() {
super.initState();
_petsFuture = _fetchVisits();
_scrollController = ScrollController()
..addListener(() {
if (_scrollController.position.atEdge &&
_scrollController.position.pixels != 0) {
_loadMore();
}
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
Future<ApiCallResponse?> _fetchVisits() async {
try {
setState(() => _loading = true);
var response = await PhpGroup.getPets.call(
devUUID: AppState().devUUID,
userUUID: AppState().userUUID,
cliID: AppState().cliUUID,
atividade: 'consultaPets',
pageSize: _pageSize,
page: _pageNumber,
);
final List<dynamic> pets = response.jsonBody['pets'] ?? [];
if (pets != null && pets.isNotEmpty) {
setState(() {
_petsWrap.addAll(pets);
_hasData = true;
_loading = false;
});
return response;
}
_showNoMoreDataSnackBar(context);
setState(() {
_hasData = false;
_loading = false;
});
return null;
} catch (e, s) {
DialogUtil.errorDefault(context);
LogUtil.requestAPIFailed(
"proccessRequest.php", "", "Consulta de Pets", e, s);
setState(() {
_hasData = false;
_loading = false;
});
}
}
void _loadMore() {
if (_hasData == true) {
_pageNumber++;
_petsFuture = _fetchVisits();
}
}
void _showNoMoreDataSnackBar(BuildContext context) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
FFLocalizations.of(context).getVariableText(
ptText: "Não há mais dados.", enText: "No more data."),
),
duration: const Duration(seconds: 3),
backgroundColor: FlutterFlowTheme.of(context).primary,
),
);
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (_hasData == false && _pageNumber <= 1 && _loading == false)
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Center(
child: Text(FFLocalizations.of(context).getVariableText(
ptText: "Nenhum Pet encontrado!",
enText: "No pets found")),
)
],
),
)
else if (_hasData == true || _pageNumber >= 1)
Expanded(
child: FutureBuilder<void>(
future: _petsFuture,
builder: (context, snapshot) {
return ListView.builder(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
controller: _scrollController,
itemCount: _petsWrap.length,
itemBuilder: (context, index) {
final item = _petsWrap[index];
return _item(context, item);
});
},
)),
if (_hasData == true && _loading == true)
Container(
padding: const EdgeInsets.only(top: 15, bottom: 15),
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
FlutterFlowTheme.of(context).primary,
),
),
),
)
].addToStart(const SizedBox(height: 0)),
);
}
Widget _item(BuildContext context, dynamic uItem) {
return CardItemTemplateComponentWidget(
imagePath:
'https://freaccess.com.br/freaccess/getImage.php?devUUID=${AppState().devUUID}&userUUID=${AppState().userUUID}&cliID=${AppState().cliUUID}&atividade=consultaFotoPet&petId=${uItem['id'] ?? ''}',
labelsHashMap: {
'${FFLocalizations.of(context).getVariableText(ptText: "Nome", enText: "Name")}:':
uItem['name'] ?? '',
'${FFLocalizations.of(context).getVariableText(ptText: "Espécie", enText: "Species")}:':
uItem['species'] ?? '',
'${FFLocalizations.of(context).getVariableText(ptText: "Raça", enText: "Breed")}:':
uItem['breed'] ?? '',
},
statusHashMap: [
if (uItem['size'] == "MIN")
{
FFLocalizations.of(context).getVariableText(
ptText: 'Mini',
enText: 'Mini',
): FlutterFlowTheme.of(context).accent4,
},
if (uItem['size'] == "PEQ")
{
FFLocalizations.of(context).getVariableText(
ptText: 'Pequeno',
enText: 'Small',
): FlutterFlowTheme.of(context).accent4,
},
if (uItem['size'] == "MED")
{
FFLocalizations.of(context).getVariableText(
ptText: 'Medio',
enText: 'Medium',
): FlutterFlowTheme.of(context).accent4,
},
if (uItem['size'] == "GRA")
{
FFLocalizations.of(context).getVariableText(
ptText: 'Grande',
enText: 'Big',
): FlutterFlowTheme.of(context).accent4,
},
if (uItem['size'] == "GIG")
{
FFLocalizations.of(context).getVariableText(
ptText: 'Gigante',
enText: 'Giant',
): FlutterFlowTheme.of(context).accent4,
},
if (uItem['gender'] == "MAC")
{
FFLocalizations.of(context).getVariableText(
ptText: 'Macho', enText: 'Male'): Color(0xFF094CB0),
},
if (uItem['gender'] == "FEM")
{
FFLocalizations.of(context).getVariableText(
ptText: 'Femêa',
enText: 'Female',
): Color(0xFFE463E7),
}
],
onTapCardItemAction: () async {
await showDialog(
useSafeArea: true,
context: context,
builder: (context) {
return Dialog(
alignment: Alignment.center,
child: buildPetDetails(
uItem,
context,
changeStatusAction,
),
);
},
).whenComplete(() {
safeSetState(() {
_pageNumber = 1;
_petsWrap = [];
_petsFuture = _fetchVisits();
});
}).catchError((e, s) {
DialogUtil.errorDefault(context);
LogUtil.requestAPIFailed(
"proccessRequest.php", "", "Consulta de Pets", e, s);
safeSetState(() {
_hasData = false;
_loading = false;
});
});
},
);
}
}

View File

@ -0,0 +1,246 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:hub/backend/api_requests/api_calls.dart';
import 'package:hub/backend/api_requests/api_manager.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/flutter_flow/form_field_controller.dart';
import 'package:hub/pages/pets_page/pets_page_widget.dart';
import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/log_util.dart';
import '/custom_code/actions/index.dart' as actions;
class PetsPageModel extends FlutterFlowModel<PetsPageWidget> {
late final TabController tabBarController;
ApiCallResponse? petsResponse;
int? petId;
BuildContext? buildContext;
// Controller para o Upload de Arquivos
bool isDataUploading = false;
FFUploadedFile? uploadedLocalFile;
String? imgBase64;
// Controller para o DropDown
String? dropDownValue1;
FormFieldController<String>? dropDownValueController1;
String? dropDownValue2;
FormFieldController<String>? dropDownValueController2;
// Controller para o TextField
FocusNode? textFieldFocusName;
TextEditingController? textControllerName;
String? textControllerNameValidator(BuildContext context, String? val) {
if (val == null || val.isEmpty) {
return FFLocalizations.of(context).getVariableText(
enText: 'This field is required',
ptText: 'Este campo é obrigatório',
);
}
return null;
}
FocusNode? textFieldFocusSpecies;
TextEditingController? textControllerSpecies;
String? textControllerSpeciesValidator(BuildContext context, String? val) {
if (val == null || val.isEmpty) {
return FFLocalizations.of(context).getVariableText(
enText: 'This field is required',
ptText: 'Este campo é obrigatório',
);
}
return null;
}
FocusNode? textFieldFocusRace;
TextEditingController? textControllerRace;
String? textControllerRaceValidator(BuildContext context, String? val) {
if (val == null || val.isEmpty) {
return FFLocalizations.of(context).getVariableText(
enText: 'This field is required',
ptText: 'Este campo é obrigatório',
);
}
return null;
}
FocusNode? textFieldFocusColor;
TextEditingController? textControllerColor;
String? Function(BuildContext, String?)? textControllerColorValidator;
DateTime? selectedDate;
FocusNode? textFieldFocusData;
TextEditingController? textControllerData;
String? textControllerDataValidator(BuildContext context, String? val) {
return null;
}
FocusNode? textFieldFocusObservation;
TextEditingController? textControllerObservation;
String? Function(BuildContext, String?)? textControllerObservationValidator;
@override
void initState(BuildContext context) {
// Se liga! Esse é o controller do TabBar
tabBarController = TabController(
vsync: Navigator.of(context),
length: 2,
);
textFieldFocusName = FocusNode();
textControllerName = TextEditingController();
// textControllerNameValidator =
// (context, value) => _textControllerNameValidator(context, value);
textFieldFocusSpecies = FocusNode();
textControllerSpecies = TextEditingController();
textFieldFocusRace = FocusNode();
textControllerRace = TextEditingController();
textFieldFocusColor = FocusNode();
textControllerColor = TextEditingController();
textFieldFocusData = FocusNode();
textControllerData = TextEditingController(
text: dateTimeFormat(
'dd/MM/yyyy',
DateTime.now(),
));
textFieldFocusObservation = FocusNode();
textControllerObservation = TextEditingController();
dropDownValueController1 =
FormFieldController<String>(dropDownValue1 ??= 'Selecione uma opção');
dropDownValueController2 =
FormFieldController<String>(dropDownValue2 ??= 'Selecione uma opção');
}
@override
void dispose() {
tabBarController.dispose();
textFieldFocusName?.dispose();
textControllerName?.dispose();
textFieldFocusSpecies?.dispose();
textControllerSpecies?.dispose();
textFieldFocusRace?.dispose();
textControllerRace?.dispose();
textFieldFocusColor?.dispose();
textControllerColor?.dispose();
textFieldFocusData?.dispose();
textControllerData?.dispose();
textFieldFocusObservation?.dispose();
textControllerObservation?.dispose();
dropDownValueController1?.dispose();
dropDownValueController2?.dispose();
}
// Validador do formulário
bool isFormValid(BuildContext context) {
if (uploadedLocalFile == null) {
return false;
}
if (textControllerName.text.isEmpty ||
textControllerName.text.length > 80 ||
textControllerName.text == '') {
return false;
}
if (textControllerSpecies.text.isEmpty ||
textControllerSpecies.text == '') {
return false;
}
if (textControllerRace.text.isEmpty || textControllerRace.text == '') {
return false;
}
if (dropDownValue1 == null ||
dropDownValue1!.isEmpty ||
dropDownValue1 == '') {
return false;
}
if (dropDownValue2 == null) {
return false;
}
return true;
}
Future<void> updatePet() async {
await PhpGroup.updatePet
.call(
cliID: AppState().cliUUID,
devUUID: AppState().devUUID,
userUUID: AppState().userUUID,
petID: petId,
image: await actions.convertImageFileToBase64(
uploadedLocalFile!,
),
birthdayDate: textControllerData!.text,
color: textControllerColor!.text,
breed: textControllerRace!.text,
species: textControllerSpecies!.text,
name: textControllerName!.text,
gender: dropDownValue1!,
notes: textControllerObservation!.text,
size: dropDownValue2!,
)
.then((response) {
if (response.jsonBody['error'] == true) {
DialogUtil.error(buildContext!,
jsonDecode(response.jsonBody['error_msg'])[0]['message']);
}
DialogUtil.success(
buildContext!,
FFLocalizations.of(buildContext!).getVariableText(
enText: 'Pet successfully updated',
ptText: 'Pet atualizado com sucesso',
));
}).catchError((error) {
log(error.toString());
DialogUtil.errorDefault(buildContext!);
});
}
Future<void> registerPet() async {
await PhpGroup.registerPet
.call(
cliID: AppState().cliUUID,
devUUID: AppState().devUUID,
userUUID: AppState().userUUID,
image: await actions.convertImageFileToBase64(
uploadedLocalFile!,
),
birthdayDate: textControllerData!.text,
color: textControllerColor!.text,
breed: textControllerRace!.text,
species: textControllerSpecies!.text,
name: textControllerName!.text,
gender: dropDownValue1!,
size: dropDownValue2!,
notes: textControllerObservation!.text,
)
.then((response) {
if (response.jsonBody['error'] == true) {
DialogUtil.error(buildContext!,
jsonDecode(response.jsonBody['error_msg'])[0]['message']);
}
DialogUtil.success(
buildContext!,
FFLocalizations.of(buildContext!).getVariableText(
enText: 'Pet successfully registered',
ptText: 'Pet cadastrado com sucesso',
));
}).catchError((error) {
DialogUtil.errorDefault(buildContext!);
});
}
}

File diff suppressed because it is too large Load Diff

View File

@ -225,7 +225,6 @@ class PreferencesPageModel with ChangeNotifier {
); );
}).whenComplete(() => notifyListeners()); }).whenComplete(() => notifyListeners());
} on Exception catch (e) { } on Exception catch (e) {
log(e.toString());
context.pop(); context.pop();
} }
}, },

View File

@ -236,7 +236,7 @@ class _VisitHistoryWidgetState extends State<VisitHistoryWidget>
builder: (context) { builder: (context) {
return Dialog( return Dialog(
alignment: Alignment.center, alignment: Alignment.center,
child: buildDetails( child: buildVisitDetails(
visitaWrapItem, visitaWrapItem,
context, context,
changeStatusAction, changeStatusAction,

View File

@ -20,10 +20,21 @@ class ValidatorUtil {
} }
static String toISO8601(String format, String value) { static String toISO8601(String format, String value) {
log('value: $value');
DateFormat dateFormat = DateFormat(format); DateFormat dateFormat = DateFormat(format);
DateTime dateTime = dateFormat.parse(value); DateTime dateTime = dateFormat.parse(value);
return dateTime.toIso8601String(); return dateTime.toIso8601String() + 'Z';
}
static String toISO8601USA(String format, String value) {
log('value: $value');
DateFormat dateFormat = DateFormat(format);
DateTime dateTime = dateFormat.parse(value);
String date = dateTime.toIso8601String() + 'Z';
date = date.substring(0, 11) + '03:00:00.000Z';
return date;
} }
static String toLocalDateTime(String format, String value) { static String toLocalDateTime(String format, String value) {
@ -32,4 +43,13 @@ class ValidatorUtil {
return DateFormat('dd/MM/yyyy HH:mm:ss').format(dateTime); return DateFormat('dd/MM/yyyy HH:mm:ss').format(dateTime);
} }
static String formatDateTimePicker(String dateTime) {
log('dateTime: $dateTime');
List<String> parts = dateTime.split(' ');
String datePart = parts[0];
List<String> dateParts = datePart.split('-');
String formattedDate = '${dateParts[2]}/${dateParts[1]}/${dateParts[0]}';
return formattedDate;
}
} }

View File

@ -186,7 +186,7 @@ packages:
source: hosted source: hosted
version: "0.3.4+2" version: "0.3.4+2"
crypto: crypto:
dependency: transitive dependency: "direct main"
description: description:
name: crypto name: crypto
sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27
@ -241,6 +241,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.1" version: "7.0.1"
dio:
dependency: "direct main"
description:
name: dio
sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260"
url: "https://pub.dev"
source: hosted
version: "5.7.0"
dio_web_adapter:
dependency: transitive
description:
name: dio_web_adapter
sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
dropdown_button2: dropdown_button2:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -97,6 +97,8 @@ dependencies:
firebase_crashlytics: ^4.0.1 firebase_crashlytics: ^4.0.1
awesome_notifications: ^0.9.3+1 awesome_notifications: ^0.9.3+1
app_tracking_transparency: ^2.0.6 app_tracking_transparency: ^2.0.6
dio: ^5.7.0
crypto: ^3.0.5
dependency_overrides: dependency_overrides:
http: 1.2.1 http: 1.2.1