This commit is contained in:
2026-06-30 17:00:31 +01:00
parent 824ff28001
commit 9d57ed4d0a
8 changed files with 330 additions and 112 deletions

View File

@@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-06-25T17:21:43.291530Z">
<DropdownSelection timestamp="2026-06-30T15:58:20.952343Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/Users/230409/.android/avd/Pixel_8_Pro.avd" />
<DeviceId pluginId="LocalEmulator" identifier="path=/Users/230409/.android/avd/Pixel_8_Pro_2.avd" />
</handle>
</Target>
</DropdownSelection>

View File

@@ -232,16 +232,23 @@ public class EstablishmentDashboardActivity extends AppCompatActivity {
.addValueEventListener(new com.google.firebase.database.ValueEventListener() {
@Override
public void onDataChange(@androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
int totalMesas = 0;
int mesasOcupadas = 0;
int mesasLivres = 0;
for (com.google.firebase.database.DataSnapshot ds : snapshot.getChildren()) {
com.example.pap_teste.models.Mesa mesa = ds.getValue(com.example.pap_teste.models.Mesa.class);
if (mesa != null && mesa.getRestauranteEmail() != null && mesa.getRestauranteEmail().trim().equalsIgnoreCase(finalEmail)) {
if ("Livre".equalsIgnoreCase(mesa.getEstado())) {
if (mesa != null && (mesa.getRestauranteEmail() == null || mesa.getRestauranteEmail().trim().equalsIgnoreCase(finalEmail))) {
totalMesas++;
if ("Ocupada".equalsIgnoreCase(mesa.getEstado()) || "Reservada".equalsIgnoreCase(mesa.getEstado())) {
mesasOcupadas++;
} else if ("Livre".equalsIgnoreCase(mesa.getEstado())) {
mesasLivres++;
}
}
}
if (txtMesasLivres != null) txtMesasLivres.setText(String.format(java.util.Locale.US, "%02d", mesasLivres));
if (txtMesasLivres != null) txtMesasLivres.setText(mesasOcupadas + " / " + totalMesas);
TextView txtMesasLivresSub = findViewById(R.id.txtMesasLivresSub);
if (txtMesasLivresSub != null) txtMesasLivresSub.setText(mesasLivres + " livres");
}
@Override
public void onCancelled(@androidx.annotation.NonNull com.google.firebase.database.DatabaseError error) {

View File

@@ -89,6 +89,13 @@ public class ExplorarRestaurantesActivity extends AppCompatActivity {
txtTitle.setText("Reserva: " + (selectedRestaurant != null ? selectedRestaurant.getName() : ""));
setupReservationOptions();
loadRestaurantRating();
boolean isFechado = selectedRestaurant != null && selectedRestaurant.isFechadoWebsite();
findViewById(R.id.btnSelectDate).setEnabled(!isFechado);
findViewById(R.id.btnSelectTime).setEnabled(!isFechado);
android.view.View etPartySize = findViewById(R.id.etPartySize);
if (etPartySize != null) etPartySize.setEnabled(!isFechado);
findViewById(R.id.btnConfirmarReserva).setEnabled(!isFechado);
}
}
@@ -160,8 +167,32 @@ public class ExplorarRestaurantesActivity extends AppCompatActivity {
String logoUrl = ds.child("logoUrl").getValue(String.class);
if (name != null && email != null) {
restaurantsList
.add(new com.example.pap_teste.models.Restaurant(name, cat, email, false, logoUrl));
com.example.pap_teste.models.Restaurant rest = new com.example.pap_teste.models.Restaurant(name, cat, email, false, logoUrl);
Boolean fechadoWebsite = ds.child("fechadoWebsite").getValue(Boolean.class);
if (fechadoWebsite != null) rest.setFechadoWebsite(fechadoWebsite);
if (ds.hasChild("schedule")) {
java.util.Map<String, com.example.pap_teste.models.ScheduleDay> schMap = new java.util.HashMap<>();
for (com.google.firebase.database.DataSnapshot schDs : ds.child("schedule").getChildren()) {
com.example.pap_teste.models.ScheduleDay sd = schDs.getValue(com.example.pap_teste.models.ScheduleDay.class);
schMap.put(schDs.getKey(), sd);
}
rest.setSchedule(schMap);
} else if (ds.hasChild("operatingHours")) {
java.util.Map<String, com.example.pap_teste.models.ScheduleDay> schMap = new java.util.HashMap<>();
for (com.google.firebase.database.DataSnapshot schDs : ds.child("operatingHours").getChildren()) {
com.example.pap_teste.models.ScheduleDay sd = schDs.getValue(com.example.pap_teste.models.ScheduleDay.class);
if (schDs.hasChild("isOpen")) {
Boolean isOpen = schDs.child("isOpen").getValue(Boolean.class);
if (isOpen != null && sd != null) {
sd.setClosed(!isOpen);
}
}
schMap.put(schDs.getKey(), sd);
}
rest.setSchedule(schMap);
}
restaurantsList.add(rest);
}
}
}
@@ -192,18 +223,72 @@ public class ExplorarRestaurantesActivity extends AppCompatActivity {
btnDate.setOnClickListener(v -> {
java.util.Calendar cal = java.util.Calendar.getInstance();
new android.app.DatePickerDialog(this, (view, year, month, dayOfMonth) -> {
selectedDate = dayOfMonth + "/" + (month + 1) + "/" + year;
btnDate.setText(selectedDate);
}, cal.get(java.util.Calendar.YEAR), cal.get(java.util.Calendar.MONTH),
cal.get(java.util.Calendar.DAY_OF_MONTH)).show();
android.app.DatePickerDialog dpd = new android.app.DatePickerDialog(this, (view, year, month, dayOfMonth) -> {
java.util.Calendar selectedCal = java.util.Calendar.getInstance();
selectedCal.set(year, month, dayOfMonth);
int dayOfWeek = selectedCal.get(java.util.Calendar.DAY_OF_WEEK);
boolean isClosed = selectedRestaurant.isClosedForDay(dayOfWeek);
if (isClosed) {
android.widget.Toast.makeText(this, "O restaurante encontra-se encerrado na data selecionada.", android.widget.Toast.LENGTH_LONG).show();
selectedDate = null;
btnDate.setText("Selecionar Data");
btnTime.setEnabled(false);
} else {
selectedDate = dayOfMonth + "/" + (month + 1) + "/" + year;
btnDate.setText(selectedDate);
btnTime.setEnabled(true);
}
}, cal.get(java.util.Calendar.YEAR), cal.get(java.util.Calendar.MONTH), cal.get(java.util.Calendar.DAY_OF_MONTH));
dpd.getDatePicker().setMinDate(System.currentTimeMillis() - 1000);
dpd.show();
});
btnTime.setOnClickListener(v -> {
if (selectedDate == null) {
android.widget.Toast.makeText(this, "Por favor, selecione primeiro a data.", android.widget.Toast.LENGTH_SHORT).show();
return;
}
java.util.Calendar cal = java.util.Calendar.getInstance();
new android.app.TimePickerDialog(this, (view, hourOfDay, minute) -> {
selectedTime = String.format(java.util.Locale.getDefault(), "%02d:%02d", hourOfDay, minute);
btnTime.setText(selectedTime);
String chosenTime = String.format(java.util.Locale.getDefault(), "%02d:%02d", hourOfDay, minute);
boolean isOutOfHours = false;
if (selectedDate != null && selectedRestaurant.getSchedule() != null) {
try {
java.util.Date d = new java.text.SimpleDateFormat("d/M/yyyy", java.util.Locale.getDefault()).parse(selectedDate);
java.util.Calendar selectedCal = java.util.Calendar.getInstance();
if (d != null) selectedCal.setTime(d);
int dayOfWeek = selectedCal.get(java.util.Calendar.DAY_OF_WEEK);
com.example.pap_teste.models.ScheduleDay sd = selectedRestaurant.getScheduleForDay(dayOfWeek);
if (sd != null && !sd.isClosed()) {
if (sd.getOpenTime() != null && sd.getCloseTime() != null && !sd.getOpenTime().isEmpty() && !sd.getCloseTime().isEmpty()) {
String open = sd.getOpenTime();
String close = sd.getCloseTime();
if (open.compareTo(close) < 0) {
if (chosenTime.compareTo(open) < 0 || chosenTime.compareTo(close) > 0) {
isOutOfHours = true;
}
} else {
if (chosenTime.compareTo(open) < 0 && chosenTime.compareTo(close) > 0) {
isOutOfHours = true;
}
}
}
}
} catch (Exception e) {}
}
if (isOutOfHours) {
android.widget.Toast.makeText(this, "Por favor selecione uma hora dentro do horário de funcionamento.", android.widget.Toast.LENGTH_LONG).show();
selectedTime = null;
btnTime.setText("Selecionar Hora");
} else {
selectedTime = chosenTime;
btnTime.setText(selectedTime);
}
}, cal.get(java.util.Calendar.HOUR_OF_DAY), cal.get(java.util.Calendar.MINUTE), true).show();
});

View File

@@ -154,6 +154,27 @@ public class NovaReservaActivity extends AppCompatActivity {
schMap.put(schDs.getKey(), sd);
}
rest.setSchedule(schMap);
} else if (ds.hasChild("operatingHours")) {
java.util.Map<String, com.example.pap_teste.models.ScheduleDay> schMap = new java.util.HashMap<>();
for (com.google.firebase.database.DataSnapshot schDs : ds.child("operatingHours").getChildren()) {
com.example.pap_teste.models.ScheduleDay sd = schDs.getValue(com.example.pap_teste.models.ScheduleDay.class);
// Handle case where operatingHours has isOpen instead of closed
if (schDs.hasChild("isOpen")) {
Boolean isOpen = schDs.child("isOpen").getValue(Boolean.class);
if (isOpen != null && sd != null) {
sd.setClosed(!isOpen);
}
}
schMap.put(schDs.getKey(), sd);
}
rest.setSchedule(schMap);
} else if (ds.hasChild("horario")) {
java.util.Map<String, com.example.pap_teste.models.ScheduleDay> schMap = new java.util.HashMap<>();
for (com.google.firebase.database.DataSnapshot schDs : ds.child("horario").getChildren()) {
com.example.pap_teste.models.ScheduleDay sd = schDs.getValue(com.example.pap_teste.models.ScheduleDay.class);
schMap.put(schDs.getKey(), sd);
}
rest.setSchedule(schMap);
}
filteredList.add(rest);
}
@@ -189,18 +210,12 @@ public class NovaReservaActivity extends AppCompatActivity {
btnDate.setOnClickListener(v -> {
java.util.Calendar cal = java.util.Calendar.getInstance();
new android.app.DatePickerDialog(this, (view, year, month, dayOfMonth) -> {
android.app.DatePickerDialog dpd = new android.app.DatePickerDialog(this, (view, year, month, dayOfMonth) -> {
java.util.Calendar selectedCal = java.util.Calendar.getInstance();
selectedCal.set(year, month, dayOfMonth);
int dayOfWeek = selectedCal.get(java.util.Calendar.DAY_OF_WEEK);
String[] dayKeys = {"sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"};
String dayKey = dayKeys[dayOfWeek - 1];
boolean isClosed = false;
if (selectedRestaurant.getSchedule() != null && selectedRestaurant.getSchedule().containsKey(dayKey)) {
com.example.pap_teste.models.ScheduleDay sd = selectedRestaurant.getSchedule().get(dayKey);
if (sd != null && sd.isClosed()) isClosed = true;
}
boolean isClosed = selectedRestaurant.isClosedForDay(dayOfWeek);
if (isClosed) {
android.widget.Toast.makeText(this, "O restaurante encontra-se encerrado na data selecionada.", android.widget.Toast.LENGTH_LONG).show();
@@ -212,8 +227,9 @@ public class NovaReservaActivity extends AppCompatActivity {
btnDate.setText(selectedDate);
btnTime.setEnabled(true);
}
}, cal.get(java.util.Calendar.YEAR), cal.get(java.util.Calendar.MONTH),
cal.get(java.util.Calendar.DAY_OF_MONTH)).show();
}, cal.get(java.util.Calendar.YEAR), cal.get(java.util.Calendar.MONTH), cal.get(java.util.Calendar.DAY_OF_MONTH));
dpd.getDatePicker().setMinDate(System.currentTimeMillis() - 1000);
dpd.show();
});
btnTime.setOnClickListener(v -> {
@@ -232,14 +248,20 @@ public class NovaReservaActivity extends AppCompatActivity {
java.util.Calendar selectedCal = java.util.Calendar.getInstance();
if (d != null) selectedCal.setTime(d);
int dayOfWeek = selectedCal.get(java.util.Calendar.DAY_OF_WEEK);
String[] dayKeys = {"sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"};
String dayKey = dayKeys[dayOfWeek - 1];
com.example.pap_teste.models.ScheduleDay sd = selectedRestaurant.getSchedule().get(dayKey);
com.example.pap_teste.models.ScheduleDay sd = selectedRestaurant.getScheduleForDay(dayOfWeek);
if (sd != null && !sd.isClosed()) {
if (sd.getOpenTime() != null && sd.getCloseTime() != null && !sd.getOpenTime().isEmpty() && !sd.getCloseTime().isEmpty()) {
if (chosenTime.compareTo(sd.getOpenTime()) < 0 || chosenTime.compareTo(sd.getCloseTime()) > 0) {
isOutOfHours = true;
String open = sd.getOpenTime();
String close = sd.getCloseTime();
if (open.compareTo(close) < 0) {
if (chosenTime.compareTo(open) < 0 || chosenTime.compareTo(close) > 0) {
isOutOfHours = true;
}
} else {
if (chosenTime.compareTo(open) < 0 && chosenTime.compareTo(close) > 0) {
isOutOfHours = true;
}
}
}
}

View File

@@ -53,4 +53,40 @@ public class Restaurant implements Serializable {
private java.util.Map<String, ScheduleDay> schedule;
public java.util.Map<String, ScheduleDay> getSchedule() { return schedule; }
public void setSchedule(java.util.Map<String, ScheduleDay> schedule) { this.schedule = schedule; }
public ScheduleDay getScheduleForDay(int dayOfWeekCalendar) {
if (schedule == null) return null;
String[] dayKeys = {"sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"};
String[] dayKeysPt = {"domingo", "segunda-feira", "terça-feira", "quarta-feira", "quinta-feira", "sexta-feira", "sábado"};
String[] dayKeysPtShort = {"domingo", "segunda", "terça", "quarta", "quinta", "sexta", "sábado"};
int index = dayOfWeekCalendar - 1;
ScheduleDay sd = schedule.get(dayKeys[index]);
if (sd == null) sd = schedule.get(dayKeysPt[index]);
if (sd == null) sd = schedule.get(dayKeysPtShort[index]);
if (sd == null) sd = schedule.get(String.valueOf(index));
if (sd == null) {
for (java.util.Map.Entry<String, ScheduleDay> entry : schedule.entrySet()) {
String k = entry.getKey().toLowerCase(java.util.Locale.ROOT).replace("-", "").replace(" ", "");
String expected1 = dayKeys[index].replace("-", "");
String expected2 = dayKeysPt[index].replace("-", "");
String expected3 = dayKeysPtShort[index].replace("-", "");
if (k.equals(expected1) || k.equals(expected2) || k.equals(expected3) || k.equals(String.valueOf(index))) {
return entry.getValue();
}
}
}
return sd;
}
public boolean isClosedForDay(int dayOfWeekCalendar) {
if (schedule == null || schedule.isEmpty()) return false; // If no schedule is set at all, default to open to avoid locking out old restaurants.
ScheduleDay sd = getScheduleForDay(dayOfWeekCalendar);
if (sd == null) {
return true; // Se o dia não existe no mapa de um restaurante com horário, está fechado.
}
return sd.isClosed();
}
}

View File

@@ -4,6 +4,7 @@ import java.io.Serializable;
public class ScheduleDay implements Serializable {
private boolean closed;
private Boolean isOpen;
private String openTime;
private String closeTime;
@@ -13,16 +14,49 @@ public class ScheduleDay implements Serializable {
public ScheduleDay(boolean closed, String openTime, String closeTime) {
this.closed = closed;
this.isOpen = !closed;
this.openTime = openTime;
this.closeTime = closeTime;
}
public boolean isClosed() {
if (isOpen != null) {
return !isOpen;
}
return closed;
}
public void setClosed(boolean closed) {
this.closed = closed;
if (this.isOpen == null) {
this.isOpen = !closed;
}
}
// Handles potential "isClosed" boolean in Firebase
public void setIsClosed(Boolean isClosed) {
if (isClosed != null) {
this.closed = isClosed;
this.isOpen = !isClosed;
}
}
// Handles potential "fechado" boolean from Portuguese web dashboards
public void setFechado(Boolean fechado) {
if (fechado != null) {
this.closed = fechado;
this.isOpen = !fechado;
}
}
@com.google.firebase.database.PropertyName("isOpen")
public Boolean getIsOpen() {
return isOpen;
}
@com.google.firebase.database.PropertyName("isOpen")
public void setIsOpen(Boolean isOpen) {
this.isOpen = isOpen;
}
public String getOpenTime() {

View File

@@ -71,116 +71,150 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:orientation="horizontal">
android:orientation="vertical">
<!-- MESAS OCUPADAS CARD -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardReservasHoje"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:layout_weight="1"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/colorSurface"
app:cardBackgroundColor="#1F1D1A"
app:cardCornerRadius="16dp"
app:cardElevation="2dp">
<LinearLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
android:padding="20dp">
<TextView
android:id="@+id/lblMesasOcupadas"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reservas"
android:textColor="@color/colorTextSecondary"
android:textSize="13sp" />
android:text="MESAS OCUPADAS"
android:textColor="#888175"
android:textSize="14sp"
android:letterSpacing="0.05"
android:fontFamily="serif"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/txtReservasHojeDash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="00"
android:textColor="@color/colorPrimary"
android:textSize="30sp"
android:fontFamily="sans-serif-medium" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:layout_weight="1"
app:cardBackgroundColor="@color/colorSurface"
app:cardCornerRadius="16dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mesas"
android:textColor="@color/colorTextSecondary"
android:textSize="13sp" />
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_clock_gold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="@id/lblMesasOcupadas" />
<TextView
android:id="@+id/txtMesasLivresDash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="00"
android:textColor="@color/colorTextPrimary"
android:textSize="30sp"
android:fontFamily="sans-serif-medium" />
</LinearLayout>
android:layout_marginTop="16dp"
android:text="0 / 0"
android:textColor="#FFFFFF"
android:textSize="38sp"
android:fontFamily="serif-monospace"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/lblMesasOcupadas" />
<TextView
android:id="@+id/txtMesasLivresSub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="0 livres"
android:textColor="#D4AF37"
android:textSize="16sp"
android:fontFamily="sans-serif-medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/txtMesasLivresDash" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:layout_width="0dp"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_weight="1"
app:cardBackgroundColor="@color/colorSurface"
app:cardCornerRadius="16dp"
app:cardElevation="2dp">
android:layout_marginTop="12dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
<!-- RESERVAS CARD -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardReservasHoje"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
android:layout_marginEnd="6dp"
android:layout_weight="1"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/colorSurface"
app:cardCornerRadius="16dp"
app:cardElevation="2dp">
<TextView
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Espera"
android:textColor="@color/colorTextSecondary"
android:textSize="13sp" />
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/txtListaEsperaDash"
android:layout_width="wrap_content"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reservas"
android:textColor="@color/colorTextSecondary"
android:textSize="13sp" />
<TextView
android:id="@+id/txtReservasHojeDash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="00"
android:textColor="@color/colorPrimary"
android:textSize="30sp"
android:fontFamily="sans-serif-medium" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- ESPERA CARD -->
<com.google.android.material.card.MaterialCardView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_weight="1"
app:cardBackgroundColor="@color/colorSurface"
app:cardCornerRadius="16dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="00"
android:textColor="@color/colorWarning"
android:textSize="30sp"
android:fontFamily="sans-serif-medium" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Espera"
android:textColor="@color/colorTextSecondary"
android:textSize="13sp" />
<TextView
android:id="@+id/txtListaEsperaDash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="00"
android:textColor="@color/colorWarning"
android:textSize="30sp"
android:fontFamily="sans-serif-medium" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</LinearLayout>
<TextView

View File

@@ -1,5 +1,5 @@
[versions]
agp = "9.1.0"
agp = "9.1.1"
junit = "4.13.2"
junitVersion = "1.3.0"
espressoCore = "3.7.0"