From c0b29ec2e174314bc8e063a53968ba9084f595d8 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Tue, 10 Sep 2024 09:39:04 +0200 Subject: [PATCH 01/38] moved appearence type for string resource implementation --- .../domain/enums/Types/AppearanceType.kt | 20 ++++++++++++++++++- .../presentation/views/Settings/Settings.kt | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/domain/enums/Types/AppearanceType.kt b/app/src/main/java/tumble/app/tumble/domain/enums/Types/AppearanceType.kt index 10b93ce..e2ceaaa 100644 --- a/app/src/main/java/tumble/app/tumble/domain/enums/Types/AppearanceType.kt +++ b/app/src/main/java/tumble/app/tumble/domain/enums/Types/AppearanceType.kt @@ -1,7 +1,25 @@ package tumble.app.tumble.domain.enums.Types +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import tumble.app.tumble.R +import tumble.app.tumble.domain.enums.ViewType + enum class AppearanceType { AUTOMATIC, LIGHT, DARK } - +@Composable +fun appearenceTypeToStringResource(appearanceType: AppearanceType): String { + return when(appearanceType){ + AppearanceType.AUTOMATIC -> { + stringResource(id = R.string.list) + } + AppearanceType.LIGHT -> { + stringResource(id = R.string.calendar) + } + AppearanceType.DARK -> { + stringResource(id = R.string.week) + } + } +} diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt index 72fefcf..8c5e08c 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt @@ -80,7 +80,7 @@ fun SettingsScreen( SettingsListGroup { SettingsNavigationButton( title = "appearance", - current = appearance.value.name, //stringResource(id = getAppearanceResource(appearance)), + current = appearance.value.name, leadingIcon = Icons.Default.DarkMode, leadingIconBackgroundColor = MaterialTheme.colors.primary, destination = { navController.navigate(Routes.accountSettingsAppearance) } From 1bba02d8199decd076e745d100f16a5a8f0406c7 Mon Sep 17 00:00:00 2001 From: Sven Date: Mon, 30 Sep 2024 13:29:04 +0200 Subject: [PATCH 02/38] added string resources --- .../domain/enums/Types/AppearanceType.kt | 8 ++-- .../AppearanceSettings/AppearanceSettings.kt | 7 ++- .../Settings/Bookmarks/BookmarksSettings.kt | 6 ++- .../Buttons/SettingsExternalButton.kt | 8 +--- .../NotificationOffsetSettings.kt | 4 +- .../presentation/views/Settings/Settings.kt | 47 +++++++++++++------ .../presentation/views/Settings/ShareSheet.kt | 5 +- .../presentation/views/account/Account.kt | 7 ++- .../ResourceSection/ResourceSectionDivider.kt | 7 +-- app/src/main/res/values-en-rUS/strings.xml | 1 + app/src/main/res/values/strings.xml | 15 ++++++ build.gradle | 4 +- 12 files changed, 80 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/domain/enums/Types/AppearanceType.kt b/app/src/main/java/tumble/app/tumble/domain/enums/Types/AppearanceType.kt index e2ceaaa..1d3d09f 100644 --- a/app/src/main/java/tumble/app/tumble/domain/enums/Types/AppearanceType.kt +++ b/app/src/main/java/tumble/app/tumble/domain/enums/Types/AppearanceType.kt @@ -10,16 +10,16 @@ enum class AppearanceType { } @Composable -fun appearenceTypeToStringResource(appearanceType: AppearanceType): String { +fun appearanceTypeToStringResource(appearanceType: AppearanceType): String { return when(appearanceType){ AppearanceType.AUTOMATIC -> { - stringResource(id = R.string.list) + stringResource(id = R.string.automatic) } AppearanceType.LIGHT -> { - stringResource(id = R.string.calendar) + stringResource(id = R.string.light) } AppearanceType.DARK -> { - stringResource(id = R.string.week) + stringResource(id = R.string.dark) } } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/AppearanceSettings/AppearanceSettings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/AppearanceSettings/AppearanceSettings.kt index 98dd098..25261ff 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/AppearanceSettings/AppearanceSettings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/AppearanceSettings/AppearanceSettings.kt @@ -8,10 +8,13 @@ import androidx.compose.material.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import androidx.navigation.NavHostController +import tumble.app.tumble.R import tumble.app.tumble.domain.enums.Types.AppearanceType +import tumble.app.tumble.domain.enums.Types.appearanceTypeToStringResource import tumble.app.tumble.extensions.presentation.noRippleClickable import tumble.app.tumble.presentation.viewmodels.SettingsViewModel import tumble.app.tumble.presentation.views.Settings.BackNav @@ -30,7 +33,7 @@ fun AppearanceSettings( Scaffold( topBar = { BackNav(onClick = { navController.popBackStack() }, - label = "Settings") + label = stringResource(R.string.settings)) } ) { padding -> @@ -39,7 +42,7 @@ fun AppearanceSettings( val appearanceTypes = AppearanceType.values() appearanceTypes.forEachIndexed { index, type -> SettingsRadioButton( - title = type.name, + title = appearanceTypeToStringResource(type), isSelected = appearance.value == type, onValueChange = { viewModel.upDateAppearance(type) }, ) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettings.kt index f6017fb..f574d1d 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettings.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import io.realm.kotlin.ext.query @@ -16,6 +17,7 @@ import io.realm.kotlin.query.find import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch +import tumble.app.tumble.R import tumble.app.tumble.domain.models.realm.Schedule import tumble.app.tumble.presentation.viewmodels.SettingsViewModel import tumble.app.tumble.presentation.views.Settings.BackNav @@ -32,7 +34,7 @@ fun BookmarksSettings( Scaffold( topBar = { BackNav(onClick = { navController.popBackStack() }, - label = "Settings") + label = stringResource(R.string.settings)) } ) { padding -> if (schedules.value.isNotEmpty()) { @@ -50,7 +52,7 @@ fun BookmarksSettings( } } } else { - Info(title = "No bookmarks yet", image = null) + Info(title = stringResource(R.string.no_bookmarks), image = null) } } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Buttons/SettingsExternalButton.kt b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Buttons/SettingsExternalButton.kt index 707824f..f367de8 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Buttons/SettingsExternalButton.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Buttons/SettingsExternalButton.kt @@ -25,12 +25,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import tumble.app.tumble.extensions.presentation.noRippleClickable -data class SettingsDetails( - val titleKey: String, - val name: String, - val details: String -) - @Composable fun SettingsExternalButton( title: String, @@ -38,7 +32,7 @@ fun SettingsExternalButton( leadingIcon: ImageVector, trailingIcon: ImageVector = Icons.Default.ArrowOutward, leadingIconBackgroundColor: Color = MaterialTheme.colors.onSurface, - action: () -> Unit + action: () -> Unit, ) { Row( modifier = Modifier diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Notifications/NotificationOffsetSettings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Notifications/NotificationOffsetSettings.kt index 82761f4..e551506 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Notifications/NotificationOffsetSettings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Notifications/NotificationOffsetSettings.kt @@ -6,9 +6,11 @@ import androidx.compose.material.Scaffold import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import tumble.app.tumble.R import tumble.app.tumble.presentation.viewmodels.SettingsViewModel import tumble.app.tumble.presentation.views.Settings.BackNav import tumble.app.tumble.presentation.views.Settings.Buttons.SettingsRadioButton @@ -39,7 +41,7 @@ fun NotificationOffsetSettings( Scaffold( topBar = { BackNav(onClick = { navController.popBackStack() }, - label = "Settings") + label = stringResource(R.string.settings)) } ) { padding -> SettingsList (modifier = Modifier.padding(padding)){ diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt index 8c5e08c..9eda317 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt @@ -1,5 +1,7 @@ package tumble.app.tumble.presentation.views.Settings +import android.content.Intent +import android.net.Uri import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -36,11 +38,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.core.content.ContextCompat.startActivity import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import tumble.app.tumble.R import tumble.app.tumble.presentation.navigation.Routes import tumble.app.tumble.presentation.viewmodels.SettingsViewModel import tumble.app.tumble.presentation.views.Settings.Buttons.SettingsExternalButton @@ -60,13 +65,25 @@ fun SettingsScreen( val currentLocale = Locale.getDefault().displayLanguage val appVersion = "1.0.0" // Replace with actual version retrieval logic + val context = LocalContext.current + + val externalNav = {uri:String -> + startActivity( + context, + Intent( + Intent.ACTION_VIEW, + Uri.parse(uri) + ), + null) + } + Scaffold ( topBar = { BackNav( onClick = {navController.popBackStack()}, - label = "Account", - title = "Settings" + label = stringResource(R.string.account), + title = stringResource(R.string.settings) ) }, ){padding -> @@ -79,7 +96,7 @@ fun SettingsScreen( SettingsList { SettingsListGroup { SettingsNavigationButton( - title = "appearance", + title = stringResource(R.string.appearance), current = appearance.value.name, leadingIcon = Icons.Default.DarkMode, leadingIconBackgroundColor = MaterialTheme.colors.primary, @@ -87,16 +104,16 @@ fun SettingsScreen( ) Divider() SettingsExternalButton( - title = "language", + title = stringResource(R.string.language), current = currentLocale, leadingIcon = Icons.Default.Language, leadingIconBackgroundColor = Color.Blue, - action = { } + action = {}, ) } SettingsListGroup { SettingsNavigationButton( - title = "notification_offset", + title = stringResource(R.string.notification_offset), leadingIcon = Icons.Default.AccessTime, leadingIconBackgroundColor = Color.Red, destination = { @@ -105,7 +122,7 @@ fun SettingsScreen( ) Divider() SettingsNavigationButton( - title = "bookmarks", + title = stringResource(R.string.bookmark), leadingIcon = Icons.Default.Bookmark, leadingIconBackgroundColor = Color.Gray, destination = { navController.navigate(Routes.accountSettingsBookmarks) } @@ -113,21 +130,23 @@ fun SettingsScreen( } SettingsListGroup { SettingsExternalButton( - title = "stringResource(id = R.string.review_app)", + title = stringResource(id = R.string.review_app), leadingIcon = Icons.Default.Star, leadingIconBackgroundColor = Color.Yellow, - action = { } + action = { + externalNav("market://details?id=") + }, ) Divider() SettingsExternalButton( - title = "stringResource(id = R.string.share_feedback)", + title = stringResource(id = R.string.share_feedback), leadingIcon = Icons.Default.Email, leadingIconBackgroundColor = Color.Blue, - action = { } + action = {externalNav("http://www.google.com")}, ) Divider() SettingsExternalButton( - title = "share_app", + title = stringResource(R.string.share_app), leadingIcon = Icons.Default.Share, leadingIconBackgroundColor = Color.Green, action = { showShareSheet = true } @@ -135,10 +154,10 @@ fun SettingsScreen( } SettingsListGroup { SettingsExternalButton( - title = "stringResource(id = R.string.github)", + title = stringResource(id = R.string.github), leadingIcon = Icons.Default.Code, leadingIconBackgroundColor = Color.Black, - action = { } + action = {externalNav("https://github.com/tumble-for-kronox/Tumble-Android")}, ) } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/ShareSheet.kt b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/ShareSheet.kt index 84a5a1b..b71de88 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/ShareSheet.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/ShareSheet.kt @@ -50,6 +50,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource import tumble.app.tumble.R import tumble.app.tumble.presentation.components.buttons.CloseCoverButton import tumble.app.tumble.presentation.views.general.CustomProgressIndicator @@ -82,7 +83,7 @@ fun ShareSheet(context: Context, onDismiss: () -> Unit) { Spacer(modifier = Modifier.height(20.dp)) Text( - text = "Share the app", + text = stringResource(R.string.share_app), fontSize = 24.sp, modifier = Modifier.align(Alignment.CenterHorizontally) ) @@ -116,7 +117,7 @@ fun ShareSheet(context: Context, onDismiss: () -> Unit) { horizontalAlignment = Alignment.CenterHorizontally ) { Text( - text = "Scan QR Code", + text = stringResource(R.string.qr_code), fontSize = 16.sp, modifier = Modifier.padding(top = 8.dp) ) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/Account.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/Account.kt index 26afe73..49d1ccb 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/Account.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/Account.kt @@ -23,9 +23,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController +import tumble.app.tumble.R import tumble.app.tumble.presentation.navigation.Routes import tumble.app.tumble.presentation.viewmodels.AccountViewModel import tumble.app.tumble.presentation.views.account.Login.AccountLogin @@ -46,7 +48,7 @@ fun Account( Scaffold( topBar = { TopAppBar( - title = { Text(text = "account") }, + title = { Text(text = stringResource(R.string.account)) }, actions = { Row { if(authStatus == AccountViewModel.AuthStatus.AUTHORIZED){ @@ -69,6 +71,7 @@ fun Account( AccountViewModel.AuthStatus.AUTHORIZED -> UserOverview(navController = navController) AccountViewModel.AuthStatus.UNAUTHORIZED -> AccountLogin() } + UserOverview(navController = navController) } if(isSigningOut){ @@ -88,7 +91,7 @@ fun Account( } }, text = { - Text(text = "coonfirm") + Text(text = "confirm") } ) } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceSectionDivider.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceSectionDivider.kt index 773473e..4e53f57 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceSectionDivider.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceSectionDivider.kt @@ -23,9 +23,11 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import tumble.app.tumble.R enum class ResourceType{ EVENT, RESOURCE @@ -58,10 +60,9 @@ fun ResourceSectionDivider( color = MaterialTheme.colors.onBackground ) if(destination != null){ - Log.e("error", "in if") when(resourceType){ - ResourceType.EVENT -> ResourceNavigationItem(title = "See all", destination) - ResourceType.RESOURCE -> ResourceNavigationItem(title = "Book more", destination) + ResourceType.EVENT -> ResourceNavigationItem(title = stringResource(R.string.see_all), destination) + ResourceType.RESOURCE -> ResourceNavigationItem(title = stringResource(R.string.book_more), destination) null -> {} } } diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml index 6cc00a1..0045e6a 100644 --- a/app/src/main/res/values-en-rUS/strings.xml +++ b/app/src/main/res/values-en-rUS/strings.xml @@ -27,4 +27,5 @@ Week No events this day No events for this week.. + Light \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 45eb460..b0e1ad2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,4 +27,19 @@ Week No events this day No events for this week.. + Light + Dark + Automatic + Settings + Account + Appearance + App Language + Notification offset + Review the app + Share feedback + Share the app + Tumble on Github + Scan QR Code + See all + Book more \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7357ddf..e506abf 100644 --- a/build.gradle +++ b/build.gradle @@ -7,8 +7,8 @@ buildscript { } } plugins { - id 'com.android.application' version '8.5.2' apply false - id 'com.android.library' version '8.5.2' apply false + id 'com.android.application' version '8.6.0' apply false + id 'com.android.library' version '8.6.0' apply false id 'org.jetbrains.kotlin.android' version '1.8.20' apply false id 'com.google.dagger.hilt.android' version '2.44' apply false id 'io.realm.kotlin' version '1.10.0' apply false From 4e3d1d9e621bde5a8f5ecfcff42b39b7a4a3d774 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Tue, 8 Oct 2024 09:31:37 +0200 Subject: [PATCH 03/38] string resources --- app/src/main/res/values/strings.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b0e1ad2..2303889 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -42,4 +42,15 @@ Scan QR Code See all Book more + Registered + No Registered Events + Unregisted + Upcoming + No Upcoming Events + No Unregistered Events + Available unitl + Available at + Register + Unregister + Signup has passed \ No newline at end of file From cb5ebed8fec055909c84bb07a8d3cfb356cee009 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Tue, 8 Oct 2024 09:33:46 +0200 Subject: [PATCH 04/38] refactor events --- .../Booking/Events/EventBookings.kt | 54 +++--- .../Booking/Events/EventCardButton.kt | 175 ++++++++++-------- .../ResourceSection/Booking/Events/Events.kt | 124 ++++++------- .../Booking/Events/UpcomingEventCardButton.kt | 31 ++-- 4 files changed, 194 insertions(+), 190 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt index 5efab61..042448d 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt @@ -1,13 +1,16 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Events - import android.os.Build import androidx.annotation.RequiresApi import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* +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.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Tag import androidx.compose.material.MaterialTheme @@ -15,10 +18,13 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier +import androidx.compose.ui.input.pointer.motionEventSpy +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import kotlinx.coroutines.ExperimentalCoroutinesApi +import tumble.app.tumble.R import tumble.app.tumble.domain.enums.PageState import tumble.app.tumble.presentation.components.buttons.CloseCoverButton import tumble.app.tumble.presentation.viewmodels.ResourceViewModel @@ -60,68 +66,54 @@ fun EventBookings( } PageState.LOADED -> { SectionDivider( - title = "stringResource(id = R.string.registered)", + title = stringResource(id = R.string.registered), image = Icons.Default.Tag, content = { - if (completeUserEvent.value?.registeredEvents != null) { - Events( - registeredEvents = completeUserEvent.value?.registeredEvents, + completeUserEvent.value?.registeredEvents?.let { events -> + RegisteredEventsView( + registeredEvents = events, onTapEventAction = { eventId, eventType -> onTapEventAction(viewModel, eventId, eventType) } ) - } else { - Text( - text = "stringResource(id = R.string.no_registered_events)", - modifier = Modifier.padding(top = 5.dp) - ) } + } ) SectionDivider( - title = "stringResource(id = R.string.unregistered)", + title = stringResource(id = R.string.unregistered), image = Icons.Default.Tag, content = { - if (completeUserEvent.value?.unregisteredEvents != null) { - Events( - unregisteredEvents = completeUserEvent.value?.unregisteredEvents, + completeUserEvent.value?.unregisteredEvents?.let { events -> + UnregisteredEventsView( + unregisteredEvents = events, onTapEventAction = { eventId, eventType -> onTapEventAction(viewModel, eventId, eventType) } ) - } else { - Text( - text = "stringResource(id = R.string.no_unregistered_events)", - modifier = Modifier.padding(top = 5.dp) - ) } } ) SectionDivider( - title = "stringResource(id = R.string.upcoming)", + title = stringResource(id = R.string.upcoming), image = Icons.Default.Tag, content = { - if (completeUserEvent.value?.upcomingEvents != null) { - Events(upcomingEvents = completeUserEvent.value?.upcomingEvents) - } else { - Text( - text = "stringResource(id = R.string.no_upcoming_events)", - modifier = Modifier.padding(top = 5.dp) - ) + completeUserEvent.value?.upcomingEvents?.let { events -> + UpcomingEventsView(upcomingEvents = events) } } ) } PageState.ERROR -> { Info( - title = "stringResource(id = R.string.server_error)", + title = stringResource(id = R.string.error_something_wrong), image = null, ) } } + Spacer(Modifier.height(30.dp)) } } - LaunchedEffect(Unit) { viewModel.getUserEventsForPage() } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt index d8caa45..f690fb5 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt @@ -2,9 +2,16 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Bookin import android.os.Build +import android.util.Log import androidx.annotation.RequiresApi import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Button import androidx.compose.material.Icon @@ -20,18 +27,22 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString +import tumble.app.tumble.extensions.presentation.formatDate import tumble.app.tumble.extensions.presentation.isValidRegistrationDate +import tumble.app.tumble.extensions.presentation.toColor import tumble.app.tumble.extensions.presentation.toLocalDateTime import tumble.app.tumble.utils.isoDateFormatterDate -enum class EventType(val icon: String) { - REGISTER("check_circle"), - UNREGISTER("cancel") +enum class EventType { + REGISTER, + UNREGISTER } @RequiresApi(Build.VERSION_CODES.O) @@ -41,95 +52,99 @@ fun EventCardButton( eventType: EventType, onTap: () -> Unit ) { - Column( + Row( modifier = Modifier .fillMaxWidth() - .padding(bottom = 10.dp) - .background(MaterialTheme.colors.surface, shape = RoundedCornerShape(15.dp)) // Replace with your theme colors - .padding() + .background(MaterialTheme.colors.surface, shape = RoundedCornerShape(20.dp)) + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically ) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth() + Column( + verticalArrangement = Arrangement.spacedBy(10.dp), + modifier = Modifier.weight(1f) ) { - Column( - verticalArrangement = Arrangement.spacedBy(10.dp), - modifier = Modifier.weight(1f) - ) { - // Event Title - Text( - text = event.title ?: "stringResource(id = R.string.no_title)", - fontSize = 17.sp, - color = MaterialTheme.colors.onSurface, // Replace with your theme colors - maxLines = 1, - overflow = TextOverflow.Ellipsis + // Event Title + Text( + text = event.title ?: "stringResource(id = R.string.no_title)", + fontSize = 17.sp, + color = MaterialTheme.colors.onSurface, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + // Event Date and Time + Row(verticalAlignment = Alignment.CenterVertically) { + Icon( + painter = rememberVectorPainter(Icons.Default.CalendarToday), + contentDescription = null, + tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) ) - // Event Date and Time - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - painter = rememberVectorPainter(Icons.Default.CalendarToday), - contentDescription = null, - tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) // Replace with your theme colors - ) - val eventDate = event.eventStart.toLocalDateTime() - val eventStart = event.eventStart.convertToHoursAndMinutesISOString() - val eventEnd = event.eventEnd.convertToHoursAndMinutesISOString() - val eventDateText = if (eventDate != null && eventStart != null && eventEnd != null) { - String.format("stringResource(id = R.string.event_time_format)", eventDate, eventStart, eventEnd) + val eventDate = isoDateFormatterDate.format(isoDateFormatterDate.parse(event.eventStart)) + val eventStart = event.eventStart.convertToHoursAndMinutesISOString() + val eventEnd = event.eventEnd.convertToHoursAndMinutesISOString() + val eventDateText = + if (eventDate != null && eventStart != null && eventEnd != null) { + "$eventDate: $eventStart - $eventEnd" } else { "stringResource(id = R.string.no_date_at_this_time)" } - Text( - text = eventDateText, - fontSize = 15.sp, - color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) // Replace with your theme colors - ) - } - // Signup Date - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - painter = rememberVectorPainter(Icons.Default.Edit), - contentDescription = null, - tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) // Replace with your theme colors - ) - val signupText = if (event.lastSignupDate.isValidRegistrationDate()) { - "${"stringResource(id = R.string.available_until)"} ${isoDateFormatterDate.parse(event.lastSignupDate) ?: "stringResource(id = R.string.no_date_set)"}" - } else { - "stringResource(id = R.string.signup_has_passed)" - } - Text( - text = signupText, - fontSize = 15.sp, - color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) // Replace with your theme colors - ) + Text( + text = eventDateText, + fontSize = 15.sp, + color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) + ) + } + // Signup Date + Row(verticalAlignment = Alignment.CenterVertically) { + Icon( + painter = rememberVectorPainter(Icons.Default.Edit), + contentDescription = null, + tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) + ) + val signupText = if (event.lastSignupDate.isValidRegistrationDate()) { + "${stringResource(id = R.string.available_until)} ${ + isoDateFormatterDate.format( + isoDateFormatterDate.parse(event.lastSignupDate) + ) ?: "stringResource(id = R.string.no_date_set)" + }" + } else { + stringResource(id = R.string.signup_has_passed) } + Text( + text = signupText, + fontSize = 15.sp, + color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) + ) } - Spacer(modifier = Modifier.width(10.dp)) - } - if (event.lastSignupDate.isValidRegistrationDate()) { - Row( - horizontalArrangement = Arrangement.End, - modifier = Modifier.fillMaxWidth() - ) { - Button( - onClick = { event.eventId?.let { onTap() } }, - modifier = Modifier - .background(MaterialTheme.colors.primary, shape = RoundedCornerShape(10.dp)) // Replace with your theme colors - .padding(10.dp) + if (event.lastSignupDate.isValidRegistrationDate()) { + Row( + horizontalArrangement = Arrangement.End, + modifier = Modifier.fillMaxWidth() ) { - Icon( - painter = rememberVectorPainter(Icons.Default.Event), - contentDescription = null, - tint = MaterialTheme.colors.onPrimary// Replace with your theme colors - ) - Spacer(modifier = Modifier.width(5.dp)) - Text( - text = if (eventType == EventType.UNREGISTER) "stringResource(id = R.string.unregister)" else "stringResource(id = R.string.register)", - fontSize = 16.sp, - color = MaterialTheme.colors.onPrimary// Replace with your theme colors - ) + Button( + onClick = { + event.eventId?.let { onTap() } }, + modifier = Modifier + .background( + MaterialTheme.colors.primary, + shape = RoundedCornerShape(10.dp) + ) + .padding(10.dp) + ) { + Icon( + painter = rememberVectorPainter(Icons.Default.Event), + contentDescription = null, + tint = MaterialTheme.colors.onPrimary + ) + Spacer(modifier = Modifier.width(5.dp)) + Text( + text = if (eventType == EventType.UNREGISTER) stringResource(id = R.string.unregister) else stringResource(id = R.string.register), + fontSize = 16.sp, + color = MaterialTheme.colors.onPrimary + ) + } } } } + Spacer(modifier = Modifier.width(10.dp)) } } \ No newline at end of file diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt index 3793da6..218d35b 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt @@ -2,112 +2,102 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Bookin import android.os.Build import androidx.annotation.RequiresApi -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import tumble.app.tumble.domain.models.network.NetworkResponse +import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse.AvailableKronoxUserEvent import tumble.app.tumble.domain.models.network.NetworkResponse.UpcomingKronoxUserEvent -@RequiresApi(Build.VERSION_CODES.O) -@Composable -fun Events( - registeredEvents: List? = null, - unregisteredEvents: List? = null, - upcomingEvents: List? = null, - onTapEventAction: ((String, EventType) -> Unit)? = null -) { - unregisteredEventsView(unregisteredEvents, onTapEventAction) - registeredEventsView(registeredEvents, onTapEventAction) - upcomingEventsView(upcomingEvents) -} @RequiresApi(Build.VERSION_CODES.O) @Composable -fun registeredEventsView( - registeredEvents: List?, - onTapEventAction: ((String, EventType) -> Unit)? +fun RegisteredEventsView( + registeredEvents: List, + onTapEventAction: ((String, EventType) -> Unit) ) { Column { - registeredEvents?.let { events -> - onTapEventAction?.let { action -> - Column( - verticalArrangement = Arrangement.spacedBy(15.dp), - modifier = Modifier.fillMaxWidth() - ) { - events.forEach { event -> - EventCardButton( - event = event, - eventType = EventType.UNREGISTER, - onTap = { action(event.eventId!!, EventType.UNREGISTER) } - ) - } + if (registeredEvents.isNotEmpty()) { + Column( + verticalArrangement = Arrangement.spacedBy(15.dp), + modifier = Modifier.fillMaxWidth() + ) { + registeredEvents.forEach { event -> + EventCardButton( + event = event, + eventType = EventType.UNREGISTER, + onTap = { onTapEventAction(event.eventId!!, EventType.UNREGISTER) } + ) + Spacer(modifier = Modifier.height(8.dp)) } } - if (events.isEmpty()) { - Text( - text = "stringResource(id = R.string.no_registered_events)", - modifier = Modifier - .padding(top = 5.dp) - ) - } + }else { + Text( + text = stringResource(id = R .string.no_registered_events), + modifier = Modifier + .padding(top = 5.dp) + ) } } } @RequiresApi(Build.VERSION_CODES.O) @Composable -fun unregisteredEventsView( - unregisteredEvents: List?, - onTapEventAction: ((String, EventType) -> Unit)? +fun UnregisteredEventsView( + unregisteredEvents: List, + onTapEventAction: ((String, EventType) -> Unit) ) { Column { - unregisteredEvents?.let { events -> - onTapEventAction?.let { action -> - Column(modifier = Modifier.fillMaxWidth()) { - events.forEach { event -> - EventCardButton( - event = event, - eventType = EventType.REGISTER, - onTap = { action(event.eventId!!, EventType.REGISTER) } - ) - } + if (unregisteredEvents.isNotEmpty()) { + Column(modifier = Modifier.fillMaxWidth()) { + unregisteredEvents.forEach { event -> + EventCardButton( + event = event, + eventType = EventType.REGISTER, + onTap = { onTapEventAction(event.eventId!!, EventType.REGISTER) } + ) + Spacer(modifier = Modifier.height(8.dp)) } } - if (events.isEmpty()) { - Text( - text = "stringResource(id = R.string.no_unregistered_events)", - modifier = Modifier - .padding(top = 5.dp) - ) - } + } + else{ + Text( + text = stringResource(id = R.string.no_unregistered_events), + modifier = Modifier + .padding(top = 5.dp) + ) } } } + @RequiresApi(Build.VERSION_CODES.O) @Composable -fun upcomingEventsView( - upcomingEvents: List? +fun UpcomingEventsView( + upcomingEvents: List ) { Column { - upcomingEvents?.let { events -> + if (upcomingEvents.isNotEmpty()) { Column(modifier = Modifier.fillMaxWidth()) { - events.forEach { event -> + upcomingEvents.forEach { event -> UpcomingEventCardButton(event = event) Spacer(modifier = Modifier.height(8.dp)) } } - if (events.isEmpty()) { - Text( - text = "stringResource(id = R.string.no_upcoming_events)", - modifier = Modifier - .padding(top = 5.dp) + } else{ + Text( + text = stringResource(id = R.string.no_upcoming_events), + modifier = Modifier + .padding(top = 5.dp) ) } } } -} \ No newline at end of file diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/UpcomingEventCardButton.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/UpcomingEventCardButton.kt index 31b7b36..996070c 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/UpcomingEventCardButton.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/UpcomingEventCardButton.kt @@ -3,7 +3,13 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Bookin import android.os.Build import androidx.annotation.RequiresApi import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Icon import androidx.compose.material.Text @@ -14,15 +20,14 @@ import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString -import tumble.app.tumble.extensions.presentation.toLocalDateTime import tumble.app.tumble.utils.isoDateFormatterDate @RequiresApi(Build.VERSION_CODES.O) @@ -33,7 +38,7 @@ fun UpcomingEventCardButton( Row( modifier = Modifier .fillMaxWidth() - .background(MaterialTheme.colors.surface, shape = RoundedCornerShape(20.dp)) // Replace with your theme colors + .background(MaterialTheme.colors.surface, shape = RoundedCornerShape(20.dp)) .padding(16.dp), verticalAlignment = Alignment.CenterVertically ) { @@ -45,7 +50,7 @@ fun UpcomingEventCardButton( Text( text = event.title, fontSize = 17.sp, - color = MaterialTheme.colors.onSurface, // Replace with your theme colors + color = MaterialTheme.colors.onSurface, maxLines = 1, overflow = TextOverflow.Ellipsis ) @@ -54,20 +59,20 @@ fun UpcomingEventCardButton( Icon( painter = rememberVectorPainter(Icons.Default.CalendarToday), contentDescription = null, - tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) // Replace with your theme colors + tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) ) - val eventDate = event.eventStart.toLocalDateTime() + val eventDate = isoDateFormatterDate.format(isoDateFormatterDate.parse(event.eventStart)) val eventEnd = event.eventEnd.convertToHoursAndMinutesISOString() val eventStart = event.eventStart.convertToHoursAndMinutesISOString() val eventDateText = if (eventDate != null && eventStart != null && eventEnd != null) { - String.format("stringResource(id = R.string.event_time_format)", eventDate, eventStart, eventEnd) + "$eventDate: $eventStart - $eventEnd" } else { "stringResource(id = R.string.no_date_at_this_time)" } Text( text = eventDateText, fontSize = 15.sp, - color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) // Replace with your theme colors + color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) ) } // Signup Availability @@ -75,12 +80,14 @@ fun UpcomingEventCardButton( Icon( painter = rememberVectorPainter(Icons.Default.Edit), contentDescription = null, - tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) // Replace with your theme colors + tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) ) Text( - text = "${"stringResource(id = R.string.available_at)"} ${ isoDateFormatterDate.parse(event.firstSignupDate) ?: "stringResource(id = R.string.no_date_set)"}", + text = "${stringResource(id = R.string.available_at)} ${ isoDateFormatterDate.format( + isoDateFormatterDate.parse(event.firstSignupDate) + ) ?: "stringResource(id = R.string.no_date_set)"}", fontSize = 15.sp, - color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) // Replace with your theme colors + color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) ) } } From c83522b44b59d377eb0f6130cc7628b0128cebf4 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Tue, 8 Oct 2024 09:36:43 +0200 Subject: [PATCH 05/38] resource fetching and event registration --- .../viewmodels/ResourceViewModel.kt | 86 +++++++++++++++++-- 1 file changed, 77 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt index 163b34f..8203f57 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt @@ -1,6 +1,7 @@ package tumble.app.tumble.presentation.viewmodels import android.os.Build +import android.util.Log import androidx.annotation.RequiresApi import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -8,6 +9,7 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -17,8 +19,13 @@ import tumble.app.tumble.data.repository.preferences.DataStoreManager import tumble.app.tumble.datasource.network.ApiResponse import tumble.app.tumble.datasource.network.kronox.KronoxRepository import tumble.app.tumble.domain.enums.PageState +import tumble.app.tumble.domain.models.network.NetworkRequest import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.models.presentation.ResourceSelectionModel +import tumble.app.tumble.presentation.viewmodels.AccountViewModel.AuthStatus +import tumble.app.tumble.utils.isoDateFormatterDate +import tumble.app.tumble.utils.isoDateFormatterNoTimeZone +import tumble.app.tumble.utils.toIsoString import java.util.Date import javax.inject.Inject @@ -44,10 +51,13 @@ class ResourceViewModel @Inject constructor( private val _eventBookingPageState = MutableStateFlow(PageState.LOADING) val eventBookingPageState: StateFlow = _eventBookingPageState - private val _allResources = MutableStateFlow?>(null) val allResources: StateFlow?> = _allResources + private val _allResourcesTypes = MutableStateFlow?>(null) + val allResourcesTypes: StateFlow?> = _allResourcesTypes + + //val allResources: List? = null private val _resourceSelectionModel = MutableStateFlow(null) @@ -56,6 +66,7 @@ class ResourceViewModel @Inject constructor( fun setBookingDate(newDate: Date){ _selectedPickerDate.value = newDate + viewModelScope.launch { getAllResourcesData(isoDateFormatterDate.format(newDate)) } } fun getUserEventsForPage(){ @@ -82,35 +93,92 @@ class ResourceViewModel @Inject constructor( } fun registerForEvent(eventId: String){ - //TODO + + viewModelScope.launch() { + try { + val refreshToken = authManager.getRefreshToken() ?: return@launch + val schoolID = dataStoreManager.authSchoolId.value.toString() + val endpoint = Endpoint.RegisterEvent(eventId = eventId, schoolId = schoolID) + val userRequest = kronoxManager.registerForEvent(endpoint, refreshToken) + if(userRequest.isSuccessful){ + Log.e("AAAAAAA", "Registered") + }else{ + Log.e("AAAAAAA", "NOT Registered") + + } + } catch (e: Exception) { + } + } } fun unregisterForEvent(eventId: String){ //TODO } - fun getAllResourceData(date: Date){ - _resourceBookingPageState.value = PageState.LOADING + fun getAllResources(){ viewModelScope.launch { try { - val endpoint = Endpoint.AllResources(dataStoreManager.authSchoolId.toString(), date = date) + val endpoint = Endpoint.AllResourcesTest(dataStoreManager.authSchoolId.value.toString()) val refreshToken = authManager.getRefreshToken() ?: return@launch + val response: ApiResponse> = kronoxManager.getAllResourcesTest(endpoint, refreshToken, null) - val response: ApiResponse> = kronoxManager.getAllResources(endpoint, refreshToken, sessionDetails = null) when(response){ is ApiResponse.Success -> { - _allResources.value = response.data - _resourceBookingPageState.value = PageState.LOADED + _allResourcesTypes.value = response.data + getAllResourcesData(date = isoDateFormatterDate.format(Date())) } - else -> { + is ApiResponse.Error -> { _resourceBookingPageState.value = PageState.ERROR } + else -> {} } }catch (e:Exception){ _resourceBookingPageState.value = PageState.ERROR } + } + } + + fun getAllResourcesData(date: String){ + viewModelScope.launch { + _resourceBookingPageState.value = PageState.LOADING + + val resources: MutableList = mutableListOf() + + _allResourcesTypes.value?.forEach { + it.id?.let { id -> + try { + val endpoint = Endpoint.AllResourceData( + dataStoreManager.authSchoolId.value.toString(), + resourceId = id, + date = date + ) + val refreshToken = authManager.getRefreshToken() ?: return@launch + val response: ApiResponse = + kronoxManager.getAllResourceData(endpoint, refreshToken, null) + + when (response) { + is ApiResponse.Success -> { + resources.add(response.data) + } + + is ApiResponse.Error -> { + _resourceBookingPageState.value = PageState.ERROR + return@launch + } + + else -> {} + } + } catch (e: Exception) { + _resourceBookingPageState.value = PageState.ERROR + return@launch + } + } } + _allResources.value = resources.toList() + _resourceBookingPageState.value = PageState.LOADED } + } + fun confirmResource(resourceId: String, bookingId: String){ From a7998bb872fff9c58f9f628a157ccf680e9e2a9c Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Tue, 8 Oct 2024 09:39:59 +0200 Subject: [PATCH 06/38] get accurate number of availabilitys --- .../Booking/Resources/ResourceLocationsList.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt index 41bacbb..ad9984e 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt @@ -1,5 +1,6 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Resources +import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -47,8 +48,7 @@ fun ResourceLocationsList( allResources.value?.get(resourceIndex)?.let { - val availableCounts = - it.availabilities?.size?:0 + val availableCounts = it.availabilities?.let { it1 -> calcAvailability(it1) }?: 0 ResourceLocationItem( resource = it, @@ -126,4 +126,8 @@ fun ResourceLocationItem( } } } +} + +fun calcAvailability(availabilities: Map>): Int{ + return availabilities.map {location -> location.value.filter { it.value.availability == NetworkResponse.AvailabilityEnum.AVAILABLE }.size}.sum() } \ No newline at end of file From db3ea0ac4869bfc38752677dc2aae229752b910e Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Tue, 8 Oct 2024 09:44:30 +0200 Subject: [PATCH 07/38] ui fixes --- .../Booking/Resources/ResourceBookings.kt | 9 +++--- .../Booking/Resources/ResourceSelection.kt | 29 +++++++++---------- .../Booking/Resources/TimeslotCard.kt | 1 - 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt index 509ed51..5baeb5f 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt @@ -39,7 +39,7 @@ fun ResourceBookings( Column( modifier = Modifier .fillMaxSize() - .background(MaterialTheme.colors.background) // Replace with your theme's background color + .background(MaterialTheme.colors.background) ) { Row { Spacer(modifier = Modifier.weight(1f)) @@ -50,7 +50,6 @@ fun ResourceBookings( Column( modifier = Modifier - .verticalScroll(scrollState) .fillMaxWidth() ) { ResourceDatePicker( @@ -59,7 +58,7 @@ fun ResourceBookings( viewModel.setBookingDate(date) } ) - Divider(color = MaterialTheme.colors.onBackground) // Replace with your theme's divider color + Divider(color = MaterialTheme.colors.onBackground) when (resourceBookingPageState.value) { PageState.LOADING -> { @@ -110,8 +109,8 @@ fun ResourceBookings( } - LaunchedEffect(viewModel.selectedPickerDate) { - viewModel.getAllResourceData(selectedPikerDate.value) + LaunchedEffect(Unit) { + viewModel.getAllResources() } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt index a26df0b..f8dea55 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt @@ -2,59 +2,58 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Bookin import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.text.BasicText import androidx.compose.material.Divider import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import androidx.navigation.NavController -import kotlinx.coroutines.launch import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.models.getAvailabilityValues +import tumble.app.tumble.presentation.components.buttons.CloseCoverButton import tumble.app.tumble.presentation.viewmodels.ResourceViewModel import tumble.app.tumble.presentation.views.general.Info -import java.time.LocalDate +import tumble.app.tumble.utils.isoDateFormatterDate @Composable fun ResourceSelection( parentViewModel: ResourceViewModel = hiltViewModel(), ) { val selectedTimeIndex = remember { mutableStateOf(0) } + val resource = parentViewModel.resourceSelectionModel!!.resource val availabilityValues = remember { - mutableStateOf>(emptyList()) + mutableStateOf>(resource.availabilities.getAvailabilityValues(timelotId = selectedTimeIndex.value)) } - val resource = parentViewModel.resourceSelectionModel!!.resource val selectedPickerDate = parentViewModel.resourceSelectionModel!!.date val timeslots = resource.timeSlots Column( modifier = Modifier .fillMaxSize() - .background(Color.White) // Replace with your background color + .background(MaterialTheme.colors.background) ) { - if (timeslots != null) { + Row { Text( - text = selectedPickerDate.toString(), + text = isoDateFormatterDate.format(selectedPickerDate), fontWeight = FontWeight.SemiBold, - color = Color.Black, // Replace with your color + color = MaterialTheme.colors.onBackground, modifier = Modifier .padding(horizontal = 15.dp, vertical = 20.dp) .fillMaxWidth() ) + Spacer(modifier = Modifier.weight(1f)) + CloseCoverButton(onClick = {parentViewModel.resourceSelectionModel = null}) + } + if (timeslots != null) { TimeslotDropdown( resource = resource, timeslots = timeslots, diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt index 79bd8c9..fdad05f 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt @@ -30,7 +30,6 @@ fun TimeslotCard( modifier = Modifier .fillMaxWidth() .padding(horizontal = 15.dp, vertical = 10.dp) - .background(Color.White) .height(70.dp) .padding(10.dp) .background(MaterialTheme.colors.surface) From c6b49cd42b3bf267bf32f7517f88f9e58aa60e06 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Tue, 8 Oct 2024 09:47:36 +0200 Subject: [PATCH 08/38] api calls for fetching resource and booking events --- .../app/tumble/data/api/ApiServiceKronox.kt | 22 ++++++++++++++++++- .../tumble/app/tumble/data/api/Endpoint.kt | 12 ++++++++++ .../data/api/kronox/KronoxApiService.kt | 7 ++++++ .../data/api/kronox/KronoxRepository.kt | 11 ++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt b/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt index 5aa1629..e2ff82e 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt @@ -6,6 +6,8 @@ import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Header import retrofit2.http.Headers +import retrofit2.http.POST +import retrofit2.http.PUT import retrofit2.http.Url import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.models.network.NetworkResponse.KronoxUserBookingElement @@ -28,6 +30,10 @@ interface ApiServiceKronox { fun put(toString: String, token: String?, body: RequestBody): Response + @PUT() + fun registerForEvent(@Url endpoint: String, + @Header("X-auth-token") refreshToken: String?): Response + @GET() fun getKronoxCompleteUserEvent( @Url endpoint: String, @@ -42,13 +48,27 @@ interface ApiServiceKronox { @Header("X-session-token") sessionDetails: String? ): Call> - @GET + @GET() fun getAllResources( @Url endpoint: String, @Header("X-auth-token") refreshToken: String?, @Header("X-session-token") sessionDetails: String? ): Call> + @GET() + fun getAllResourcesTest( + @Url endpoint: String, + @Header("X-auth-token") refreshToken: String?, + @Header("X-session-token") sessionDetails: String?, + ): Call> + + @GET() + fun getAllResourceData( + @Url endpoint: String, + @Header("X-auth-token") refreshToken: String?, + @Header("X-session-token") sessionDetails: String?, + ): Call + @GET() suspend fun get( @Url url: String, diff --git a/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt b/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt index 3df866a..6ce9f24 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt @@ -21,6 +21,8 @@ sealed class Endpoint { data class ConfirmResource(val schoolId: String) : Endpoint() data class UnBookResource(val schoolId: String, val bookingId: String) : Endpoint() object News : Endpoint() + data class AllResourcesTest(val schoolId: String) : Endpoint() + data class AllResourceData(val schoolId: String, val resourceId: String, val date: String) : Endpoint() } fun Endpoint.url(): String { @@ -53,6 +55,16 @@ fun Endpoint.url(): String { .appendQueryParameter("schoolId", schoolId) .appendQueryParameter("date", date.toIsoString()) } + is Endpoint.AllResourceData -> { + components.path("/api/resources/$resourceId") + .appendQueryParameter("schoolId", schoolId) + .appendQueryParameter("date", date) + + } + is Endpoint.AllResourcesTest -> { + components.path("/api/resources") + .appendQueryParameter("schoolId", schoolId) + } is Endpoint.UserBookings -> { components.path("/api/resources/userbookings") .appendQueryParameter("schoolId", schoolId) diff --git a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt index 4bf808a..bd6bce7 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt @@ -28,6 +28,13 @@ interface KronoxApiService { suspend fun getAllResources(endpoint: Endpoint.AllResources, refreshToken: String?, sessionDetails: String?): ApiResponse> + suspend fun getAllResourcesTest(endpoint: Endpoint.AllResourcesTest, refreshToken: String?, sessionDetails: String?): ApiResponse> + + suspend fun getAllResourceData(endpoint: Endpoint.AllResourceData, refreshToken: String?, sessionDetails: String?): ApiResponse + + + suspend fun registerForEvent(endpoint: Endpoint.RegisterEvent, refreshToken: String?): Response + // @Headers( // "Content-Type: application/json; charset=utf-8", // "Accept: application/json; charset=utf-8" diff --git a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt index ed4c969..86612cf 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt @@ -46,6 +46,17 @@ class KronoxRepository @Inject constructor(private val retrofit: Retrofit): Kron return kronoxApiService.getAllResources(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() } + override suspend fun getAllResourcesTest(endpoint: Endpoint.AllResourcesTest, refreshToken: String?, sessionDetails: String?): ApiResponse>{ + return kronoxApiService.getAllResourcesTest(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() + } + + override suspend fun getAllResourceData(endpoint: Endpoint.AllResourceData, refreshToken: String?, sessionDetails: String?): ApiResponse{ + return kronoxApiService.getAllResourceData(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() + } + + override suspend fun registerForEvent(endpoint: Endpoint.RegisterEvent, refreshToken: String?): Response { + return kronoxApiService.registerForEvent(endpoint.url(), refreshToken) + } From 9fa34179f3a83ff5ea1e9340394c96f58bde332e Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Tue, 8 Oct 2024 09:48:23 +0200 Subject: [PATCH 09/38] fixed location id being null --- .../models/NetworkResponseAvailabilitiesExtension.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt b/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt index 2585690..64beaa6 100644 --- a/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt +++ b/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt @@ -20,10 +20,10 @@ fun availabilities.getAvailabilityValues(timelotId: Int): List() - for ((_, availabilityValues) in availabilities){ + for ((location, availabilityValues) in availabilities){ val availabilityValue = availabilityValues[timelotId] if(availabilityValue?.availability == NetworkResponse.AvailabilityEnum.AVAILABLE){ - availabilityValueResult.add(availabilityValue) + availabilityValueResult.add(availabilityValue.copy(locationID = location)) } } return availabilityValueResult From 703fcce7cef1440e2f999639f134a831d6ea778d Mon Sep 17 00:00:00 2001 From: Sven Date: Tue, 8 Oct 2024 10:15:21 +0200 Subject: [PATCH 10/38] string resources --- .../presentation/views/Settings/Settings.kt | 31 +++++++++---------- .../presentation/views/Settings/ShareSheet.kt | 2 +- app/src/main/res/values/strings.xml | 1 + 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt index 9eda317..ccae968 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Settings.kt @@ -2,18 +2,17 @@ package tumble.app.tumble.presentation.views.Settings import android.content.Intent import android.net.Uri +import android.provider.Settings import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.material.Button import androidx.compose.material.Divider import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Text -import androidx.compose.material.TopAppBar import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AccessTime import androidx.compose.material.icons.filled.ArrowBackIosNew @@ -36,7 +35,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -46,6 +44,7 @@ import androidx.core.content.ContextCompat.startActivity import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import tumble.app.tumble.R +import tumble.app.tumble.domain.enums.Types.appearanceTypeToStringResource import tumble.app.tumble.presentation.navigation.Routes import tumble.app.tumble.presentation.viewmodels.SettingsViewModel import tumble.app.tumble.presentation.views.Settings.Buttons.SettingsExternalButton @@ -97,7 +96,7 @@ fun SettingsScreen( SettingsListGroup { SettingsNavigationButton( title = stringResource(R.string.appearance), - current = appearance.value.name, + current = appearanceTypeToStringResource(appearance.value), leadingIcon = Icons.Default.DarkMode, leadingIconBackgroundColor = MaterialTheme.colors.primary, destination = { navController.navigate(Routes.accountSettingsAppearance) } @@ -108,7 +107,9 @@ fun SettingsScreen( current = currentLocale, leadingIcon = Icons.Default.Language, leadingIconBackgroundColor = Color.Blue, - action = {}, + action = { + startActivity(context, Intent(Settings.ACTION_LOCALE_SETTINGS), null) + }, ) } SettingsListGroup { @@ -133,17 +134,15 @@ fun SettingsScreen( title = stringResource(id = R.string.review_app), leadingIcon = Icons.Default.Star, leadingIconBackgroundColor = Color.Yellow, - action = { - externalNav("market://details?id=") - }, - ) - Divider() - SettingsExternalButton( - title = stringResource(id = R.string.share_feedback), - leadingIcon = Icons.Default.Email, - leadingIconBackgroundColor = Color.Blue, - action = {externalNav("http://www.google.com")}, + action = { externalNav("market://details?id=com.tumble.kronoxtoapp") },// might work ) +// Divider() +// SettingsExternalButton( +// title = stringResource(id = R.string.share_feedback), +// leadingIcon = Icons.Default.Email, +// leadingIconBackgroundColor = Color.Blue, +// action = { externalNav("http://www.google.com") }, // +// ) Divider() SettingsExternalButton( title = stringResource(R.string.share_app), @@ -157,7 +156,7 @@ fun SettingsScreen( title = stringResource(id = R.string.github), leadingIcon = Icons.Default.Code, leadingIconBackgroundColor = Color.Black, - action = {externalNav("https://github.com/tumble-for-kronox/Tumble-Android")}, + action = { externalNav("https://github.com/tumble-for-kronox/Tumble-Android") }, ) } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/ShareSheet.kt b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/ShareSheet.kt index b71de88..ed36061 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/ShareSheet.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/ShareSheet.kt @@ -157,7 +157,7 @@ fun CopyButton(link: String, context: Context) { horizontalArrangement = Arrangement.SpaceBetween ) { Column { - Text(text = "Copy link", fontSize = 16.sp) + Text(text = stringResource(R.string.copy_tumble_link) , fontSize = 16.sp) Text(text = link, fontSize = 12.sp, color = Color.Gray) } Icon( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b0e1ad2..e4a5a73 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -42,4 +42,5 @@ Scan QR Code See all Book more + Copy link \ No newline at end of file From f5f31685f174c5768978d300a830a54be0c48c66 Mon Sep 17 00:00:00 2001 From: Sven Date: Tue, 8 Oct 2024 14:08:26 +0200 Subject: [PATCH 11/38] api calls for resource booking --- .../app/tumble/data/api/ApiServiceKronox.kt | 24 ++++++++++- .../tumble/app/tumble/data/api/Endpoint.kt | 15 ++++--- .../data/api/kronox/KronoxApiService.kt | 10 ++++- .../data/api/kronox/KronoxRepository.kt | 24 +++++++++-- .../viewmodels/ResourceViewModel.kt | 41 ++++++++++++------- 5 files changed, 86 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt b/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt index e2ff82e..bfa473a 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt @@ -3,12 +3,14 @@ package tumble.app.tumble.datasource.network import okhttp3.RequestBody import retrofit2.Call import retrofit2.Response +import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Header import retrofit2.http.Headers import retrofit2.http.POST import retrofit2.http.PUT import retrofit2.http.Url +import tumble.app.tumble.domain.models.network.NetworkRequest import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.models.network.NetworkResponse.KronoxUserBookingElement import tumble.app.tumble.domain.models.network.NewsItems @@ -34,6 +36,26 @@ interface ApiServiceKronox { fun registerForEvent(@Url endpoint: String, @Header("X-auth-token") refreshToken: String?): Response + @PUT() + fun bookResource( + @Url endpoint: String, + @Header("X-auth-token") refreshToken: String?, + @Body resource: NetworkRequest.BookKronoxResource + ): Response + + @PUT() + fun confirmResource( + @Url endpoint: String, + @Header("X-auth-token") refreshToken: String?, + @Body resource: NetworkRequest.ConfirmKronoxResource + ): Response + + @PUT() + fun unBookResource( + @Url endpoint: String, + @Header("X-auth-token") refreshToken: String?, + ): Response + @GET() fun getKronoxCompleteUserEvent( @Url endpoint: String, @@ -56,7 +78,7 @@ interface ApiServiceKronox { ): Call> @GET() - fun getAllResourcesTest( + fun getAllResourcesTypes( @Url endpoint: String, @Header("X-auth-token") refreshToken: String?, @Header("X-session-token") sessionDetails: String?, diff --git a/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt b/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt index 6ce9f24..98689d9 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt @@ -10,7 +10,7 @@ sealed class Endpoint { data class Schedule(val scheduleId: String, val schoolId: String) : Endpoint() data class UserEvents(val schoolId: String) : Endpoint() data class ResourceAvailabilities(val schoolId: String, val resourceId: String, val date: String) : Endpoint() - data class AllResources(val schoolId: String, val date: Date) : Endpoint() + data class AllResources(val schoolId: String) : Endpoint() data class UserBookings(val schoolId: String) : Endpoint() data class Login(val schoolId: String) : Endpoint() data class Users(val schoolId: String) : Endpoint() @@ -21,7 +21,7 @@ sealed class Endpoint { data class ConfirmResource(val schoolId: String) : Endpoint() data class UnBookResource(val schoolId: String, val bookingId: String) : Endpoint() object News : Endpoint() - data class AllResourcesTest(val schoolId: String) : Endpoint() + //data class AllResourcesTest(val schoolId: String) : Endpoint() data class AllResourceData(val schoolId: String, val resourceId: String, val date: String) : Endpoint() } @@ -51,9 +51,8 @@ fun Endpoint.url(): String { .appendQueryParameter("date", date) } is Endpoint.AllResources -> { - components.path("/api/resources/all") + components.path("/api/resources") .appendQueryParameter("schoolId", schoolId) - .appendQueryParameter("date", date.toIsoString()) } is Endpoint.AllResourceData -> { components.path("/api/resources/$resourceId") @@ -61,10 +60,10 @@ fun Endpoint.url(): String { .appendQueryParameter("date", date) } - is Endpoint.AllResourcesTest -> { - components.path("/api/resources") - .appendQueryParameter("schoolId", schoolId) - } +// is Endpoint.AllResourcesTest -> { +// components.path("/api/resources") +// .appendQueryParameter("schoolId", schoolId) +// } is Endpoint.UserBookings -> { components.path("/api/resources/userbookings") .appendQueryParameter("schoolId", schoolId) diff --git a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt index bd6bce7..83272a6 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt @@ -11,6 +11,7 @@ import retrofit2.http.PUT import retrofit2.http.Url import tumble.app.tumble.data.api.Endpoint import tumble.app.tumble.datasource.network.ApiResponse +import tumble.app.tumble.domain.models.network.NetworkRequest import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.models.network.NetworkResponse.KronoxUserBookingElement import tumble.app.tumble.domain.models.network.NewsItems @@ -28,13 +29,18 @@ interface KronoxApiService { suspend fun getAllResources(endpoint: Endpoint.AllResources, refreshToken: String?, sessionDetails: String?): ApiResponse> - suspend fun getAllResourcesTest(endpoint: Endpoint.AllResourcesTest, refreshToken: String?, sessionDetails: String?): ApiResponse> +// suspend fun getAllResourcesTypes(endpoint: Endpoint.AllResourcesTest, refreshToken: String?, sessionDetails: String?): ApiResponse> suspend fun getAllResourceData(endpoint: Endpoint.AllResourceData, refreshToken: String?, sessionDetails: String?): ApiResponse - suspend fun registerForEvent(endpoint: Endpoint.RegisterEvent, refreshToken: String?): Response + suspend fun bookResource(endpoint: Endpoint.BookResource, refreshToken: String?, resource: NetworkRequest.BookKronoxResource): Response + + suspend fun confirmResource(endpoint: Endpoint.ConfirmResource, refreshToken: String?, resource: NetworkRequest.ConfirmKronoxResource): Response + + suspend fun unBookResource(endpoint: Endpoint.UnBookResource, refreshToken: String?): Response + // @Headers( // "Content-Type: application/json; charset=utf-8", // "Accept: application/json; charset=utf-8" diff --git a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt index 86612cf..36170e6 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt @@ -10,6 +10,7 @@ import tumble.app.tumble.data.api.url import tumble.app.tumble.datasource.network.ApiResponse import tumble.app.tumble.datasource.network.ApiServiceKronox import tumble.app.tumble.datasource.network.extensions.callToApiResponse +import tumble.app.tumble.domain.models.network.NetworkRequest import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.models.network.NetworkResponse.KronoxUserBookingElement import tumble.app.tumble.domain.models.network.NewsItems @@ -46,9 +47,9 @@ class KronoxRepository @Inject constructor(private val retrofit: Retrofit): Kron return kronoxApiService.getAllResources(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() } - override suspend fun getAllResourcesTest(endpoint: Endpoint.AllResourcesTest, refreshToken: String?, sessionDetails: String?): ApiResponse>{ - return kronoxApiService.getAllResourcesTest(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() - } +// override suspend fun getAllResourcesTypes(endpoint: Endpoint.AllResourcesTest, refreshToken: String?, sessionDetails: String?): ApiResponse>{ +// return kronoxApiService.getAllResourcesTypes(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() +// } override suspend fun getAllResourceData(endpoint: Endpoint.AllResourceData, refreshToken: String?, sessionDetails: String?): ApiResponse{ return kronoxApiService.getAllResourceData(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() @@ -58,7 +59,24 @@ class KronoxRepository @Inject constructor(private val retrofit: Retrofit): Kron return kronoxApiService.registerForEvent(endpoint.url(), refreshToken) } + override suspend fun bookResource(endpoint: Endpoint.BookResource, refreshToken: String?, resource: NetworkRequest.BookKronoxResource): Response { + return kronoxApiService.bookResource(endpoint.url(), refreshToken, resource) + } + override suspend fun confirmResource( + endpoint: Endpoint.ConfirmResource, + refreshToken: String?, + resource: NetworkRequest.ConfirmKronoxResource + ): Response { + return kronoxApiService.confirmResource(endpoint.url(), refreshToken, resource) + } + + override suspend fun unBookResource( + endpoint: Endpoint.UnBookResource, + refreshToken: String? + ): Response { + return kronoxApiService.unBookResource(endpoint.url(), refreshToken) + } // override suspend fun get( // endpoint: Endpoint, diff --git a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt index 8203f57..f70fd48 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt @@ -57,13 +57,11 @@ class ResourceViewModel @Inject constructor( private val _allResourcesTypes = MutableStateFlow?>(null) val allResourcesTypes: StateFlow?> = _allResourcesTypes - //val allResources: List? = null private val _resourceSelectionModel = MutableStateFlow(null) var resourceSelectionModel by mutableStateOf(null) - fun setBookingDate(newDate: Date){ _selectedPickerDate.value = newDate viewModelScope.launch { getAllResourcesData(isoDateFormatterDate.format(newDate)) } @@ -118,9 +116,9 @@ class ResourceViewModel @Inject constructor( fun getAllResources(){ viewModelScope.launch { try { - val endpoint = Endpoint.AllResourcesTest(dataStoreManager.authSchoolId.value.toString()) + val endpoint = Endpoint.AllResources(dataStoreManager.authSchoolId.value.toString()) val refreshToken = authManager.getRefreshToken() ?: return@launch - val response: ApiResponse> = kronoxManager.getAllResourcesTest(endpoint, refreshToken, null) + val response: ApiResponse> = kronoxManager.getAllResources(endpoint, refreshToken, null) when(response){ is ApiResponse.Success -> { @@ -179,20 +177,35 @@ class ResourceViewModel @Inject constructor( } } - - fun confirmResource(resourceId: String, bookingId: String){ - //TODO - } + val endpoint = Endpoint.ConfirmResource(dataStoreManager.authSchoolId.value.toString()) + val resource = NetworkRequest.ConfirmKronoxResource(resourceId, bookingId) + val refreshToken = authManager.getRefreshToken() ?: return - fun bookResource(resourceId: String, date: Date, availabilityValue: NetworkResponse.AvailabilityValue):Boolean{ - //TODO - return false + viewModelScope.launch { + val response = kronoxManager.confirmResource(endpoint, refreshToken, resource) + } } - fun unbookResource(bookingId: String): Boolean{ - //TODO - return true + fun bookResource(resourceId: String, date: Date, availabilityValue: NetworkResponse.AvailabilityValue){ + val endpoint = Endpoint.BookResource(dataStoreManager.authSchoolId.value.toString()) + val resource = NetworkRequest.BookKronoxResource(resourceId, isoDateFormatterDate.format(date), availabilityValue) + val refreshToken = authManager.getRefreshToken() ?: return + + viewModelScope.launch { + val response = kronoxManager.bookResource(endpoint, refreshToken, resource) + if (response.isSuccessful){ + return@launch + } + } } + fun unBookResource(bookingId: String){ + val endpoint = Endpoint.UnBookResource(dataStoreManager.authSchoolId.value.toString(), bookingId) + val refreshToken = authManager.getRefreshToken() ?: return + + viewModelScope.launch { + val response = kronoxManager.unBookResource(endpoint, refreshToken) + } + } } \ No newline at end of file From 1e48bc5f52c4b87f0d7106f13b20320de02c76d7 Mon Sep 17 00:00:00 2001 From: Sven Date: Tue, 8 Oct 2024 14:10:29 +0200 Subject: [PATCH 12/38] minor refactor --- .../Booking/Resources/ResourceSelection.kt | 8 +++----- .../ResourceSection/Booking/Resources/TimelotSelection.kt | 6 ++---- app/src/main/res/values/strings.xml | 1 + 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt index f8dea55..3a94f24 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt @@ -65,15 +65,13 @@ fun ResourceSelection( ) Divider(modifier = Modifier.padding(vertical = 8.dp)) TimeslotSelection( - resourceId = resource.id!!, - bookResource = { resourceId, date, availabilityValue -> + bookResource = { availabilityValue -> parentViewModel.bookResource( - resourceId = resourceId, - date = date, + resourceId = resource.id!!, + date = selectedPickerDate, availabilityValue = availabilityValue ) }, - selectedPickerDate = selectedPickerDate, availabilityValues = availabilityValues ) } else { diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt index 84e7cf3..d115a1b 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt @@ -33,9 +33,7 @@ enum class BookingButtonState { @Composable fun TimeslotSelection( - resourceId: String, - bookResource: (String, Date, NetworkResponse.AvailabilityValue) -> Boolean, - selectedPickerDate: Date, + bookResource: (NetworkResponse.AvailabilityValue) -> Unit, availabilityValues: MutableState> ) { val buttonStateMap = remember { mutableMapOf() } @@ -64,7 +62,7 @@ fun TimeslotSelection( availabilityValues.value.forEach { availabilityValue -> availabilityValue.locationID?.let { locationId -> TimeslotCard( - onBook = { bookResource(resourceId, selectedPickerDate, availabilityValue) }, + onBook = { bookResource(availabilityValue) }, locationId = locationId, bookingButtonState = buttonStateMap[locationId] ?: BookingButtonState.AVAILABLE ) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b0e1ad2..e4a5a73 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -42,4 +42,5 @@ Scan QR Code See all Book more + Copy link \ No newline at end of file From 58d371f0fe34365e095bf81ca3560935b77f743f Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Fri, 25 Oct 2024 17:45:49 +0200 Subject: [PATCH 13/38] added api for resources --- .../app/tumble/data/api/ApiServiceKronox.kt | 23 +++++------ .../data/api/kronox/KronoxApiService.kt | 12 ++++-- .../data/api/kronox/KronoxRepository.kt | 39 ++++++++++++------- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt b/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt index bfa473a..3e3d279 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt @@ -34,27 +34,35 @@ interface ApiServiceKronox { @PUT() fun registerForEvent(@Url endpoint: String, - @Header("X-auth-token") refreshToken: String?): Response + @Header("X-auth-token") refreshToken: String?): Call + + @PUT() + fun registerForAllEvents(@Url endpoint: String, + @Header("X-auth-token") refreshToken: String?): Call> + + @PUT() + fun unRegisterForEvent(@Url endpoint: String, + @Header("X-auth-token") refreshToken: String?): Call @PUT() fun bookResource( @Url endpoint: String, @Header("X-auth-token") refreshToken: String?, @Body resource: NetworkRequest.BookKronoxResource - ): Response + ): Call @PUT() fun confirmResource( @Url endpoint: String, @Header("X-auth-token") refreshToken: String?, @Body resource: NetworkRequest.ConfirmKronoxResource - ): Response + ): Call @PUT() fun unBookResource( @Url endpoint: String, @Header("X-auth-token") refreshToken: String?, - ): Response + ): Call @GET() fun getKronoxCompleteUserEvent( @@ -77,13 +85,6 @@ interface ApiServiceKronox { @Header("X-session-token") sessionDetails: String? ): Call> - @GET() - fun getAllResourcesTypes( - @Url endpoint: String, - @Header("X-auth-token") refreshToken: String?, - @Header("X-session-token") sessionDetails: String?, - ): Call> - @GET() fun getAllResourceData( @Url endpoint: String, diff --git a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt index 83272a6..8be3f8c 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt @@ -33,13 +33,17 @@ interface KronoxApiService { suspend fun getAllResourceData(endpoint: Endpoint.AllResourceData, refreshToken: String?, sessionDetails: String?): ApiResponse - suspend fun registerForEvent(endpoint: Endpoint.RegisterEvent, refreshToken: String?): Response + suspend fun registerForEvent(endpoint: Endpoint.RegisterEvent, refreshToken: String?): ApiResponse - suspend fun bookResource(endpoint: Endpoint.BookResource, refreshToken: String?, resource: NetworkRequest.BookKronoxResource): Response + suspend fun bookResource(endpoint: Endpoint.BookResource, refreshToken: String?, resource: NetworkRequest.BookKronoxResource): ApiResponse - suspend fun confirmResource(endpoint: Endpoint.ConfirmResource, refreshToken: String?, resource: NetworkRequest.ConfirmKronoxResource): Response + suspend fun confirmResource(endpoint: Endpoint.ConfirmResource, refreshToken: String?, resource: NetworkRequest.ConfirmKronoxResource): ApiResponse - suspend fun unBookResource(endpoint: Endpoint.UnBookResource, refreshToken: String?): Response + suspend fun unBookResource(endpoint: Endpoint.UnBookResource, refreshToken: String?): ApiResponse + + suspend fun unRegisterForEvent(endpoint: Endpoint.UnregisterEvent, refreshToken: String?): ApiResponse + + suspend fun registerForAllEvents(endpoint: Endpoint.RegisterAllEvents, refreshToken: String?): ApiResponse> // @Headers( // "Content-Type: application/json; charset=utf-8", diff --git a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt index 36170e6..1d1a5b5 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt @@ -1,5 +1,6 @@ package tumble.app.tumble.datasource.network.kronox +import android.util.Log import okhttp3.Request import okhttp3.RequestBody import retrofit2.Call @@ -40,44 +41,56 @@ class KronoxRepository @Inject constructor(private val retrofit: Retrofit): Kron } override suspend fun getKronoxUserBookings(endpoint: Endpoint.UserBookings, refreshToken: String?, sessionDetails: String?): ApiResponse>{ - return kronoxApiService.getKronoxUserBookings(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() + val call = kronoxApiService.getKronoxUserBookings(endpoint.url(), refreshToken, sessionDetails) + return call.callToApiResponse() } override suspend fun getAllResources(endpoint: Endpoint.AllResources, refreshToken: String?, sessionDetails: String?): ApiResponse>{ return kronoxApiService.getAllResources(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() } -// override suspend fun getAllResourcesTypes(endpoint: Endpoint.AllResourcesTest, refreshToken: String?, sessionDetails: String?): ApiResponse>{ -// return kronoxApiService.getAllResourcesTypes(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() -// } - override suspend fun getAllResourceData(endpoint: Endpoint.AllResourceData, refreshToken: String?, sessionDetails: String?): ApiResponse{ return kronoxApiService.getAllResourceData(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() } - override suspend fun registerForEvent(endpoint: Endpoint.RegisterEvent, refreshToken: String?): Response { - return kronoxApiService.registerForEvent(endpoint.url(), refreshToken) + override suspend fun registerForEvent(endpoint: Endpoint.RegisterEvent, refreshToken: String?): ApiResponse { + return kronoxApiService.registerForEvent(endpoint.url(), refreshToken).callToApiResponse() } - override suspend fun bookResource(endpoint: Endpoint.BookResource, refreshToken: String?, resource: NetworkRequest.BookKronoxResource): Response { - return kronoxApiService.bookResource(endpoint.url(), refreshToken, resource) + override suspend fun bookResource(endpoint: Endpoint.BookResource, refreshToken: String?, resource: NetworkRequest.BookKronoxResource): ApiResponse { + return kronoxApiService.bookResource(endpoint.url(), refreshToken, resource).callToApiResponse() } override suspend fun confirmResource( endpoint: Endpoint.ConfirmResource, refreshToken: String?, resource: NetworkRequest.ConfirmKronoxResource - ): Response { - return kronoxApiService.confirmResource(endpoint.url(), refreshToken, resource) + ): ApiResponse { + return kronoxApiService.confirmResource(endpoint.url(), refreshToken, resource).callToApiResponse() } override suspend fun unBookResource( endpoint: Endpoint.UnBookResource, refreshToken: String? - ): Response { - return kronoxApiService.unBookResource(endpoint.url(), refreshToken) + ): ApiResponse { + return kronoxApiService.unBookResource(endpoint.url(), refreshToken).callToApiResponse() + } + + override suspend fun unRegisterForEvent( + endpoint: Endpoint.UnregisterEvent, + refreshToken: String? + ): ApiResponse { + return kronoxApiService.unRegisterForEvent(endpoint.url(), refreshToken).callToApiResponse() } + override suspend fun registerForAllEvents( + endpoint: Endpoint.RegisterAllEvents, + refreshToken: String? + ): ApiResponse> { + return kronoxApiService.registerForAllEvents(endpoint.url(), refreshToken).callToApiResponse() + } + + // override suspend fun get( // endpoint: Endpoint, // refreshToken: String?, From 8fdf62a03bc652b0fe48ea215d7a00fd24d4d38f Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Fri, 25 Oct 2024 17:56:35 +0200 Subject: [PATCH 14/38] fixed bug with reciving data from backend --- .../domain/models/network/NetworkResponse.kt | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/domain/models/network/NetworkResponse.kt b/app/src/main/java/tumble/app/tumble/domain/models/network/NetworkResponse.kt index 19195ee..b805a22 100644 --- a/app/src/main/java/tumble/app/tumble/domain/models/network/NetworkResponse.kt +++ b/app/src/main/java/tumble/app/tumble/domain/models/network/NetworkResponse.kt @@ -107,15 +107,15 @@ sealed class NetworkResponse { @JsonClass(generateAdapter = true) data class AvailableKronoxUserEvent( @Transient - val id: UUID = UUID.randomUUID(), - val eventId: String?, - val title: String?, - val type: String?, + val eventId: UUID = UUID.randomUUID(), + val id: String?, + val title: String, + val type: String, val eventStart: String, val eventEnd: String, val lastSignupDate: String, - val participatorID: String?, - val supportID: String?, + val participatorId: String?, + val supportId: String?, val anonymousCode: String, val isRegistered: Boolean, val supportAvailable: Boolean, @@ -149,16 +149,16 @@ sealed class NetworkResponse { val name: String?, val timeSlots: List?, val date: String?, - val locationIDS: List?, + val locationIds: List?, val availabilities: Map>? ): NetworkResponse() @JsonClass(generateAdapter = true) data class AvailabilityValue( val availability: AvailabilityEnum?, - val locationID: String?, + val locationId: String?, val resourceType: String?, - val timeSlotID: String?, + val timeSlotId: String?, val bookedBy: String? ): NetworkResponse() @@ -179,13 +179,13 @@ sealed class NetworkResponse { @JsonClass(generateAdapter = true) data class KronoxUserBookingElement( val id: String, - val resourceID: String, + val resourceId: String, val timeSlot: TimeSlot, - val locationID: String, + val locationId: String, val showConfirmButton: Boolean, - val showUnBookButton: Boolean, - val confirmationOpen: String?, - val confirmationClosed: String? + val showUnbookButton: Boolean, + val confirmationOpen: String, + val confirmationClosed: String ): NetworkResponse() @JsonClass(generateAdapter = true) @@ -207,8 +207,8 @@ sealed class NetworkResponse { val eventStart: String?, val eventEnd: String?, val lastSignupDate: String?, - val participatorID: String?, - val supportID: String?, + val participatorId: String?, + val supportId: String?, val anonymousCode: String?, val isRegistered: Boolean?, val supportAvailable: Boolean?, From a113edddc608d932ccb149cd8705d33104b606ea Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Fri, 25 Oct 2024 17:58:18 +0200 Subject: [PATCH 15/38] added function that returns first time slot with availability --- .../NetworkResponseAvailabilitiesExtension.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt b/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt index 64beaa6..2e9d334 100644 --- a/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt +++ b/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt @@ -16,6 +16,17 @@ fun availabilities.timelotHasAvailable(timelotId: Int):Boolean { return false } +fun availabilities.getFirstTimeSlotWithAvailability(numOfTimeSlots: Int): Int{ + for(i in 0..numOfTimeSlots){ + for(j in this!!.values){ + if(j[i]!!.availability == NetworkResponse.AvailabilityEnum.AVAILABLE){ + return i + } + } + } + return 1 +} + fun availabilities.getAvailabilityValues(timelotId: Int): List{ val availabilities = this?: return emptyList() @@ -23,7 +34,7 @@ fun availabilities.getAvailabilityValues(timelotId: Int): List Date: Fri, 25 Oct 2024 19:58:17 +0200 Subject: [PATCH 16/38] navigation for account --- .../app/tumble/presentation/navigation/Routes.kt | 2 +- .../navigation/navgraphs/AccountNavGraph.kt | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/navigation/Routes.kt b/app/src/main/java/tumble/app/tumble/presentation/navigation/Routes.kt index 890643c..871b41a 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/navigation/Routes.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/navigation/Routes.kt @@ -18,7 +18,7 @@ object Routes { // Protected routes const val accountResources = "account/resources" - const val accountResourceDetails = "account/resources?resourceId={id}" + const val accountResourceDetails = "account/resources/{id}" const val accountEvents = "account/events" const val accountEventDetails = "account/events?eventId={id}" diff --git a/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/AccountNavGraph.kt b/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/AccountNavGraph.kt index 1de6270..f982328 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/AccountNavGraph.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/AccountNavGraph.kt @@ -8,6 +8,7 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable +import androidx.navigation.navDeepLink import tumble.app.tumble.presentation.navigation.Routes import tumble.app.tumble.presentation.views.Settings.AppearanceSettings.AppearanceSettings import tumble.app.tumble.presentation.views.Settings.Bookmarks.BookmarksSettings @@ -16,6 +17,7 @@ import tumble.app.tumble.presentation.views.Settings.SettingsScreen import tumble.app.tumble.presentation.views.account.Account import tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Events.EventBookings import tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Resources.ResourceBookings +import tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Resources.ResourceSelection @RequiresApi(Build.VERSION_CODES.O) @Composable @@ -84,7 +86,7 @@ private fun NavGraphBuilder.accountSettingsBookmarks(navController: NavHostContr @RequiresApi(Build.VERSION_CODES.O) private fun NavGraphBuilder.accountResources(navController: NavHostController) { composable(Routes.accountResources) { - //ResourceBookings(navController = navController) + ResourceBookings(navController = navController) } } @@ -92,9 +94,13 @@ private fun NavGraphBuilder.accountResources(navController: NavHostController) { private fun NavGraphBuilder.accountResourceDetails(navController: NavHostController) { composable( Routes.accountResourceDetails, + deepLinks = listOf( + navDeepLink { uriPattern = Routes.AccountResourceDetailsUri}, + ) ) { backStackEntry -> val id = backStackEntry.arguments?.getString("id") - ResourceBookings(navController = navController) + ResourceSelection(navController = navController) + //ResourceBookings(navController = navController) } } From fed7bba84925edcaba12f2d8c71f4211972d0752 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Fri, 25 Oct 2024 20:16:37 +0200 Subject: [PATCH 17/38] added sheed header and miner ui updates --- .../components/sheets/SheetHeader.kt | 37 +++++++++++++++++++ .../bookmarks/EventDetails/DetailsBuilder.kt | 5 ++- .../EventDetails/EventDetailsCard.kt | 2 +- .../EventDetails/EventDetailsSheet.kt | 31 ++++++++-------- 4 files changed, 57 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/tumble/app/tumble/presentation/components/sheets/SheetHeader.kt diff --git a/app/src/main/java/tumble/app/tumble/presentation/components/sheets/SheetHeader.kt b/app/src/main/java/tumble/app/tumble/presentation/components/sheets/SheetHeader.kt new file mode 100644 index 0000000..773f3f2 --- /dev/null +++ b/app/src/main/java/tumble/app/tumble/presentation/components/sheets/SheetHeader.kt @@ -0,0 +1,37 @@ +package tumble.app.tumble.presentation.components.sheets + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.sp +import tumble.app.tumble.presentation.components.buttons.CloseCoverButton + + +@Composable +fun SheetHeader( + title: String, + onClose: () -> Unit +){ + + Box(contentAlignment = Alignment.Center) { + Row(verticalAlignment = Alignment.CenterVertically) { + Spacer(modifier = Modifier.weight(1f)) + Text( + text = title,// make string resource + fontSize = 20.sp + ) + Spacer(modifier = Modifier.weight(1f)) + } + Row { + Spacer(modifier = Modifier.weight(1f)) + CloseCoverButton { + onClose() + } + } + } + +} diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/DetailsBuilder.kt b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/DetailsBuilder.kt index 6309535..064173b 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/DetailsBuilder.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/DetailsBuilder.kt @@ -17,6 +17,7 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontWeight @@ -50,13 +51,13 @@ fun DetailsBuilder( contentDescription = null, contentScale = ContentScale.Crop, modifier = Modifier.size(17.dp), - alpha = 1f + colorFilter = ColorFilter.tint(MaterialTheme.colors.onSurface) ) Text( text = title, fontSize = 17.sp, fontWeight = FontWeight.Bold, - color = MaterialTheme.colors.onBackground + color = MaterialTheme.colors.onSurface ) } Spacer(modifier = Modifier.height(5.dp)) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsCard.kt b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsCard.kt index 652251c..a76ed83 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsCard.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsCard.kt @@ -32,7 +32,7 @@ fun EventDetailsCard( ){ Column( modifier = Modifier - .padding() + .padding(horizontal = 15.dp) .background( if (event.isSpecial) Color.Red.copy(alpha = 0.2f) else color.copy(alpha = 0.2f), shape = RoundedCornerShape(15.dp) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsSheet.kt b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsSheet.kt index 8766a3e..d0f6a9c 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsSheet.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsSheet.kt @@ -10,30 +10,38 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import tumble.app.tumble.domain.models.realm.Event import tumble.app.tumble.extensions.presentation.toColor import tumble.app.tumble.observables.AppController import tumble.app.tumble.presentation.components.buttons.CloseCoverButton +import tumble.app.tumble.presentation.components.sheets.SheetHeader @Composable fun EventDetailsSheet( event: Event, -){ - Column(modifier = Modifier - .fillMaxSize() - .background(MaterialTheme.colors.background) - ){ - Spacer(modifier = Modifier.height(20.dp)) - Box{ +) { + Column( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colors.background) + ) { + + SheetHeader(title = "Details", onClose = {onClose()}) + + //Spacer(modifier = Modifier.height(20.dp)) + Box { Column( modifier = Modifier .verticalScroll(rememberScrollState()) .background(MaterialTheme.colors.background) - ){ + ) { EventDetailsCard( openColorPicker = { openColorPicker() }, event = event, @@ -42,15 +50,8 @@ fun EventDetailsSheet( EventDetailsBody(event) Spacer(modifier = Modifier.height(60.dp)) } - Row { - Spacer(modifier = Modifier.weight(1f)) - CloseCoverButton { - onClose() - } - } //ColorPicker() } - Spacer(modifier = Modifier.height(30.dp)) } } From 8c38405d5b147467a69710b64c86b6d81b57a685 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Fri, 25 Oct 2024 20:23:59 +0200 Subject: [PATCH 18/38] event and resource sheets --- .../Booking/Sheets/EventDetails.kt | 96 ++++++++++++++ .../Booking/Sheets/ResourceDetails.kt | 122 ++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt create mode 100644 app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt new file mode 100644 index 0000000..f794786 --- /dev/null +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt @@ -0,0 +1,96 @@ +package tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Sheets + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AccessTime +import androidx.compose.material.icons.filled.CalendarMonth +import androidx.compose.material.icons.filled.CheckCircleOutline +import androidx.compose.material.icons.filled.Info +import androidx.compose.material.icons.filled.LocationOn +import androidx.compose.material.icons.filled.Timelapse +import androidx.compose.material.icons.filled.Title +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import tumble.app.tumble.domain.models.network.NetworkResponse +import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString +import tumble.app.tumble.extensions.presentation.formatDate +import tumble.app.tumble.presentation.components.buttons.CloseCoverButton +import tumble.app.tumble.presentation.components.sheets.SheetHeader +import tumble.app.tumble.presentation.views.bookmarks.EventDetails.DetailsBuilder + +@Composable +fun EventDetailsSheet( + event: NetworkResponse.AvailableKronoxUserEvent, + onClose: () -> Unit + //sheetContent: @Composable () -> Unit +) { + Column( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colors.background) + ) { + SheetHeader(title = "Event details", onClose = onClose) + Box { + Column( + modifier = Modifier + .verticalScroll(rememberScrollState()) + .background(MaterialTheme.colors.background) + ) { + + //sheetContent() + + DetailsBuilder(title = "Title", image = Icons.Default.Title) { + + Text( + text = event.title.toString(), + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + + } + DetailsBuilder(title = "Type", image = Icons.Default.Info) { + Text( + text = event.type.toString(), + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } + + DetailsBuilder(title = "Date", image = Icons.Default.CalendarMonth) { + val eventDate = event.eventStart.formatDate() + val eventStart = event.eventStart.convertToHoursAndMinutesISOString() + val eventEnd = event.eventEnd.convertToHoursAndMinutesISOString() + Text( + text = "$eventDate, from $eventStart to $eventEnd" + , + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } + + DetailsBuilder(title = "Available until", image = Icons.Default.Timelapse) { + Text( + text = event.lastSignupDate.formatDate().orEmpty() + , + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } + Spacer(modifier = Modifier.height(60.dp)) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt new file mode 100644 index 0000000..bf16790 --- /dev/null +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt @@ -0,0 +1,122 @@ +package tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Sheets + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CalendarMonth +import androidx.compose.material.icons.filled.CheckCircleOutline +import androidx.compose.material.icons.filled.LocationOn +import androidx.compose.material.icons.filled.Timelapse +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import tumble.app.tumble.domain.models.network.NetworkResponse +import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString +import tumble.app.tumble.extensions.presentation.formatDate +import tumble.app.tumble.presentation.components.sheets.SheetHeader +import tumble.app.tumble.presentation.views.bookmarks.EventDetails.DetailsBuilder + + +@Composable +fun ResourceDetailsSheet( + booking: NetworkResponse.KronoxUserBookingElement, + onClose: () -> Unit, + onBookingRemove: () -> Unit +) { + Column( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colors.background) + ) { + + SheetHeader(title = "Resource details", onClose = onClose) + Box { + Column( + modifier = Modifier + .verticalScroll(rememberScrollState()) + .background(MaterialTheme.colors.background) + ) { + + DetailsBuilder(title = "Location", image = Icons.Default.LocationOn) { + if (booking.locationId?.isNotEmpty() == true) { + Text( + text = booking.locationId.toString(), + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } else { + Text( + text = "No location listed at this time", + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } + } + DetailsBuilder(title = "Timeslot", image = Icons.Default.Timelapse) { + Text( + text = "${ + booking.timeSlot.from?.convertToHoursAndMinutesISOString().orEmpty() + } - ${booking.timeSlot.to?.convertToHoursAndMinutesISOString().orEmpty()}", + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } + + DetailsBuilder(title = "Date", image = Icons.Default.CalendarMonth) { + Text( + text = booking.timeSlot.from?.formatDate().orEmpty(), + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } + + DetailsBuilder(title = "Confirmation", image = Icons.Default.CheckCircleOutline) { + val bookingDate = booking.timeSlot.from?.formatDate() + val bookingConfirmationStart = + booking.confirmationOpen.convertToHoursAndMinutesISOString() + val bookingConfirmationEnd = + booking.confirmationClosed.convertToHoursAndMinutesISOString() + Text( + text = "$bookingDate, from $bookingConfirmationStart to $bookingConfirmationEnd" + ) + } + + } + } + Spacer(modifier = Modifier.weight(1f)) + + if (booking.showUnbookButton == true) { + Button( + onClick = { onBookingRemove() }, + shape = RoundedCornerShape(15.dp), + colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.primary), + modifier = Modifier.fillMaxWidth().padding(horizontal = 15.dp), + elevation = null + ) { + + Text( + text = "Remove booking", + fontSize = 20.sp, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colors.onPrimary + ) + } + } + Spacer(modifier = Modifier.height(60.dp)) + } + } From a9b92e0e9ab152baff61163318dc365b2c9e8752 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 08:40:43 +0200 Subject: [PATCH 19/38] updated view models --- .../viewmodels/AccountViewModel.kt | 173 +++++++++++++----- .../viewmodels/ResourceViewModel.kt | 99 +++++----- 2 files changed, 190 insertions(+), 82 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/AccountViewModel.kt b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/AccountViewModel.kt index 63f623d..b716c13 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/AccountViewModel.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/AccountViewModel.kt @@ -1,5 +1,6 @@ package tumble.app.tumble.presentation.viewmodels +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -10,6 +11,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import tumble.app.tumble.data.api.Endpoint import tumble.app.tumble.data.api.auth.AuthManager +import tumble.app.tumble.data.api.url import tumble.app.tumble.data.repository.preferences.CombinedData import tumble.app.tumble.data.repository.preferences.DataStoreManager import tumble.app.tumble.datasource.SchoolManager @@ -21,6 +23,7 @@ import tumble.app.tumble.domain.models.network.NetworkRequest import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.models.network.NetworkResponse.KronoxUserBookingElement import tumble.app.tumble.domain.enums.PageState +import tumble.app.tumble.domain.models.network.NetworkResponse.AvailableKronoxUserEvent import tumble.app.tumble.domain.models.presentation.School import javax.inject.Inject @@ -49,8 +52,8 @@ class AccountViewModel @Inject constructor( private val _registeredBookingsSectionState = MutableStateFlow(PageState.LOADING) val registeredBookingsSectionState: StateFlow = _registeredBookingsSectionState - private val _combinedData = MutableStateFlow(CombinedData(-1, false, ViewType.LIST, false)) - val combinedData: StateFlow = _combinedData +// private val _combinedData = MutableStateFlow(CombinedData(-1, false, ViewType.LIST, false)) +// val combinedData: StateFlow = _combinedData private val _userBookings = MutableStateFlow(null) val userBookings: StateFlow = _userBookings @@ -61,14 +64,41 @@ class AccountViewModel @Inject constructor( private val _attemptingLogin = MutableStateFlow(false) val attemptingLogin: StateFlow = _attemptingLogin + private val _booking = MutableStateFlow(null) + val booking: StateFlow = _booking + + private val _event = MutableStateFlow(null) + val event: StateFlow = _event + + fun setEvent(event: AvailableKronoxUserEvent){ + _event.value = event + } + + fun unSetEvent(){ + _event.value = null + } + + fun setBooking(booking: KronoxUserBookingElement){ + _booking.value = booking + } + + fun unSetBooking(){ + _booking.value = null + } + + fun autoSignUpEnabled(): Boolean{ + return dataStoreManager.autoSignup.value + } + init { viewModelScope.launch { autoLogin() - dataStoreManager.authSchoolId.combine(dataStoreManager.autoSignup) { authSchoolId, autoSignup -> - CombinedData(authSchoolId = authSchoolId, autoSignup = autoSignup) - }.collect { combinedData -> - _combinedData.value = combinedData - } + +// dataStoreManager.authSchoolId.combine(dataStoreManager.autoSignup) { authSchoolId, autoSignup -> +// CombinedData(authSchoolId = authSchoolId, autoSignup = autoSignup) +// }.collect { combinedData -> +// _combinedData.value = combinedData +// } } } @@ -99,13 +129,13 @@ class AccountViewModel @Inject constructor( } fun getSchoolName(): School?{ - return schoolManager.getSchoolById(combinedData.value.authSchoolId) + return schoolManager.getSchoolById(dataStoreManager.authSchoolId.value) } fun getUserEventsForSection() { viewModelScope.launch(Dispatchers.IO) { _registeredEventSectionState.value = PageState.LOADING - val endpoint = Endpoint.UserEvents(combinedData.value.authSchoolId.toString()) + val endpoint = Endpoint.UserEvents(dataStoreManager.authSchoolId.value.toString()) if (refreshToken.value != null) { val response: ApiResponse = kronoxManager.getKronoxCompleteUserEvent(endpoint, refreshToken.value, sessionDetails.value) @@ -122,6 +152,79 @@ class AccountViewModel @Inject constructor( } } + fun getUserBookingsForSection() { + viewModelScope.launch(Dispatchers.IO) { + _registeredBookingsSectionState.value = PageState.LOADING + val endpoint = Endpoint.UserBookings(dataStoreManager.authSchoolId.value.toString()) + if (refreshToken.value != null) { + + val response: ApiResponse> = + kronoxManager.getKronoxUserBookings(endpoint, refreshToken.value, sessionDetails.value) + + when (response) { + is ApiResponse.Success -> { + _userBookings.value = NetworkResponse.KronoxUserBookings(bookings = response.data) + _registeredBookingsSectionState.value = PageState.LOADED + scheduleBookingNotifications() + } + is ApiResponse.Error -> { + _registeredBookingsSectionState.value = PageState.ERROR + } + else -> { + _registeredBookingsSectionState.value = PageState.ERROR + } + } + } + } + } + + fun unBookResource(bookingId: String){ + val endpoint = Endpoint.UnBookResource(dataStoreManager.authSchoolId.value.toString(), bookingId) + val refreshToken = authManager.getRefreshToken() ?: return + + viewModelScope.launch { + val response = kronoxManager.unBookResource(endpoint, refreshToken) + when(response){ + is ApiResponse.Error -> { + if(response.errorMessage == "Empty response body"){ + Log.e("unbooked", "Success") + }else{ + Log.e("unbooked", "Error") + Log.e("unbooked", response.errorMessage) + } + } + else -> { + Log.e("unbooked", "lmao") + + } + } + } + } + + fun confirmResource(resourceId: String, bookingId: String){ + val endpoint = Endpoint.ConfirmResource(dataStoreManager.authSchoolId.value.toString()) + val resource = NetworkRequest.ConfirmKronoxResource(resourceId, bookingId) + val refreshToken = authManager.getRefreshToken() ?: return + + viewModelScope.launch { + val response = kronoxManager.confirmResource(endpoint, refreshToken, resource) + when(response){ + is ApiResponse.Error -> { + if(response.errorMessage == "Empty response body"){ + Log.e("confirm", "Success") + }else{ + Log.e("confirm", "Error") + Log.e("confirm", response.errorMessage) + } + } + else -> { + Log.e("confirm", "Error") + } + } + } + } + + // fun getUserEventsForSection() { // viewModelScope.launch(Dispatchers.IO) { // _registeredEventSectionState.value = PageState.LOADING @@ -159,28 +262,7 @@ class AccountViewModel @Inject constructor( // } // } - fun getUserBookingsForSection() { - viewModelScope.launch(Dispatchers.IO) { - _registeredBookingsSectionState.value = PageState.LOADING - val endpoint = Endpoint.UserBookings(combinedData.value.authSchoolId.toString()) - if (refreshToken.value != null) { - val response: ApiResponse> = - kronoxManager.getKronoxUserBookings(endpoint, refreshToken.value, sessionDetails.value) - when (response) { - is ApiResponse.Success -> { - _userBookings.value = NetworkResponse.KronoxUserBookings(bookings = response.data) - _registeredBookingsSectionState.value = PageState.LOADED - } - is ApiResponse.Error -> { - _registeredBookingsSectionState.value = PageState.ERROR - } - else -> { - _registeredBookingsSectionState.value = PageState.ERROR - } - } - } - } - } + // fun unregisterForEvent(eventId: String) { // viewModelScope.launch(Dispatchers.IO) { @@ -199,14 +281,8 @@ class AccountViewModel @Inject constructor( // } fun toggleAutoSignup(value: Boolean) { - viewModelScope.launch(Dispatchers.IO) { - combinedData.value.autoSignup?.let {autoSignup -> - if (autoSignup) { - val endpoint: Endpoint = Endpoint.RegisterAllEvents(combinedData.value.authSchoolId.toString()) - //val response: Response = kronoxManager.put(endpoint, refreshToken.value, sessionDetails.value, null) - } - dataStoreManager.setAutoSignup(value) - } + viewModelScope.launch { + dataStoreManager.setAutoSignup(value) } } @@ -215,7 +291,22 @@ class AccountViewModel @Inject constructor( } private fun registerAutoSignup() { - viewModelScope.launch(Dispatchers.IO) { + val endpoint = Endpoint.RegisterAllEvents(dataStoreManager.authSchoolId.value.toString()) + val refreshToken = authManager.getRefreshToken() ?: return + viewModelScope.launch { + val response = kronoxManager.registerForAllEvents(endpoint, refreshToken) + when (response) { + is ApiResponse.Success -> { + Log.e("AutoSignup", "Success") + } + is ApiResponse.Error -> { + Log.e("AutoSignup", "Error") + Log.e("AutoSignup", response.errorMessage) + } + else -> { + Log.e("AutoSignup", "Error") + } + } // Implement the logic for automatic event registration } } @@ -227,7 +318,7 @@ class AccountViewModel @Inject constructor( } private fun autoLogin() { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch { try { val user = authManager.autoLoginUser() updateUser(user) diff --git a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt index f70fd48..44a473f 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.compose.viewModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow @@ -35,7 +36,6 @@ class ResourceViewModel @Inject constructor( val authManager: AuthManager, val dataStoreManager: DataStoreManager, val kronoxManager: KronoxRepository - ): ViewModel(){ private val _selectedPickerDate = MutableStateFlow(Date()) @@ -59,14 +59,23 @@ class ResourceViewModel @Inject constructor( //val allResources: List? = null - private val _resourceSelectionModel = MutableStateFlow(null) - var resourceSelectionModel by mutableStateOf(null) +// private val _resourceSelectionModel = MutableStateFlow(null) +// var resourceSelectionModel by mutableStateOf(null) + + +// private val _resourceSelectioned = MutableStateFlow(null) +// var resourceSelectioned = mutableStateOf(null) + fun setBookingDate(newDate: Date){ _selectedPickerDate.value = newDate viewModelScope.launch { getAllResourcesData(isoDateFormatterDate.format(newDate)) } } +// fun setResourceSelection(resource: NetworkResponse.KronoxResourceElement){ +// resourceSelectioned.value = resource +// } + fun getUserEventsForPage(){ viewModelScope.launch { _eventBookingPageState.value = PageState.LOADING @@ -91,26 +100,49 @@ class ResourceViewModel @Inject constructor( } fun registerForEvent(eventId: String){ - viewModelScope.launch() { - try { - val refreshToken = authManager.getRefreshToken() ?: return@launch - val schoolID = dataStoreManager.authSchoolId.value.toString() - val endpoint = Endpoint.RegisterEvent(eventId = eventId, schoolId = schoolID) - val userRequest = kronoxManager.registerForEvent(endpoint, refreshToken) - if(userRequest.isSuccessful){ - Log.e("AAAAAAA", "Registered") - }else{ - Log.e("AAAAAAA", "NOT Registered") - + val refreshToken = authManager.getRefreshToken() ?: return@launch + val schoolID = dataStoreManager.authSchoolId.value.toString() + val endpoint = Endpoint.RegisterEvent(eventId = eventId, schoolId = schoolID) + val response = kronoxManager.registerForEvent(endpoint, refreshToken) + + when(response){ + is ApiResponse.Error -> { + if(response.errorMessage == "Empty response body"){ + Log.e("unbooked", "Success") + }else{ + Log.e("unbooked", "Error") + Log.e("unbooked", response.errorMessage) + } + } + else -> { + Log.e("unbooked", "lmao") } - } catch (e: Exception) { } } } fun unregisterForEvent(eventId: String){ - //TODO + viewModelScope.launch { + + val endpoint = Endpoint.UnregisterEvent(eventId, dataStoreManager.authSchoolId.value.toString()) + val refreshToken = authManager.getRefreshToken() ?: return@launch + val response = kronoxManager.unRegisterForEvent(endpoint, refreshToken) + + when(response){ + is ApiResponse.Error -> { + if(response.errorMessage == "Empty response body"){ + Log.e("unRegister", "Success") + }else{ + Log.e("unRegister", "Error") + Log.e("unRegister", response.errorMessage) + } + } + else -> { + Log.e("unRegister", "lmao") + } + } + } } fun getAllResources(){ @@ -177,35 +209,20 @@ class ResourceViewModel @Inject constructor( } } - fun confirmResource(resourceId: String, bookingId: String){ - val endpoint = Endpoint.ConfirmResource(dataStoreManager.authSchoolId.value.toString()) - val resource = NetworkRequest.ConfirmKronoxResource(resourceId, bookingId) - val refreshToken = authManager.getRefreshToken() ?: return - - viewModelScope.launch { - val response = kronoxManager.confirmResource(endpoint, refreshToken, resource) - } - } - - fun bookResource(resourceId: String, date: Date, availabilityValue: NetworkResponse.AvailabilityValue){ + suspend fun bookResource(resourceId: String, date: Date, availabilityValue: NetworkResponse.AvailabilityValue): Boolean{ val endpoint = Endpoint.BookResource(dataStoreManager.authSchoolId.value.toString()) val resource = NetworkRequest.BookKronoxResource(resourceId, isoDateFormatterDate.format(date), availabilityValue) - val refreshToken = authManager.getRefreshToken() ?: return + val refreshToken = authManager.getRefreshToken() ?: return false - viewModelScope.launch { - val response = kronoxManager.bookResource(endpoint, refreshToken, resource) - if (response.isSuccessful){ - return@launch - } - } - } - - fun unBookResource(bookingId: String){ - val endpoint = Endpoint.UnBookResource(dataStoreManager.authSchoolId.value.toString(), bookingId) - val refreshToken = authManager.getRefreshToken() ?: return - viewModelScope.launch { - val response = kronoxManager.unBookResource(endpoint, refreshToken) + val response: ApiResponse = kronoxManager.bookResource(endpoint, refreshToken, resource) + when(response){ + is ApiResponse.Error -> { + return response.errorMessage == "Empty response body" + } + else -> { + return false + } } } } \ No newline at end of file From 516db56bd10b36dc7612fbf0482cecf715112193 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 09:00:17 +0200 Subject: [PATCH 20/38] event and resource sheets now display --- .../app/tumble/presentation/views/account/Account.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/Account.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/Account.kt index 49d1ccb..cbe0096 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/Account.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/Account.kt @@ -32,6 +32,8 @@ import tumble.app.tumble.presentation.navigation.Routes import tumble.app.tumble.presentation.viewmodels.AccountViewModel import tumble.app.tumble.presentation.views.account.Login.AccountLogin import tumble.app.tumble.presentation.views.account.User.ProfileSection.UserOverview +import tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Sheets.EventDetailsSheet +import tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Sheets.ResourceDetailsSheet @Composable fun Account( @@ -44,6 +46,8 @@ fun Account( } val authStatus by viewModel.authStatus.collectAsState() + val booking = viewModel.booking.collectAsState() + val event = viewModel.event.collectAsState() Scaffold( topBar = { @@ -71,7 +75,6 @@ fun Account( AccountViewModel.AuthStatus.AUTHORIZED -> UserOverview(navController = navController) AccountViewModel.AuthStatus.UNAUTHORIZED -> AccountLogin() } - UserOverview(navController = navController) } if(isSigningOut){ @@ -96,6 +99,13 @@ fun Account( ) } } + booking.value?.let { + ResourceDetailsSheet(it, {viewModel.unSetBooking()}, {viewModel.unBookResource(it.id)}) + } + event.value?.let { + EventDetailsSheet(it, {viewModel.unSetEvent()}) + } + } From 032fc3e49355094d09bde60d2d56295ac1160352 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 09:21:36 +0200 Subject: [PATCH 21/38] event screen ui --- .../Booking/Events/EventBookings.kt | 29 +++++---- .../Booking/Events/EventCardButton.kt | 65 +++++++++---------- .../ResourceSection/Booking/Events/Events.kt | 17 +++-- 3 files changed, 55 insertions(+), 56 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt index 042448d..62abc9f 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt @@ -9,11 +9,13 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Tag import androidx.compose.material.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState @@ -28,6 +30,7 @@ import tumble.app.tumble.R import tumble.app.tumble.domain.enums.PageState import tumble.app.tumble.presentation.components.buttons.CloseCoverButton import tumble.app.tumble.presentation.viewmodels.ResourceViewModel +import tumble.app.tumble.presentation.views.Settings.BackNav import tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.SectionDivider import tumble.app.tumble.presentation.views.general.CustomProgressIndicator import tumble.app.tumble.presentation.views.general.Info @@ -41,25 +44,23 @@ fun EventBookings( ) { val completeUserEvent = viewModel.completeUserEvent.collectAsState() val eventBookingPageState = viewModel.eventBookingPageState.collectAsState() - - BoxWithConstraints( - modifier = Modifier - .fillMaxSize() - .background(MaterialTheme.colors.background) - ) { - val scrollState = rememberScrollState() - + val scrollState = rememberScrollState() + Scaffold ( + topBar = { + BackNav( + onClick = {navController.popBackStack()}, + label = stringResource(R.string.account), + title = stringResource(R.string.events) + ) + }, + ) { padding -> Column( modifier = Modifier + .fillMaxSize() .verticalScroll(scrollState) .background(MaterialTheme.colors.background) + .padding(padding) ) { - Row { - Spacer(modifier = Modifier.weight(1f)) - CloseCoverButton { - navController.popBackStack() - } - } when (eventBookingPageState.value) { PageState.LOADING -> { CustomProgressIndicator() diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt index f690fb5..786af9f 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.Text @@ -52,16 +53,14 @@ fun EventCardButton( eventType: EventType, onTap: () -> Unit ) { - Row( + Column( modifier = Modifier .fillMaxWidth() - .background(MaterialTheme.colors.surface, shape = RoundedCornerShape(20.dp)) - .padding(16.dp), - verticalAlignment = Alignment.CenterVertically + ) { Column( verticalArrangement = Arrangement.spacedBy(10.dp), - modifier = Modifier.weight(1f) + modifier = Modifier.background(MaterialTheme.colors.surface, shape = RoundedCornerShape(20.dp)).padding(16.dp).fillMaxWidth() ) { // Event Title Text( @@ -78,7 +77,7 @@ fun EventCardButton( contentDescription = null, tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) ) - val eventDate = isoDateFormatterDate.format(isoDateFormatterDate.parse(event.eventStart)) + val eventDate = event.eventStart.formatDate() val eventStart = event.eventStart.convertToHoursAndMinutesISOString() val eventEnd = event.eventEnd.convertToHoursAndMinutesISOString() val eventDateText = @@ -101,9 +100,7 @@ fun EventCardButton( tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) ) val signupText = if (event.lastSignupDate.isValidRegistrationDate()) { - "${stringResource(id = R.string.available_until)} ${ - isoDateFormatterDate.format( - isoDateFormatterDate.parse(event.lastSignupDate) + "${stringResource(id = R.string.available_until)} ${(event.lastSignupDate.formatDate() ) ?: "stringResource(id = R.string.no_date_set)" }" } else { @@ -115,33 +112,31 @@ fun EventCardButton( color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) ) } - if (event.lastSignupDate.isValidRegistrationDate()) { - Row( - horizontalArrangement = Arrangement.End, - modifier = Modifier.fillMaxWidth() + } + if (event.lastSignupDate.isValidRegistrationDate()) { + Row( + horizontalArrangement = Arrangement.End, + modifier = Modifier.fillMaxWidth() + ) { + Button( + onClick = { + event.id?.let { onTap() } }, + modifier = Modifier + .padding(10.dp), + colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.primary), + shape = RoundedCornerShape(10.dp) ) { - Button( - onClick = { - event.eventId?.let { onTap() } }, - modifier = Modifier - .background( - MaterialTheme.colors.primary, - shape = RoundedCornerShape(10.dp) - ) - .padding(10.dp) - ) { - Icon( - painter = rememberVectorPainter(Icons.Default.Event), - contentDescription = null, - tint = MaterialTheme.colors.onPrimary - ) - Spacer(modifier = Modifier.width(5.dp)) - Text( - text = if (eventType == EventType.UNREGISTER) stringResource(id = R.string.unregister) else stringResource(id = R.string.register), - fontSize = 16.sp, - color = MaterialTheme.colors.onPrimary - ) - } + Icon( + painter = rememberVectorPainter(Icons.Default.Event), + contentDescription = null, + tint = MaterialTheme.colors.onPrimary + ) + Spacer(modifier = Modifier.width(5.dp)) + Text( + text = if (eventType == EventType.UNREGISTER) stringResource(id = R.string.unregister) else stringResource(id = R.string.register), + fontSize = 16.sp, + color = MaterialTheme.colors.onPrimary + ) } } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt index 218d35b..99ac84f 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt @@ -34,9 +34,8 @@ fun RegisteredEventsView( EventCardButton( event = event, eventType = EventType.UNREGISTER, - onTap = { onTapEventAction(event.eventId!!, EventType.UNREGISTER) } + onTap = { onTapEventAction(event.id!!, EventType.UNREGISTER) } ) - Spacer(modifier = Modifier.height(8.dp)) } } }else { @@ -57,14 +56,16 @@ fun UnregisteredEventsView( ) { Column { if (unregisteredEvents.isNotEmpty()) { - Column(modifier = Modifier.fillMaxWidth()) { + Column( + verticalArrangement = Arrangement.spacedBy(15.dp), + modifier = Modifier.fillMaxWidth() + ) { unregisteredEvents.forEach { event -> EventCardButton( event = event, eventType = EventType.REGISTER, - onTap = { onTapEventAction(event.eventId!!, EventType.REGISTER) } + onTap = { onTapEventAction(event.id!!, EventType.REGISTER) } ) - Spacer(modifier = Modifier.height(8.dp)) } } } @@ -86,10 +87,12 @@ fun UpcomingEventsView( ) { Column { if (upcomingEvents.isNotEmpty()) { - Column(modifier = Modifier.fillMaxWidth()) { + Column( + verticalArrangement = Arrangement.spacedBy(15.dp), + modifier = Modifier.fillMaxWidth() + ) { upcomingEvents.forEach { event -> UpcomingEventCardButton(event = event) - Spacer(modifier = Modifier.height(8.dp)) } } } else{ From 045ca8521411b60712fe3a56fb7ad14ebb815e27 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 09:34:33 +0200 Subject: [PATCH 22/38] resource booking UI --- .../Booking/Resources/ResourceBookings.kt | 50 ++++--- .../Booking/Resources/ResourceDatePicker.kt | 45 ++----- .../Resources/ResourceLocationsList.kt | 34 ++--- .../Booking/Resources/ResourceSelection.kt | 114 +++++++++------- .../Booking/Resources/ResourceTimeDropdown.kt | 125 +++++++++--------- .../Booking/Resources/TimelotSelection.kt | 25 ++-- .../Booking/Resources/TimeslotCard.kt | 20 +-- 7 files changed, 202 insertions(+), 211 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt index 5baeb5f..c4dcd3a 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt @@ -4,23 +4,27 @@ import android.os.Build import androidx.annotation.RequiresApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material.MaterialTheme import androidx.compose.material3.Divider +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.core.net.toUri import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import kotlinx.coroutines.ExperimentalCoroutinesApi +import tumble.app.tumble.R import tumble.app.tumble.domain.enums.PageState import tumble.app.tumble.domain.models.presentation.ResourceSelectionModel -import tumble.app.tumble.presentation.components.buttons.CloseCoverButton +import tumble.app.tumble.observables.AppController +import tumble.app.tumble.presentation.navigation.UriBuilder import tumble.app.tumble.presentation.viewmodels.ResourceViewModel +import tumble.app.tumble.presentation.views.Settings.BackNav import tumble.app.tumble.presentation.views.general.CustomProgressIndicator import tumble.app.tumble.presentation.views.general.Info import java.util.Calendar @@ -35,31 +39,28 @@ fun ResourceBookings( ) { val resourceBookingPageState = viewModel.resourceBookingPageState.collectAsState() val selectedPikerDate = viewModel.selectedPickerDate.collectAsState() - val scrollState = rememberScrollState() - Column( - modifier = Modifier - .fillMaxSize() - .background(MaterialTheme.colors.background) - ) { - Row { - Spacer(modifier = Modifier.weight(1f)) - CloseCoverButton { - navController.popBackStack() - } - } - + + Scaffold ( + topBar = { + BackNav( + onClick = {navController.popBackStack()}, + label = stringResource(R.string.account), + title = stringResource(R.string.resources) + ) + }, + ) { padding -> Column( modifier = Modifier - .fillMaxWidth() + .fillMaxSize() + .padding(padding) + .background(MaterialTheme.colors.background) ) { ResourceDatePicker( - selectedDate = selectedPikerDate.value, onDateChange = { date -> viewModel.setBookingDate(date) } ) Divider(color = MaterialTheme.colors.onBackground) - when (resourceBookingPageState.value) { PageState.LOADING -> { Box( @@ -76,7 +77,10 @@ fun ResourceBookings( ResourceLocationsList( parentViewModel = viewModel, selectedPickerDate = selectedPikerDate.value, - navigateToResourceSelection = { resource, date -> viewModel.resourceSelectionModel = ResourceSelectionModel(resource,date)} + navigateToResourceSelection = { resource, date -> + AppController.shared.resourceModel = ResourceSelectionModel(resource, date) + navController.navigate(UriBuilder.buildAccountResourceDetailsUri(resource.id.toString()).toUri()) + } ) } PageState.ERROR -> { @@ -103,12 +107,6 @@ fun ResourceBookings( } } } - - viewModel.resourceSelectionModel?.let { - ResourceSelection() - } - - LaunchedEffect(Unit) { viewModel.getAllResources() } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceDatePicker.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceDatePicker.kt index 57279cf..5bc23f0 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceDatePicker.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceDatePicker.kt @@ -5,30 +5,19 @@ import androidx.annotation.RequiresApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text import androidx.compose.material3.DatePicker -import androidx.compose.material3.DatePickerColors import androidx.compose.material3.DatePickerDefaults import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.OutlinedButton import androidx.compose.material3.rememberDatePickerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp -import tumble.app.tumble.utils.isoDateFormatterDate -import java.text.SimpleDateFormat -import java.time.LocalDate -import java.time.format.DateTimeFormatter -import java.util.Calendar import java.util.Date @@ -36,46 +25,38 @@ import java.util.Date @OptIn(ExperimentalMaterial3Api::class) @Composable fun ResourceDatePicker( - selectedDate: Date, onDateChange: (Date) -> Unit ) { - val context = LocalContext.current - val calendar = Calendar.getInstance() - calendar.time = Date() - val dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") - val minDate = LocalDate.now().minusYears(1) - val datePickerState = rememberDatePickerState() - val showDatePickerDialog = remember { mutableStateOf(false) } - Column( modifier = Modifier .fillMaxWidth() .padding(horizontal = 15.dp) - //.background(MaterialTheme.colors.background) // Replace with your background color - .height(300.dp) + .background(color = MaterialTheme.colors.background) ) { - OutlinedButton( - onClick = { showDatePickerDialog.value = !showDatePickerDialog.value }, - modifier = Modifier.align(Alignment.CenterHorizontally) - ) { - Text(text = "Pick a date: ${isoDateFormatterDate.format(selectedDate)}") - } - DatePicker( state = datePickerState, showModeToggle = showDatePickerDialog.value, - //colors = DatePickerDefaults.colors(selectedDayContentColor = MaterialTheme.colors.primary) + colors = DatePickerDefaults.colors( + selectedDayContentColor = MaterialTheme.colors.onBackground, + dayContentColor = MaterialTheme.colors.onBackground, + selectedDayContainerColor = MaterialTheme.colors.primary, + weekdayContentColor = MaterialTheme.colors.primary, + todayContentColor = MaterialTheme.colors.onBackground, + todayDateBorderColor = MaterialTheme.colors.primary, + yearContentColor = Color.Yellow, + subheadContentColor = Color.Yellow + ), + title = null, + headline = null, ) } - LaunchedEffect(key1 = datePickerState.selectedDateMillis) { datePickerState.selectedDateMillis?.let { onDateChange(Date(it)) } } - } \ No newline at end of file diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt index ad9984e..9206b83 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt @@ -1,15 +1,18 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Resources -import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AccessTime @@ -19,14 +22,12 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.presentation.viewmodels.ResourceViewModel -import java.time.LocalDate import java.util.Date @Composable @@ -35,21 +36,15 @@ fun ResourceLocationsList( selectedPickerDate: Date, navigateToResourceSelection: (NetworkResponse.KronoxResourceElement, Date) -> Unit ) { - val allResources = parentViewModel.allResources.collectAsState() - LazyColumn( modifier = Modifier .fillMaxSize() .padding(top = 16.dp) ) { - items((allResources.value?: emptyList()).size) { resourceIndex -> - allResources.value?.get(resourceIndex)?.let { - val availableCounts = it.availabilities?.let { it1 -> calcAvailability(it1) }?: 0 - ResourceLocationItem( resource = it, selectedPickerDate = selectedPickerDate, @@ -62,6 +57,7 @@ fun ResourceLocationsList( ) } } + item { Spacer(modifier = Modifier.height(60.dp)) } } } @@ -72,18 +68,14 @@ fun ResourceLocationItem( availableCounts: Int, onClick: () -> Unit ) { - val backgroundColor = if (availableCounts > 0) { - Color.White - } else { - Color.Gray - } - Row( modifier = Modifier .fillMaxWidth() .clickable { onClick() } - .background(backgroundColor) + .padding(5.dp) + .background(MaterialTheme.colors.surface, shape = RoundedCornerShape(16.dp)) .padding(16.dp) + ) { Column( modifier = Modifier.weight(1f), @@ -92,7 +84,7 @@ fun ResourceLocationItem( Text( text = resource.name ?: "No name", fontSize = 18.sp, - color = Color.Black, // Replace with your theme color + color = MaterialTheme.colors.onBackground, maxLines = 1, overflow = TextOverflow.Ellipsis ) @@ -102,12 +94,12 @@ fun ResourceLocationItem( Icon( imageVector = Icons.Default.Event, contentDescription = null, - tint = Color.Gray.copy(alpha = 0.7f) + tint = MaterialTheme.colors.onSurface ) Text( text = selectedPickerDate.toString(), fontSize = 15.sp, - color = Color.Gray.copy(alpha = 0.7f) + color = MaterialTheme.colors.onSurface ) } Row( @@ -116,12 +108,12 @@ fun ResourceLocationItem( Icon( imageVector = Icons.Default.AccessTime, contentDescription = null, - tint = Color.Gray.copy(alpha = 0.7f) + tint = MaterialTheme.colors.onSurface ) Text( text = "Available timeslots: $availableCounts", fontSize = 15.sp, - color = Color.Gray.copy(alpha = 0.7f) + color = MaterialTheme.colors.onSurface ) } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt index 3a94f24..549249f 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt @@ -1,5 +1,7 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Resources +import android.os.Build +import androidx.annotation.RequiresApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -10,75 +12,93 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material.Divider import androidx.compose.material.MaterialTheme import androidx.compose.material.Text +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavController +import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.models.getAvailabilityValues -import tumble.app.tumble.presentation.components.buttons.CloseCoverButton +import tumble.app.tumble.extensions.models.getFirstTimeSlotWithAvailability +import tumble.app.tumble.observables.AppController import tumble.app.tumble.presentation.viewmodels.ResourceViewModel +import tumble.app.tumble.presentation.views.Settings.BackNav import tumble.app.tumble.presentation.views.general.Info -import tumble.app.tumble.utils.isoDateFormatterDate +import tumble.app.tumble.utils.isoVerboseDateFormatter +@RequiresApi(Build.VERSION_CODES.O) @Composable fun ResourceSelection( parentViewModel: ResourceViewModel = hiltViewModel(), + navController: NavController ) { - val selectedTimeIndex = remember { mutableStateOf(0) } - val resource = parentViewModel.resourceSelectionModel!!.resource + val resource = AppController.shared.resourceModel!!.resource + val selectedTimeIndex = remember { mutableStateOf(resource.availabilities.getFirstTimeSlotWithAvailability(resource.timeSlots!!.size)) } val availabilityValues = remember { mutableStateOf>(resource.availabilities.getAvailabilityValues(timelotId = selectedTimeIndex.value)) } - val selectedPickerDate = parentViewModel.resourceSelectionModel!!.date + val selectedPickerDate = AppController.shared.resourceModel!!.date val timeslots = resource.timeSlots - - Column( - modifier = Modifier - .fillMaxSize() - .background(MaterialTheme.colors.background) - ) { - Row { - Text( - text = isoDateFormatterDate.format(selectedPickerDate), - fontWeight = FontWeight.SemiBold, - color = MaterialTheme.colors.onBackground, - modifier = Modifier - .padding(horizontal = 15.dp, vertical = 20.dp) - .fillMaxWidth() - ) - Spacer(modifier = Modifier.weight(1f)) - CloseCoverButton(onClick = {parentViewModel.resourceSelectionModel = null}) - } - if (timeslots != null) { - TimeslotDropdown( - resource = resource, - timeslots = timeslots, - selectedIndex = selectedTimeIndex, - onIndexChange = { index -> - selectedTimeIndex.value = index - availabilityValues.value = resource.availabilities.getAvailabilityValues(timelotId = index) - } + Scaffold ( + topBar = { + BackNav( + onClick = {navController.popBackStack()}, + label = stringResource(R.string.resources), + title = stringResource(R.string.rooms) ) - Divider(modifier = Modifier.padding(vertical = 8.dp)) - TimeslotSelection( - bookResource = { availabilityValue -> - parentViewModel.bookResource( - resourceId = resource.id!!, - date = selectedPickerDate, - availabilityValue = availabilityValue + }, + ) { padding -> + Column( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colors.background) + .padding(padding) + ) { + Row { + Text( + text = isoVerboseDateFormatter.format(selectedPickerDate), + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colors.onBackground, + modifier = Modifier + .padding(horizontal = 15.dp, vertical = 20.dp) + .fillMaxWidth() + ) + Spacer(modifier = Modifier.weight(1f)) + } + if (timeslots != null) { + TimeslotDropdown( + resource = resource, + timeslots = timeslots, + selectedIndex = selectedTimeIndex, + onIndexChange = { index -> + selectedTimeIndex.value = index + availabilityValues.value = + resource.availabilities.getAvailabilityValues(timelotId = index) + } + ) + Divider(modifier = Modifier.padding(vertical = 8.dp)) + TimeslotSelection( + bookResource = { availabilityValue -> + parentViewModel.bookResource( + resourceId = resource.id!!, + date = selectedPickerDate, + availabilityValue = availabilityValue ) - }, - availabilityValues = availabilityValues - ) - } else { - Info( - title = "No available timeslots", - image = null, - ) + }, + availabilityValues = availabilityValues + ) + } else { + Info( + title = "No available timeslots", + image = null, + ) + } } } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceTimeDropdown.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceTimeDropdown.kt index 4d5df4e..e98e8c2 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceTimeDropdown.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceTimeDropdown.kt @@ -5,27 +5,30 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults import androidx.compose.material.Divider import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material.icons.filled.ArrowForwardIos import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -42,27 +45,23 @@ fun TimeslotDropdown( selectedIndex: MutableState, onIndexChange: (Int) -> Unit ) { - var isSelecting = remember { mutableStateOf(false) } - var selectionTitle = remember { mutableStateOf("") } - val scope = rememberCoroutineScope() - + val isSelecting = remember { mutableStateOf(false) } + val selectionTitle = remember { mutableStateOf("") } Column( modifier = Modifier .fillMaxWidth() - .background(MaterialTheme.colors.surface) - .padding(vertical = 8.dp) - .padding(horizontal = 15.dp) + .padding(16.dp) + .background(MaterialTheme.colors.surface, shape = RoundedCornerShape(16.dp)) + .padding(10.dp) .clickable { - scope.launch { isSelecting.value = !isSelecting.value - } } .animateContentSize() - .padding(bottom = 15.dp) ) { Row( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically ) { Text( text = selectionTitle.value, @@ -71,44 +70,38 @@ fun TimeslotDropdown( color = MaterialTheme.colors.onSurface ) Icon( - imageVector = Icons.Default.ArrowDropDown, + imageVector = Icons.Default.ArrowForwardIos, contentDescription = null, - tint = MaterialTheme.colors.onSurface + tint = MaterialTheme.colors.onSurface, + modifier = Modifier.rotate(90f) ) } - if (isSelecting.value) { Divider(color = Color.White) - Column( - modifier = Modifier.padding(horizontal = 15.dp) - ) { - timeslots.forEachIndexed { index, timeslot -> - timeslot.id?.let { timeslotId -> - if (resource.availabilities.timelotHasAvailable(timeslotId)) { - val start = timeslot.from?.convertToHoursAndMinutesISOString() - val end = timeslot.to?.convertToHoursAndMinutesISOString() - - if (start != null && end != null) { - DropdownMenuItemView( - isSelecting = isSelecting, - selectionTitle = selectionTitle, - selectedIndex = selectedIndex, - item = DropdownItem( - id = index, - title = "$start - $end", - onSelect = { - onIndexChange(index) - } - ) + timeslots.forEachIndexed { index, timeslot -> + timeslot.id?.let { timeslotId -> + if (resource.availabilities.timelotHasAvailable(timeslotId)) { + val start = timeslot.from?.convertToHoursAndMinutesISOString() + val end = timeslot.to?.convertToHoursAndMinutesISOString() + if (start != null && end != null) { + DropdownMenuItemView( + isSelecting = isSelecting, + selectionTitle = selectionTitle, + selectedIndex = selectedIndex, + item = DropdownItem( + id = index, + title = "$start - $end", + onSelect = { + onIndexChange(index) + } ) - } + ) } } } } } } - LaunchedEffect(timeslots, selectedIndex.value) { timeslots.getOrNull(selectedIndex.value)?.let { timeslot -> val start = timeslot.from?.convertToHoursAndMinutesISOString() @@ -127,33 +120,39 @@ fun DropdownMenuItemView( selectedIndex: MutableState, item: DropdownItem ) { - Button( - onClick = { - isSelecting.value = false - selectionTitle.value = item.title - item.onSelect() - }, - colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.surface), - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 5.dp) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically ) { - Row( + Button( + onClick = { + isSelecting.value = false + selectionTitle.value = item.title + item.onSelect() + }, + colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.surface), modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween + elevation = null, + contentPadding = PaddingValues(0.dp) ) { - Text( - text = item.title, - fontSize = 18.sp, - fontWeight = FontWeight.SemiBold, - color = MaterialTheme.colors.onSurface - ) - if (selectedIndex.value == item.id) { - Icon( - imageVector = Icons.Default.CheckCircle, - contentDescription = null, - tint = MaterialTheme.colors.onSurface + Row( + modifier = Modifier.fillMaxWidth(), + ) { + Text( + text = item.title, + fontSize = 18.sp, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colors.onSurface ) + Spacer(Modifier.weight(1f)) + if (selectedIndex.value == item.id) { + Icon( + imageVector = Icons.Default.CheckCircle, + contentDescription = null, + tint = MaterialTheme.colors.onSurface + ) + } } } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt index d115a1b..c6e3e18 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt @@ -9,11 +9,8 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import kotlinx.coroutines.CoroutineScope @@ -22,8 +19,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.presentation.views.general.Info -import java.time.LocalDate -import java.util.Date enum class BookingButtonState { LOADING, @@ -33,7 +28,7 @@ enum class BookingButtonState { @Composable fun TimeslotSelection( - bookResource: (NetworkResponse.AvailabilityValue) -> Unit, + bookResource: suspend (NetworkResponse.AvailabilityValue) -> Boolean, availabilityValues: MutableState> ) { val buttonStateMap = remember { mutableMapOf() } @@ -60,9 +55,15 @@ fun TimeslotSelection( .padding(16.dp) ) { availabilityValues.value.forEach { availabilityValue -> - availabilityValue.locationID?.let { locationId -> + availabilityValue.locationId?.let { locationId -> TimeslotCard( - onBook = { bookResource(availabilityValue) }, + onBook = { handleBooking( + locationId = locationId, + availabilityValue = availabilityValue, + bookResource = bookResource, + buttonStateMap = buttonStateMap, + scope = scope + )}, locationId = locationId, bookingButtonState = buttonStateMap[locationId] ?: BookingButtonState.AVAILABLE ) @@ -77,7 +78,7 @@ private fun setupButtons( buttonStateMap: MutableMap ) { availabilityValues.value.forEach { availabilityValue -> - availabilityValue.locationID?.let { locationId -> + availabilityValue.locationId?.let { locationId -> buttonStateMap[locationId] = BookingButtonState.AVAILABLE } } @@ -86,16 +87,14 @@ private fun setupButtons( private fun handleBooking( locationId: String, availabilityValue: NetworkResponse.AvailabilityValue, - resourceId: String, - selectedPickerDate: LocalDate, - bookResource: suspend (String, LocalDate, NetworkResponse.AvailabilityValue) -> Boolean, + bookResource: suspend (NetworkResponse.AvailabilityValue) -> Boolean, buttonStateMap: MutableMap, scope: CoroutineScope ) { buttonStateMap[locationId] = BookingButtonState.LOADING scope.launch { val result = withContext(Dispatchers.IO) { - bookResource(resourceId, selectedPickerDate, availabilityValue) + bookResource(availabilityValue) } buttonStateMap[locationId] = if (result) BookingButtonState.BOOKED else BookingButtonState.AVAILABLE } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt index fdad05f..d814540 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt @@ -4,13 +4,14 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight @@ -29,10 +30,10 @@ fun TimeslotCard( Row( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 15.dp, vertical = 10.dp) - .height(70.dp) - .padding(10.dp) - .background(MaterialTheme.colors.surface) + .padding(5.dp) + .background(MaterialTheme.colors.surface, shape = RoundedCornerShape(16.dp)) + .padding(10.dp), + verticalAlignment = Alignment.CenterVertically ) { Text( text = locationId, @@ -47,10 +48,11 @@ fun TimeslotCard( onBook() } }, - enabled = bookingButtonState != BookingButtonState.BOOKED, + colors = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent), modifier = Modifier - .background(MaterialTheme.colors.primary) - .padding(7.5.dp) + .background(color = MaterialTheme.colors.primary, shape = RoundedCornerShape(20.dp)), + elevation = null, + enabled = bookingButtonState != BookingButtonState.BOOKED, ) { when (bookingButtonState) { BookingButtonState.LOADING -> { From cc0610992ef5db589ceaf653e0e00e42e33ff391 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 09:41:52 +0200 Subject: [PATCH 23/38] added selected resource modle to app controller --- .../main/java/tumble/app/tumble/observables/AppController.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/tumble/app/tumble/observables/AppController.kt b/app/src/main/java/tumble/app/tumble/observables/AppController.kt index b36634d..a4ac0c8 100644 --- a/app/src/main/java/tumble/app/tumble/observables/AppController.kt +++ b/app/src/main/java/tumble/app/tumble/observables/AppController.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import tumble.app.tumble.domain.models.presentation.EventDetailsSheetModel +import tumble.app.tumble.domain.models.presentation.ResourceSelectionModel import tumble.app.tumble.domain.models.presentation.SearchPreviewModel import tumble.app.tumble.presentation.views.navigation.BottomNavItem import javax.inject.Inject @@ -24,6 +25,7 @@ class AppController @Inject constructor() : ViewModel() { var searchPreview by mutableStateOf(null) var eventSheet by mutableStateOf(null) + var resourceModel by mutableStateOf(null) var selectedAppTab by mutableStateOf(BottomNavItem.HOME) private val _isUpdatingBookmarks = MutableStateFlow(false) var isUpdatingBookmarks = _isUpdatingBookmarks.asStateFlow() From 6fc05acaad33e9ee4c978a8c54754f4805853576 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 09:44:11 +0200 Subject: [PATCH 24/38] user over view resources UI --- .../User/ResourceSection/RegisteredBooking.kt | 59 ++++++++++++--- .../User/ResourceSection/RegisteredEvent.kt | 15 ++-- .../User/ResourceSection/ResourceCard.kt | 24 +++---- .../ResourceSection/ResourceSectionDivider.kt | 17 ++--- .../account/User/ResourceSection/Resources.kt | 71 +++++++++---------- 5 files changed, 104 insertions(+), 82 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredBooking.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredBooking.kt index 63d7302..f9bc0bf 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredBooking.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredBooking.kt @@ -1,19 +1,28 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import kotlinx.coroutines.ExperimentalCoroutinesApi import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.enums.PageState import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString +import tumble.app.tumble.extensions.presentation.formatDate import tumble.app.tumble.presentation.views.general.CustomProgressIndicator @OptIn(ExperimentalCoroutinesApi::class) @@ -21,12 +30,14 @@ import tumble.app.tumble.presentation.views.general.CustomProgressIndicator fun RegisteredBooking( onClickResource: (NetworkResponse.KronoxUserBookingElement) -> Unit, state: State, - bookings: List? + bookings: List?, + confirmBooking: (String, String) -> Unit, + unBook: (String) -> Unit ){ Column( modifier = Modifier - .fillMaxWidth() - .padding(top = 16.dp) + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(8.dp) ) { when(state.value){ PageState.LOADING -> { @@ -35,15 +46,46 @@ fun RegisteredBooking( PageState.LOADED -> { if(!bookings.isNullOrEmpty()){ bookings.forEach{ resource -> + val eventStart = resource.timeSlot.from?.convertToHoursAndMinutesISOString() + val eventEnd = resource.timeSlot.to?.convertToHoursAndMinutesISOString() ResourceCard( - eventStart = resource.timeSlot.from?.convertToHoursAndMinutesISOString()?:"(no date)", - eventEnd = resource.timeSlot.to?.convertToHoursAndMinutesISOString()?:"(no date)", + eventStart = eventStart?:"(no date)", + eventEnd = eventEnd?:"(no date)", title = "Booked resource", - location = resource.locationID, - date = resource.timeSlot.from?: "(no date)", + location = resource.locationId, + date = resource.timeSlot.from?.formatDate()?:"(no date)", onClick = { onClickResource(resource) } ) - + if (resource.showConfirmButton){ + Row ( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ){ + Button( + onClick = {confirmBooking(resource.resourceId, resource.id)}, + colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.primary), + shape = RoundedCornerShape(15.dp), + ) { + Text( + text = "Confirm", + fontSize = 16.sp, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colors.onPrimary + ) + } + Button( + onClick = {unBook(resource.id)}, + colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.primary), + shape = RoundedCornerShape(15.dp),) { + Text( + text = "unBook", + fontSize = 16.sp, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colors.onPrimary + ) + } + } + } } }else{ Text(text = "no booking resource yet", @@ -60,5 +102,4 @@ fun RegisteredBooking( } Spacer(modifier = Modifier.height(16.dp)) } - } \ No newline at end of file diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredEvent.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredEvent.kt index 06b1511..3b13fc8 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredEvent.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredEvent.kt @@ -1,5 +1,6 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -14,6 +15,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.enums.PageState import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString +import tumble.app.tumble.extensions.presentation.formatDate import tumble.app.tumble.presentation.views.general.CustomProgressIndicator @OptIn(ExperimentalCoroutinesApi::class) @@ -23,35 +25,30 @@ fun RegisteredEvent( state: State, registeredEvents: List? ){ - Column( modifier = Modifier - .fillMaxWidth() - .padding(top = 16.dp) + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(8.dp) ) { when(state.value){ PageState.LOADING -> { CustomProgressIndicator() } PageState.LOADED -> { - if(!registeredEvents.isNullOrEmpty()){ registeredEvents.forEach{ event -> val eventStart = event.eventStart.convertToHoursAndMinutesISOString() val eventEnd = event.eventEnd.convertToHoursAndMinutesISOString() - if (eventStart != null && eventEnd != null){ ResourceCard( eventStart = eventStart, eventEnd = eventEnd, type = event.type, title = event.title, - date = event.eventStart?:"(no date)", + date = event.eventStart.formatDate()?:"(no date)", onClick = { onClickEvent(event) } - ) } - } }else{ Text( @@ -67,6 +64,4 @@ fun RegisteredEvent( } Spacer(modifier = Modifier.height(16.dp)) } - - } \ No newline at end of file diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceCard.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceCard.kt index 93c3415..987c84e 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceCard.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceCard.kt @@ -8,13 +8,15 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.ButtonDefaults import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.CalendarToday import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Place -import androidx.compose.material3.Button +import androidx.compose.material.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -34,34 +36,32 @@ fun ResourceCard( location: String? = null, onClick: () -> Unit ){ - Button( onClick = { onClick() }, + shape = RoundedCornerShape(16.dp), + colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.surface), modifier = Modifier - .fillMaxWidth() - .padding(16.dp) + .fillMaxWidth(), ) { Column( - verticalArrangement = Arrangement.spacedBy(8.dp) + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalAlignment = Alignment.Start, + modifier = Modifier.fillMaxWidth() ) { - TitileView(title = title) - + TitleView(title = title) if(!type.isNullOrEmpty()){ InformationView(icon = Icons.Default.Info, text = type) } if(!location.isNullOrEmpty()){ InformationView(icon = Icons.Default.Place, text = location) } - DataView(date = date, start = eventStart, end = eventEnd) - } - } } @Composable -fun TitileView(title: String?){ +fun TitleView(title: String?){ Text( text = title?: "No titile", fontSize = 17.sp, @@ -77,7 +77,6 @@ fun InformationView(icon: ImageVector, text: String){ verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = 4.dp) ){ - Icon( imageVector = icon, contentDescription = null, @@ -110,7 +109,6 @@ fun DataView( tint = MaterialTheme.colors.onBackground.copy(alpha = 0.7f) ) Spacer(modifier = Modifier.width(4.dp)) - Text( text = "$date, from $start to $end", fontSize = 15.sp, diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceSectionDivider.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceSectionDivider.kt index 4e53f57..af8d73d 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceSectionDivider.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceSectionDivider.kt @@ -1,7 +1,5 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection -import android.util.Log -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -22,7 +20,6 @@ import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -38,10 +35,8 @@ fun ResourceSectionDivider( title: String, resourceType: ResourceType? = null, destination: (() -> Unit)? = null, - onBook: (() -> Unit)? = null, content: @Composable () -> Unit ){ - Column( modifier = Modifier .fillMaxSize() @@ -51,7 +46,8 @@ fun ResourceSectionDivider( modifier = Modifier .fillMaxWidth() .padding(bottom = 10.dp), - horizontalArrangement = Arrangement.SpaceBetween + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically ){ Text( text = title, @@ -76,16 +72,12 @@ fun ResourceNavigationItem( title: String, destination: () -> Unit ){ - Button( onClick = { destination() }, - colors = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent), - modifier = Modifier - .background(color = MaterialTheme.colors.primary, shape = RoundedCornerShape(20.dp)), + colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.primary), + shape = RoundedCornerShape(15.dp), elevation = null - ) { - Row (verticalAlignment = Alignment.CenterVertically){ Text( text = title, @@ -102,5 +94,4 @@ fun ResourceNavigationItem( ) } } - } \ No newline at end of file diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt index 062186c..9f18df2 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt @@ -2,7 +2,10 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.AlertDialog @@ -20,11 +23,12 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import kotlinx.coroutines.launch -import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.presentation.navigation.Routes import tumble.app.tumble.presentation.viewmodels.AccountViewModel @@ -43,17 +47,12 @@ fun Resources( var showingConfirmationDialog by remember { mutableStateOf(false) } - LaunchedEffect(key1 = Unit) { getResourcesAndEvents() } - - val combinedData = parentViewModel.combinedData.collectAsState() val userBookings = parentViewModel.userBookings.collectAsState() val userEvents = parentViewModel.completeUserEvent.collectAsState() - val registeredBookingsState = parentViewModel.registeredBookingsSectionState.collectAsState() - Column( modifier = Modifier .fillMaxSize() @@ -61,20 +60,27 @@ fun Resources( .background(color = MaterialTheme.colors.background) ) { //TODO pull to refresh - ResourceSectionDivider(title = "User options"){ - Switch( - checked = combinedData.value.autoSignup?: false, - onCheckedChange = { - if(it){ - showingConfirmationDialog = true - }else{ - parentViewModel.toggleAutoSignup(false) - } - }, - colors = SwitchDefaults.colors(checkedThumbColor = MaterialTheme.colors.primary) - ) - + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = "Automatic exam signup" + ) + Spacer(modifier = Modifier.weight(1f)) + Switch( + checked = parentViewModel.autoSignUpEnabled(), + onCheckedChange = { + if (it) { + showingConfirmationDialog = true + } else { + parentViewModel.toggleAutoSignup(false) + } + }, + colors = SwitchDefaults.colors( + checkedThumbColor = MaterialTheme.colors.onPrimary, + checkedTrackColor = MaterialTheme.colors.primary + ) + ) + } if(showingConfirmationDialog){ AlertDialog( onDismissRequest = { showingConfirmationDialog = false }, @@ -100,50 +106,41 @@ fun Resources( } } ResourceSectionDivider( - title = "Your bookings", + title = "Your bookings", // string resource resourceType = ResourceType.RESOURCE, destination = { navController.navigate(Routes.accountResources) } ) { RegisteredBooking( - onClickResource = { }, + onClickResource = { parentViewModel.setBooking(it) }, state = registeredBookingsState, - bookings = userBookings.value?.bookings?: emptyList() + bookings = userBookings.value?.bookings?: emptyList(), + confirmBooking = {resourceId, bookingId -> parentViewModel.confirmResource(resourceId, bookingId)}, + unBook = {bookingId -> parentViewModel.unBookResource(bookingId)} ) } ResourceSectionDivider( - title = "Your event", + title = "Your event", // string resource resourceType = ResourceType.EVENT, destination = { navController.navigate(Routes.accountEvents) } ) { RegisteredEvent( - onClickEvent = { }, + onClickEvent = { parentViewModel.setEvent(it) }, state = parentViewModel.registeredEventSectionState.collectAsState(), registeredEvents = userEvents.value?.registeredEvents?: emptyList() ) } + Spacer(modifier = Modifier.height(60.dp)) } LaunchedEffect(key1 = scrollState.value) { - scrollOffset = scrollState.value.toFloat() - if(scrollOffset >= 80){ coroutinScope.launch { collapsedHeader.value = true } - } else{ + } else if (scrollOffset == 0f){ coroutinScope.launch { collapsedHeader.value = false } } } -} - - -fun onClickResource(resource: NetworkResponse.KronoxUserBookingElement){ - -} - - -fun onClickEvent(resource: NetworkResponse.KronoxUserBookingElement){ - } \ No newline at end of file From 12809ef5d77b1c70e7937c6253ee9c0c42a58b3b Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 09:45:03 +0200 Subject: [PATCH 25/38] changed data formating --- app/src/main/java/tumble/app/tumble/utils/Formatters.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/tumble/app/tumble/utils/Formatters.kt b/app/src/main/java/tumble/app/tumble/utils/Formatters.kt index 8002c09..bc56c1c 100644 --- a/app/src/main/java/tumble/app/tumble/utils/Formatters.kt +++ b/app/src/main/java/tumble/app/tumble/utils/Formatters.kt @@ -15,7 +15,7 @@ val isoDateFormatter: SimpleDateFormat by lazy { } val isoDateFormatterNoTimeZone: SimpleDateFormat by lazy { - val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.getDefault()) + val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault()) formatter.timeZone = TimeZone.getDefault() formatter } @@ -29,4 +29,9 @@ val isoDateFormatterDate: SimpleDateFormat by lazy { val month_date: SimpleDateFormat by lazy { val formatter = SimpleDateFormat("MMMM", Locale.getDefault()) formatter +} + +val isoVerboseDateFormatter: SimpleDateFormat by lazy { + val formatter = SimpleDateFormat("EEEE, MMM d,yyyy", Locale.getDefault()) + formatter } \ No newline at end of file From 574cbf27f979cd2a52c6cf0a96427c64c2e43d33 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 09:51:05 +0200 Subject: [PATCH 26/38] user banner UI --- .../account/User/ProfileSection/UserAvatar.kt | 6 ++--- .../User/ProfileSection/UserOverview.kt | 25 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ProfileSection/UserAvatar.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ProfileSection/UserAvatar.kt index bfc1c36..1f408b5 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ProfileSection/UserAvatar.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ProfileSection/UserAvatar.kt @@ -1,5 +1,6 @@ package tumble.app.tumble.presentation.views.account.User.ProfileSection +import androidx.compose.animation.animateContentSize import androidx.compose.foundation.background import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.CircleShape @@ -8,7 +9,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -21,9 +21,10 @@ fun UserAvatar(name: String, collapsedHeader: Boolean){ text = abbreviation, fontSize = if (collapsedHeader) 20.sp else 40.sp, fontWeight = FontWeight.SemiBold, - color = Color.White, + color = MaterialTheme.colors.onPrimary, textAlign = TextAlign.Center, modifier = Modifier + .animateContentSize () .padding(16.dp) .clip(CircleShape) .background(MaterialTheme.colors.primary) @@ -31,7 +32,6 @@ fun UserAvatar(name: String, collapsedHeader: Boolean){ ) } - fun String.abbreviate(): String { return this.split(" ").mapNotNull { it.firstOrNull()?.toString() }.take(2).joinToString("") } \ No newline at end of file diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ProfileSection/UserOverview.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ProfileSection/UserOverview.kt index 295b4fb..2577273 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ProfileSection/UserOverview.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ProfileSection/UserOverview.kt @@ -1,6 +1,8 @@ package tumble.app.tumble.presentation.views.account.User.ProfileSection +import androidx.compose.animation.animateContentSize import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -25,7 +27,6 @@ import androidx.navigation.NavHostController import tumble.app.tumble.presentation.viewmodels.AccountViewModel import tumble.app.tumble.presentation.views.account.User.ResourceSection.Resources - @Composable fun UserOverview( viewModel: AccountViewModel = hiltViewModel(), @@ -34,22 +35,22 @@ fun UserOverview( val collapsedHeader = remember { mutableStateOf(false) } - val user = viewModel.user.collectAsState() - Column( modifier = Modifier .fillMaxSize() - .background(MaterialTheme.colors.background) + .background(MaterialTheme.colors.background), ) { - Row ( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .padding(horizontal = 15.dp) - .fillMaxWidth() - ){ - user.value?.name?.let { name -> - user.value?.username?.let { username -> + user.value?.name?.let { name -> + user.value?.username?.let { username -> + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Start, + modifier = Modifier + .animateContentSize() + .padding(horizontal = 15.dp) + .fillMaxWidth() + ) { UserAvatar(name = name, collapsedHeader = collapsedHeader.value) Spacer(modifier = Modifier.width(5.dp)) Column( From 2bcd15591693bb9ef95fd84260bf5a70e114b32d Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 09:54:03 +0200 Subject: [PATCH 27/38] string resources --- app/src/main/res/values-en-rUS/strings.xml | 29 ++++++++++++++++++++++ app/src/main/res/values/strings.xml | 14 +++++++++++ 2 files changed, 43 insertions(+) diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml index 0045e6a..630a542 100644 --- a/app/src/main/res/values-en-rUS/strings.xml +++ b/app/src/main/res/values-en-rUS/strings.xml @@ -28,4 +28,33 @@ No events this day No events for this week.. Light + Dark + Automatic + Settings + Account + Appearance + App Language + Notification offset + Review the app + Share feedback + Share the app + Tumble on Github + Scan QR Code + See all + Book more + Copy link + Registered + Unregistered + Upcoming + Available until + Signup has passed + Unregister + register + No Registerd Events + No Unregistered Events + No Upcoming Events + Available at + Resources + Rooms + Events \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e4a5a73..d8e20f0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -43,4 +43,18 @@ See all Book more Copy link + Registered + Unregistered + Upcoming + Available until + Signup has passed + Unregister + register + No Registerd Events + No Unregistered Events + No Upcoming Events + Available at + Resources + Rooms + Events \ No newline at end of file From cb9468d14a08f2975b459e424b8d80feee9d60a7 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 09:55:06 +0200 Subject: [PATCH 28/38] misc --- app/build.gradle | 1 + build.gradle | 4 ++-- gradle.properties | 1 - gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 97153a6..c6b12d4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,6 +38,7 @@ android { } buildFeatures { compose true + buildConfig true } composeOptions { kotlinCompilerExtensionVersion '1.4.6' // Check and update if a newer version is available diff --git a/build.gradle b/build.gradle index e506abf..e7bd6ac 100644 --- a/build.gradle +++ b/build.gradle @@ -7,8 +7,8 @@ buildscript { } } plugins { - id 'com.android.application' version '8.6.0' apply false - id 'com.android.library' version '8.6.0' apply false + id 'com.android.application' version '8.7.0' apply false + id 'com.android.library' version '8.7.0' apply false id 'org.jetbrains.kotlin.android' version '1.8.20' apply false id 'com.google.dagger.hilt.android' version '2.44' apply false id 'io.realm.kotlin' version '1.10.0' apply false diff --git a/gradle.properties b/gradle.properties index a2e90d8..f19c7b9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,5 +21,4 @@ kotlin.code.style=official # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true -android.defaults.buildfeatures.buildconfig=true android.nonFinalResIds=false \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 78d1ceb..598a2d7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Thu Apr 20 16:07:30 CEST 2023 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME From 923a8bcb77105ccc9390ab5111dbec6001895b69 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 13:12:15 +0200 Subject: [PATCH 29/38] miner clean up --- .../app/tumble/extensions/models/DayExtensions.kt | 5 ----- .../tumble/extensions/presentation/StringExtensions.kt | 3 --- .../app/tumble/presentation/navigation/Routes.kt | 2 +- .../navigation/navgraphs/AccountNavGraph.kt | 8 ++++---- .../tumble/presentation/viewmodels/SearchViewModel.kt | 1 - .../tumble/app/tumble/presentation/views/AppParent.kt | 5 ----- .../tumble/presentation/views/bookmarks/Bookmarks.kt | 10 ---------- .../views/bookmarks/Week/BookmarkWeekView.kt | 3 --- .../tumble/app/tumble/presentation/views/home/Home.kt | 5 ----- .../tumble/presentation/views/search/ProgrammeCard.kt | 2 -- .../tumble/presentation/views/search/SearchField.kt | 8 +++----- .../presentation/views/search/SearchPreviewSheet.kt | 6 ------ 12 files changed, 8 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/extensions/models/DayExtensions.kt b/app/src/main/java/tumble/app/tumble/extensions/models/DayExtensions.kt index 3014264..e7f433f 100644 --- a/app/src/main/java/tumble/app/tumble/extensions/models/DayExtensions.kt +++ b/app/src/main/java/tumble/app/tumble/extensions/models/DayExtensions.kt @@ -1,16 +1,11 @@ package tumble.app.tumble.extensions.models import android.os.Build -import android.util.Log import androidx.annotation.RequiresApi -import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.models.realm.Day import tumble.app.tumble.utils.isoDateFormatter import tumble.app.tumble.utils.preprocessDateString -import java.time.Instant import java.time.LocalDate -import java.time.ZoneId -import java.time.format.DateTimeFormatter fun List.ordered(): List { diff --git a/app/src/main/java/tumble/app/tumble/extensions/presentation/StringExtensions.kt b/app/src/main/java/tumble/app/tumble/extensions/presentation/StringExtensions.kt index 53a9afb..7169c86 100644 --- a/app/src/main/java/tumble/app/tumble/extensions/presentation/StringExtensions.kt +++ b/app/src/main/java/tumble/app/tumble/extensions/presentation/StringExtensions.kt @@ -5,17 +5,14 @@ import androidx.annotation.RequiresApi import java.text.SimpleDateFormat import java.util.* import androidx.compose.ui.graphics.Color -import tumble.app.tumble.utils.isoDateFormatter import tumble.app.tumble.utils.isoDateFormatterNoTimeZone import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.time.format.DateTimeParseException fun String.formatDate(): String? { - //val isoDateFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.XXX'Z'", Locale.getDefault()) // Adjust this format if your ISO string is in a different format val targetFormatter = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) - val date = isoDateFormatterNoTimeZone.parse(this) return date?.let { targetFormatter.format(it) } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/navigation/Routes.kt b/app/src/main/java/tumble/app/tumble/presentation/navigation/Routes.kt index 14bf523..a7be44a 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/navigation/Routes.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/navigation/Routes.kt @@ -22,7 +22,7 @@ object Routes { const val accountResources = "account/resources" const val accountResourceDetails = "account/resources/{id}" const val accountEvents = "account/events" - const val accountEventDetails = "account/events?eventId={id}" + const val accountEventDetails = "account/events/{id}" // Deep links var HomeUri = "https://${shared.tumbleUrl}/$home" diff --git a/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/AccountNavGraph.kt b/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/AccountNavGraph.kt index 2232b23..258f787 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/AccountNavGraph.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/AccountNavGraph.kt @@ -76,7 +76,7 @@ private fun NavGraphBuilder.accountSettingsLanguage(navController: NavHostContro private fun NavGraphBuilder.accountSettingsNotifications(navController: NavHostController) { composable(Routes.accountSettingsNotifications) { - NotificationOffsetSettings(navController = navController) + NotificationOffsetSettings() } } @@ -110,7 +110,7 @@ private fun NavGraphBuilder.accountResourceDetails(navController: NavHostControl @RequiresApi(Build.VERSION_CODES.O) private fun NavGraphBuilder.accountEvents(navController: NavHostController) { composable(Routes.accountEvents) { - //EventBookings(navController = navController) + EventBookings(navController = navController) } } @@ -119,8 +119,8 @@ private fun NavGraphBuilder.accountEventDetails(navController: NavHostController composable( Routes.accountEventDetails, ) { backStackEntry -> - val id = backStackEntry.arguments?.getString("id") - EventBookings(navController = navController) +// val id = backStackEntry.arguments?.getString("id") +// EventBookings(navController = navController) } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/SearchViewModel.kt b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/SearchViewModel.kt index e1a4e36..059be54 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/SearchViewModel.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/SearchViewModel.kt @@ -11,7 +11,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job import kotlinx.coroutines.launch -import retrofit2.Response import tumble.app.tumble.data.api.Endpoint import tumble.app.tumble.data.api.url import tumble.app.tumble.data.repository.preferences.DataStoreManager diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/AppParent.kt b/app/src/main/java/tumble/app/tumble/presentation/views/AppParent.kt index 78bb649..81c37c7 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/AppParent.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/AppParent.kt @@ -9,10 +9,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold import androidx.compose.material.Surface -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier @@ -29,7 +27,6 @@ import tumble.app.tumble.presentation.views.navigation.BottomNavItem import tumble.app.tumble.presentation.views.navigation.TopBar import tumble.app.tumble.ui.theme.TumbleTheme -@OptIn(ExperimentalMaterial3Api::class) @RequiresApi(Build.VERSION_CODES.O) @SuppressLint("UnusedMaterialScaffoldPaddingParameter") @Preview(showBackground = true, name = "AppParent preview") @@ -52,8 +49,6 @@ fun AppParent() { BottomNavItem.ACCOUNT -> accountNavController } - val combinedData by viewModel.combinedData.collectAsState() - TumbleTheme(userPreferences = apperance.value) { Surface( modifier = Modifier.fillMaxSize(), diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Bookmarks.kt b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Bookmarks.kt index 7c265d8..a0e1672 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Bookmarks.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Bookmarks.kt @@ -2,25 +2,17 @@ package tumble.app.tumble.presentation.views.bookmarks import android.os.Build import androidx.annotation.RequiresApi -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Scaffold -import androidx.compose.material.Text -import androidx.compose.material.TopAppBar -import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.core.net.toUri import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -29,7 +21,6 @@ import tumble.app.tumble.domain.enums.BookmarksStatus import tumble.app.tumble.domain.models.presentation.EventDetailsSheetModel import tumble.app.tumble.domain.models.realm.Event import tumble.app.tumble.observables.AppController -import tumble.app.tumble.presentation.navigation.UriBuilder import tumble.app.tumble.presentation.viewmodels.BookmarksViewModel import tumble.app.tumble.presentation.viewmodels.ParentViewModel import tumble.app.tumble.presentation.views.bookmarks.EventDetails.EventDetailsSheet @@ -47,7 +38,6 @@ fun Bookmarks( val onEventSelection = { event: Event -> AppController.shared.eventSheet = EventDetailsSheetModel(event = event) -// navController.navigate( UriBuilder.buildBookmarksDetailsUri(event.eventId).toUri() ) } val bookmarksStatus = viewModel.status diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Week/BookmarkWeekView.kt b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Week/BookmarkWeekView.kt index ddbef35..d8cc9b4 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Week/BookmarkWeekView.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Week/BookmarkWeekView.kt @@ -18,8 +18,6 @@ import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -117,7 +115,6 @@ fun BookmarkWeekView( indicatorScrollState = indicatorScrollState, pagerState = pagerState, ) - Spacer(modifier = Modifier.height(60.dp)) } } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/home/Home.kt b/app/src/main/java/tumble/app/tumble/presentation/views/home/Home.kt index 1db3611..75decea 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/home/Home.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/home/Home.kt @@ -4,7 +4,6 @@ import androidx.annotation.RequiresApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material.* -import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet import androidx.compose.runtime.* @@ -37,15 +36,12 @@ fun HomeScreen( parentViewModel: ParentViewModel = hiltViewModel(), navController: NavHostController = rememberNavController() ) { -// val schedules by viewModel.schedules(query = "YOUR_QUERY_HERE").collectAsState(initial = listOf()) val newsStatus = viewModel.newsSectionStatus val homeStatus = viewModel.status - val news = viewModel.news val showSheet = remember { mutableStateOf(false) } val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden) - Column( modifier = Modifier .padding(horizontal = 15.dp, vertical = 10.dp) @@ -74,7 +70,6 @@ fun HomeScreen( } Spacer(Modifier.weight(1f)) } - if (showSheet.value) { ModalBottomSheet(onDismissRequest = { showSheet.value = false }) { NewsSheet(news = news, sheetState = sheetState, showSheet = showSheet) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/search/ProgrammeCard.kt b/app/src/main/java/tumble/app/tumble/presentation/views/search/ProgrammeCard.kt index 7d10fad..d46ff10 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/search/ProgrammeCard.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/search/ProgrammeCard.kt @@ -1,7 +1,6 @@ package tumble.app.tumble.presentation.views.search import androidx.compose.foundation.Image -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -20,7 +19,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/search/SearchField.kt b/app/src/main/java/tumble/app/tumble/presentation/views/search/SearchField.kt index 5ffc782..f8031fd 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/search/SearchField.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/search/SearchField.kt @@ -15,13 +15,11 @@ import androidx.compose.material3.DockedSearchBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.SearchBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur @@ -43,13 +41,13 @@ fun SearchField( searching: MutableState, selectedSchool: MutableState ){ - var searchBarText by remember { + val searchBarText by remember { mutableStateOf(searchBarText) } - var searching by remember { + val searching by remember { mutableStateOf(searching) } - var enabled = selectedSchool.value != null + val enabled = selectedSchool.value != null val focusManager = LocalFocusManager.current val context = LocalContext.current diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/search/SearchPreviewSheet.kt b/app/src/main/java/tumble/app/tumble/presentation/views/search/SearchPreviewSheet.kt index 0ded6d8..7b6295b 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/search/SearchPreviewSheet.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/search/SearchPreviewSheet.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -29,7 +28,6 @@ import tumble.app.tumble.presentation.views.general.CustomProgressIndicator import tumble.app.tumble.presentation.views.general.Info import tumble.app.tumble.R - @RequiresApi(Build.VERSION_CODES.O) @OptIn(ExperimentalCoroutinesApi::class) @Composable @@ -41,7 +39,6 @@ fun SearchPreviewSheet( fun bookmark(){ viewModel.bookmark(searchPreviewModel.scheduleId, searchPreviewModel.schoolId) } - Box ( modifier = Modifier .fillMaxSize() @@ -62,7 +59,6 @@ fun SearchPreviewSheet( } } } - Row ( modifier = Modifier .fillMaxWidth() @@ -75,12 +71,10 @@ fun SearchPreviewSheet( BookmarkButton(bookmark = { bookmark() }, buttonState = viewModel.buttonState) else Box {} - CloseCoverButton( onClick = { navController.popBackStack() }, ) } - LaunchedEffect(Unit) { viewModel.getSchedule(searchPreviewModel.scheduleId, searchPreviewModel.schoolId) } From 4a16eef408a0142b6db818aff53dcd3bd62ad9e4 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 13:17:27 +0200 Subject: [PATCH 30/38] updated resource and event scaffolding --- .../Booking/Events/EventBookings.kt | 125 ++++++++---------- .../Booking/Resources/ResourceBookings.kt | 113 +++++++--------- .../Booking/Resources/ResourceSelection.kt | 99 ++++++-------- .../presentation/views/navigation/TopBar.kt | 4 + 4 files changed, 147 insertions(+), 194 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt index 62abc9f..ca95ba9 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventBookings.kt @@ -3,34 +3,24 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Bookin import android.os.Build import androidx.annotation.RequiresApi import androidx.compose.foundation.background -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.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Tag import androidx.compose.material.MaterialTheme -import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier -import androidx.compose.ui.input.pointer.motionEventSpy import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import kotlinx.coroutines.ExperimentalCoroutinesApi import tumble.app.tumble.R import tumble.app.tumble.domain.enums.PageState -import tumble.app.tumble.presentation.components.buttons.CloseCoverButton import tumble.app.tumble.presentation.viewmodels.ResourceViewModel -import tumble.app.tumble.presentation.views.Settings.BackNav import tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.SectionDivider import tumble.app.tumble.presentation.views.general.CustomProgressIndicator import tumble.app.tumble.presentation.views.general.Info @@ -45,74 +35,63 @@ fun EventBookings( val completeUserEvent = viewModel.completeUserEvent.collectAsState() val eventBookingPageState = viewModel.eventBookingPageState.collectAsState() val scrollState = rememberScrollState() - Scaffold ( - topBar = { - BackNav( - onClick = {navController.popBackStack()}, - label = stringResource(R.string.account), - title = stringResource(R.string.events) - ) - }, - ) { padding -> - Column( - modifier = Modifier - .fillMaxSize() - .verticalScroll(scrollState) - .background(MaterialTheme.colors.background) - .padding(padding) - ) { - when (eventBookingPageState.value) { - PageState.LOADING -> { - CustomProgressIndicator() - } - PageState.LOADED -> { - SectionDivider( - title = stringResource(id = R.string.registered), - image = Icons.Default.Tag, - content = { - completeUserEvent.value?.registeredEvents?.let { events -> - RegisteredEventsView( - registeredEvents = events, - onTapEventAction = { eventId, eventType -> - onTapEventAction(viewModel, eventId, eventType) - } - ) - } + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(scrollState) + .background(MaterialTheme.colors.background) + ) { + when (eventBookingPageState.value) { + PageState.LOADING -> { + CustomProgressIndicator() + } + PageState.LOADED -> { + SectionDivider( + title = stringResource(id = R.string.registered), + image = Icons.Default.Tag, + content = { + completeUserEvent.value?.registeredEvents?.let { events -> + RegisteredEventsView( + registeredEvents = events, + onTapEventAction = { eventId, eventType -> + onTapEventAction(viewModel, eventId, eventType) + } + ) } - ) - SectionDivider( - title = stringResource(id = R.string.unregistered), - image = Icons.Default.Tag, - content = { - completeUserEvent.value?.unregisteredEvents?.let { events -> - UnregisteredEventsView( - unregisteredEvents = events, - onTapEventAction = { eventId, eventType -> - onTapEventAction(viewModel, eventId, eventType) - } - ) - } + + } + ) + SectionDivider( + title = stringResource(id = R.string.unregistered), + image = Icons.Default.Tag, + content = { + completeUserEvent.value?.unregisteredEvents?.let { events -> + UnregisteredEventsView( + unregisteredEvents = events, + onTapEventAction = { eventId, eventType -> + onTapEventAction(viewModel, eventId, eventType) + } + ) } - ) - SectionDivider( - title = stringResource(id = R.string.upcoming), - image = Icons.Default.Tag, - content = { - completeUserEvent.value?.upcomingEvents?.let { events -> - UpcomingEventsView(upcomingEvents = events) - } + } + ) + SectionDivider( + title = stringResource(id = R.string.upcoming), + image = Icons.Default.Tag, + content = { + completeUserEvent.value?.upcomingEvents?.let { events -> + UpcomingEventsView(upcomingEvents = events) } - ) - } - PageState.ERROR -> { - Info( - title = stringResource(id = R.string.error_something_wrong), - image = null, - ) - } + } + ) + } + PageState.ERROR -> { + Info( + title = stringResource(id = R.string.error_something_wrong), + image = null, + ) } - Spacer(Modifier.height(30.dp)) } } LaunchedEffect(Unit) { diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt index c4dcd3a..4239ef5 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt @@ -6,25 +6,21 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material.MaterialTheme import androidx.compose.material3.Divider -import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.core.net.toUri import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import kotlinx.coroutines.ExperimentalCoroutinesApi -import tumble.app.tumble.R import tumble.app.tumble.domain.enums.PageState import tumble.app.tumble.domain.models.presentation.ResourceSelectionModel import tumble.app.tumble.observables.AppController import tumble.app.tumble.presentation.navigation.UriBuilder import tumble.app.tumble.presentation.viewmodels.ResourceViewModel -import tumble.app.tumble.presentation.views.Settings.BackNav import tumble.app.tumble.presentation.views.general.CustomProgressIndicator import tumble.app.tumble.presentation.views.general.Info import java.util.Calendar @@ -40,68 +36,57 @@ fun ResourceBookings( val resourceBookingPageState = viewModel.resourceBookingPageState.collectAsState() val selectedPikerDate = viewModel.selectedPickerDate.collectAsState() - Scaffold ( - topBar = { - BackNav( - onClick = {navController.popBackStack()}, - label = stringResource(R.string.account), - title = stringResource(R.string.resources) - ) - }, - ) { padding -> - Column( - modifier = Modifier - .fillMaxSize() - .padding(padding) - .background(MaterialTheme.colors.background) - ) { - ResourceDatePicker( - onDateChange = { date -> - viewModel.setBookingDate(date) + Column( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colors.background) + ) { + ResourceDatePicker( + onDateChange = { date -> + viewModel.setBookingDate(date) + } + ) + Divider(color = MaterialTheme.colors.onBackground) + when (resourceBookingPageState.value) { + PageState.LOADING -> { + Box( + modifier = Modifier + .fillMaxWidth() + .height(200.dp) + .padding(16.dp), + contentAlignment = Alignment.Center + ) { + CustomProgressIndicator() } - ) - Divider(color = MaterialTheme.colors.onBackground) - when (resourceBookingPageState.value) { - PageState.LOADING -> { - Box( - modifier = Modifier - .fillMaxWidth() - .height(200.dp) - .padding(16.dp), - contentAlignment = Alignment.Center - ) { - CustomProgressIndicator() + } + PageState.LOADED -> { + ResourceLocationsList( + parentViewModel = viewModel, + selectedPickerDate = selectedPikerDate.value, + navigateToResourceSelection = { resource, date -> + AppController.shared.resourceModel = ResourceSelectionModel(resource, date) + navController.navigate(UriBuilder.buildAccountResourceDetailsUri(resource.id.toString()).toUri()) } - } - PageState.LOADED -> { - ResourceLocationsList( - parentViewModel = viewModel, - selectedPickerDate = selectedPikerDate.value, - navigateToResourceSelection = { resource, date -> - AppController.shared.resourceModel = ResourceSelectionModel(resource, date) - navController.navigate(UriBuilder.buildAccountResourceDetailsUri(resource.id.toString()).toUri()) - } - ) - } - PageState.ERROR -> { - Box( - modifier = Modifier - .fillMaxWidth() - .height(200.dp) - .padding(16.dp), - contentAlignment = Alignment.Center - ) { - if (isWeekend(selectedPikerDate.value)) { - Info( - title = "No rooms available on weekends", - image = null//R.drawable.moon_zzz // Replace with your drawable resource - ) - } else { - Info( - title = "Could not contact the server, try again later", - image = null //R.drawable.arrow_clockwise // Replace with your drawable resource - ) - } + ) + } + PageState.ERROR -> { + Box( + modifier = Modifier + .fillMaxWidth() + .height(200.dp) + .padding(16.dp), + contentAlignment = Alignment.Center + ) { + if (isWeekend(selectedPikerDate.value)) { + Info( + title = "No rooms available on weekends", + image = null//R.drawable.moon_zzz // Replace with your drawable resource + ) + } else { + Info( + title = "Could not contact the server, try again later", + image = null //R.drawable.arrow_clockwise // Replace with your drawable resource + ) } } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt index 549249f..1578c89 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt @@ -12,23 +12,19 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material.Divider import androidx.compose.material.MaterialTheme import androidx.compose.material.Text -import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController -import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.models.getAvailabilityValues import tumble.app.tumble.extensions.models.getFirstTimeSlotWithAvailability import tumble.app.tumble.observables.AppController import tumble.app.tumble.presentation.viewmodels.ResourceViewModel -import tumble.app.tumble.presentation.views.Settings.BackNav import tumble.app.tumble.presentation.views.general.Info import tumble.app.tumble.utils.isoVerboseDateFormatter @@ -45,60 +41,49 @@ fun ResourceSelection( } val selectedPickerDate = AppController.shared.resourceModel!!.date val timeslots = resource.timeSlots - Scaffold ( - topBar = { - BackNav( - onClick = {navController.popBackStack()}, - label = stringResource(R.string.resources), - title = stringResource(R.string.rooms) + Column( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colors.background) + ) { + Row { + Text( + text = isoVerboseDateFormatter.format(selectedPickerDate), + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colors.onBackground, + modifier = Modifier + .padding(horizontal = 15.dp, vertical = 20.dp) + .fillMaxWidth() + ) + Spacer(modifier = Modifier.weight(1f)) + } + if (timeslots != null) { + TimeslotDropdown( + resource = resource, + timeslots = timeslots, + selectedIndex = selectedTimeIndex, + onIndexChange = { index -> + selectedTimeIndex.value = index + availabilityValues.value = + resource.availabilities.getAvailabilityValues(timelotId = index) + } + ) + Divider(modifier = Modifier.padding(vertical = 8.dp)) + TimeslotSelection( + bookResource = { availabilityValue -> + parentViewModel.bookResource( + resourceId = resource.id!!, + date = selectedPickerDate, + availabilityValue = availabilityValue + ) + }, + availabilityValues = availabilityValues + ) + } else { + Info( + title = "No available timeslots", + image = null, ) - }, - ) { padding -> - Column( - modifier = Modifier - .fillMaxSize() - .background(MaterialTheme.colors.background) - .padding(padding) - ) { - Row { - Text( - text = isoVerboseDateFormatter.format(selectedPickerDate), - fontWeight = FontWeight.SemiBold, - color = MaterialTheme.colors.onBackground, - modifier = Modifier - .padding(horizontal = 15.dp, vertical = 20.dp) - .fillMaxWidth() - ) - Spacer(modifier = Modifier.weight(1f)) - } - if (timeslots != null) { - TimeslotDropdown( - resource = resource, - timeslots = timeslots, - selectedIndex = selectedTimeIndex, - onIndexChange = { index -> - selectedTimeIndex.value = index - availabilityValues.value = - resource.availabilities.getAvailabilityValues(timelotId = index) - } - ) - Divider(modifier = Modifier.padding(vertical = 8.dp)) - TimeslotSelection( - bookResource = { availabilityValue -> - parentViewModel.bookResource( - resourceId = resource.id!!, - date = selectedPickerDate, - availabilityValue = availabilityValue - ) - }, - availabilityValues = availabilityValues - ) - } else { - Info( - title = "No available timeslots", - image = null, - ) - } } } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/navigation/TopBar.kt b/app/src/main/java/tumble/app/tumble/presentation/views/navigation/TopBar.kt index 89b94eb..7aa4bbf 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/navigation/TopBar.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/navigation/TopBar.kt @@ -24,6 +24,8 @@ fun TopBarBackButton(currentNavController: NavHostController) { val route = getCurrentRoute(currentNavController); return when(route) { + Routes.accountResources, + Routes.accountEvents, Routes.accountSettings -> BackButton( { currentNavController.popBackStack() }, stringResource(R.string.account) @@ -55,6 +57,8 @@ fun TopBarTitle(currentNavController: NavHostController) { Routes.accountSettingsLanguage -> Text(stringResource(R.string.app_language)) Routes.accountSettingsNotifications -> Text(stringResource(R.string.notification_offset)) Routes.searchDetails -> Text(stringResource(R.string.search)) + Routes.accountEvents -> Text(stringResource(R.string.events)) + Routes.accountResources -> Text(stringResource(R.string.resources)) else -> Text(stringResource(R.string.app_name)) } From d52d13fa34f928597df5babe09bc75a81d90ebc3 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 26 Oct 2024 14:12:40 +0200 Subject: [PATCH 31/38] added string resources --- .../Booking/Events/EventCardButton.kt | 10 ++----- .../ResourceSection/Booking/Events/Events.kt | 4 --- .../Booking/Events/UpcomingEventCardButton.kt | 10 +++---- .../Booking/Resources/ResourceBookings.kt | 6 ++-- .../Resources/ResourceLocationsList.kt | 6 ++-- .../Booking/Resources/ResourceSelection.kt | 4 ++- .../Booking/Resources/ResourceTimeDropdown.kt | 2 -- .../Booking/Resources/TimelotSelection.kt | 4 ++- .../Booking/Sheets/EventDetails.kt | 24 ++++++--------- .../Booking/Sheets/ResourceDetails.kt | 23 +++++++------- .../User/ResourceSection/RegisteredBooking.kt | 19 +++++++----- .../User/ResourceSection/RegisteredEvent.kt | 8 +++-- .../User/ResourceSection/ResourceCard.kt | 4 ++- .../account/User/ResourceSection/Resources.kt | 18 ++++++----- app/src/main/res/values-en-rUS/strings.xml | 30 +++++++++++++++++++ app/src/main/res/values/strings.xml | 30 +++++++++++++++++++ 16 files changed, 130 insertions(+), 72 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt index 786af9f..5b79e6a 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/EventCardButton.kt @@ -2,7 +2,6 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Bookin import android.os.Build -import android.util.Log import androidx.annotation.RequiresApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -25,10 +24,8 @@ import androidx.compose.material.icons.filled.Event import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -37,9 +34,6 @@ import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString import tumble.app.tumble.extensions.presentation.formatDate import tumble.app.tumble.extensions.presentation.isValidRegistrationDate -import tumble.app.tumble.extensions.presentation.toColor -import tumble.app.tumble.extensions.presentation.toLocalDateTime -import tumble.app.tumble.utils.isoDateFormatterDate enum class EventType { REGISTER, @@ -84,7 +78,7 @@ fun EventCardButton( if (eventDate != null && eventStart != null && eventEnd != null) { "$eventDate: $eventStart - $eventEnd" } else { - "stringResource(id = R.string.no_date_at_this_time)" + stringResource(id = R.string.no_date) } Text( text = eventDateText, @@ -101,7 +95,7 @@ fun EventCardButton( ) val signupText = if (event.lastSignupDate.isValidRegistrationDate()) { "${stringResource(id = R.string.available_until)} ${(event.lastSignupDate.formatDate() - ) ?: "stringResource(id = R.string.no_date_set)" + ) ?: stringResource(id = R.string.no_date) }" } else { stringResource(id = R.string.signup_has_passed) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt index 99ac84f..39100ec 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/Events.kt @@ -4,9 +4,7 @@ import android.os.Build import androidx.annotation.RequiresApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -17,7 +15,6 @@ import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse.AvailableKronoxUserEvent import tumble.app.tumble.domain.models.network.NetworkResponse.UpcomingKronoxUserEvent - @RequiresApi(Build.VERSION_CODES.O) @Composable fun RegisteredEventsView( @@ -79,7 +76,6 @@ fun UnregisteredEventsView( } } - @RequiresApi(Build.VERSION_CODES.O) @Composable fun UpcomingEventsView( diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/UpcomingEventCardButton.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/UpcomingEventCardButton.kt index 996070c..572d2d1 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/UpcomingEventCardButton.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Events/UpcomingEventCardButton.kt @@ -28,7 +28,7 @@ import androidx.compose.ui.unit.sp import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString -import tumble.app.tumble.utils.isoDateFormatterDate +import tumble.app.tumble.extensions.presentation.formatDate @RequiresApi(Build.VERSION_CODES.O) @Composable @@ -61,13 +61,13 @@ fun UpcomingEventCardButton( contentDescription = null, tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) ) - val eventDate = isoDateFormatterDate.format(isoDateFormatterDate.parse(event.eventStart)) + val eventDate = event.eventStart.formatDate() val eventEnd = event.eventEnd.convertToHoursAndMinutesISOString() val eventStart = event.eventStart.convertToHoursAndMinutesISOString() val eventDateText = if (eventDate != null && eventStart != null && eventEnd != null) { "$eventDate: $eventStart - $eventEnd" } else { - "stringResource(id = R.string.no_date_at_this_time)" + stringResource(id = R.string.no_date) } Text( text = eventDateText, @@ -83,9 +83,7 @@ fun UpcomingEventCardButton( tint = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) ) Text( - text = "${stringResource(id = R.string.available_at)} ${ isoDateFormatterDate.format( - isoDateFormatterDate.parse(event.firstSignupDate) - ) ?: "stringResource(id = R.string.no_date_set)"}", + text = "${stringResource(id = R.string.available_at)} ${event.firstSignupDate.formatDate() ?: stringResource(id = R.string.no_date)}", fontSize = 15.sp, color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f) ) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt index 4239ef5..b9ad4c6 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceBookings.kt @@ -11,11 +11,13 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.core.net.toUri import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import kotlinx.coroutines.ExperimentalCoroutinesApi +import tumble.app.tumble.R import tumble.app.tumble.domain.enums.PageState import tumble.app.tumble.domain.models.presentation.ResourceSelectionModel import tumble.app.tumble.observables.AppController @@ -79,12 +81,12 @@ fun ResourceBookings( ) { if (isWeekend(selectedPikerDate.value)) { Info( - title = "No rooms available on weekends", + title = stringResource(R.string.no_rooms_on_weekend), image = null//R.drawable.moon_zzz // Replace with your drawable resource ) } else { Info( - title = "Could not contact the server, try again later", + title = stringResource(R.string.could_not_contact_server), image = null //R.drawable.arrow_clockwise // Replace with your drawable resource ) } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt index 9206b83..50fcc8d 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceLocationsList.kt @@ -22,10 +22,12 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.presentation.viewmodels.ResourceViewModel import java.util.Date @@ -82,7 +84,7 @@ fun ResourceLocationItem( verticalArrangement = Arrangement.spacedBy(8.dp) ) { Text( - text = resource.name ?: "No name", + text = resource.name ?: stringResource(R.string.no_name), fontSize = 18.sp, color = MaterialTheme.colors.onBackground, maxLines = 1, @@ -111,7 +113,7 @@ fun ResourceLocationItem( tint = MaterialTheme.colors.onSurface ) Text( - text = "Available timeslots: $availableCounts", + text = "${stringResource(R.string.available_timeslots)}: $availableCounts", fontSize = 15.sp, color = MaterialTheme.colors.onSurface ) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt index 1578c89..07bfdb3 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt @@ -16,10 +16,12 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.models.getAvailabilityValues import tumble.app.tumble.extensions.models.getFirstTimeSlotWithAvailability @@ -81,7 +83,7 @@ fun ResourceSelection( ) } else { Info( - title = "No available timeslots", + title = stringResource(R.string.no_timeslots), image = null, ) } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceTimeDropdown.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceTimeDropdown.kt index e98e8c2..551137b 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceTimeDropdown.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceTimeDropdown.kt @@ -25,7 +25,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate @@ -33,7 +32,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import kotlinx.coroutines.launch import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.models.timelotHasAvailable import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt index c6e3e18..fc5987b 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt @@ -12,11 +12,13 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.presentation.views.general.Info @@ -45,7 +47,7 @@ fun TimeslotSelection( .padding(16.dp), verticalArrangement = Arrangement.Center ) { - Info(title = "No available timeslots", image = null) + Info(title = stringResource(R.string.no_timeslots), image = null) } } else { Column( diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt index f794786..e7a45ae 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt @@ -3,7 +3,6 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Bookin import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height @@ -12,22 +11,19 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.AccessTime import androidx.compose.material.icons.filled.CalendarMonth -import androidx.compose.material.icons.filled.CheckCircleOutline import androidx.compose.material.icons.filled.Info -import androidx.compose.material.icons.filled.LocationOn import androidx.compose.material.icons.filled.Timelapse import androidx.compose.material.icons.filled.Title import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString import tumble.app.tumble.extensions.presentation.formatDate -import tumble.app.tumble.presentation.components.buttons.CloseCoverButton import tumble.app.tumble.presentation.components.sheets.SheetHeader import tumble.app.tumble.presentation.views.bookmarks.EventDetails.DetailsBuilder @@ -42,7 +38,7 @@ fun EventDetailsSheet( .fillMaxSize() .background(MaterialTheme.colors.background) ) { - SheetHeader(title = "Event details", onClose = onClose) + SheetHeader(title = stringResource(R.string.event_details), onClose = onClose) Box { Column( modifier = Modifier @@ -50,26 +46,24 @@ fun EventDetailsSheet( .background(MaterialTheme.colors.background) ) { - //sheetContent() - - DetailsBuilder(title = "Title", image = Icons.Default.Title) { + DetailsBuilder(title = stringResource(R.string.title), image = Icons.Default.Title) { Text( - text = event.title.toString(), + text = event.title, fontSize = 16.sp, color = MaterialTheme.colors.onSurface ) } - DetailsBuilder(title = "Type", image = Icons.Default.Info) { + DetailsBuilder(title = stringResource(R.string.type), image = Icons.Default.Info) { Text( - text = event.type.toString(), + text = event.type, fontSize = 16.sp, color = MaterialTheme.colors.onSurface ) } - DetailsBuilder(title = "Date", image = Icons.Default.CalendarMonth) { + DetailsBuilder(title = stringResource(R.string.date), image = Icons.Default.CalendarMonth) { val eventDate = event.eventStart.formatDate() val eventStart = event.eventStart.convertToHoursAndMinutesISOString() val eventEnd = event.eventEnd.convertToHoursAndMinutesISOString() @@ -81,7 +75,7 @@ fun EventDetailsSheet( ) } - DetailsBuilder(title = "Available until", image = Icons.Default.Timelapse) { + DetailsBuilder(title = stringResource(R.string.available_until), image = Icons.Default.Timelapse) { Text( text = event.lastSignupDate.formatDate().orEmpty() , diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt index bf16790..aeb84db 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt @@ -22,9 +22,11 @@ import androidx.compose.material.icons.filled.LocationOn import androidx.compose.material.icons.filled.Timelapse import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString import tumble.app.tumble.extensions.presentation.formatDate @@ -44,7 +46,7 @@ fun ResourceDetailsSheet( .background(MaterialTheme.colors.background) ) { - SheetHeader(title = "Resource details", onClose = onClose) + SheetHeader(title = stringResource(R.string.resource_details), onClose = onClose) Box { Column( modifier = Modifier @@ -52,22 +54,22 @@ fun ResourceDetailsSheet( .background(MaterialTheme.colors.background) ) { - DetailsBuilder(title = "Location", image = Icons.Default.LocationOn) { - if (booking.locationId?.isNotEmpty() == true) { + DetailsBuilder(title = stringResource(R.string.location), image = Icons.Default.LocationOn) { + if (booking.locationId.isNotEmpty()) { Text( - text = booking.locationId.toString(), + text = booking.locationId, fontSize = 16.sp, color = MaterialTheme.colors.onSurface ) } else { Text( - text = "No location listed at this time", + text = stringResource(R.string.no_location), fontSize = 16.sp, color = MaterialTheme.colors.onSurface ) } } - DetailsBuilder(title = "Timeslot", image = Icons.Default.Timelapse) { + DetailsBuilder(title = stringResource(R.string.timeslot), image = Icons.Default.Timelapse) { Text( text = "${ booking.timeSlot.from?.convertToHoursAndMinutesISOString().orEmpty() @@ -77,7 +79,7 @@ fun ResourceDetailsSheet( ) } - DetailsBuilder(title = "Date", image = Icons.Default.CalendarMonth) { + DetailsBuilder(title = stringResource(R.string.date), image = Icons.Default.CalendarMonth) { Text( text = booking.timeSlot.from?.formatDate().orEmpty(), fontSize = 16.sp, @@ -85,7 +87,7 @@ fun ResourceDetailsSheet( ) } - DetailsBuilder(title = "Confirmation", image = Icons.Default.CheckCircleOutline) { + DetailsBuilder(title = stringResource(R.string.confirmation), image = Icons.Default.CheckCircleOutline) { val bookingDate = booking.timeSlot.from?.formatDate() val bookingConfirmationStart = booking.confirmationOpen.convertToHoursAndMinutesISOString() @@ -99,8 +101,7 @@ fun ResourceDetailsSheet( } } Spacer(modifier = Modifier.weight(1f)) - - if (booking.showUnbookButton == true) { + if (booking.showUnbookButton) { Button( onClick = { onBookingRemove() }, shape = RoundedCornerShape(15.dp), @@ -110,7 +111,7 @@ fun ResourceDetailsSheet( ) { Text( - text = "Remove booking", + text = stringResource(R.string.remove_booking), fontSize = 20.sp, fontWeight = FontWeight.SemiBold, color = MaterialTheme.colors.onPrimary diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredBooking.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredBooking.kt index f9bc0bf..9c9f1ef 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredBooking.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredBooking.kt @@ -15,10 +15,12 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import kotlinx.coroutines.ExperimentalCoroutinesApi +import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.enums.PageState import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString @@ -48,12 +50,13 @@ fun RegisteredBooking( bookings.forEach{ resource -> val eventStart = resource.timeSlot.from?.convertToHoursAndMinutesISOString() val eventEnd = resource.timeSlot.to?.convertToHoursAndMinutesISOString() + val noDate = stringResource(R.string.no_date) ResourceCard( - eventStart = eventStart?:"(no date)", - eventEnd = eventEnd?:"(no date)", - title = "Booked resource", + eventStart = eventStart?: noDate, + eventEnd = eventEnd?: noDate, + title = stringResource(R.string.user_booked_resource), location = resource.locationId, - date = resource.timeSlot.from?.formatDate()?:"(no date)", + date = resource.timeSlot.from?.formatDate()?: noDate, onClick = { onClickResource(resource) } ) if (resource.showConfirmButton){ @@ -67,7 +70,7 @@ fun RegisteredBooking( shape = RoundedCornerShape(15.dp), ) { Text( - text = "Confirm", + text = stringResource(R.string.confirm), fontSize = 16.sp, fontWeight = FontWeight.SemiBold, color = MaterialTheme.colors.onPrimary @@ -78,7 +81,7 @@ fun RegisteredBooking( colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.primary), shape = RoundedCornerShape(15.dp),) { Text( - text = "unBook", + text = stringResource(R.string.cancel_booking), fontSize = 16.sp, fontWeight = FontWeight.SemiBold, color = MaterialTheme.colors.onPrimary @@ -88,14 +91,14 @@ fun RegisteredBooking( } } }else{ - Text(text = "no booking resource yet", + Text(text = stringResource(R.string.no_booked_resource), modifier = Modifier.padding(16.dp) ) } } PageState.ERROR -> { Text( - text = "Could not contat the server, try again later", + text = stringResource(R.string.could_not_contact_server), modifier = Modifier.padding(16.dp) ) } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredEvent.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredEvent.kt index 3b13fc8..17c8034 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredEvent.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/RegisteredEvent.kt @@ -10,8 +10,10 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import kotlinx.coroutines.ExperimentalCoroutinesApi +import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.enums.PageState import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString @@ -45,20 +47,20 @@ fun RegisteredEvent( eventEnd = eventEnd, type = event.type, title = event.title, - date = event.eventStart.formatDate()?:"(no date)", + date = event.eventStart.formatDate()?: stringResource(R.string.no_date), onClick = { onClickEvent(event) } ) } } }else{ Text( - text = "No registed event yet", + text = stringResource(R.string.no_registered_event_yet), modifier = Modifier.padding(16.dp) ) } } PageState.ERROR -> { - Text(text = "Could not contact the server, try again later", + Text(text = stringResource(R.string.could_not_contact_server), modifier = Modifier.padding(16.dp)) } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceCard.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceCard.kt index 987c84e..54d6779 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceCard.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/ResourceCard.kt @@ -22,9 +22,11 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import tumble.app.tumble.R @Composable fun ResourceCard( @@ -63,7 +65,7 @@ fun ResourceCard( @Composable fun TitleView(title: String?){ Text( - text = title?: "No titile", + text = title?: stringResource(R.string.no_title), fontSize = 17.sp, color = MaterialTheme.colors.onSurface, maxLines = 1, diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt index 9f18df2..f5cbb21 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt @@ -25,10 +25,12 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import kotlinx.coroutines.launch +import tumble.app.tumble.R import tumble.app.tumble.presentation.navigation.Routes import tumble.app.tumble.presentation.viewmodels.AccountViewModel @@ -60,10 +62,10 @@ fun Resources( .background(color = MaterialTheme.colors.background) ) { //TODO pull to refresh - ResourceSectionDivider(title = "User options"){ + ResourceSectionDivider(title = stringResource(R.string.user_options)){ Row(verticalAlignment = Alignment.CenterVertically) { Text( - text = "Automatic exam signup" + text = stringResource(R.string.auto_signup) ) Spacer(modifier = Modifier.weight(1f)) Switch( @@ -84,14 +86,14 @@ fun Resources( if(showingConfirmationDialog){ AlertDialog( onDismissRequest = { showingConfirmationDialog = false }, - title = { Text(text = "Confirm Action")}, - text = { Text(text = "are you sure you want to enable this experimental feature?")}, + title = { Text(text = stringResource(R.string.confirm_Action))}, + text = { Text(text = stringResource(R.string.experimental_feature_confirmation))}, confirmButton = { TextButton(onClick = { parentViewModel.toggleAutoSignup(true) showingConfirmationDialog = false }) { - Text(text = "Yes") + Text(text = stringResource(R.string.yes)) } }, dismissButton = { @@ -99,14 +101,14 @@ fun Resources( parentViewModel.toggleAutoSignup(false) showingConfirmationDialog = false }) { - Text(text = "Cancel") + Text(text = stringResource(R.string.cancel)) } } ) } } ResourceSectionDivider( - title = "Your bookings", // string resource + title = stringResource(R.string.user_booking), resourceType = ResourceType.RESOURCE, destination = { navController.navigate(Routes.accountResources) } ) { @@ -119,7 +121,7 @@ fun Resources( ) } ResourceSectionDivider( - title = "Your event", // string resource + title = stringResource(R.string.user_events), resourceType = ResourceType.EVENT, destination = { navController.navigate(Routes.accountEvents) } ) { diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml index d6f7ea2..8577b97 100644 --- a/app/src/main/res/values-en-rUS/strings.xml +++ b/app/src/main/res/values-en-rUS/strings.xml @@ -63,4 +63,34 @@ Settings Save Remove + Booked resource + (no date) + no booked resource yet + Could not contact the server, try again later + Confirm + cancel booking + No registered event yet + No title + User options + Automatic exam signup + Confirm Action + are you sure you want to enable this experimental feature? + Yes + Cancel + Your Events + Your Bookings + No rooms available on weekends + No name + Available timeslots + No available timesots + Event details + Title + Type + Date + Location + No location listed at this time + Timeslot + Confirmation + Remove booking + Resource details \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 76116d7..55e0673 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -63,4 +63,34 @@ Settings Save Remove + Booked resource + (no date) + no booked resource yet + Could not contact the server, try again later + Confirm + cancel booking + No registered event yet + No title + User options + Automatic exam signup + Confirm Action + are you sure you want to enable this experimental feature? + Yes + Cancel + Your Events + Your Bookings + No rooms available on weekends + No name + Available timeslots + No available timesots + Event details + Title + Type + Date + Location + No location listed at this time + Timeslot + Confirmation + Remove booking + Resource details \ No newline at end of file From 5b6f0bcbd7e54e5272783a8bf1865ecf02c791b2 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sun, 27 Oct 2024 17:38:06 +0100 Subject: [PATCH 32/38] renamed function --- .../presentation/views/bookmarks/Week/BookmarkWeekView.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Week/BookmarkWeekView.kt b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Week/BookmarkWeekView.kt index d8cc9b4..e6deb5e 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Week/BookmarkWeekView.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Week/BookmarkWeekView.kt @@ -81,7 +81,7 @@ fun BookmarkWeekView( modifier = Modifier .fillMaxSize() .pointerInput(Unit) { - test(pointerInputScope = this, pagerState = pagerState, updateUserScroll = updateUserScroll) + handleLeftSwipeOnFirstPage(pointerInputScope = this, pagerState = pagerState, updateUserScroll = updateUserScroll) } ) { page -> var showContend by remember { @@ -133,7 +133,7 @@ fun BookmarkWeekView( } @OptIn(ExperimentalFoundationApi::class) -suspend fun test(pointerInputScope: PointerInputScope, pagerState: PagerState, updateUserScroll: (Boolean) -> Unit){ +suspend fun handleLeftSwipeOnFirstPage(pointerInputScope: PointerInputScope, pagerState: PagerState, updateUserScroll: (Boolean) -> Unit){ pointerInputScope.let { it.awaitEachGesture { awaitFirstDown(pass = PointerEventPass.Initial) From c9de00056ad3d90c2d38691306cd6b7d207e33a5 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sun, 27 Oct 2024 17:44:04 +0100 Subject: [PATCH 33/38] past days not electable anymore --- .../Booking/Resources/ResourceDatePicker.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceDatePicker.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceDatePicker.kt index 5bc23f0..72b6826 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceDatePicker.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceDatePicker.kt @@ -1,6 +1,8 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Resources +import android.icu.util.Calendar import android.os.Build +import android.util.Log import androidx.annotation.RequiresApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column @@ -31,6 +33,10 @@ fun ResourceDatePicker( val showDatePickerDialog = remember { mutableStateOf(false) } + val starOfDay = remember { + mutableStateOf(Calendar.getInstance().apply { set(Calendar.MILLISECONDS_IN_DAY, 0)}) + } + Column( modifier = Modifier .fillMaxWidth() @@ -50,6 +56,7 @@ fun ResourceDatePicker( yearContentColor = Color.Yellow, subheadContentColor = Color.Yellow ), + dateValidator = { Calendar.getInstance().apply { timeInMillis = it }.after(starOfDay.value) }, title = null, headline = null, ) From a48519522ec42a75e02eb1b8c9a9991103986b36 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sun, 27 Oct 2024 17:46:10 +0100 Subject: [PATCH 34/38] button state now updates --- .../Booking/Resources/ResourceSelection.kt | 8 ++++---- .../ResourceSection/Booking/Resources/TimelotSelection.kt | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt index 07bfdb3..0e0c16c 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt @@ -13,6 +13,7 @@ import androidx.compose.material.Divider import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier @@ -22,7 +23,6 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import tumble.app.tumble.R -import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.models.getAvailabilityValues import tumble.app.tumble.extensions.models.getFirstTimeSlotWithAvailability import tumble.app.tumble.observables.AppController @@ -37,9 +37,9 @@ fun ResourceSelection( navController: NavController ) { val resource = AppController.shared.resourceModel!!.resource - val selectedTimeIndex = remember { mutableStateOf(resource.availabilities.getFirstTimeSlotWithAvailability(resource.timeSlots!!.size)) } + val selectedTimeIndex = remember { mutableIntStateOf(resource.availabilities.getFirstTimeSlotWithAvailability(resource.timeSlots!!.size)) } val availabilityValues = remember { - mutableStateOf>(resource.availabilities.getAvailabilityValues(timelotId = selectedTimeIndex.value)) + mutableStateOf(resource.availabilities.getAvailabilityValues(timelotId = selectedTimeIndex.intValue)) } val selectedPickerDate = AppController.shared.resourceModel!!.date val timeslots = resource.timeSlots @@ -65,7 +65,7 @@ fun ResourceSelection( timeslots = timeslots, selectedIndex = selectedTimeIndex, onIndexChange = { index -> - selectedTimeIndex.value = index + selectedTimeIndex.intValue = index availabilityValues.value = resource.availabilities.getAvailabilityValues(timelotId = index) } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt index fc5987b..f1be3f3 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimelotSelection.kt @@ -1,5 +1,6 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Resources +import android.util.Log import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize @@ -9,6 +10,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier @@ -33,7 +35,7 @@ fun TimeslotSelection( bookResource: suspend (NetworkResponse.AvailabilityValue) -> Boolean, availabilityValues: MutableState> ) { - val buttonStateMap = remember { mutableMapOf() } + val buttonStateMap = remember { mutableStateMapOf() } val scope = rememberCoroutineScope() LaunchedEffect(availabilityValues.value) { From fcc47b4d97de74d8f1ac8f8eafec12a565c2ebe0 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sun, 27 Oct 2024 17:52:56 +0100 Subject: [PATCH 35/38] updated how resources are fetched --- .../app/tumble/data/api/ApiServiceKronox.kt | 2 +- .../tumble/app/tumble/data/api/Endpoint.kt | 16 +--- .../data/api/kronox/KronoxApiService.kt | 6 +- .../data/api/kronox/KronoxRepository.kt | 15 ++-- .../viewmodels/ResourceViewModel.kt | 73 ++++++------------- 5 files changed, 33 insertions(+), 79 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt b/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt index 3e3d279..e9ffe55 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/ApiServiceKronox.kt @@ -49,7 +49,7 @@ interface ApiServiceKronox { @Url endpoint: String, @Header("X-auth-token") refreshToken: String?, @Body resource: NetworkRequest.BookKronoxResource - ): Call + ): Call @PUT() fun confirmResource( diff --git a/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt b/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt index 98689d9..40213f7 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/Endpoint.kt @@ -1,6 +1,7 @@ package tumble.app.tumble.data.api import android.net.Uri +import androidx.compose.ui.platform.InspectableModifier import tumble.app.tumble.core.NetworkSettings import tumble.app.tumble.utils.toIsoString import java.util.Date @@ -10,7 +11,6 @@ sealed class Endpoint { data class Schedule(val scheduleId: String, val schoolId: String) : Endpoint() data class UserEvents(val schoolId: String) : Endpoint() data class ResourceAvailabilities(val schoolId: String, val resourceId: String, val date: String) : Endpoint() - data class AllResources(val schoolId: String) : Endpoint() data class UserBookings(val schoolId: String) : Endpoint() data class Login(val schoolId: String) : Endpoint() data class Users(val schoolId: String) : Endpoint() @@ -21,8 +21,7 @@ sealed class Endpoint { data class ConfirmResource(val schoolId: String) : Endpoint() data class UnBookResource(val schoolId: String, val bookingId: String) : Endpoint() object News : Endpoint() - //data class AllResourcesTest(val schoolId: String) : Endpoint() - data class AllResourceData(val schoolId: String, val resourceId: String, val date: String) : Endpoint() + data class AllResources(val schoolId: String, val date: String): Endpoint() } fun Endpoint.url(): String { @@ -51,19 +50,10 @@ fun Endpoint.url(): String { .appendQueryParameter("date", date) } is Endpoint.AllResources -> { - components.path("/api/resources") - .appendQueryParameter("schoolId", schoolId) - } - is Endpoint.AllResourceData -> { - components.path("/api/resources/$resourceId") + components.path("/api/resources/all") .appendQueryParameter("schoolId", schoolId) .appendQueryParameter("date", date) - } -// is Endpoint.AllResourcesTest -> { -// components.path("/api/resources") -// .appendQueryParameter("schoolId", schoolId) -// } is Endpoint.UserBookings -> { components.path("/api/resources/userbookings") .appendQueryParameter("schoolId", schoolId) diff --git a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt index 8be3f8c..dee1245 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxApiService.kt @@ -29,13 +29,9 @@ interface KronoxApiService { suspend fun getAllResources(endpoint: Endpoint.AllResources, refreshToken: String?, sessionDetails: String?): ApiResponse> -// suspend fun getAllResourcesTypes(endpoint: Endpoint.AllResourcesTest, refreshToken: String?, sessionDetails: String?): ApiResponse> - - suspend fun getAllResourceData(endpoint: Endpoint.AllResourceData, refreshToken: String?, sessionDetails: String?): ApiResponse - suspend fun registerForEvent(endpoint: Endpoint.RegisterEvent, refreshToken: String?): ApiResponse - suspend fun bookResource(endpoint: Endpoint.BookResource, refreshToken: String?, resource: NetworkRequest.BookKronoxResource): ApiResponse + suspend fun bookResource(endpoint: Endpoint.BookResource, refreshToken: String?, resource: NetworkRequest.BookKronoxResource): ApiResponse suspend fun confirmResource(endpoint: Endpoint.ConfirmResource, refreshToken: String?, resource: NetworkRequest.ConfirmKronoxResource): ApiResponse diff --git a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt index 1d1a5b5..fe9452d 100644 --- a/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt +++ b/app/src/main/java/tumble/app/tumble/data/api/kronox/KronoxRepository.kt @@ -1,10 +1,7 @@ package tumble.app.tumble.datasource.network.kronox -import android.util.Log import okhttp3.Request import okhttp3.RequestBody -import retrofit2.Call -import retrofit2.Response import retrofit2.Retrofit import tumble.app.tumble.data.api.Endpoint import tumble.app.tumble.data.api.url @@ -45,19 +42,19 @@ class KronoxRepository @Inject constructor(private val retrofit: Retrofit): Kron return call.callToApiResponse() } - override suspend fun getAllResources(endpoint: Endpoint.AllResources, refreshToken: String?, sessionDetails: String?): ApiResponse>{ + override suspend fun getAllResources( + endpoint: Endpoint.AllResources, + refreshToken: String?, + sessionDetails: String? + ): ApiResponse> { return kronoxApiService.getAllResources(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() } - override suspend fun getAllResourceData(endpoint: Endpoint.AllResourceData, refreshToken: String?, sessionDetails: String?): ApiResponse{ - return kronoxApiService.getAllResourceData(endpoint.url(), refreshToken, sessionDetails).callToApiResponse() - } - override suspend fun registerForEvent(endpoint: Endpoint.RegisterEvent, refreshToken: String?): ApiResponse { return kronoxApiService.registerForEvent(endpoint.url(), refreshToken).callToApiResponse() } - override suspend fun bookResource(endpoint: Endpoint.BookResource, refreshToken: String?, resource: NetworkRequest.BookKronoxResource): ApiResponse { + override suspend fun bookResource(endpoint: Endpoint.BookResource, refreshToken: String?, resource: NetworkRequest.BookKronoxResource): ApiResponse { return kronoxApiService.bookResource(endpoint.url(), refreshToken, resource).callToApiResponse() } diff --git a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt index 44a473f..069d041 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt @@ -54,22 +54,20 @@ class ResourceViewModel @Inject constructor( private val _allResources = MutableStateFlow?>(null) val allResources: StateFlow?> = _allResources - private val _allResourcesTypes = MutableStateFlow?>(null) - val allResourcesTypes: StateFlow?> = _allResourcesTypes +// private val _allResourcesTypes = MutableStateFlow?>(null) +// val allResourcesTypes: StateFlow?> = _allResourcesTypes //val allResources: List? = null // private val _resourceSelectionModel = MutableStateFlow(null) // var resourceSelectionModel by mutableStateOf(null) - // private val _resourceSelectioned = MutableStateFlow(null) // var resourceSelectioned = mutableStateOf(null) - fun setBookingDate(newDate: Date){ _selectedPickerDate.value = newDate - viewModelScope.launch { getAllResourcesData(isoDateFormatterDate.format(newDate)) } + viewModelScope.launch { getAllResources(isoDateFormatterDate.format(newDate)) } } // fun setResourceSelection(resource: NetworkResponse.KronoxResourceElement){ @@ -145,82 +143,55 @@ class ResourceViewModel @Inject constructor( } } - fun getAllResources(){ + fun getAllResources(date: String = isoDateFormatterDate.format(Date())){ viewModelScope.launch { try { - val endpoint = Endpoint.AllResources(dataStoreManager.authSchoolId.value.toString()) + val endpoint = Endpoint.AllResources(dataStoreManager.authSchoolId.value.toString(), date) val refreshToken = authManager.getRefreshToken() ?: return@launch val response: ApiResponse> = kronoxManager.getAllResources(endpoint, refreshToken, null) when(response){ is ApiResponse.Success -> { - _allResourcesTypes.value = response.data - getAllResourcesData(date = isoDateFormatterDate.format(Date())) + Log.e("getAllResourcesTest", "Success") + _allResources.value = response.data + _resourceBookingPageState.value = PageState.LOADED } is ApiResponse.Error -> { + Log.e("getAllResourcesTest", "Error") + Log.e("getAllResourcesTest", response.errorMessage) _resourceBookingPageState.value = PageState.ERROR } else -> {} } }catch (e:Exception){ + Log.e("getAllResources", "Error") _resourceBookingPageState.value = PageState.ERROR } } } - fun getAllResourcesData(date: String){ - viewModelScope.launch { - _resourceBookingPageState.value = PageState.LOADING - - val resources: MutableList = mutableListOf() - - _allResourcesTypes.value?.forEach { - it.id?.let { id -> - try { - val endpoint = Endpoint.AllResourceData( - dataStoreManager.authSchoolId.value.toString(), - resourceId = id, - date = date - ) - val refreshToken = authManager.getRefreshToken() ?: return@launch - val response: ApiResponse = - kronoxManager.getAllResourceData(endpoint, refreshToken, null) - - when (response) { - is ApiResponse.Success -> { - resources.add(response.data) - } - - is ApiResponse.Error -> { - _resourceBookingPageState.value = PageState.ERROR - return@launch - } - - else -> {} - } - } catch (e: Exception) { - _resourceBookingPageState.value = PageState.ERROR - return@launch - } - } - } - _allResources.value = resources.toList() - _resourceBookingPageState.value = PageState.LOADED - } - } - suspend fun bookResource(resourceId: String, date: Date, availabilityValue: NetworkResponse.AvailabilityValue): Boolean{ val endpoint = Endpoint.BookResource(dataStoreManager.authSchoolId.value.toString()) val resource = NetworkRequest.BookKronoxResource(resourceId, isoDateFormatterDate.format(date), availabilityValue) val refreshToken = authManager.getRefreshToken() ?: return false - val response: ApiResponse = kronoxManager.bookResource(endpoint, refreshToken, resource) + val response: ApiResponse = kronoxManager.bookResource(endpoint, refreshToken, resource) when(response){ + is ApiResponse.Success ->{ + Log.e("BookedResource", "Success") + return true + } is ApiResponse.Error -> { + if(response.errorMessage == "Empty response body") { + Log.e("BookedResource", "Success") + }else{ + Log.e("BookedResource", "Error") + } return response.errorMessage == "Empty response body" } else -> { + Log.e("BookedResource", "Error") return false } } From 0b3ccf21f141d3502171d9a020bcd45546349359 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sun, 27 Oct 2024 17:55:51 +0100 Subject: [PATCH 36/38] updated reasource details top bar --- .../models/NetworkResponseAvailabilitiesExtension.kt | 5 +++-- .../app/tumble/extensions/models/RealmScheduleExtensions.kt | 2 -- .../User/ResourceSection/Booking/Resources/TimeslotCard.kt | 6 ++---- .../app/tumble/presentation/views/navigation/TopBar.kt | 6 +++++- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt b/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt index 2e9d334..e127e43 100644 --- a/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt +++ b/app/src/main/java/tumble/app/tumble/extensions/models/NetworkResponseAvailabilitiesExtension.kt @@ -1,5 +1,6 @@ package tumble.app.tumble.extensions.models +import android.util.Log import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.domain.models.network.availabilities @@ -31,10 +32,10 @@ fun availabilities.getAvailabilityValues(timelotId: Int): List() - for ((location, availabilityValues) in availabilities){ + for (availabilityValues in availabilities.values){ val availabilityValue = availabilityValues[timelotId] if(availabilityValue?.availability == NetworkResponse.AvailabilityEnum.AVAILABLE){ - availabilityValueResult.add(availabilityValue.copy(locationId = location, timeSlotId = timelotId.toString())) + availabilityValueResult.add(availabilityValue) } } return availabilityValueResult diff --git a/app/src/main/java/tumble/app/tumble/extensions/models/RealmScheduleExtensions.kt b/app/src/main/java/tumble/app/tumble/extensions/models/RealmScheduleExtensions.kt index d3040b2..b9bff8d 100644 --- a/app/src/main/java/tumble/app/tumble/extensions/models/RealmScheduleExtensions.kt +++ b/app/src/main/java/tumble/app/tumble/extensions/models/RealmScheduleExtensions.kt @@ -1,7 +1,6 @@ package tumble.app.tumble.extensions.models import android.os.Build -import android.util.Log import androidx.annotation.RequiresApi import io.realm.kotlin.ext.copyFromRealm import io.realm.kotlin.ext.toRealmList @@ -10,7 +9,6 @@ import tumble.app.tumble.domain.models.realm.Event import tumble.app.tumble.domain.models.realm.Schedule import tumble.app.tumble.extensions.presentation.toLocalDateTime import tumble.app.tumble.utils.preprocessDateString -import java.time.Instant import java.time.LocalDate import java.time.LocalDateTime import java.time.OffsetDateTime diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt index d814540..d5f5c3c 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/TimeslotCard.kt @@ -13,7 +13,6 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -48,9 +47,8 @@ fun TimeslotCard( onBook() } }, - colors = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent), - modifier = Modifier - .background(color = MaterialTheme.colors.primary, shape = RoundedCornerShape(20.dp)), + colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.primary, disabledBackgroundColor = MaterialTheme.colors.primary), + shape = RoundedCornerShape(20.dp), elevation = null, enabled = bookingButtonState != BookingButtonState.BOOKED, ) { diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/navigation/TopBar.kt b/app/src/main/java/tumble/app/tumble/presentation/views/navigation/TopBar.kt index 7aa4bbf..56aea7b 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/navigation/TopBar.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/navigation/TopBar.kt @@ -37,6 +37,10 @@ fun TopBarBackButton(currentNavController: NavHostController) { { currentNavController.popBackStack() }, stringResource(R.string.accountSettings) ) + Routes.accountResourceDetails -> BackButton( + { currentNavController.popBackStack()}, + stringResource(R.string.resources) + ) else -> {} } @@ -59,7 +63,7 @@ fun TopBarTitle(currentNavController: NavHostController) { Routes.searchDetails -> Text(stringResource(R.string.search)) Routes.accountEvents -> Text(stringResource(R.string.events)) Routes.accountResources -> Text(stringResource(R.string.resources)) - + Routes.accountResourceDetails -> Text(stringResource(R.string.rooms)) else -> Text(stringResource(R.string.app_name)) } } From 351eafc962f24287fe21fc599e17d6b4e07fae02 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Tue, 29 Oct 2024 13:10:13 +0100 Subject: [PATCH 37/38] updates to be in line with new topbar handeling --- .../tumble/app/tumble/core/NetworkSettings.kt | 2 +- .../navigation/navgraphs/BookmarksNavGraph.kt | 2 +- .../viewmodels/ResourceViewModel.kt | 22 +--- .../tumble/presentation/views/AppParent.kt | 1 + .../Booking/Resources/ResourceSelection.kt | 22 +++- .../Booking/Sheets/EventDetails.kt | 102 +++++++-------- .../Booking/Sheets/ResourceDetails.kt | 121 +++++++++--------- .../account/User/ResourceSection/Resources.kt | 3 - .../presentation/views/bookmarks/Bookmarks.kt | 6 +- .../EventDetails/EventDetailsSheet.kt | 59 +++++---- .../views/bookmarks/List/ToTopButton.kt | 2 +- 11 files changed, 179 insertions(+), 163 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/core/NetworkSettings.kt b/app/src/main/java/tumble/app/tumble/core/NetworkSettings.kt index 27336c1..9229727 100644 --- a/app/src/main/java/tumble/app/tumble/core/NetworkSettings.kt +++ b/app/src/main/java/tumble/app/tumble/core/NetworkSettings.kt @@ -15,7 +15,7 @@ class NetworkSettings private constructor(val port: Int, val scheme: String, val ) val development = NetworkSettings( - port = 7036, scheme = "http", tumbleUrl = "10.0.2.2" + port = 7036, scheme = "https", tumbleUrl = "10.0.2.2" ) } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/BookmarksNavGraph.kt b/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/BookmarksNavGraph.kt index 5b9e6ba..73666d2 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/BookmarksNavGraph.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/navigation/navgraphs/BookmarksNavGraph.kt @@ -54,6 +54,6 @@ private fun NavGraphBuilder.bookmarksDetails(navController: NavHostController, s } ) { backStackEntry -> val id = backStackEntry.arguments?.getString("id") - EventDetailsSheet(event = AppController.shared.eventSheet!!.event) + EventDetailsSheet(event = AppController.shared.eventSheet!!.event, setTopNavState) } } \ No newline at end of file diff --git a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt index 069d041..6b4e6b5 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/ResourceViewModel.kt @@ -54,26 +54,11 @@ class ResourceViewModel @Inject constructor( private val _allResources = MutableStateFlow?>(null) val allResources: StateFlow?> = _allResources -// private val _allResourcesTypes = MutableStateFlow?>(null) -// val allResourcesTypes: StateFlow?> = _allResourcesTypes - - //val allResources: List? = null - -// private val _resourceSelectionModel = MutableStateFlow(null) -// var resourceSelectionModel by mutableStateOf(null) - -// private val _resourceSelectioned = MutableStateFlow(null) -// var resourceSelectioned = mutableStateOf(null) - fun setBookingDate(newDate: Date){ _selectedPickerDate.value = newDate - viewModelScope.launch { getAllResources(isoDateFormatterDate.format(newDate)) } + viewModelScope.launch { getAllResources(newDate) } } -// fun setResourceSelection(resource: NetworkResponse.KronoxResourceElement){ -// resourceSelectioned.value = resource -// } - fun getUserEventsForPage(){ viewModelScope.launch { _eventBookingPageState.value = PageState.LOADING @@ -143,10 +128,11 @@ class ResourceViewModel @Inject constructor( } } - fun getAllResources(date: String = isoDateFormatterDate.format(Date())){ + fun getAllResources(date: Date = Date()){ + val dateString = isoDateFormatterDate.format(date) viewModelScope.launch { try { - val endpoint = Endpoint.AllResources(dataStoreManager.authSchoolId.value.toString(), date) + val endpoint = Endpoint.AllResources(dataStoreManager.authSchoolId.value.toString(), dateString) val refreshToken = authManager.getRefreshToken() ?: return@launch val response: ApiResponse> = kronoxManager.getAllResources(endpoint, refreshToken, null) diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/AppParent.kt b/app/src/main/java/tumble/app/tumble/presentation/views/AppParent.kt index 84590a3..c36b4cc 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/AppParent.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/AppParent.kt @@ -11,6 +11,7 @@ import androidx.compose.material.Scaffold import androidx.compose.material.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt index 0e0c16c..4f8b214 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Resources/ResourceSelection.kt @@ -13,6 +13,7 @@ import androidx.compose.material.Divider import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -26,16 +27,23 @@ import tumble.app.tumble.R import tumble.app.tumble.extensions.models.getAvailabilityValues import tumble.app.tumble.extensions.models.getFirstTimeSlotWithAvailability import tumble.app.tumble.observables.AppController +import tumble.app.tumble.presentation.components.buttons.BackButton import tumble.app.tumble.presentation.viewmodels.ResourceViewModel import tumble.app.tumble.presentation.views.general.Info +import tumble.app.tumble.presentation.views.navigation.AppBarState import tumble.app.tumble.utils.isoVerboseDateFormatter @RequiresApi(Build.VERSION_CODES.O) @Composable fun ResourceSelection( parentViewModel: ResourceViewModel = hiltViewModel(), - navController: NavController + navController: NavController, + setTopNavState: (AppBarState) -> Unit + ) { + val pageTitle = stringResource(R.string.rooms) + val backTitle = stringResource(R.string.resources) + val resource = AppController.shared.resourceModel!!.resource val selectedTimeIndex = remember { mutableIntStateOf(resource.availabilities.getFirstTimeSlotWithAvailability(resource.timeSlots!!.size)) } val availabilityValues = remember { @@ -43,6 +51,18 @@ fun ResourceSelection( } val selectedPickerDate = AppController.shared.resourceModel!!.date val timeslots = resource.timeSlots + LaunchedEffect(key1 = true) { + setTopNavState( + AppBarState( + title = pageTitle, + navigationAction = { + BackButton(backTitle) { + navController.popBackStack() + } + } + ) + ) + } Column( modifier = Modifier .fillMaxSize() diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt index e7a45ae..6006c19 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/EventDetails.kt @@ -1,11 +1,8 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Sheets import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.MaterialTheme @@ -16,75 +13,80 @@ import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Timelapse import androidx.compose.material.icons.filled.Title import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString import tumble.app.tumble.extensions.presentation.formatDate -import tumble.app.tumble.presentation.components.sheets.SheetHeader +import tumble.app.tumble.presentation.components.buttons.CloseCoverButton import tumble.app.tumble.presentation.views.bookmarks.EventDetails.DetailsBuilder +import tumble.app.tumble.presentation.views.navigation.AppBarState @Composable fun EventDetailsSheet( event: NetworkResponse.AvailableKronoxUserEvent, - onClose: () -> Unit - //sheetContent: @Composable () -> Unit + onClose: () -> Unit, + setTopNavState: (AppBarState) -> Unit ) { + val title = stringResource(R.string.event_details) + LaunchedEffect(key1 = true) { + setTopNavState( + AppBarState( + title = title, + actions = { + CloseCoverButton { + onClose() + } + } + ) + ) + } + Column( modifier = Modifier .fillMaxSize() + .verticalScroll(rememberScrollState()) .background(MaterialTheme.colors.background) ) { - SheetHeader(title = stringResource(R.string.event_details), onClose = onClose) - Box { - Column( - modifier = Modifier - .verticalScroll(rememberScrollState()) - .background(MaterialTheme.colors.background) - ) { + DetailsBuilder(title = stringResource(R.string.title), image = Icons.Default.Title) { - DetailsBuilder(title = stringResource(R.string.title), image = Icons.Default.Title) { + Text( + text = event.title, + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) - Text( - text = event.title, - fontSize = 16.sp, - color = MaterialTheme.colors.onSurface - ) - - } - DetailsBuilder(title = stringResource(R.string.type), image = Icons.Default.Info) { - Text( - text = event.type, - fontSize = 16.sp, - color = MaterialTheme.colors.onSurface - ) - } + } + DetailsBuilder(title = stringResource(R.string.type), image = Icons.Default.Info) { + Text( + text = event.type, + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } - DetailsBuilder(title = stringResource(R.string.date), image = Icons.Default.CalendarMonth) { - val eventDate = event.eventStart.formatDate() - val eventStart = event.eventStart.convertToHoursAndMinutesISOString() - val eventEnd = event.eventEnd.convertToHoursAndMinutesISOString() - Text( - text = "$eventDate, from $eventStart to $eventEnd" - , - fontSize = 16.sp, - color = MaterialTheme.colors.onSurface - ) - } + DetailsBuilder(title = stringResource(R.string.date), image = Icons.Default.CalendarMonth) { + val eventDate = event.eventStart.formatDate() + val eventStart = event.eventStart.convertToHoursAndMinutesISOString() + val eventEnd = event.eventEnd.convertToHoursAndMinutesISOString() + Text( + text = "$eventDate, from $eventStart to $eventEnd" + , + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } - DetailsBuilder(title = stringResource(R.string.available_until), image = Icons.Default.Timelapse) { - Text( - text = event.lastSignupDate.formatDate().orEmpty() - , - fontSize = 16.sp, - color = MaterialTheme.colors.onSurface - ) - } - Spacer(modifier = Modifier.height(60.dp)) - } + DetailsBuilder(title = stringResource(R.string.available_until), image = Icons.Default.Timelapse) { + Text( + text = event.lastSignupDate.formatDate().orEmpty() + , + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) } } } \ No newline at end of file diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt index aeb84db..5ab20eb 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Booking/Sheets/ResourceDetails.kt @@ -1,12 +1,10 @@ package tumble.app.tumble.presentation.views.account.User.ResourceSection.Booking.Sheets import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape @@ -21,6 +19,7 @@ import androidx.compose.material.icons.filled.CheckCircleOutline import androidx.compose.material.icons.filled.LocationOn import androidx.compose.material.icons.filled.Timelapse import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -30,75 +29,81 @@ import tumble.app.tumble.R import tumble.app.tumble.domain.models.network.NetworkResponse import tumble.app.tumble.extensions.presentation.convertToHoursAndMinutesISOString import tumble.app.tumble.extensions.presentation.formatDate -import tumble.app.tumble.presentation.components.sheets.SheetHeader +import tumble.app.tumble.presentation.components.buttons.CloseCoverButton import tumble.app.tumble.presentation.views.bookmarks.EventDetails.DetailsBuilder +import tumble.app.tumble.presentation.views.navigation.AppBarState @Composable fun ResourceDetailsSheet( booking: NetworkResponse.KronoxUserBookingElement, onClose: () -> Unit, - onBookingRemove: () -> Unit + onBookingRemove: () -> Unit, + setTopNavState: (AppBarState) -> Unit + ) { + val title = stringResource(R.string.resource_details) + + LaunchedEffect(key1 = true) { + setTopNavState( + AppBarState( + title = title, + actions = { + CloseCoverButton { + onClose() + } + } + ) + ) + } Column( modifier = Modifier .fillMaxSize() + .verticalScroll(rememberScrollState()) .background(MaterialTheme.colors.background) ) { + DetailsBuilder(title = stringResource(R.string.location), image = Icons.Default.LocationOn) { + if (booking.locationId.isNotEmpty()) { + Text( + text = booking.locationId, + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } else { + Text( + text = stringResource(R.string.no_location), + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } + } + DetailsBuilder(title = stringResource(R.string.timeslot), image = Icons.Default.Timelapse) { + Text( + text = "${ + booking.timeSlot.from?.convertToHoursAndMinutesISOString().orEmpty() + } - ${booking.timeSlot.to?.convertToHoursAndMinutesISOString().orEmpty()}", + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } - SheetHeader(title = stringResource(R.string.resource_details), onClose = onClose) - Box { - Column( - modifier = Modifier - .verticalScroll(rememberScrollState()) - .background(MaterialTheme.colors.background) - ) { - - DetailsBuilder(title = stringResource(R.string.location), image = Icons.Default.LocationOn) { - if (booking.locationId.isNotEmpty()) { - Text( - text = booking.locationId, - fontSize = 16.sp, - color = MaterialTheme.colors.onSurface - ) - } else { - Text( - text = stringResource(R.string.no_location), - fontSize = 16.sp, - color = MaterialTheme.colors.onSurface - ) - } - } - DetailsBuilder(title = stringResource(R.string.timeslot), image = Icons.Default.Timelapse) { - Text( - text = "${ - booking.timeSlot.from?.convertToHoursAndMinutesISOString().orEmpty() - } - ${booking.timeSlot.to?.convertToHoursAndMinutesISOString().orEmpty()}", - fontSize = 16.sp, - color = MaterialTheme.colors.onSurface - ) - } - - DetailsBuilder(title = stringResource(R.string.date), image = Icons.Default.CalendarMonth) { - Text( - text = booking.timeSlot.from?.formatDate().orEmpty(), - fontSize = 16.sp, - color = MaterialTheme.colors.onSurface - ) - } - - DetailsBuilder(title = stringResource(R.string.confirmation), image = Icons.Default.CheckCircleOutline) { - val bookingDate = booking.timeSlot.from?.formatDate() - val bookingConfirmationStart = - booking.confirmationOpen.convertToHoursAndMinutesISOString() - val bookingConfirmationEnd = - booking.confirmationClosed.convertToHoursAndMinutesISOString() - Text( - text = "$bookingDate, from $bookingConfirmationStart to $bookingConfirmationEnd" - ) - } + DetailsBuilder(title = stringResource(R.string.date), image = Icons.Default.CalendarMonth) { + Text( + text = booking.timeSlot.from?.formatDate().orEmpty(), + fontSize = 16.sp, + color = MaterialTheme.colors.onSurface + ) + } - } + DetailsBuilder(title = stringResource(R.string.confirmation), image = Icons.Default.CheckCircleOutline) { + val bookingDate = booking.timeSlot.from?.formatDate() + val bookingConfirmationStart = + booking.confirmationOpen.convertToHoursAndMinutesISOString() + val bookingConfirmationEnd = + booking.confirmationClosed.convertToHoursAndMinutesISOString() + Text( + text = "$bookingDate, from $bookingConfirmationStart to $bookingConfirmationEnd" + ) } Spacer(modifier = Modifier.weight(1f)) if (booking.showUnbookButton) { @@ -109,7 +114,6 @@ fun ResourceDetailsSheet( modifier = Modifier.fillMaxWidth().padding(horizontal = 15.dp), elevation = null ) { - Text( text = stringResource(R.string.remove_booking), fontSize = 20.sp, @@ -118,6 +122,5 @@ fun ResourceDetailsSheet( ) } } - Spacer(modifier = Modifier.height(60.dp)) - } } +} diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt index f5cbb21..32f71c0 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/account/User/ResourceSection/Resources.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.AlertDialog @@ -26,7 +25,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import kotlinx.coroutines.launch @@ -131,7 +129,6 @@ fun Resources( registeredEvents = userEvents.value?.registeredEvents?: emptyList() ) } - Spacer(modifier = Modifier.height(60.dp)) } LaunchedEffect(key1 = scrollState.value) { scrollOffset = scrollState.value.toFloat() diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Bookmarks.kt b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Bookmarks.kt index bd69b02..190fb70 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Bookmarks.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/Bookmarks.kt @@ -1,7 +1,5 @@ package tumble.app.tumble.presentation.views.bookmarks -import android.os.Build -import androidx.annotation.RequiresApi import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -46,7 +44,7 @@ fun Bookmarks( val bookmarksStatus = viewModel.status val viewType = viewModel.defaultViewType.collectAsState() - LaunchedEffect(key1 = true) { + LaunchedEffect(key1 = AppController.shared.eventSheet) { setTopNavState( AppBarState( title = pageTitle @@ -72,6 +70,6 @@ fun Bookmarks( Spacer(Modifier.weight(1f)) } AppController.shared.eventSheet?.let { - EventDetailsSheet(event = it.event) + EventDetailsSheet(event = it.event, setTopNavState) } } \ No newline at end of file diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsSheet.kt b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsSheet.kt index ed3f038..bf17d00 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsSheet.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/EventDetails/EventDetailsSheet.kt @@ -11,49 +11,58 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import tumble.app.tumble.R import tumble.app.tumble.domain.models.realm.Event import tumble.app.tumble.extensions.presentation.toColor import tumble.app.tumble.observables.AppController import tumble.app.tumble.presentation.components.buttons.CloseCoverButton +import tumble.app.tumble.presentation.components.sheets.SheetHeader +import tumble.app.tumble.presentation.views.navigation.AppBarState @Composable fun EventDetailsSheet( event: Event, + setTopNavState: (AppBarState) -> Unit + ) { + + val title = stringResource(R.string.event_details) + LaunchedEffect(key1 = true) { + setTopNavState( + AppBarState( + title = title, + actions = { + CloseCoverButton { + onClose() + } + } + ) + ) + } + Column( modifier = Modifier .fillMaxSize() .background(MaterialTheme.colors.background) ) { - - SheetHeader(title = "Details", onClose = {onClose()}) - - //Spacer(modifier = Modifier.height(20.dp)) - Box { - Column( - modifier = Modifier - .verticalScroll(rememberScrollState()) - .background(MaterialTheme.colors.background) - ) { - EventDetailsCard( - openColorPicker = { openColorPicker() }, - event = event, - color = event.course?.color?.toColor() ?: Color.Gray - ) - EventDetailsBody(event) - Spacer(modifier = Modifier.height(60.dp)) - } - Row { - Spacer(modifier = Modifier.weight(1f)) - CloseCoverButton { - onClose() - } - } - //ColorPicker() + Column( + modifier = Modifier + .verticalScroll(rememberScrollState()) + .background(MaterialTheme.colors.background) + ) { + EventDetailsCard( + openColorPicker = { openColorPicker() }, + event = event, + color = event.course?.color?.toColor() ?: Color.Gray + ) + EventDetailsBody(event) } + //ColorPicker() } } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/List/ToTopButton.kt b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/List/ToTopButton.kt index a9be83e..b21136f 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/List/ToTopButton.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/bookmarks/List/ToTopButton.kt @@ -17,7 +17,7 @@ fun ToTopButton( onClick: () -> Unit){ FloatingActionButton( onClick = onClick, containerColor = MaterialTheme.colors.primary, - modifier = Modifier.padding(bottom = 40.dp), + //modifier = Modifier.padding(bottom = 40.dp), shape = CircleShape ){ Icon( From 81b1fe743ea89c054bbd9b673567f2d0f4526bd5 Mon Sep 17 00:00:00 2001 From: SvenLindstrom Date: Sat, 9 Nov 2024 09:52:51 +0100 Subject: [PATCH 38/38] fixed bug no longer crashes when toggling bookmarks --- .../app/tumble/data/repository/realm/RealmManager.kt | 7 +++++++ .../tumble/presentation/viewmodels/SettingsViewModel.kt | 9 +++++++-- .../views/Settings/Bookmarks/BookmarksSettings.kt | 8 +++++--- .../views/Settings/Bookmarks/BookmarksSettingsRow.kt | 9 +++------ 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/tumble/app/tumble/data/repository/realm/RealmManager.kt b/app/src/main/java/tumble/app/tumble/data/repository/realm/RealmManager.kt index 3372b40..3afec44 100644 --- a/app/src/main/java/tumble/app/tumble/data/repository/realm/RealmManager.kt +++ b/app/src/main/java/tumble/app/tumble/data/repository/realm/RealmManager.kt @@ -73,6 +73,13 @@ class RealmManager { } } + suspend fun updateScheduleVisibility(scheduleId: String, visibility: Boolean){ + realm.write { + val schedule: Schedule? = this.query("scheduleId == $0", scheduleId).first().find() + schedule?.toggled = visibility + } + } + fun getCourseColors(): MutableMap { val courses: RealmResults = realm.query().find() val courseColors = mutableMapOf() diff --git a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/SettingsViewModel.kt b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/SettingsViewModel.kt index 88a2af5..ccf2243 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/viewmodels/SettingsViewModel.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/viewmodels/SettingsViewModel.kt @@ -3,19 +3,18 @@ package tumble.app.tumble.presentation.viewmodels import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import io.realm.kotlin.ext.copyFromRealm import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch -import tumble.app.tumble.data.api.Endpoint import tumble.app.tumble.data.notifications.NotificationManager import tumble.app.tumble.data.repository.preferences.CombinedData import tumble.app.tumble.data.repository.preferences.DataStoreManager import tumble.app.tumble.data.repository.realm.RealmManager import tumble.app.tumble.datasource.SchoolManager import tumble.app.tumble.domain.enums.Types.AppearanceType -import tumble.app.tumble.domain.enums.ViewType import tumble.app.tumble.domain.models.realm.Event import tumble.app.tumble.domain.models.realm.Schedule import tumble.app.tumble.presentation.views.Settings.Notifications.NotificationOffset @@ -110,6 +109,12 @@ class SettingsViewModel @Inject constructor( //TODO } + fun updateBookmarkVisibility(visibility: Boolean, schedule: Schedule){ + viewModelScope.launch { + realmManager.updateScheduleVisibility(schedule.scheduleId, visibility) + } + } + fun deleteAllSchedules(){ //TODO } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettings.kt b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettings.kt index c7e6c05..0e711d0 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettings.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettings.kt @@ -40,12 +40,14 @@ fun BookmarksSettings( if (schedules.value.isNotEmpty()) { SettingsList { - schedules.value.forEachIndexed { index, schedule -> + schedules.value.forEach{ schedule -> BookmarkSettingsRow( schedule = schedule, - index = index, - onDelete = { offsets, id -> + onDelete = { offsets -> parentViewModel.deleteBookmark(schedule) + }, + onToggle = {visibility -> + parentViewModel.updateBookmarkVisibility(visibility, schedule) } ) } diff --git a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettingsRow.kt b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettingsRow.kt index 671d1ab..a24588a 100644 --- a/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettingsRow.kt +++ b/app/src/main/java/tumble/app/tumble/presentation/views/Settings/Bookmarks/BookmarksSettingsRow.kt @@ -36,8 +36,8 @@ import tumble.app.tumble.domain.models.realm.Schedule @Composable fun BookmarkSettingsRow( schedule: Schedule, - index: Int, - onDelete: (Int, String) -> Unit + onDelete: (String) -> Unit, + onToggle: (Boolean) -> Unit, ) { val scope = rememberCoroutineScope() @@ -60,15 +60,12 @@ fun BookmarkSettingsRow( checked = isToggled, onCheckedChange = { checked -> isToggled = checked - schedule.toggled = checked + onToggle(checked) // Trigger the widget update when the toggle changes }, colors = SwitchDefaults.colors(checkedThumbColor = MaterialTheme.colors.primary), modifier = Modifier.scale(2f) ) - - - } }