Add pets history screen and fix logical problems in register

This commit is contained in:
J. A. Messias 2024-09-12 09:07:15 -03:00
parent 2a9f58f9e6
commit a50acbd0d8
15 changed files with 1237 additions and 158 deletions

View File

@ -61,13 +61,14 @@ class DeletePet {
String? devUUID = '',
String? userUUID = '',
String? cliID = '',
String? petID = '',
String? atividade = 'excluirPet',
int? petID = 0,
}) async {
final baseUrl = PhpGroup.getBaseUrl();
return ApiManager.instance.makeApiCall(
callName: 'deletePet',
apiUrl: '$baseUrl/deletePet.php',
apiUrl: '$baseUrl/processRequest.php',
callType: ApiCallType.POST,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
@ -76,7 +77,8 @@ class DeletePet {
'devUUID': devUUID,
'userUUID': userUUID,
'cliID': cliID,
'id': petID,
'atividade': atividade,
'petId': petID,
},
bodyType: BodyType.X_WWW_FORM_URL_ENCODED,
returnBody: true,
@ -94,7 +96,8 @@ class UpdatePet {
String? devUUID = '',
String? userUUID = '',
String? cliID = '',
String? petID = '',
String? atividade = 'atualizarPet',
int? petID = 0,
String? image = '',
String? name = '',
String? species = '',
@ -109,7 +112,7 @@ class UpdatePet {
return ApiManager.instance.makeApiCall(
callName: 'updatePet',
apiUrl: '$baseUrl/updatePet.php',
apiUrl: '$baseUrl/processRequest.php',
callType: ApiCallType.POST,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
@ -118,13 +121,14 @@ class UpdatePet {
'devUUID': devUUID,
'userUUID': userUUID,
'cliID': cliID,
'atividade': atividade,
'id': petID,
'image': image,
'name': name,
'species': species,
'breed': breed,
'color': color,
'birthdayDate': birthdayDate,
'birthdayDate': ValidatorUtil.toISO8601USA('dd/MM/yyyy', birthdayDate!),
'gender': gender,
'size': size,
'notes': notes,
@ -145,14 +149,15 @@ class GetPets {
String? devUUID = '',
String? userUUID = '',
String? cliID = '',
String? page = '',
String? pageSize = '',
String? atividade = 'consultaPets',
int? page = 0,
int? pageSize = 0,
}) async {
final baseUrl = PhpGroup.getBaseUrl();
return ApiManager.instance.makeApiCall(
callName: 'getPets',
apiUrl: '$baseUrl/getPets.php',
apiUrl: '$baseUrl/processRequest.php',
callType: ApiCallType.POST,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
@ -161,6 +166,7 @@ class GetPets {
'devUUID': devUUID,
'userUUID': userUUID,
'cliID': cliID,
'atividade': atividade,
'page': page,
'pageSize': pageSize,
},
@ -179,13 +185,14 @@ class GetPetPhoto {
String? devUUID = '',
String? userUUID = '',
String? cliID = '',
String? petID = '',
String? atividade = 'consultaFotoPet',
int? petId = 0,
}) async {
final baseUrl = PhpGroup.getBaseUrl();
return ApiManager.instance.makeApiCall(
callName: 'getPetPhoto',
apiUrl: '$baseUrl/getPetPhoto.php',
apiUrl: '$baseUrl/getImage.php',
callType: ApiCallType.POST,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
@ -193,15 +200,16 @@ class GetPetPhoto {
params: {
'devUUID': devUUID,
'userUUID': userUUID,
'atividade': atividade,
'cliID': cliID,
'petId': petID,
'petId': petId,
},
bodyType: BodyType.X_WWW_FORM_URL_ENCODED,
bodyType: BodyType.BLOB,
returnBody: true,
encodeBodyUtf8: false,
decodeUtf8: false,
cache: false,
alwaysAllowBody: false,
isStreamingApi: false,
);
}
}
@ -242,7 +250,8 @@ class RegisterPet {
'breed': breed,
if (color != '') 'color': color,
if (birthdayDate != '')
'birthdayDate': ValidatorUtil.toISO8601('dd/MM/yyyy', birthdayDate!),
'birthdayDate':
ValidatorUtil.toISO8601USA('dd/MM/yyyy', birthdayDate!),
'gender': gender,
'size': size,
if (notes != '') 'notes': notes,

View File

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

View File

@ -0,0 +1,69 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
class ApiService {
static const _baseUrl = 'https://freaccess.com.br/freaccess';
static final Dio _dio = Dio(BaseOptions(
baseUrl: _baseUrl,
// headers: {'Authorization': 'Bearer $_apiKey'},
));
static Future<Response> makeApiCall({
required String endpoint,
required Map<String, dynamic> body,
bool isMultipart = false,
Uint8List? file,
Uint8List? blob,
}) async {
try {
Response response;
if (isMultipart && file != null) {
FormData formData = FormData.fromMap(body);
formData.files.add(MapEntry('file', MultipartFile.fromBytes(file)));
response = await _dio.post(endpoint, data: formData);
} else if (blob != null) {
// Convert the blob to base64 string
String base64Image = base64Encode(blob);
// Set the request headers
Map<String, dynamic> headers = {
'Content-Type': 'application/json',
};
// Create the request body as JSON
Map<String, dynamic> requestBody = {
'image': base64Image,
};
response = await _dio.post(
endpoint,
data: jsonEncode(requestBody),
options: Options(headers: headers),
);
} else {
// Set the request headers
Map<String, dynamic> headers = {
'Content-Type': 'application/json',
};
response = await _dio.post(
endpoint,
data: jsonEncode(body),
options: Options(headers: headers),
);
}
debugPrint('API call to $endpoint successful');
debugPrint('Api call body: $body');
debugPrint('Response: ${response.data}');
debugPrint('Response headers: ${response.headers}');
debugPrint('Response status: ${response.statusCode}');
return response;
} catch (e) {
rethrow;
}
}
}

View File

@ -5,7 +5,6 @@ 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:hub/flutter_flow/upload_data.dart';
import 'package:hub/flutter_flow/uploaded_file.dart';
@ -13,12 +12,14 @@ 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})
required this.labelText,
this.uploadedFiles})
: super(key: key);
@override
@ -26,12 +27,9 @@ class MediaUploadButtonUtil extends StatefulWidget {
}
class _MediaUploadButtonUtilState extends State<MediaUploadButtonUtil> {
FFUploadedFile _uploadedFiles = FFUploadedFile(bytes: Uint8List.fromList([]));
@override
void initState() {
super.initState();
_uploadedFiles = FFUploadedFile(bytes: Uint8List.fromList([]));
}
@override
@ -40,7 +38,7 @@ class _MediaUploadButtonUtilState extends State<MediaUploadButtonUtil> {
padding: const EdgeInsetsDirectional.fromSTEB(24.0, 0.0, 24.0, 0.0),
child: Builder(
builder: (context) {
if ((_uploadedFiles.bytes?.isNotEmpty ?? false)) {
if ((widget.uploadedFiles != null)) {
return InkWell(
splashColor: Colors.transparent,
focusColor: Colors.transparent,
@ -49,15 +47,15 @@ class _MediaUploadButtonUtilState extends State<MediaUploadButtonUtil> {
onTap: () async {
setState(() {
widget.isUploading = false;
_uploadedFiles =
widget.uploadedFiles =
FFUploadedFile(bytes: Uint8List.fromList([]));
widget.onUploadComplete(_uploadedFiles);
widget.onUploadComplete(widget.uploadedFiles!);
});
},
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.memory(
_uploadedFiles.bytes ?? Uint8List.fromList([]),
widget.uploadedFiles!.bytes ?? Uint8List.fromList([]),
width: 300.0,
height: 200.0,
fit: BoxFit.cover,
@ -105,9 +103,9 @@ class _MediaUploadButtonUtilState extends State<MediaUploadButtonUtil> {
if (selectedUploadedFiles.length ==
selectedMedia.length) {
setState(() {
_uploadedFiles = selectedUploadedFiles.first;
widget.uploadedFiles = selectedUploadedFiles.first;
});
widget.onUploadComplete(_uploadedFiles);
widget.onUploadComplete(widget.uploadedFiles!);
showUploadMessage(context, 'Success!');
} else {

View File

@ -1,5 +1,8 @@
import 'dart:developer';
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/details_component/details_component_widget.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.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:share_plus/share_plus.dart';
Widget buildDetails(
dynamic visitaWrapItem,
Widget buildVisitDetails(
dynamic item,
BuildContext context,
Future<dynamic> Function(BuildContext, int, int, String, String)?
changeStatusAction) {
return DetailsComponentWidget(
buttons: [
if (getStatus(visitaWrapItem['VAW_STATUS']) ==
status.active) // REJECT ACTION
if (getStatus(item['VAW_STATUS']) == status.active) // REJECT ACTION
FFButtonWidget(
text: FFLocalizations.of(context).getVariableText(
ptText: 'Cancelar',
@ -37,10 +39,10 @@ Widget buildDetails(
await changeStatusAction
?.call(
context,
int.parse(visitaWrapItem['VAW_DESTINO']),
int.parse(visitaWrapItem['VAW_ID']),
visitaWrapItem['VAW_CHAVE'] ?? '',
visitaWrapItem['VTE_DOCUMENTO'] ?? '',
int.parse(item['VAW_DESTINO']),
int.parse(item['VAW_ID']),
item['VAW_CHAVE'] ?? '',
item['VTE_DOCUMENTO'] ?? '',
)
.then((value) {
// Navigator.pop(context, value);
@ -93,8 +95,7 @@ Widget buildDetails(
// borderRadius: 12,
),
),
if (getStatus(visitaWrapItem['VAW_STATUS']) !=
status.active) // RECALL ACTION
if (getStatus(item['VAW_STATUS']) != status.active) // RECALL ACTION
FFButtonWidget(
text: FFLocalizations.of(context).getVariableText(
ptText: 'Reagendar',
@ -106,10 +107,10 @@ Widget buildDetails(
context.pop();
context.pushNamed('scheduleCompleteVisitPage', extra: {
'dropdownValue1': visitaWrapItem['MOT_DESCRICAO'],
'dropdownValue2': visitaWrapItem['NAC_DESCRICAO'],
'visitorJsonList': [visitaWrapItem],
'visitorStrList': visitaWrapItem['VTE_DOCUMENTO'],
'dropdownValue1': item['MOT_DESCRICAO'],
'dropdownValue2': item['NAC_DESCRICAO'],
'visitorJsonList': [item],
'visitorStrList': item['VTE_DOCUMENTO'],
});
},
options: FFButtonOptions(
@ -127,8 +128,7 @@ Widget buildDetails(
// borderRadius: 12,
),
),
if (getStatus(visitaWrapItem['VAW_STATUS']) ==
status.active) // SHARE ACTION
if (getStatus(item['VAW_STATUS']) == status.active) // SHARE ACTION
FFButtonWidget(
text: FFLocalizations.of(context).getVariableText(
ptText: 'Compartilhar',
@ -137,13 +137,13 @@ Widget buildDetails(
icon: const Icon(Icons.share),
onPressed: () async {
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\*:
- Início: ${visitaWrapItem['VAW_DTINICIO']}
- Fim: ${visitaWrapItem['VAW_DTFIM']}
- Início: ${item['VAW_DTINICIO']}
- 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(
@ -164,59 +164,57 @@ URL do Convite: https://visita.freaccess.com.br/${visitaWrapItem['VAW_ID']}/${Ap
],
labelsHashMap: Map<String, String>.from({
'${FFLocalizations.of(context).getVariableText(ptText: "Nome", enText: "Name")}:':
visitaWrapItem['VTE_NOME'] ?? '',
item['VTE_NOME'] ?? '',
'${FFLocalizations.of(context).getVariableText(ptText: "Inicio", enText: "Start")}:':
visitaWrapItem['VAW_DTINICIO'] != '' &&
visitaWrapItem['VAW_DTINICIO'] != null
item['VAW_DTINICIO'] != '' && item['VAW_DTINICIO'] != null
? 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")}:':
visitaWrapItem['VAW_DTFIM'] != '' &&
visitaWrapItem['VAW_DTFIM'] != null
item['VAW_DTFIM'] != '' && item['VAW_DTFIM'] != null
? ValidatorUtil.toLocalDateTime(
'yyyy-MM-dd HH:mm:ss', visitaWrapItem['VAW_DTFIM'])
'yyyy-MM-dd HH:mm:ss', item['VAW_DTFIM'])
: '',
}),
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: [
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.active)
if (getStatus(item['VAW_STATUS']) == status.active)
Map<String, Color>.from({
FFLocalizations.of(context).getVariableText(
ptText: 'Ativo',
enText: 'Active',
): FlutterFlowTheme.of(context).warning,
}),
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.unknown)
if (getStatus(item['VAW_STATUS']) == status.unknown)
Map<String, Color>.from({
FFLocalizations.of(context).getVariableText(
ptText: 'Pendente',
enText: 'Pending',
): FlutterFlowTheme.of(context).alternate,
}),
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.canceled)
if (getStatus(item['VAW_STATUS']) == status.canceled)
Map<String, Color>.from({
FFLocalizations.of(context).getVariableText(
ptText: 'Cancelado',
enText: 'Canceled',
): FlutterFlowTheme.of(context).error,
}),
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.finished)
if (getStatus(item['VAW_STATUS']) == status.finished)
Map<String, Color>.from({
FFLocalizations.of(context).getVariableText(
ptText: 'Finalizado',
enText: 'Finished',
): FlutterFlowTheme.of(context).success,
}),
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.blocked)
if (getStatus(item['VAW_STATUS']) == status.blocked)
Map<String, Color>.from({
FFLocalizations.of(context).getVariableText(
ptText: 'Bloqueado',
enText: 'Blocked',
): FlutterFlowTheme.of(context).error,
}),
if (getStatus(visitaWrapItem['VAW_STATUS']) == status.inactive)
if (getStatus(item['VAW_STATUS']) == status.inactive)
Map<String, Color>.from({
FFLocalizations.of(context).getVariableText(
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';
const kThemeModeKey = '__theme_mode__';
SharedPreferences? _prefs;

View File

@ -201,7 +201,16 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) => GoRouter(
FFRoute(
name: 'petsPage',
path: '/petsPage',
builder: (context, params) => PetsPageWidget(),
builder: (context, params) {
final pet = params.getParam(
'pet',
ParamType.JSON,
);
return PetsPageWidget(
pet: pet,
);
},
),
// FFRoute(
// name: 'settingsPage',

View File

@ -79,6 +79,7 @@ class _AppState extends State<App> {
Future.delayed(const Duration(milliseconds: 1000),
() => setState(() => _appStateNotifier.stopShowingSplashImage()));
}
//
// Future<void> showCustomTrackingDialog(BuildContext context) async {
// await showDialog<void>(
@ -115,8 +116,6 @@ class _AppState extends State<App> {
// log("UUID de Publicidade: $uuid");
// }
void setLocale(String language) {
setState(() => _locale = createLocale(language));
FFLocalizations.storeLocale(language);

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

@ -13,13 +13,12 @@ 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 =
FFUploadedFile(bytes: Uint8List.fromList([]));
FFUploadedFile? uploadedLocalFile;
String? imgBase64;
// Controller para o DropDown
@ -148,7 +147,7 @@ class PetsPageModel extends FlutterFlowModel<PetsPageWidget> {
// Validador do formulário
bool isFormValid(BuildContext context) {
if (uploadedLocalFile.bytes?.isEmpty ?? true) {
if (uploadedLocalFile == null) {
return false;
}
if (textControllerName.text.isEmpty ||
@ -175,17 +174,47 @@ class PetsPageModel extends FlutterFlowModel<PetsPageWidget> {
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) {
log(response.jsonBody.toString());
if (response.jsonBody['error'] == true) {
DialogUtil.error(buildContext!,
jsonDecode(response.jsonBody['error_msg'])[0]['message']);
}
}).catchError((error) {
log(error.toString());
DialogUtil.errorDefault(buildContext!);
});
}
Future<void> registerPet() async {
if (isFormValid == true) {
await PhpGroup.registerPet
.call(
cliID: AppState().cliUUID,
devUUID: AppState().devUUID,
userUUID: AppState().userUUID,
image: await actions.convertImageFileToBase64(
uploadedLocalFile,
uploadedLocalFile!,
),
// birthdayDate: textControllerData!.text,
birthdayDate: textControllerData!.text,
color: textControllerColor!.text,
breed: textControllerRace!.text,
species: textControllerSpecies!.text,
@ -195,14 +224,18 @@ class PetsPageModel extends FlutterFlowModel<PetsPageWidget> {
notes: textControllerObservation!.text,
)
.then((response) {
if (response.jsonBody['error'] == true)
log('Erro ao registrar pet: ${response.jsonBody}');
return DialogUtil.errorDefault(buildContext!);
return true;
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) {
log(error.toString());
return DialogUtil.errorDefault(buildContext!);
DialogUtil.errorDefault(buildContext!);
});
}
}
}

View File

@ -1,12 +1,16 @@
import 'dart:convert';
import 'dart:developer';
import 'package:easy_debounce/easy_debounce.dart';
import 'package:flutter/material.dart';
import 'package:crypto/crypto.dart' as crypto;
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart';
import 'package:hub/backend/api_requests/api_calls.dart';
import 'package:hub/backend/api_requests/api_service.dart';
import 'package:hub/components/atomic_components/shared_components_atoms/appbar.dart';
import 'package:hub/components/atomic_components/shared_components_atoms/custom_datepicker.dart';
@ -15,6 +19,7 @@ import 'package:hub/components/atomic_components/shared_components_atoms/custom_
import 'package:hub/components/atomic_components/shared_components_atoms/media_upload_button.dart';
import 'package:hub/components/atomic_components/shared_components_atoms/submit_button.dart';
import 'package:hub/components/atomic_components/shared_components_atoms/tabview.dart';
import 'package:hub/custom_code/actions/convert_to_upload_file.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
@ -23,6 +28,7 @@ import 'package:hub/flutter_flow/form_field_controller.dart';
import 'package:hub/flutter_flow/internationalization.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/flutter_flow/upload_data.dart';
import 'package:hub/pages/pets_page/pets_history_screen.dart';
import 'package:hub/pages/pets_page/pets_page_model.dart';
import 'package:hub/shared/utils/dialog_util.dart';
@ -31,7 +37,12 @@ import 'package:sqflite/sqflite.dart';
import '/custom_code/actions/index.dart' as actions;
class PetsPageWidget extends StatefulWidget {
PetsPageWidget({super.key});
dynamic pet;
PetsPageWidget({
super.key,
this.pet,
});
@override
State<PetsPageWidget> createState() => _PetsPageWidgetState();
@ -41,39 +52,7 @@ class _PetsPageWidgetState extends State<PetsPageWidget>
with SingleTickerProviderStateMixin {
late PetsPageModel _model;
final _formKey = GlobalKey<FormState>();
Future<void> registerPet() async {
await PhpGroup.registerPet
.call(
cliID: AppState().cliUUID,
devUUID: AppState().devUUID,
userUUID: AppState().userUUID,
image: await actions.convertImageFileToBase64(
_model.uploadedLocalFile,
),
birthdayDate: _model.textControllerData!.text,
color: _model.textControllerColor!.text,
breed: _model.textControllerRace!.text,
species: _model.textControllerSpecies!.text,
name: _model.textControllerName!.text,
gender: _model.dropDownValue1!,
size: _model.dropDownValue2!,
notes: _model.textControllerObservation!.text,
)
.then((response) {
log('aqui é pá');
if (response.jsonBody['error'] == true) {
DialogUtil.error(
context, jsonDecode(response.jsonBody['error_msg'])[0]['message']);
log('aqui é trum');
}
}).catchError((error) {
log('aqui é pum');
DialogUtil.errorDefault(context);
});
}
bool isEditing = false;
@override
void initState() {
@ -81,24 +60,54 @@ class _PetsPageWidgetState extends State<PetsPageWidget>
_model = PetsPageModel();
_model.tabBarController = TabController(length: 2, vsync: this);
_model.textControllerName ??= TextEditingController();
widget.pet != null ? isEditing = true : isEditing = false;
// _handleUploadComplete(actions.convertToUploadFile())
if (widget.pet != null) {
int petId = widget.pet['id'];
_model.petId = petId;
(() async {
Response response = await get(Uri.parse(
'https://freaccess.com.br/freaccess/getImage.php?devUUID=${AppState().devUUID}&userUUID=${AppState().userUUID}&cliID=${AppState().cliUUID}&atividade=consultaFotoPet&petId=$petId'));
String base64 = base64Encode(response.bodyBytes);
FFUploadedFile uploadedFile = await convertToUploadFile(base64);
_handleUploadComplete(uploadedFile);
})();
}
_model.textControllerName ??= TextEditingController(
text: widget.pet != null ? widget.pet['name'] : '');
_model.textFieldFocusName ??= FocusNode();
_model.textControllerSpecies ??= TextEditingController();
_model.textControllerSpecies ??= TextEditingController(
text: widget.pet != null ? widget.pet['species'] : '');
_model.textFieldFocusSpecies ??= FocusNode();
_model.textControllerRace ??= TextEditingController();
_model.textControllerRace ??= TextEditingController(
text: widget.pet != null ? widget.pet['breed'] : '');
_model.textFieldFocusRace ??= FocusNode();
_model.textControllerColor ??= TextEditingController();
_model.textControllerColor ??= TextEditingController(
text: widget.pet != null ? widget.pet['color'] : '');
_model.textFieldFocusColor ??= FocusNode();
_model.textControllerData ??= TextEditingController();
_model.textControllerData ??= TextEditingController(
text: widget.pet != null
? ValidatorUtil.formatDateTimePicker(widget.pet['birthdayDate'])
: '');
_model.textFieldFocusData ??= FocusNode();
_model.textControllerObservation ??= TextEditingController();
_model.textControllerObservation ??= TextEditingController(
text: widget.pet != null ? widget.pet['notes'] : '');
_model.textFieldFocusObservation ??= FocusNode();
if (widget.pet != null) {
_model.dropDownValue1 ??= widget.pet['gender'] ?? '';
_model.dropDownValue2 ??= widget.pet['size'] ?? '';
}
_model.dropDownValueController1 ??=
FormFieldController<String>(_model.dropDownValue1 ??= '');
@ -113,6 +122,7 @@ class _PetsPageWidgetState extends State<PetsPageWidget>
}
void _handleUploadComplete(FFUploadedFile uploadedFile) {
log('Chamou o handleUploadComplete');
setState(() {
_model.uploadedLocalFile = uploadedFile;
});
@ -120,6 +130,7 @@ class _PetsPageWidgetState extends State<PetsPageWidget>
@override
Widget build(BuildContext context) {
log('Chamou o build');
_model.buildContext = context;
return Scaffold(
appBar: _buildAppBar(context),
@ -135,11 +146,14 @@ class _PetsPageWidgetState extends State<PetsPageWidget>
return TabViewUtil(
context: context,
model: _model,
labelTab1: 'Cadastrar',
labelTab2: 'Consultar',
labelTab1: FFLocalizations.of(context)
.getVariableText(ptText: 'Cadastrar', enText: 'Register'),
labelTab2: FFLocalizations.of(context)
.getVariableText(ptText: 'Consultar', enText: 'History'),
controller: _model.tabBarController,
widget1: _buildRegisterForm(context),
widget2: const Center(child: Text('Consultar')),
widget1:
isEditing ? _buildEditForm(context) : _buildRegisterForm(context),
widget2: PetsHistoryScreen(),
);
}
@ -209,7 +223,8 @@ class _PetsPageWidgetState extends State<PetsPageWidget>
hintText: FFLocalizations.of(context).getVariableText(
ptText: 'Espécie', enText: 'Species'),
suffixIcon: Icons.pest_control,
haveMaxLength: false,
haveMaxLength: true,
maxLength: 80,
),
),
Padding(
@ -224,7 +239,8 @@ class _PetsPageWidgetState extends State<PetsPageWidget>
hintText: FFLocalizations.of(context)
.getVariableText(ptText: 'Raça', enText: 'Race'),
suffixIcon: Icons.pets,
haveMaxLength: false,
haveMaxLength: true,
maxLength: 80,
),
),
Padding(
@ -239,7 +255,467 @@ class _PetsPageWidgetState extends State<PetsPageWidget>
hintText: FFLocalizations.of(context)
.getVariableText(ptText: 'Cor', enText: 'Color'),
suffixIcon: Icons.invert_colors,
haveMaxLength: false,
haveMaxLength: true,
maxLength: 80,
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 15),
child: 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: _model.textControllerData,
focusNode: _model.textFieldFocusData,
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: FFLocalizations.of(context)
.getVariableText(
ptText: 'Data de Nascimento',
enText: 'Date of Birth',
),
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: _model
.textControllerDataValidator
.asValidator(context),
),
),
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: () async {
final pickedDate = await showDatePicker(
context: context,
initialDate: getCurrentTimestamp,
firstDate: DateTime(1990),
lastDate: DateTime.now(),
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) {
setState(() {
log('Chamou o setState da datinha');
_model.selectedDate = DateTime(
pickedDate.year,
pickedDate.month,
pickedDate.day,
);
log(_model.selectedDate.toString());
_model.textControllerData =
TextEditingController(
text: dateTimeFormat(
'dd/MM/yyyy',
_model.selectedDate,
locale: FFLocalizations.of(context)
.languageCode,
));
log(_model.textControllerData.text);
_model.textControllerData?.selection =
TextSelection.collapsed(
offset: _model.textControllerData!
.text.length,
);
});
}
},
child: Container(
width: double.infinity,
height: 80.0,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(10.0),
),
),
),
),
],
),
),
],
),
),
Align(
alignment: const AlignmentDirectional(-1.0, 0.0),
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(
24.0, 0, 0.0, 15),
child: Text(
FFLocalizations.of(context).getVariableText(
ptText: 'Selecione as opções disponíveis',
enText: 'Select the available options',
),
textAlign: TextAlign.start,
style: FlutterFlowTheme.of(context)
.bodySmall
.override(
fontFamily: FlutterFlowTheme.of(context)
.bodySmallFamily,
letterSpacing: 0.0,
fontWeight: FontWeight.w600,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context)
.bodyMediumFamily),
),
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 15),
child: CustomSelect(
options: const ['MAC', 'FEM'],
controller: _model.dropDownValueController1 ??=
FormFieldController<String>(
_model.dropDownValue1 ??= ''),
isRequired: true,
changed: (val) => safeSetState(() {
_model.dropDownValue1 = val;
}),
dropDownValue: _model.dropDownValue1,
optionsLabel: [
FFLocalizations.of(context).getVariableText(
ptText: 'Macho', enText: 'Male'),
FFLocalizations.of(context).getVariableText(
ptText: 'Fêmea', enText: 'Female')
],
hintText: FFLocalizations.of(context).getVariableText(
ptText: 'Selecione o gênero do Pet',
enText: 'Select the gender of the Pet')),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 15),
child: CustomSelect(
options: const ['MIN', 'PEQ', 'MED', 'GRA', 'GIG'],
controller: _model.dropDownValueController2 ??=
FormFieldController<String>(
_model.dropDownValue2 ??= ''),
isRequired: true,
changed: (val) => safeSetState(() {
_model.dropDownValue2 = val;
}),
optionsLabel: [
FFLocalizations.of(context).getVariableText(
ptText: 'Mini', enText: 'Mini'),
FFLocalizations.of(context).getVariableText(
ptText: 'Pequeno', enText: 'Small'),
FFLocalizations.of(context).getVariableText(
ptText: 'Médio', enText: 'Medium'),
FFLocalizations.of(context).getVariableText(
ptText: 'Grande', enText: 'Big'),
FFLocalizations.of(context).getVariableText(
ptText: 'Gigante', enText: 'Giant'),
],
hintText: FFLocalizations.of(context).getVariableText(
ptText: 'Selecione o porte do Pet',
enText: 'Select the size of the Pet')),
),
Align(
alignment: const AlignmentDirectional(-1.0, 0.0),
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(
24.0, 0, 0.0, 15),
child: Text(
FFLocalizations.of(context).getVariableText(
ptText:
'Você tem alguma observação sobre o seu Pet?',
enText:
'Do you have any observations about your Pet?',
),
textAlign: TextAlign.start,
style: FlutterFlowTheme.of(context)
.bodySmall
.override(
fontFamily: FlutterFlowTheme.of(context)
.bodySmallFamily,
letterSpacing: 0.0,
fontWeight: FontWeight.w600,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context)
.bodyMediumFamily),
),
),
),
),
CustomInputUtil(
controller: _model.textControllerObservation,
validator: _model.textControllerObservationValidator
.asValidator(context),
focusNode: _model.textFieldFocusObservation,
labelText: FFLocalizations.of(context).getVariableText(
ptText: 'Escreva as suas observações aqui...',
enText: 'Write your observations here...'),
hintText: FFLocalizations.of(context).getVariableText(
ptText: 'Escreva as suas observações aqui...',
enText: 'Write your observations here...'),
suffixIcon: Icons.text_fields,
haveMaxLength: true,
maxLength: 80,
),
Padding(
padding: const EdgeInsets.fromLTRB(70, 20, 70, 30),
child: SubmitButtonUtil(
labelText: FFLocalizations.of(context)
.getVariableText(
ptText: 'Cadastrar', enText: 'Register'),
onPressed: _model.isFormValid(context)
? _model.registerPet
: null),
),
])),
],
),
);
}
Widget _buildEditForm(BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Align(
alignment: const AlignmentDirectional(-1.0, 0.0),
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(24.0, 20, 0.0, 15),
child: Text(
FFLocalizations.of(context).getVariableText(
ptText: 'Preencha o formulário com os dados do seu Pet',
enText: 'Fill out the form with your Pet\'s data',
),
textAlign: TextAlign.start,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).bodyMediumFamily),
),
),
),
),
Form(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 20),
child: MediaUploadButtonUtil(
onUploadComplete: _handleUploadComplete,
isUploading: _model.isDataUploading,
uploadedFiles: _model.uploadedLocalFile,
labelText: FFLocalizations.of(context).getVariableText(
ptText: 'Clique para adicionar a foto de seu Pet',
enText: 'Click to add your Pet\'s photo'),
),
),
CustomInputUtil(
controller: _model.textControllerName,
validator: _model.textControllerNameValidator
.asValidator(context),
focusNode: _model.textFieldFocusName,
labelText: FFLocalizations.of(context)
.getVariableText(ptText: 'Nome', enText: 'Name'),
hintText: FFLocalizations.of(context)
.getVariableText(ptText: 'Nome', enText: 'Name'),
suffixIcon: Icons.person,
haveMaxLength: true,
maxLength: 80,
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 15),
child: CustomInputUtil(
controller: _model.textControllerSpecies,
validator: _model.textControllerSpeciesValidator
.asValidator(context),
focusNode: _model.textFieldFocusSpecies,
labelText: FFLocalizations.of(context).getVariableText(
ptText: 'Espécie', enText: 'Species'),
hintText: FFLocalizations.of(context).getVariableText(
ptText: 'Espécie', enText: 'Species'),
suffixIcon: Icons.pest_control,
haveMaxLength: true,
maxLength: 80,
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 15),
child: CustomInputUtil(
controller: _model.textControllerRace,
validator: _model.textControllerRaceValidator
.asValidator(context),
focusNode: _model.textFieldFocusRace,
labelText: FFLocalizations.of(context)
.getVariableText(ptText: 'Raça', enText: 'Race'),
hintText: FFLocalizations.of(context)
.getVariableText(ptText: 'Raça', enText: 'Race'),
suffixIcon: Icons.pets,
haveMaxLength: true,
maxLength: 80,
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 15),
child: CustomInputUtil(
controller: _model.textControllerColor,
validator: _model.textControllerColorValidator
.asValidator(context),
focusNode: _model.textFieldFocusColor,
labelText: FFLocalizations.of(context)
.getVariableText(ptText: 'Cor', enText: 'Color'),
hintText: FFLocalizations.of(context)
.getVariableText(ptText: 'Cor', enText: 'Color'),
suffixIcon: Icons.invert_colors,
haveMaxLength: true,
maxLength: 80,
),
),
Padding(
@ -587,9 +1063,10 @@ class _PetsPageWidgetState extends State<PetsPageWidget>
child: SubmitButtonUtil(
labelText: FFLocalizations.of(context)
.getVariableText(
ptText: 'Cadastrar', enText: 'Register'),
onPressed:
_model.isFormValid(context) ? registerPet : null),
ptText: 'Salvar', enText: 'Save'),
onPressed: _model.isFormValid(context)
? _model.updatePet
: null),
),
])),
],

View File

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

View File

@ -20,10 +20,22 @@ class ValidatorUtil {
}
static String toISO8601(String format, String value) {
log('value: $value');
DateFormat dateFormat = DateFormat(format);
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';
log('date: $date');
return date;
}
static String toLocalDateTime(String format, String value) {
@ -32,4 +44,13 @@ class ValidatorUtil {
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
version: "0.3.4+2"
crypto:
dependency: transitive
dependency: "direct main"
description:
name: crypto
sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27
@ -241,6 +241,22 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: "direct main"
description:

View File

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