Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3267fee439 |
@@ -34,8 +34,8 @@ android {
|
||||
applicationId = "pl.firmatpp.kierowca"
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
versionCode = 101
|
||||
versionName = "1.0.48"
|
||||
versionCode = 102
|
||||
versionName = "1.0.49"
|
||||
setProperty("archivesBaseName", "pl.firmatpp.kierowca")
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
||||
@@ -1053,10 +1053,23 @@ private fun LeaveCalendarScreen(
|
||||
val context = LocalContext.current
|
||||
val listState = rememberLazyListState()
|
||||
val months = remember(state.leaveCalendarLoadedUntil) { leaveCalendarMonths(state.leaveCalendarLoadedUntil) }
|
||||
var detailsDate by remember { mutableStateOf<LocalDate?>(null) }
|
||||
val detailsEntries = detailsDate
|
||||
?.let { DriverLeaveRequestUiRules.calendarEntriesForDate(state.leaveCalendarEntries, it) }
|
||||
.orEmpty()
|
||||
var showConflictDetails by remember { mutableStateOf(false) }
|
||||
val selectedConflictEntries = remember(
|
||||
state.leaveCalendarEntries,
|
||||
state.leaveCalendarHasSelection,
|
||||
state.leaveRequestDateFrom,
|
||||
state.leaveRequestDateTo,
|
||||
) {
|
||||
if (state.leaveCalendarHasSelection) {
|
||||
DriverLeaveRequestUiRules.calendarEntriesForRange(
|
||||
entries = state.leaveCalendarEntries,
|
||||
dateFrom = state.leaveRequestDateFrom,
|
||||
dateTo = state.leaveRequestDateTo,
|
||||
)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
|
||||
LaunchedEffect(months.size, state.leaveCalendarLoading) {
|
||||
@@ -1074,6 +1087,8 @@ private fun LeaveCalendarScreen(
|
||||
bottomBar = {
|
||||
LeaveCalendarContinueBar(
|
||||
state = state,
|
||||
conflictCount = selectedConflictEntries.size,
|
||||
onShowConflicts = { showConflictDetails = true },
|
||||
onContinue = onContinue,
|
||||
)
|
||||
},
|
||||
@@ -1093,11 +1108,8 @@ private fun LeaveCalendarScreen(
|
||||
selectedFrom = state.leaveRequestDateFrom,
|
||||
selectedTo = state.leaveRequestDateTo,
|
||||
hasSelection = state.leaveCalendarHasSelection,
|
||||
onDayClick = { date, entries ->
|
||||
onDayClick = { date, _ ->
|
||||
onDateSelected(date.toString())
|
||||
if (entries.isNotEmpty()) {
|
||||
detailsDate = date
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -1121,15 +1133,15 @@ private fun LeaveCalendarScreen(
|
||||
}
|
||||
}
|
||||
|
||||
if (detailsDate != null && detailsEntries.isNotEmpty()) {
|
||||
if (showConflictDetails && selectedConflictEntries.isNotEmpty()) {
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = { detailsDate = null },
|
||||
onDismissRequest = { showConflictDetails = false },
|
||||
sheetState = sheetState,
|
||||
containerColor = TppTheme.colors.card,
|
||||
) {
|
||||
LeaveCalendarDetailsSheet(
|
||||
date = detailsDate,
|
||||
entries = detailsEntries,
|
||||
title = "Urlopy w wybranym terminie",
|
||||
entries = selectedConflictEntries,
|
||||
onCall = { dialUri ->
|
||||
context.startActivity(Intent(Intent.ACTION_DIAL, Uri.parse(dialUri)))
|
||||
},
|
||||
@@ -1139,7 +1151,12 @@ private fun LeaveCalendarScreen(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LeaveCalendarContinueBar(state: DriverUiState, onContinue: () -> Unit) {
|
||||
private fun LeaveCalendarContinueBar(
|
||||
state: DriverUiState,
|
||||
conflictCount: Int,
|
||||
onShowConflicts: () -> Unit,
|
||||
onContinue: () -> Unit,
|
||||
) {
|
||||
val selectionText = when {
|
||||
!state.leaveCalendarHasSelection -> "Wybierz pierwszy dzień urlopu"
|
||||
else -> leaveDateRange(state.leaveRequestDateFrom, state.leaveRequestDateTo)
|
||||
@@ -1178,6 +1195,28 @@ private fun LeaveCalendarContinueBar(state: DriverUiState, onContinue: () -> Uni
|
||||
Text("Dalej", fontWeight = FontWeight.Bold)
|
||||
}
|
||||
}
|
||||
if (state.leaveCalendarHasSelection && conflictCount > 0) {
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TppTheme.colors.warningContainer, RoundedCornerShape(4.dp))
|
||||
.border(1.dp, TppTheme.colors.warningOutline, RoundedCornerShape(4.dp))
|
||||
.padding(horizontal = 12.dp, vertical = 10.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(Icons.Outlined.Info, contentDescription = null, tint = Color(0xFF7A5A00), modifier = Modifier.size(20.dp))
|
||||
Text(
|
||||
"Nakłada się z ${leaveConflictCountLabel(conflictCount)}",
|
||||
color = Color(0xFF7A5A00),
|
||||
fontWeight = FontWeight.Bold,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
TextButton(onClick = onShowConflicts) {
|
||||
Text("Zobacz", color = TppTheme.colors.forest, fontWeight = FontWeight.Bold)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1307,7 +1346,7 @@ private fun LeaveCalendarDayCell(
|
||||
|
||||
@Composable
|
||||
private fun LeaveCalendarDetailsSheet(
|
||||
date: LocalDate?,
|
||||
title: String,
|
||||
entries: List<DriverLeaveCalendarEntryDto>,
|
||||
onCall: (String) -> Unit,
|
||||
) {
|
||||
@@ -1316,7 +1355,7 @@ private fun LeaveCalendarDetailsSheet(
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Text(
|
||||
date?.let { DateTimeFormatter.ofPattern("d MMMM yyyy", Locale("pl", "PL")).format(it) } ?: "Urlopy w tym dniu",
|
||||
title,
|
||||
color = TppTheme.colors.ink,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 22.sp,
|
||||
@@ -2926,6 +2965,9 @@ private fun photoCountLabel(count: Int): String =
|
||||
else -> "zdjęć"
|
||||
}
|
||||
|
||||
private fun leaveConflictCountLabel(count: Int): String =
|
||||
if (count == 1) "1 urlopem" else "$count urlopami"
|
||||
|
||||
@Composable
|
||||
private fun ManifestSection(route: DriverRouteDto, selectedDate: String, onNavigate: (NavigationPointDto) -> Unit) {
|
||||
val stripColor = routeStatusColor(route.status)
|
||||
|
||||
@@ -61,6 +61,19 @@ object DriverLeaveRequestUiRules {
|
||||
from != null && to != null && !date.isBefore(from) && !date.isAfter(to)
|
||||
}
|
||||
|
||||
fun calendarEntriesForRange(entries: List<DriverLeaveCalendarEntryDto>, dateFrom: String, dateTo: String): List<DriverLeaveCalendarEntryDto> {
|
||||
val selectedFrom = runCatching { LocalDate.parse(dateFrom) }.getOrNull() ?: return emptyList()
|
||||
val selectedTo = runCatching { LocalDate.parse(dateTo) }.getOrNull() ?: return emptyList()
|
||||
val from = minOf(selectedFrom, selectedTo)
|
||||
val to = maxOf(selectedFrom, selectedTo)
|
||||
|
||||
return entries.filter { entry ->
|
||||
val entryFrom = entry.dateFrom?.let { runCatching { LocalDate.parse(it) }.getOrNull() }
|
||||
val entryTo = entry.dateTo?.let { runCatching { LocalDate.parse(it) }.getOrNull() }
|
||||
entryFrom != null && entryTo != null && !entryTo.isBefore(from) && !entryFrom.isAfter(to)
|
||||
}
|
||||
}
|
||||
|
||||
fun phoneDialUri(phoneNumber: String?): String? {
|
||||
val raw = phoneNumber?.trim().orEmpty()
|
||||
if (raw.isBlank()) return null
|
||||
|
||||
@@ -64,6 +64,25 @@ class DriverLeaveRequestUiRulesTest {
|
||||
assertEquals(listOf("week", "single-day"), matching.map { it.id })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findsCalendarEntriesThatOverlapSelectedRange() {
|
||||
val entries = listOf(
|
||||
calendarEntry(id = "starts-before", dateFrom = "2026-08-01", dateTo = "2026-08-04"),
|
||||
calendarEntry(id = "inside", dateFrom = "2026-08-06", dateTo = "2026-08-07"),
|
||||
calendarEntry(id = "ends-after", dateFrom = "2026-08-09", dateTo = "2026-08-12"),
|
||||
calendarEntry(id = "before", dateFrom = "2026-07-20", dateTo = "2026-07-22"),
|
||||
calendarEntry(id = "after", dateFrom = "2026-08-13", dateTo = "2026-08-14"),
|
||||
)
|
||||
|
||||
val matching = DriverLeaveRequestUiRules.calendarEntriesForRange(
|
||||
entries = entries,
|
||||
dateFrom = "2026-08-03",
|
||||
dateTo = "2026-08-10",
|
||||
)
|
||||
|
||||
assertEquals(listOf("starts-before", "inside", "ends-after"), matching.map { it.id })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun normalizesPhoneNumberIntoDialerUri() {
|
||||
assertEquals("tel:+48600700800", DriverLeaveRequestUiRules.phoneDialUri("+48 600 700 800"))
|
||||
|
||||
Reference in New Issue
Block a user