commit ad97419f8755143761e5cba288d573390005cf25
parent a0cef3250a2ab790da571cb1f34d15d9e3d80305
Author: MTRNord <MTRNord@users.noreply.github.com>
Date: Mon, 28 Jul 2025 09:59:14 +0200
improve day view
Diffstat:
4 files changed, 216 insertions(+), 16 deletions(-)
diff --git a/app/src/main/java/space/midnightthoughts/nordiccalendar/MainActivity.kt b/app/src/main/java/space/midnightthoughts/nordiccalendar/MainActivity.kt
@@ -137,7 +137,16 @@ class MainActivity : ComponentActivity() {
modifier = innerPadding,
isRefreshing = isRefreshing,
onRefresh = { calendarViewModel.updateEvents() },
- navController = navController
+ navController = navController,
+ viewModel = calendarViewModel,
+ startMillis = calendarViewModel.run {
+ javaClass.getDeclaredField("startMillis")
+ .apply { isAccessible = true }.get(this) as Long
+ },
+ endMillis = calendarViewModel.run {
+ javaClass.getDeclaredField("endMillis")
+ .apply { isAccessible = true }.get(this) as Long
+ }
)
}
}
diff --git a/app/src/main/java/space/midnightthoughts/nordiccalendar/components/AppScaffold.kt b/app/src/main/java/space/midnightthoughts/nordiccalendar/components/AppScaffold.kt
@@ -2,7 +2,7 @@ package space.midnightthoughts.nordiccalendar.components
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -66,7 +66,10 @@ fun AppScaffold(
navigationIcon = {
if (onBackClick != null) {
IconButton(onClick = onBackClick) {
- Icon(Icons.Filled.ArrowBack, contentDescription = "Zurück")
+ Icon(
+ Icons.AutoMirrored.Filled.ArrowBack,
+ contentDescription = "Zurück"
+ )
}
} else {
IconButton(onClick = { scope.launch { drawerState.open() } }) {
diff --git a/app/src/main/java/space/midnightthoughts/nordiccalendar/screens/CalendarScreen.kt b/app/src/main/java/space/midnightthoughts/nordiccalendar/screens/CalendarScreen.kt
@@ -4,10 +4,12 @@ import android.annotation.SuppressLint
import android.util.Log
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@@ -18,10 +20,15 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material.icons.automirrored.filled.ArrowForward
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
@@ -39,17 +46,20 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import space.midnightthoughts.nordiccalendar.util.Event
+import space.midnightthoughts.nordiccalendar.viewmodels.CalendarViewModel
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
+
@SuppressLint("UnusedBoxWithConstraintsScope")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -60,7 +70,10 @@ fun CalendarScreen(
modifier: Modifier = Modifier,
isRefreshing: Boolean,
onRefresh: (() -> Unit),
- navController: NavController
+ navController: NavController,
+ viewModel: CalendarViewModel, // <-- ViewModel als Parameter
+ startMillis: Long,
+ endMillis: Long
) {
Log.d(
"CalendarScreen",
@@ -191,35 +204,57 @@ fun CalendarScreen(
(maxWidthPx - with(density) { timeColumnWidth.toPx() }) / maxColumns
val offsetX =
(col * columnWidthPx).toInt() + with(density) { timeColumnWidth.toPx() }.toInt()
+ val minCardHeightDp = 60.dp
+ val isCompact = with(density) { eventHeightPx.toDp() } < minCardHeightDp
Card(
modifier = Modifier
.width(with(density) { columnWidthPx.toDp() })
+ .defaultMinSize(minHeight = 24.dp)
.padding(end = 8.dp)
.offset { IntOffset(offsetX, offsetY.toInt()) }
.height(with(density) { eventHeightPx.toDp() })
.clickable { navController.navigate("eventDetails/${event.id}") },
- colors = CardDefaults.outlinedCardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
+ colors = if (isCompact) {
+ CardDefaults.outlinedCardColors(
+ containerColor = MaterialTheme.colorScheme.primary
+ )
+ } else CardDefaults.outlinedCardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
border = BorderStroke(
1.dp,
color = MaterialTheme.colorScheme.outline
)
) {
- Column(modifier = Modifier.padding(12.dp)) {
- Text(event.title, style = MaterialTheme.typography.bodyLarge)
- Spacer(modifier = Modifier.height(4.dp))
+ Column(
+ modifier = Modifier
+ .padding(
+ horizontal = 12.dp,
+ vertical = if (isCompact) 4.dp else 12.dp,
+ )
+ .fillMaxSize(),
+ verticalArrangement = if (isCompact) Arrangement.Center else Arrangement.Top,
+ ) {
Text(
- hourFormat.format(Date(event.startTime)) + " - " + hourFormat.format(
- Date(event.endTime)
- ),
- style = MaterialTheme.typography.bodyMedium,
- color = MaterialTheme.colorScheme.primary
+ event.title,
+ overflow = TextOverflow.Ellipsis,
+ style = if (isCompact) MaterialTheme.typography.bodySmall else MaterialTheme.typography.bodyLarge
)
- Spacer(modifier = Modifier.height(16.dp))
- if (!event.description.isNullOrBlank()) {
+ if (!isCompact) {
+ Spacer(modifier = Modifier.height(4.dp))
Text(
- event.description,
+ hourFormat.format(Date(event.startTime)) + " - " + hourFormat.format(
+ Date(event.endTime)
+ ),
style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.primary
)
+ Spacer(modifier = Modifier.height(8.dp))
+ if (!event.description.isNullOrBlank()) {
+ Text(
+ event.description,
+ style = MaterialTheme.typography.bodyMedium,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
}
}
}
@@ -268,6 +303,55 @@ fun CalendarScreen(
}
}
}
+ // Zeitraum-Navigation und Titel
+ val dateFormat = when (selectedTab) {
+ 0, 1 -> SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
+ 2 -> SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
+ else -> SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
+ }
+ val rangeText = when (selectedTab) {
+ 0, 1 -> dateFormat.format(Date(startMillis)) + " – " + dateFormat.format(
+ Date(
+ endMillis
+ )
+ )
+
+ 2 -> dateFormat.format(Date(startMillis))
+ else -> ""
+ }
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp, vertical = 8.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ IconButton(onClick = {
+ when (selectedTab) {
+ 0 -> viewModel.prevMonth()
+ 1 -> viewModel.prevWeek()
+ 2 -> viewModel.prevDay()
+ }
+ }) {
+ Icon(
+ Icons.AutoMirrored.Filled.ArrowBack,
+ contentDescription = "Vorheriger Zeitraum"
+ )
+ }
+ Text(rangeText, style = MaterialTheme.typography.titleMedium)
+ IconButton(onClick = {
+ when (selectedTab) {
+ 0 -> viewModel.nextMonth()
+ 1 -> viewModel.nextWeek()
+ 2 -> viewModel.nextDay()
+ }
+ }) {
+ Icon(
+ Icons.AutoMirrored.Filled.ArrowForward,
+ contentDescription = "Nächster Zeitraum"
+ )
+ }
+ }
}
}
}
diff --git a/app/src/main/java/space/midnightthoughts/nordiccalendar/viewmodels/CalendarViewModel.kt b/app/src/main/java/space/midnightthoughts/nordiccalendar/viewmodels/CalendarViewModel.kt
@@ -151,4 +151,108 @@ class CalendarViewModel(app: Application) : AndroidViewModel(app) {
isRefreshing.value = false
}
}
+
+ fun nextDay() {
+ if (_selectedTab.value != 2) return
+ val cal = java.util.Calendar.getInstance().apply { timeInMillis = startMillis }
+ cal.add(java.util.Calendar.DAY_OF_MONTH, 1)
+ startMillis = cal.timeInMillis
+ cal.set(java.util.Calendar.HOUR_OF_DAY, 23)
+ cal.set(java.util.Calendar.MINUTE, 59)
+ cal.set(java.util.Calendar.SECOND, 59)
+ endMillis = cal.timeInMillis
+ updateEventsCustom()
+ }
+
+ fun prevDay() {
+ if (_selectedTab.value != 2) return
+ val cal = java.util.Calendar.getInstance().apply { timeInMillis = startMillis }
+ cal.add(java.util.Calendar.DAY_OF_MONTH, -1)
+ startMillis = cal.timeInMillis
+ cal.set(java.util.Calendar.HOUR_OF_DAY, 23)
+ cal.set(java.util.Calendar.MINUTE, 59)
+ cal.set(java.util.Calendar.SECOND, 59)
+ endMillis = cal.timeInMillis
+ updateEventsCustom()
+ }
+
+ fun nextWeek() {
+ if (_selectedTab.value != 1) return
+ val cal = java.util.Calendar.getInstance().apply { timeInMillis = startMillis }
+ cal.add(java.util.Calendar.WEEK_OF_YEAR, 1)
+ startMillis = cal.timeInMillis
+ cal.add(java.util.Calendar.DAY_OF_WEEK, 6)
+ cal.set(java.util.Calendar.HOUR_OF_DAY, 23)
+ cal.set(java.util.Calendar.MINUTE, 59)
+ cal.set(java.util.Calendar.SECOND, 59)
+ endMillis = cal.timeInMillis
+ updateEventsCustom()
+ }
+
+ fun prevWeek() {
+ if (_selectedTab.value != 1) return
+ val cal = java.util.Calendar.getInstance().apply { timeInMillis = startMillis }
+ cal.add(java.util.Calendar.WEEK_OF_YEAR, -1)
+ startMillis = cal.timeInMillis
+ cal.add(java.util.Calendar.DAY_OF_WEEK, 6)
+ cal.set(java.util.Calendar.HOUR_OF_DAY, 23)
+ cal.set(java.util.Calendar.MINUTE, 59)
+ cal.set(java.util.Calendar.SECOND, 59)
+ endMillis = cal.timeInMillis
+ updateEventsCustom()
+ }
+
+ fun nextMonth() {
+ if (_selectedTab.value != 0) return
+ val cal = java.util.Calendar.getInstance().apply { timeInMillis = startMillis }
+ cal.add(java.util.Calendar.MONTH, 1)
+ cal.set(java.util.Calendar.DAY_OF_MONTH, 1)
+ startMillis = cal.timeInMillis
+ cal.set(
+ java.util.Calendar.DAY_OF_MONTH,
+ cal.getActualMaximum(java.util.Calendar.DAY_OF_MONTH)
+ )
+ cal.set(java.util.Calendar.HOUR_OF_DAY, 23)
+ cal.set(java.util.Calendar.MINUTE, 59)
+ cal.set(java.util.Calendar.SECOND, 59)
+ endMillis = cal.timeInMillis
+ updateEventsCustom()
+ }
+
+ fun prevMonth() {
+ if (_selectedTab.value != 0) return
+ val cal = java.util.Calendar.getInstance().apply { timeInMillis = startMillis }
+ cal.add(java.util.Calendar.MONTH, -1)
+ cal.set(java.util.Calendar.DAY_OF_MONTH, 1)
+ startMillis = cal.timeInMillis
+ cal.set(
+ java.util.Calendar.DAY_OF_MONTH,
+ cal.getActualMaximum(java.util.Calendar.DAY_OF_MONTH)
+ )
+ cal.set(java.util.Calendar.HOUR_OF_DAY, 23)
+ cal.set(java.util.Calendar.MINUTE, 59)
+ cal.set(java.util.Calendar.SECOND, 59)
+ endMillis = cal.timeInMillis
+ updateEventsCustom()
+ }
+
+ private fun updateEventsCustom() {
+ isRefreshing.value = true
+ val tab = _selectedTab.value
+ Log.d(
+ "CalendarViewModel",
+ "Updating events for selected calendars: ${_selectedCalendars.value.map { it.name }}"
+ )
+ viewModelScope.launch {
+ val selectedIds = _selectedCalendars.value.map { it.id }
+ Log.d("CalendarViewModel", "Selected calendar IDs: $selectedIds")
+ _events.value = calendarData.getEventsForCalendars(
+ contentResolver,
+ selectedIds,
+ startMillis,
+ endMillis
+ )
+ isRefreshing.value = false
+ }
+ }
}