From 823552e71098d8e60a86e6f4ef801e8729170c42 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 16:53:40 +0200 Subject: [PATCH 001/325] Add TopBar and MainContainer to CategorySummaryView --- .../compose/category/CategoryComponent.kt | 3 + .../compose/category/CategorySummaryView.kt | 132 ++++++++++++++---- 2 files changed, 106 insertions(+), 29 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 40eb0dc4..5823c8b9 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -41,6 +41,9 @@ fun CategoryComponent(screenState: MutableState) { onBackButton = { screenState.value = Screen.Dashboard}, onEditButton = { screenState.value = Screen.CategoryEdit}, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) Screen.CategoryEdit -> CategoryEditView( state = viewState, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index a9cefeff..8c1116cb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -1,11 +1,15 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.css.margin +import org.jetbrains.compose.web.css.marginBottom +import org.jetbrains.compose.web.css.marginLeft +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.dom.* @Composable @@ -13,36 +17,106 @@ fun CategorySummaryView( state: State, onBackButton: () -> Unit, onEditButton: () -> Unit, - onCategoryCreateButton: () -> Unit + onCategoryCreateButton: () -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToCategory: () -> Unit, + onChangeToSettings: () -> Unit ) { val viewState by remember { state } - H1{Text("CategorySummaryView")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } + }) + + MainFlexContainer { + Div(attrs = { + classes("mdc-card", AppStylesheet.card) } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Dashboard") - } - Button(attrs = { - onClick { onEditButton() } - }) { - Text("Edit Category (Needs to be set for each category)") - } - Button(attrs = { - onClick { onCategoryCreateButton() } - }) { - Text("Create Category") + ) { + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Category Summary") } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onCategoryCreateButton() } + style { margin(2.percent) } + }) { + Text("Create Category") + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Text("Kat 1") + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onEditButton() } + }) { + Text("Edit Category (Needs to be set for each category)") + } + } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Text("Kat 2") + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onEditButton() } + }) { + Text("Edit Category (Needs to be set for each category)") + } + } + } } } } From c583a5523a3cdbc58ae6a1f47f6c75bf0b92d570 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 19:53:43 +0200 Subject: [PATCH 002/325] Add Form in CategoryCreateView and Buttonlogic in CategoryComponent --- .../compose/category/CategoryComponent.kt | 7 +- .../compose/category/CategoryCreateView.kt | 250 ++++++++++++++++-- 2 files changed, 237 insertions(+), 20 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 40eb0dc4..66c397a1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.common.User import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel @@ -34,7 +35,11 @@ fun CategoryComponent(screenState: MutableState) { when (screenState.value) { Screen.CategoryCreate -> CategoryCreateView( state = viewState, - onBackButton = { screenState.value = Screen.CategorySummary} + onCreateCategoryButtonPressed = { name, color, image, budget -> + categoryViewModel.createCategory(Category.In(name, color.drop(1), image, budget)) }, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) Screen.CategorySummary -> CategorySummaryView( state = viewState, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index a889b22d..efb46c63 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -1,36 +1,248 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.CategoryImagesToImageList +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.css.marginBottom +import org.jetbrains.compose.web.css.marginLeft +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.dom.* @Composable fun CategoryCreateView( state: State, - onBackButton: () -> Unit + onCreateCategoryButtonPressed: (name: String, color: String, image: Category.Image, budget: Float) -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToSettings: () -> Unit, + onChangeToCategory: () -> Unit, ) { + var categoryNameTextFieldState by remember { mutableStateOf("") } + var categoryColorTextFieldState by remember { mutableStateOf("") } + var categoryImageState by remember { mutableStateOf(Category.Image.DEFAULT) } + var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("CategoryCreateView")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } + }) + + MainFlexContainer { + Div(attrs = { + classes("mdc-card", AppStylesheet.card) } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to To Category Overview") + ) { + H1 { Text("Create a new Category") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onCreateCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() + } + } + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Category Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + onInput { + categoryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(50.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Color") } + Input( + type = InputType.Color + ) { + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent)} + } + ) { Text("Image") } + CategoryImagesToImageList(onClick = {categoryImageState = it}) + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number + ) { + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + onInput { + categoryBudgetTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } + } } } } From c026fe7e452cc9576253b458fc25796d545e91ba Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 19:54:11 +0200 Subject: [PATCH 003/325] Add ImageList as Composable --- .../hsfl/budgetBinder/compose/Composables.kt | 52 +++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index aabe2f32..1703d973 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -1,33 +1,35 @@ package de.hsfl.budgetBinder.compose -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState +import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Image /*Main Container for every mayor layout*/ @Composable -fun MainFlexContainer(content: @Composable () -> Unit){ - Div ( +fun MainFlexContainer(content: @Composable () -> Unit) { + Div( attrs = { classes("mdc-top-app-bar--fixed-adjust", AppStylesheet.flexContainer) } - ){ - Div (attrs = { classes(AppStylesheet.pufferFlexContainer) }) - Div (attrs = { classes(AppStylesheet.contentFlexContainer)}) + ) { + Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) + Div(attrs = { classes(AppStylesheet.contentFlexContainer) }) { content() } - Div (attrs = { classes(AppStylesheet.pufferFlexContainer)}) + Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) } } @Composable -fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit){ +fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit) { Header( attrs = { classes("mdc-top-app-bar") @@ -62,3 +64,35 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } } } + +@Composable +fun CategoryImagesToImageList(onClick : (Category.Image) -> Unit) { + Div( + attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Ul( + attrs = { + classes("mdc-image-list", "my-image-list") + } + ) { + for (image in Category.Image.values()) { + Li( + attrs = { + classes("mdc-image-list__item") + } + ) { + Div( + attrs = { + classes("mdc-image-list__image-aspect-container", "mdc-icon-button") + onClick { onClick } + } + ) { + CategoryImageToIcon(image) + } + } + } + } + } +} From e309270a2961501f9f6ade328da5bd87a02cfa8e Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:14:52 +0200 Subject: [PATCH 004/325] Add function to get all entries that belong to a category_id --- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 35b27268..2fce9cd4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -58,4 +58,7 @@ fun EntryList(list: List, categoryList : List){ for (entry in list){ EntryListElement(entry,categoryList) } -} \ No newline at end of file +} + +fun entriesFromCategory(list: List, category_id: Int?):List = + list.filter { it.category_id == category_id } \ No newline at end of file From 259bc676e01f16b40a89816604980bad859784f0 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:22:26 +0200 Subject: [PATCH 005/325] Rework Dashboard Logic, add logic to switch to different categories --- .../compose/dashboard/DashboardView.kt | 136 ++++++++++++++++-- 1 file changed, 121 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 9d91d87e..2fc01241 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -3,14 +3,15 @@ package de.hsfl.budgetBinder.compose.dashboard import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry -import de.hsfl.budgetBinder.compose.category.Bar +import de.hsfl.budgetBinder.compose.Icon +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.category.BudgetBar import de.hsfl.budgetBinder.compose.entry.EntryList +import de.hsfl.budgetBinder.compose.entry.entriesFromCategory +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text -import kotlin.math.log +import kotlinx.serialization.json.JsonNull.content +import org.jetbrains.compose.web.dom.* @Composable @@ -25,10 +26,9 @@ fun DashboardView( val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } var categoryList by remember { mutableStateOf>(emptyList()) } - var entryList by remember { mutableStateOf>(emptyList()) } - Div { + MainFlexContainer { H1 { Text("DashboardView") } Button(attrs = { onClick { onSettingsButton() } @@ -50,9 +50,10 @@ fun DashboardView( }) { Text("Edit Entry (Needs to be there for every Entry shown)") } - } - Div { - UpdateDashboardData(categoryList, entryList) + Div { + DashboardData(categoryList, entryList) + } + CreateNewEntryButton(onEntryCreateButton) } //Process new Category Data when (categoriesViewState) { @@ -100,13 +101,118 @@ fun DashboardView( //CircularProgressIndicator() } } + + } @Composable -fun UpdateDashboardData(categoryList: List, entryList: List) { +fun DashboardData(categoryList: List, entryList: List) { console.log("Category $categoryList and Entry $entryList") - if (categoryList.isNotEmpty() && entryList.isNotEmpty()) { - Bar(categoryList[0], entryList) //Bar for first Category, needs to be changed later - EntryList(entryList, categoryList) + var focusedCategory by remember { mutableStateOf(-1) } //Variable from -1 (all) to categoryList.size + console.log("Focus:${focusedCategory}") + fun changeFocusedCategory(increase: Boolean): Int { + var newFocus = focusedCategory + if (increase) newFocus++ + else newFocus-- + newFocus = + when { + (newFocus) < -1 -> -1 + (newFocus > categoryList.size) -> categoryList.size + else -> { + newFocus + } + } + return newFocus + } + + if (entryList.isNotEmpty()) { + when (focusedCategory) { + //Overall View + -1 -> { + var everyBudgetTogether = 0f + for (category in categoryList) { + everyBudgetTogether += category.budget + } + val fakeOverallBudget = + Category(0, "Overall", "111111", Category.Image.DEFAULT, everyBudgetTogether) + SwipeContainer ( + content = {BudgetBar(fakeOverallBudget, entryList)}, //Every CategoryBudget with every Entry's Budget + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + ) + + EntryList(entryList, categoryList) //List of Every Entry + } + //Normal Category View + in categoryList.indices -> { + val filteredEntryList = + entriesFromCategory(entryList, categoryList[focusedCategory].id) + SwipeContainer ( + content = {BudgetBar(categoryList[focusedCategory], filteredEntryList)}, //Every Category with their Entries' Budget + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + ) + EntryList( + filteredEntryList, + listOf(categoryList[focusedCategory]) + ) //Only gives CategoryData of selected category, as everything else seems unnecessary + } + + //No Category View + categoryList.size -> { + val filteredEntryList = entriesFromCategory(entryList, null) + val fakeNoCategory = + Category(0, "No Category", "111111", Category.Image.DEFAULT, 0f) + SwipeContainer ( + content = {BudgetBar(fakeNoCategory, filteredEntryList)}, //"No Category" with their Entries' Budget + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + ) + EntryList( + filteredEntryList, + emptyList() + ) //Needs no categoryList, as they have no category + } + } + } else { + //TODO: Show something like: NO DATA TO SHOW! + } + +} + + +@Composable +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { + Button(attrs = { + onClick { onEntryCreateButton() } + }) { + Text("Create Entry") + } +} + +@Composable +fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Boolean) -> Unit) { + Div( + attrs = { + classes(AppStylesheet.flexContainer) + }) { + Div(attrs = { + classes(AppStylesheet.arrowFlexContainer) + onClick{onFocusCategoryChange(false)} + }){ + Icon("arrow_back_ios_new") + } + Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) + { + content() + } + Div(attrs = { + classes(AppStylesheet.arrowFlexContainer) + onClick{onFocusCategoryChange(true)} + }) { + Icon("arrow_forward_ios_new") + } } } + + + + + From d10e11667e456f65eb667477b1d51ae2ee05de4d Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:23:00 +0200 Subject: [PATCH 006/325] Add general Icon function to get an function with the namestring --- .../de/hsfl/budgetBinder/compose/Composables.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index aabe2f32..bed3b465 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -62,3 +62,15 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } } } + +@Composable +fun Icon (icon_name: String){ + Span( + attrs = { + classes("material-icons") + style { + width(24.px) + height(24.px) } + } + ) {Text(icon_name)} +} From 04907b9b9aa460b87fe244ba0b070003ffbe6feb Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:23:39 +0200 Subject: [PATCH 007/325] Make slight style adjustments --- .../compose/category/CategoryComponent.kt | 11 +++++++---- .../hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 11 ++++++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 40eb0dc4..935f8e0c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -63,15 +63,18 @@ fun categoryIdToCategory(category_id: Int?,categoryList: List): Catego @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun Bar(category: Category, entryList: List){ +fun BudgetBar(category: Category, entryList: List){ + //category = Category we want to show + //entryList = List of entries //width and height are for aspect ratio - tries to fill out wherever its in, so its more like - val width = 200 - val height = 80 + val width = 20 + val height = 2 val budget = category.budget var usedBudget = 0f for (entry in entryList) { - usedBudget+= entry.amount + usedBudget-= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget } + H1{Text("${category.name} - Budget")} Div{ if (usedBudget < budget) { //Money Text diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index b498f7f6..4b3a372f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -1,6 +1,7 @@ package de.hsfl.budgetBinder.compose.theme import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.css.keywords.auto import org.jetbrains.compose.web.css.selectors.CSSSelector /*All Information found about Stylesheets: @@ -36,6 +37,7 @@ object AppStylesheet : StyleSheet() { //Container for flex elements, used in MainFlexContainer val flexContainer by style { display(DisplayStyle.Flex) + justifyContent(JustifyContent.Center) } //Container for empty sides, used in MainFlexContainer val pufferFlexContainer by style { @@ -48,9 +50,16 @@ object AppStylesheet : StyleSheet() { } //Container for main content, used in MainFlexContainer val contentFlexContainer by style { - justifyContent(JustifyContent.Center) flex("50%") } + //Container for main content in BudgetBar + val budgetBarContainer by style { + flex("90%") + } + //Container for arrow in BudgetBar + val arrowFlexContainer by style { + flex("0.1 0.1 5%") + } //EntryList val entryListElement by style{ From 789f2d893fd48a0d56a781efa9d0db8dedd721d7 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:30:38 +0200 Subject: [PATCH 008/325] Format dashboard category switch buttons --- .../de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 4 ++-- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 2fc01241..1b75ffd2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -194,7 +194,7 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool classes(AppStylesheet.flexContainer) }) { Div(attrs = { - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.arrowFlexContainer, "mdc-button") onClick{onFocusCategoryChange(false)} }){ Icon("arrow_back_ios_new") @@ -204,7 +204,7 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool content() } Div(attrs = { - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.arrowFlexContainer, "mdc-button") onClick{onFocusCategoryChange(true)} }) { Icon("arrow_forward_ios_new") diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 4b3a372f..003ba0ff 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -59,6 +59,7 @@ object AppStylesheet : StyleSheet() { //Container for arrow in BudgetBar val arrowFlexContainer by style { flex("0.1 0.1 5%") + height(auto) } //EntryList From 0c50bbccb4507490a380a213a468a08366f6e4fe Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 20:52:09 +0200 Subject: [PATCH 009/325] Add highlight when image is chosen and button functionality in composable --- .../de/hsfl/budgetBinder/compose/Composables.kt | 17 ++++++++++------- .../compose/category/CategoryComponent.kt | 1 - .../compose/category/CategoryCreateView.kt | 5 +++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 1703d973..282a58c9 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -2,13 +2,9 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import de.hsfl.budgetBinder.presentation.Screen -import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* -import org.jetbrains.compose.web.svg.Image /*Main Container for every mayor layout*/ @@ -66,7 +62,8 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } @Composable -fun CategoryImagesToImageList(onClick : (Category.Image) -> Unit) { +fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { + var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } Div( attrs = { classes("mdc-card", AppStylesheet.card) @@ -85,8 +82,14 @@ fun CategoryImagesToImageList(onClick : (Category.Image) -> Unit) { ) { Div( attrs = { - classes("mdc-image-list__image-aspect-container", "mdc-icon-button") - onClick { onClick } + if (highlightImage == image) + classes( + "mdc-image-list__image-aspect-container", + "mdc-icon-button", + "mdc-button--raised" + ) + else classes("mdc-image-list__image-aspect-container", "mdc-icon-button") + onClick { onClick(image); highlightImage = image } } ) { CategoryImageToIcon(image) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 66c397a1..a4ab5a07 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -4,7 +4,6 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY import de.hsfl.budgetBinder.common.Entry -import de.hsfl.budgetBinder.common.User import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index efb46c63..91566936 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -8,6 +8,8 @@ import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.min +import org.jetbrains.compose.web.attributes.required import org.jetbrains.compose.web.css.marginBottom import org.jetbrains.compose.web.css.marginLeft import org.jetbrains.compose.web.css.percent @@ -113,6 +115,7 @@ fun CategoryCreateView( ) { classes("mdc-text-field__input") value(categoryNameTextFieldState) + required(true) onInput { categoryNameTextFieldState = it.value } @@ -207,6 +210,8 @@ fun CategoryCreateView( ) { classes("mdc-text-field__input") value(categoryBudgetTextFieldState) + required(true) + min("1") onInput { categoryBudgetTextFieldState = it.value.toString() } From 256ba55ec5e347bf508270ba51006f472fa088ec Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 20:57:34 +0200 Subject: [PATCH 010/325] Change width of color input from 50% to 100% --- .../de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index 91566936..a63d68e4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -135,7 +135,7 @@ fun CategoryCreateView( Label( attrs = { classes("mdc-text-field", "mdc-text-field--outlined") - style { width(50.percent) } + style { width(100.percent) } } ) { Span( From d8520aa48e79c2c6cedeae6e6d7d1ec41f74d335 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 21:37:10 +0200 Subject: [PATCH 011/325] Add all cases to BudgetBar --- .../compose/category/CategoryComponent.kt | 93 ++++++++++++------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 935f8e0c..9f1fc087 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -10,6 +10,7 @@ import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob +import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* @@ -28,34 +29,44 @@ fun CategoryComponent(screenState: MutableState) { val changeCategoryByIdUseCase: ChangeCategoryByIdUseCase by di.instance() val deleteCategoryByIdUseCase: DeleteCategoryByIdUseCase by di.instance() val getAllEntriesByCategoryUseCase: GetAllEntriesByCategoryUseCase by di.instance() - val categoryViewModel = CategoryViewModel(getAllCategoriesUseCase, getCategoryByIdUseCase,createCategoryUseCase, changeCategoryByIdUseCase, deleteCategoryByIdUseCase, getAllEntriesByCategoryUseCase, scope) + val categoryViewModel = CategoryViewModel( + getAllCategoriesUseCase, + getCategoryByIdUseCase, + createCategoryUseCase, + changeCategoryByIdUseCase, + deleteCategoryByIdUseCase, + getAllEntriesByCategoryUseCase, + scope + ) val viewState = categoryViewModel.state.collectAsState(scope) when (screenState.value) { Screen.CategoryCreate -> CategoryCreateView( state = viewState, - onBackButton = { screenState.value = Screen.CategorySummary} + onBackButton = { screenState.value = Screen.CategorySummary } ) Screen.CategorySummary -> CategorySummaryView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard}, - onEditButton = { screenState.value = Screen.CategoryEdit}, - onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, + onBackButton = { screenState.value = Screen.Dashboard }, + onEditButton = { screenState.value = Screen.CategoryEdit }, + onCategoryCreateButton = { screenState.value = Screen.CategoryCreate }, ) Screen.CategoryEdit -> CategoryEditView( state = viewState, - onBackButton = { screenState.value = Screen.CategorySummary} + onBackButton = { screenState.value = Screen.CategorySummary } ) Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( state = viewState, - onFinishedButton = { screenState.value = Screen.Dashboard} //Should go back to the previous Screen, which could be CategorySummary or EntryCreate. + onFinishedButton = { + screenState.value = Screen.Dashboard + } //Should go back to the previous Screen, which could be CategorySummary or EntryCreate. ) else -> {} } } -fun categoryIdToCategory(category_id: Int?,categoryList: List): Category { - for (category in categoryList){ +fun categoryIdToCategory(category_id: Int?, categoryList: List): Category { + for (category in categoryList) { if (category.id == category_id) return category } return DEFAULT_CATEGORY //If the category wasn't found (or is set to no category) return default @@ -63,7 +74,7 @@ fun categoryIdToCategory(category_id: Int?,categoryList: List): Catego @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun BudgetBar(category: Category, entryList: List){ +fun BudgetBar(category: Category, entryList: List) { //category = Category we want to show //entryList = List of entries //width and height are for aspect ratio - tries to fill out wherever its in, so its more like @@ -72,44 +83,56 @@ fun BudgetBar(category: Category, entryList: List){ val budget = category.budget var usedBudget = 0f for (entry in entryList) { - usedBudget-= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget + usedBudget -= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget } - H1{Text("${category.name} - Budget")} - Div{ - if (usedBudget < budget) { + H1 { Text("${category.name} - Budget") } + Div { + if (usedBudget <= budget && budget > 0) { //Normal not Spent Budget //Money Text - Div(attrs={style { - display(DisplayStyle.Flex) - justifyContent(JustifyContent("space-between")) - }}){ - Div{Text(usedBudget.toString()+"€")} - Div{Text(budget.toString()+"€")} + MoneyTextDiv { + Div { Text(usedBudget.toString() + "€") } + Div { Text(budget.toString() + "€") } } - //Bar - Svg(viewBox = "0 0 $width $height"){//For aspect ratio - tries to fill out wherever its in + Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { attr("fill", Color.lightgray.toString()) }) - Rect(x = 0, y = 0, width = usedBudget/budget*width, height = height, { - attr("fill", Color.darkred.toString()) + if (0 < usedBudget) // If there is used budget, draw it + Rect(x = 0, y = 0, width = usedBudget / budget * width, height = height, { + attr("fill", "#" + category.color) + }) + } + } else if (usedBudget > budget && budget > 0) { //Over Budget + MoneyTextDiv { + Div { Text("Budget limit for " + category.name + " reached! " + usedBudget.toString() + "€ of " + budget.toString() + "€ Budget spent") } + } + Svg(viewBox = "0 0 $width $height") { + Rect(x = 0, y = 0, width = width, height = height, { + attr("fill", "#b00020") }) } - } - else{ - //SpentBudget Text - Div(attrs={style { - display(DisplayStyle.Flex) - justifyContent(JustifyContent("center")) - }}){ - Div{Text("Budget limit for "+category.name+" reached! "+usedBudget.toString()+"€ of "+budget.toString()+"€ Budget spent")} + } else if (budget <= 0f) { //No Category View or other unpredictable case + MoneyTextDiv { + Div { Text(usedBudget.toString() + "€ without category spent") } } - //Bar - Svg(viewBox = "0 0 $width $height"){//For aspect ratio - tries to fill out wherever its in + Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { - attr("fill", Color.red.toString()) + attr("fill", "#" + category.color) }) } } } } +@Composable +fun MoneyTextDiv(content: @Composable () -> Unit) { + Div(attrs = { + style { + display(DisplayStyle.Flex) + justifyContent(JustifyContent("space-between")) + } + }) { + content() + } +} + From 7623e58b0cff9ccf0cdfd9db21c3b17d8b84d9a7 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 22:21:12 +0200 Subject: [PATCH 012/325] Don't show switch button when there is no other category in that direction. Add typography to BudgetBar's texts --- .../compose/category/CategoryComponent.kt | 10 ++--- .../compose/dashboard/DashboardView.kt | 42 +++++++++++++++---- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 9f1fc087..dbda8a92 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -85,13 +85,13 @@ fun BudgetBar(category: Category, entryList: List) { for (entry in entryList) { usedBudget -= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget } - H1 { Text("${category.name} - Budget") } + H1(attrs={classes("mdc-typography--headline4")}) { Text("${category.name} - Budget") } Div { if (usedBudget <= budget && budget > 0) { //Normal not Spent Budget //Money Text MoneyTextDiv { - Div { Text(usedBudget.toString() + "€") } - Div { Text(budget.toString() + "€") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(budget.toString() + "€") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { @@ -104,7 +104,7 @@ fun BudgetBar(category: Category, entryList: List) { } } else if (usedBudget > budget && budget > 0) { //Over Budget MoneyTextDiv { - Div { Text("Budget limit for " + category.name + " reached! " + usedBudget.toString() + "€ of " + budget.toString() + "€ Budget spent") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text("Budget limit for " + category.name + " reached! " + usedBudget.toString() + "€ of " + budget.toString() + "€ Budget spent") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { @@ -113,7 +113,7 @@ fun BudgetBar(category: Category, entryList: List) { } } else if (budget <= 0f) { //No Category View or other unpredictable case MoneyTextDiv { - Div { Text(usedBudget.toString() + "€ without category spent") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€ without category spent") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 1b75ffd2..3ebca113 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -11,6 +11,10 @@ import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState import kotlinx.serialization.json.JsonNull.content +import org.jetbrains.compose.web.css.paddingLeft +import org.jetbrains.compose.web.css.paddingRight +import org.jetbrains.compose.web.css.px +import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* @@ -137,7 +141,8 @@ fun DashboardData(categoryList: List, entryList: List) { Category(0, "Overall", "111111", Category.Image.DEFAULT, everyBudgetTogether) SwipeContainer ( content = {BudgetBar(fakeOverallBudget, entryList)}, //Every CategoryBudget with every Entry's Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)}, + leftOn = false ) EntryList(entryList, categoryList) //List of Every Entry @@ -163,7 +168,8 @@ fun DashboardData(categoryList: List, entryList: List) { Category(0, "No Category", "111111", Category.Image.DEFAULT, 0f) SwipeContainer ( content = {BudgetBar(fakeNoCategory, filteredEntryList)}, //"No Category" with their Entries' Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)}, + rightOn = false ) EntryList( filteredEntryList, @@ -188,26 +194,44 @@ fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { } @Composable -fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Boolean) -> Unit) { +fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Boolean) -> Unit, leftOn: Boolean = true, rightOn:Boolean = true) { Div( attrs = { classes(AppStylesheet.flexContainer) }) { Div(attrs = { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") - onClick{onFocusCategoryChange(false)} + if(leftOn) { + classes(AppStylesheet.arrowFlexContainer, "mdc-button") + onClick { onFocusCategoryChange(false) } + } + else{ + classes(AppStylesheet.arrowFlexContainer) + style{ + paddingLeft(8.px) + paddingRight(8.px) + } + } }){ - Icon("arrow_back_ios_new") + if(leftOn) Icon("arrow_back_ios_new") } Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) { content() } Div(attrs = { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") - onClick{onFocusCategoryChange(true)} + if(rightOn) { + classes(AppStylesheet.arrowFlexContainer, "mdc-button") + onClick { onFocusCategoryChange(true) } + } + else{ + classes(AppStylesheet.arrowFlexContainer) + style{ + paddingLeft(8.px) + paddingRight(8.px) + } + } }) { - Icon("arrow_forward_ios_new") + if(rightOn) Icon("arrow_forward_ios_new") } } } From d9a4b56d2a85a37d06984620c409a1658a0ddb0c Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 16:53:40 +0200 Subject: [PATCH 013/325] Add TopBar and MainContainer to CategorySummaryView --- .../compose/category/CategoryComponent.kt | 3 + .../compose/category/CategorySummaryView.kt | 132 ++++++++++++++---- 2 files changed, 106 insertions(+), 29 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index a4ab5a07..da5a5ae4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -45,6 +45,9 @@ fun CategoryComponent(screenState: MutableState) { onBackButton = { screenState.value = Screen.Dashboard}, onEditButton = { screenState.value = Screen.CategoryEdit}, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) Screen.CategoryEdit -> CategoryEditView( state = viewState, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index a9cefeff..8c1116cb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -1,11 +1,15 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.css.margin +import org.jetbrains.compose.web.css.marginBottom +import org.jetbrains.compose.web.css.marginLeft +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.dom.* @Composable @@ -13,36 +17,106 @@ fun CategorySummaryView( state: State, onBackButton: () -> Unit, onEditButton: () -> Unit, - onCategoryCreateButton: () -> Unit + onCategoryCreateButton: () -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToCategory: () -> Unit, + onChangeToSettings: () -> Unit ) { val viewState by remember { state } - H1{Text("CategorySummaryView")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } + }) + + MainFlexContainer { + Div(attrs = { + classes("mdc-card", AppStylesheet.card) } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Dashboard") - } - Button(attrs = { - onClick { onEditButton() } - }) { - Text("Edit Category (Needs to be set for each category)") - } - Button(attrs = { - onClick { onCategoryCreateButton() } - }) { - Text("Create Category") + ) { + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Category Summary") } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onCategoryCreateButton() } + style { margin(2.percent) } + }) { + Text("Create Category") + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Text("Kat 1") + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onEditButton() } + }) { + Text("Edit Category (Needs to be set for each category)") + } + } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Text("Kat 2") + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onEditButton() } + }) { + Text("Edit Category (Needs to be set for each category)") + } + } + } } } } From 93f2cdc72ebc1562bbbe729ae3a071e6ebcc8b80 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 13:15:37 +0200 Subject: [PATCH 014/325] Add CategoryList as Composable --- .../hsfl/budgetBinder/compose/Composables.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 282a58c9..f453722b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -3,8 +3,15 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob import org.jetbrains.compose.web.dom.* +import org.kodein.di.compose.localDI +import org.kodein.di.instance /*Main Container for every mayor layout*/ @@ -99,3 +106,29 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { } } } + +@Composable +fun CategoryList(categoryList : List){ + Div { + console.log(categoryList.size) + for (category in categoryList) + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Text("${category.name}") + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { } + }) { + Text("Edit Category") + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { } + }) { + Text("Delete Category") + } + } + } +} From 5363894a6465662b0ecb395a6882456ca1545528 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 13:16:31 +0200 Subject: [PATCH 015/325] Add getAllCategories() at init --- .../budgetBinder/presentation/viewmodel/CategoryViewModel.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt index c8240a54..14ccdfe2 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt @@ -21,6 +21,10 @@ class CategoryViewModel( private val _state = MutableStateFlow(UiState.Empty) val state: StateFlow = _state + init { + getAllCategories() + } + fun getAllCategories() { getAllCategoriesUseCase.categories().onEach { when (it) { From 16464c3de4b7e29613972a2f062caf0e0f050203 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 13:16:53 +0200 Subject: [PATCH 016/325] Delete unused Buttons --- .../de/hsfl/budgetBinder/compose/category/CategoryComponent.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index da5a5ae4..04422b2c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -42,8 +42,6 @@ fun CategoryComponent(screenState: MutableState) { ) Screen.CategorySummary -> CategorySummaryView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard}, - onEditButton = { screenState.value = Screen.CategoryEdit}, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, From d1653694c7d54828add417545818252dc2468ed7 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 13:18:06 +0200 Subject: [PATCH 017/325] Delete unused Buttons and add CategoryList() from Composables --- .../compose/category/CategorySummaryView.kt | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 8c1116cb..07758e1a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -1,13 +1,13 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.css.margin -import org.jetbrains.compose.web.css.marginBottom -import org.jetbrains.compose.web.css.marginLeft import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* @@ -15,13 +15,12 @@ import org.jetbrains.compose.web.dom.* @Composable fun CategorySummaryView( state: State, - onBackButton: () -> Unit, - onEditButton: () -> Unit, onCategoryCreateButton: () -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { + var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } topBarMain( @@ -80,10 +79,20 @@ fun CategorySummaryView( }) { Text("Create Category") } + CategoryList(categoryList) Div { when (viewState) { is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + when (val element = (viewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + categoryList = it + } + } + } + } } is UiState.Error -> { Text((viewState as UiState.Error).error) @@ -92,30 +101,6 @@ fun CategorySummaryView( //CircularProgressIndicator() } } - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - Text("Kat 1") - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onEditButton() } - }) { - Text("Edit Category (Needs to be set for each category)") - } - } - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - Text("Kat 2") - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onEditButton() } - }) { - Text("Edit Category (Needs to be set for each category)") - } - } } } } From 107b93bde0ea494a6e6465eb20981966f21eb72c Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:14:40 +0200 Subject: [PATCH 018/325] Add marginRight --- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index b498f7f6..6bb759f2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -60,7 +60,6 @@ object AppStylesheet : StyleSheet() { val card by style { margin(10.px) marginTop(25.px) - } val image by style { @@ -70,4 +69,8 @@ object AppStylesheet : StyleSheet() { val margin by style { margin(10.px) } + + val marginRight by style { + marginRight(1.percent) + } } \ No newline at end of file From 98016ca7aca14bae6866d6fc3be3f6c961bfff02 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:15:26 +0200 Subject: [PATCH 019/325] Change display of categoryList to not showing --- .../de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index a63d68e4..22d8391a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -237,7 +237,7 @@ fun CategoryCreateView( Div { when (viewState) { is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + //Text((viewState as UiState.Success<*>).element.toString()) } is UiState.Error -> { Text((viewState as UiState.Error).error) From ca25490f250119f4b5e199460ae7600bb878d6b1 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:15:48 +0200 Subject: [PATCH 020/325] Delete unused imports --- .../hsfl/budgetBinder/compose/category/CategorySummaryView.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 07758e1a..93799a7b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -2,11 +2,14 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain +import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState +import org.jetbrains.compose.web.css.flex import org.jetbrains.compose.web.css.margin import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* From 14af7a0645e490237d3eec6c192055514dfddfe2 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:16:51 +0200 Subject: [PATCH 021/325] Add color, image and budget for each displayed category --- .../hsfl/budgetBinder/compose/Composables.kt | 69 +++++++++++++------ 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index f453722b..26bf8c22 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -3,15 +3,14 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.css.flex +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* -import org.kodein.di.compose.localDI -import org.kodein.di.instance +import org.jetbrains.compose.web.svg.Rect +import org.jetbrains.compose.web.svg.Svg /*Main Container for every mayor layout*/ @@ -107,27 +106,57 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { } } +@OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun CategoryList(categoryList : List){ +fun CategoryList(categoryList: List) { Div { console.log(categoryList.size) for (category in categoryList) Div(attrs = { - classes("mdc-card", AppStylesheet.card) + classes("mdc-card", AppStylesheet.card, AppStylesheet.flexContainer) } ) { - Text("${category.name}") - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { } - }) { - Text("Edit Category") + Div( + attrs = { + classes(AppStylesheet.margin) + style { flex(100.percent) } + } + ) { + Text("Name: ${category.name}") + Div(attrs = { style { width(3.percent) } }) { + Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in + Rect(x = 0, y = 0, width = 1, height = 1, { + attr("fill", "#${category.color}") + }) + } + } + Div { + Text("Image: ") + CategoryImageToIcon(category.image) + } + Text("Budget: ${category.budget}€") } - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { } - }) { - Text("Delete Category") + Div( + attrs = { + style { flex(100.percent) } + classes(AppStylesheet.flexContainer) + } + ) { + Div(attrs = { style { flex(75.percent) } }) { } + Button(attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + onClick { } + style { flex(25.percent)} + }) { + Text("Edit Category") + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { } + style { flex(25.percent) } + }) { + Text("Delete Category") + } } } } From cacb0a0124e252e15293d1d76200256fb9cde1e3 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 12:47:55 +0200 Subject: [PATCH 022/325] Add first form of style for entries on dashboard --- .../compose/dashboard/DashboardView.kt | 8 ++++---- .../budgetBinder/compose/entry/EntryComponent.kt | 12 +++++++----- .../budgetBinder/compose/theme/AppStylesheet.kt | 16 +++++++++++++--- .../budgetBinder/presentation/CategoryIcon.kt | 12 +++++++++--- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 3ebca113..f708b458 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -201,11 +201,11 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool }) { Div(attrs = { if(leftOn) { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") + classes(AppStylesheet.imageFlexContainer, "mdc-button") onClick { onFocusCategoryChange(false) } } else{ - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.imageFlexContainer) style{ paddingLeft(8.px) paddingRight(8.px) @@ -220,11 +220,11 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool } Div(attrs = { if(rightOn) { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") + classes(AppStylesheet.imageFlexContainer, "mdc-button") onClick { onFocusCategoryChange(true) } } else{ - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.imageFlexContainer) style{ paddingLeft(8.px) paddingRight(8.px) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 2fce9cd4..29776ac3 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.category.categoryIdToCategory +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen @@ -45,11 +46,12 @@ fun EntryComponent(screenState: MutableState) { //Should be put in own File @Composable fun EntryListElement(entry: Entry, categoryList : List){ - Div { + Div (attrs = { + classes("mdc-card","mdc-card--outlined", AppStylesheet.entryListElement) + }) { CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) - Text(entry.name) - Text(entry.amount.toString()+"€") - + Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} + Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.text) }){Text(entry.amount.toString()+"€")}} } } @@ -61,4 +63,4 @@ fun EntryList(list: List, categoryList : List){ } fun entriesFromCategory(list: List, category_id: Int?):List = - list.filter { it.category_id == category_id } \ No newline at end of file + list.filter { it.category_id == category_id } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 003ba0ff..69eff8c6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -57,14 +57,24 @@ object AppStylesheet : StyleSheet() { flex("90%") } //Container for arrow in BudgetBar - val arrowFlexContainer by style { + val imageFlexContainer by style { flex("0.1 0.1 5%") height(auto) } //EntryList val entryListElement by style{ - + flexDirection(FlexDirection("row")) + alignItems(AlignItems.Center) + margin(10.px) + marginTop(0.px) + } + val entryListElementText by style{ + flex("2 2 90%") + } + val text by style{ + textAlign("center") + padding(10.px) } val card by style { @@ -80,4 +90,4 @@ object AppStylesheet : StyleSheet() { val margin by style { margin(10.px) } -} \ No newline at end of file +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt index bedf3bb9..f84b6cb5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt @@ -2,14 +2,20 @@ package de.hsfl.budgetBinder.presentation import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import org.jetbrains.compose.web.css.padding +import org.jetbrains.compose.web.css.px +import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Span import org.jetbrains.compose.web.dom.Text @Composable actual fun CategoryImageToIcon(icon: Category.Image) { - Span( + Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){ + Span( attrs = { classes("material-icons") + style { padding(8.px) } } ) { Text( @@ -60,5 +66,5 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Category.Image.PEST -> "pest_control" } ) - } -} \ No newline at end of file + }} +} From 7805703e1acb3343d62252944e0ce989ed57a571 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 14:47:17 +0200 Subject: [PATCH 023/325] Add first form of newEntry button style --- .../hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 7 +++++-- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 8 +++++++- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 6 ++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index f708b458..b9271e25 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -185,11 +185,14 @@ fun DashboardData(categoryList: List, entryList: List) { @Composable -fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { //TODO: endlich mal schön machen! Button(attrs = { + classes("mdc-fab","mdc-fab--touch") onClick { onEntryCreateButton() } }) { - Text("Create Entry") + Div(attrs= {classes("mdc-fab__ripple")} ) + Icon("add") + Div(attrs= {classes("mdc-fab__touch")} ) } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 29776ac3..300be387 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -16,6 +16,7 @@ import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Text import org.kodein.di.compose.localDI import org.kodein.di.instance +import kotlin.math.absoluteValue @Composable fun EntryComponent(screenState: MutableState) { @@ -51,9 +52,14 @@ fun EntryListElement(entry: Entry, categoryList : List){ }) { CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} - Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.text) }){Text(entry.amount.toString()+"€")}} + Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.moneyText) }){Text(amountToString(entry.amount))}} } } +fun amountToString(amount:Float):String{ + //This whole thing just so it's "- 10 €" and not "-10 €" + val x = if (amount < 0) "-" else "" + return "$x ${amount.absoluteValue} €" +} @Composable fun EntryList(list: List, categoryList : List){ diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 69eff8c6..c1d6dd9a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -76,6 +76,12 @@ object AppStylesheet : StyleSheet() { textAlign("center") padding(10.px) } + val moneyText by style{ + textAlign("center") + padding(10.px) + whiteSpace("nowrap") + + } val card by style { margin(10.px) From eb21c7adaf78be360923d29e259bea7ada6c3ad5 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 15:25:08 +0200 Subject: [PATCH 024/325] Fix position for newEntry button --- .../compose/dashboard/DashboardView.kt | 27 ++++++++++--------- .../compose/theme/AppStylesheet.kt | 7 ++++- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index b9271e25..90c43329 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -11,10 +11,8 @@ import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState import kotlinx.serialization.json.JsonNull.content -import org.jetbrains.compose.web.css.paddingLeft -import org.jetbrains.compose.web.css.paddingRight -import org.jetbrains.compose.web.css.px -import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.css.keywords.auto import org.jetbrains.compose.web.dom.* @@ -185,14 +183,19 @@ fun DashboardData(categoryList: List, entryList: List) { @Composable -fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { //TODO: endlich mal schön machen! - Button(attrs = { - classes("mdc-fab","mdc-fab--touch") - onClick { onEntryCreateButton() } - }) { - Div(attrs= {classes("mdc-fab__ripple")} ) - Icon("add") - Div(attrs= {classes("mdc-fab__touch")} ) +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { + Div (attrs = {style { + display(DisplayStyle.Flex) + justifyContent(JustifyContent.FlexEnd) + }}) { + Button(attrs = { + classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) + onClick { onEntryCreateButton() } + }) { + Div(attrs = { classes("mdc-fab__ripple") }) + Icon("add") + Div(attrs = { classes("mdc-fab__touch") }) + } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index c1d6dd9a..b7f7e471 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -51,6 +51,7 @@ object AppStylesheet : StyleSheet() { //Container for main content, used in MainFlexContainer val contentFlexContainer by style { flex("50%") + position(Position.Relative) } //Container for main content in BudgetBar val budgetBarContainer by style { @@ -80,7 +81,11 @@ object AppStylesheet : StyleSheet() { textAlign("center") padding(10.px) whiteSpace("nowrap") - + } + val newEntryButton by style{ + position(Position.Fixed) + bottom(16.px) + marginRight(20.px) } val card by style { From 317ba1815a09a1ff9d51e35aec6a19f71f4a244c Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 15:47:58 +0200 Subject: [PATCH 025/325] Add topBar (change later!). Add newEntry-button click reference --- .../compose/dashboard/DashboardView.kt | 77 ++++++++++++------- .../compose/entry/EntryComponent.kt | 7 +- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 90c43329..19e8429f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -9,6 +9,7 @@ import de.hsfl.budgetBinder.compose.category.BudgetBar import de.hsfl.budgetBinder.compose.entry.EntryList import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.css.* @@ -23,38 +24,54 @@ fun DashboardView( onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, onEntryCreateButton: () -> Unit, - onEntryEditButton: () -> Unit + onEntryEditButton: (id:Int) -> Unit ) { val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } var categoryList by remember { mutableStateOf>(emptyList()) } var entryList by remember { mutableStateOf>(emptyList()) } + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onCategorySummaryButton() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onSettingsButton() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } + } + }) + MainFlexContainer { - H1 { Text("DashboardView") } - Button(attrs = { - onClick { onSettingsButton() } - }) { - Text("Open Settings") - } - Button(attrs = { - onClick { onCategorySummaryButton() } - }) { - Text("Open Category List (Summary of every Category)") - } - Button(attrs = { - onClick { onEntryCreateButton() } - }) { - Text("Create Entry") - } - Button(attrs = { - onClick { onEntryEditButton() } - }) { - Text("Edit Entry (Needs to be there for every Entry shown)") - } - Div { - DashboardData(categoryList, entryList) - } + Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) } //Process new Category Data @@ -108,7 +125,7 @@ fun DashboardView( } @Composable -fun DashboardData(categoryList: List, entryList: List) { +fun DashboardData(categoryList: List, entryList: List, onEntry: (id:Int) -> Unit) { console.log("Category $categoryList and Entry $entryList") var focusedCategory by remember { mutableStateOf(-1) } //Variable from -1 (all) to categoryList.size console.log("Focus:${focusedCategory}") @@ -143,7 +160,7 @@ fun DashboardData(categoryList: List, entryList: List) { leftOn = false ) - EntryList(entryList, categoryList) //List of Every Entry + EntryList(entryList, categoryList, onEntry) //List of Every Entry } //Normal Category View in categoryList.indices -> { @@ -155,7 +172,8 @@ fun DashboardData(categoryList: List, entryList: List) { ) EntryList( filteredEntryList, - listOf(categoryList[focusedCategory]) + listOf(categoryList[focusedCategory]), + onEntry ) //Only gives CategoryData of selected category, as everything else seems unnecessary } @@ -171,7 +189,8 @@ fun DashboardData(categoryList: List, entryList: List) { ) EntryList( filteredEntryList, - emptyList() + emptyList(), + onEntry ) //Needs no categoryList, as they have no category } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 300be387..5bf0d4a8 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -46,9 +46,10 @@ fun EntryComponent(screenState: MutableState) { //Should be put in own File @Composable -fun EntryListElement(entry: Entry, categoryList : List){ +fun EntryListElement(entry: Entry, categoryList : List, onEntry: (id:Int) -> Unit){ Div (attrs = { classes("mdc-card","mdc-card--outlined", AppStylesheet.entryListElement) + onClick { onEntry(entry.id) } }) { CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} @@ -62,9 +63,9 @@ fun amountToString(amount:Float):String{ } @Composable -fun EntryList(list: List, categoryList : List){ +fun EntryList(list: List, categoryList : List, onEntry: (id:Int) -> Unit){ for (entry in list){ - EntryListElement(entry,categoryList) + EntryListElement(entry,categoryList,onEntry) } } From a594121ad34ad6b94efdc44d3496bc31294bba35 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 10:49:48 +0200 Subject: [PATCH 026/325] Format files --- .../compose/category/CategoryComponent.kt | 3 +- .../compose/entry/EntryComponent.kt | 48 ++++++++++++++----- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index dbda8a92..1484e42e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -90,7 +90,8 @@ fun BudgetBar(category: Category, entryList: List) { if (usedBudget <= budget && budget > 0) { //Normal not Spent Budget //Money Text MoneyTextDiv { - Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€") } + Div(attrs = { + classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€") } Div(attrs = { classes("mdc-typography--headline5") }) { Text(budget.toString() + "€") } } Svg(viewBox = "0 0 $width $height") { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 5bf0d4a8..dc315361 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -27,7 +27,14 @@ fun EntryComponent(screenState: MutableState) { val changeEntryByIdUseCase: ChangeEntryByIdUseCase by di.instance() val deleteEntryByIdUseCase: DeleteEntryByIdUseCase by di.instance() val createNewEntryUseCase: CreateNewEntryUseCase by di.instance() - val userViewModel = EntryViewModel(getAllEntriesUseCase, getEntryByIdUseCase, createNewEntryUseCase,changeEntryByIdUseCase,deleteEntryByIdUseCase, scope) + val userViewModel = EntryViewModel( + getAllEntriesUseCase, + getEntryByIdUseCase, + createNewEntryUseCase, + changeEntryByIdUseCase, + deleteEntryByIdUseCase, + scope + ) val viewState = userViewModel.state.collectAsState(scope) when (screenState.value) { @@ -38,7 +45,7 @@ fun EntryComponent(screenState: MutableState) { ) Screen.EntryEdit -> EntryEditView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard} + onBackButton = { screenState.value = Screen.Dashboard } ) else -> {} } @@ -46,28 +53,43 @@ fun EntryComponent(screenState: MutableState) { //Should be put in own File @Composable -fun EntryListElement(entry: Entry, categoryList : List, onEntry: (id:Int) -> Unit){ - Div (attrs = { - classes("mdc-card","mdc-card--outlined", AppStylesheet.entryListElement) +fun EntryListElement(entry: Entry, categoryList: List, onEntry: (id: Int) -> Unit) { + Div(attrs = { + classes("mdc-card", "mdc-card--outlined", AppStylesheet.entryListElement) onClick { onEntry(entry.id) } }) { - CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) - Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} - Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.moneyText) }){Text(amountToString(entry.amount))}} + CategoryImageToIcon(categoryIdToCategory(entry.category_id, categoryList).image) + Div(attrs = { classes(AppStylesheet.entryListElementText) }) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text(entry.name) } + } + Div(attrs = { classes(AppStylesheet.imageFlexContainer) }) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.moneyText + ) + }) { Text(amountToString(entry.amount)) } + } } } -fun amountToString(amount:Float):String{ + +fun amountToString(amount: Float): String { //This whole thing just so it's "- 10 €" and not "-10 €" val x = if (amount < 0) "-" else "" return "$x ${amount.absoluteValue} €" } @Composable -fun EntryList(list: List, categoryList : List, onEntry: (id:Int) -> Unit){ - for (entry in list){ - EntryListElement(entry,categoryList,onEntry) +fun EntryList(list: List, categoryList: List, onEntry: (id: Int) -> Unit) { + for (entry in list) { + EntryListElement(entry, categoryList, onEntry) } } -fun entriesFromCategory(list: List, category_id: Int?):List = +fun entriesFromCategory(list: List, category_id: Int?): List = list.filter { it.category_id == category_id } From 140a4182da5e866fcf205257195e4dfef54618d2 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 11:54:28 +0200 Subject: [PATCH 027/325] Add first non-working version of snackbar-feedback --- .../hsfl/budgetBinder/compose/Composables.kt | 57 +++++++++++++++---- .../compose/dashboard/DashboardView.kt | 4 +- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index bed3b465..32b17fbd 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -11,23 +11,23 @@ import org.jetbrains.compose.web.dom.* /*Main Container for every mayor layout*/ @Composable -fun MainFlexContainer(content: @Composable () -> Unit){ - Div ( +fun MainFlexContainer(content: @Composable () -> Unit) { + Div( attrs = { classes("mdc-top-app-bar--fixed-adjust", AppStylesheet.flexContainer) } - ){ - Div (attrs = { classes(AppStylesheet.pufferFlexContainer) }) - Div (attrs = { classes(AppStylesheet.contentFlexContainer)}) + ) { + Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) + Div(attrs = { classes(AppStylesheet.contentFlexContainer) }) { content() } - Div (attrs = { classes(AppStylesheet.pufferFlexContainer)}) + Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) } } @Composable -fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit){ +fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit) { Header( attrs = { classes("mdc-top-app-bar") @@ -63,14 +63,51 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } } + +///* Gives a material icon based on the icon name*/// @Composable -fun Icon (icon_name: String){ +fun Icon(icon_name: String) { Span( attrs = { classes("material-icons") style { width(24.px) - height(24.px) } + height(24.px) + } + } + ) { Text(icon_name) } +} + + +// Snackbar that shows msg +@Composable +fun FeedbackSnackbar(msg: String) { + Aside(attrs = { classes("mdc-snackbar") }) { + Div(attrs = { + classes("mdc-snackbar__surface") + attr(attr = "role", value = "status") + attr(attr = "aria-relevant", value = "additions") + }) { + Div(attrs = { + classes("mdc-snackbar__label") + attr(attr = "aria-atomic", value = "false") + }) { + Text(msg) + } + Div(attrs = { + classes("mdc-snackbar__actions") + attr(attr = "aria-atomic", value = "true") + }) { + Button(attrs = { classes("mdc-button", "mdc-snackbar__action") }) { + Div(attrs = { + classes("mdc-button__ripple") + }) + Span(attrs = { classes("mdc-button__label") }) + { Text("Dismiss") } + } + } } - ) {Text(icon_name)} + } } + + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 19e8429f..5d07678e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -3,6 +3,7 @@ package de.hsfl.budgetBinder.compose.dashboard import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.Icon import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.category.BudgetBar @@ -73,6 +74,7 @@ fun DashboardView( MainFlexContainer { Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) + FeedbackSnackbar("haha test") } //Process new Category Data when (categoriesViewState) { @@ -111,9 +113,9 @@ fun DashboardView( } } } - } is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) //TODO: make it work Text((entriesViewState as UiState.Error).error) } is UiState.Loading -> { From fcb821203eb151ddf6d2d4fe326f0522596cf96b Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 11:58:32 +0200 Subject: [PATCH 028/325] Give feedback when there are no entries to load --- .../compose/dashboard/DashboardView.kt | 7 ++++++- .../budgetBinder/compose/entry/EntryComponent.kt | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 5d07678e..1b817392 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -197,7 +197,12 @@ fun DashboardData(categoryList: List, entryList: List, onEntry: } } } else { - //TODO: Show something like: NO DATA TO SHOW! + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text("No data to load") } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index dc315361..5c204a64 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -86,8 +86,18 @@ fun amountToString(amount: Float): String { @Composable fun EntryList(list: List, categoryList: List, onEntry: (id: Int) -> Unit) { - for (entry in list) { - EntryListElement(entry, categoryList, onEntry) + if (list.isEmpty()) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text("No Entries in this category") } + } + else { + for (entry in list) { + EntryListElement(entry, categoryList, onEntry) + } } } From 66797280bd0a0524e225c0ad0fcbfd38dc75e84e Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 12:05:19 +0200 Subject: [PATCH 029/325] Show BudgetBar when when there are no entries or categories --- .../hsfl/budgetBinder/compose/category/CategoryComponent.kt | 4 ++-- .../de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 1484e42e..129c5f31 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -112,9 +112,9 @@ fun BudgetBar(category: Category, entryList: List) { attr("fill", "#b00020") }) } - } else if (budget <= 0f) { //No Category View or other unpredictable case + } else if (budget <= 0f) { //No Category View or other unpredictable case (or no categories, overall screen) MoneyTextDiv { - Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€ without category spent") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€ spent") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 1b817392..3fffe916 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -146,7 +146,7 @@ fun DashboardData(categoryList: List, entryList: List, onEntry: return newFocus } - if (entryList.isNotEmpty()) { + //if (entryList.isNotEmpty()) { when (focusedCategory) { //Overall View -1 -> { @@ -196,14 +196,14 @@ fun DashboardData(categoryList: List, entryList: List, onEntry: ) //Needs no categoryList, as they have no category } } - } else { + /*} else { Div(attrs = { classes( "mdc-typography--headline5", AppStylesheet.text ) }) { Text("No data to load") } - } + }*/ } From 35e77031e77eb65f327cf2ef2bb69499a79d2c51 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 15:02:43 +0200 Subject: [PATCH 030/325] Snackbar disappears when clicked on (this is a form of logic in view, may change later) --- .../hsfl/budgetBinder/compose/Composables.kt | 27 +++++++++++++++---- .../compose/dashboard/DashboardComponent.kt | 3 +-- .../compose/dashboard/DashboardView.kt | 3 +-- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 32b17fbd..bf4e8efa 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -1,7 +1,7 @@ package de.hsfl.budgetBinder.compose -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState +import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.Screen @@ -81,12 +81,26 @@ fun Icon(icon_name: String) { // Snackbar that shows msg @Composable -fun FeedbackSnackbar(msg: String) { - Aside(attrs = { classes("mdc-snackbar") }) { +fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { + var hiddenValue by remember { mutableStateOf(hidden)} + Aside( + attrs = { + when(hiddenValue){ + false -> classes("mdc-snackbar","mdc-snackbar--open") + true -> classes("mdc-snackbar","maria") + } + onClick { + hiddenValue = true + console.log(this@Aside) + console.log("ldsadsad") + + } + }) { Div(attrs = { classes("mdc-snackbar__surface") attr(attr = "role", value = "status") attr(attr = "aria-relevant", value = "additions") + }) { Div(attrs = { classes("mdc-snackbar__label") @@ -98,7 +112,9 @@ fun FeedbackSnackbar(msg: String) { classes("mdc-snackbar__actions") attr(attr = "aria-atomic", value = "true") }) { - Button(attrs = { classes("mdc-button", "mdc-snackbar__action") }) { + Button(attrs = { + classes("mdc-button", "mdc-snackbar__action") + }) { Div(attrs = { classes("mdc-button__ripple") }) @@ -111,3 +127,4 @@ fun FeedbackSnackbar(msg: String) { } + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index af091bed..5df2d38d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -19,7 +19,6 @@ fun DashboardComponent(screenState: MutableState) { val dashboardViewModel = DashboardViewModel(getAllEntriesUseCase,getAllCategoriesUseCase, scope) val categoriesViewState = dashboardViewModel.categoriesState.collectAsState(scope) val entriesViewState = dashboardViewModel.entriesState.collectAsState(scope) - DashboardView( categoriesState = categoriesViewState, entriesState = entriesViewState, @@ -28,4 +27,4 @@ fun DashboardComponent(screenState: MutableState) { onEntryCreateButton = {screenState.value = Screen.EntryCreate}, onEntryEditButton = {screenState.value = Screen.EntryEdit} ) -} \ No newline at end of file +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 3fffe916..7f30e6bc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -31,13 +31,12 @@ fun DashboardView( val entriesViewState by remember { entriesState } var categoryList by remember { mutableStateOf>(emptyList()) } var entryList by remember { mutableStateOf>(emptyList()) } - topBarMain( logoButton = { Img( src = "images/Logo.png", alt = "Logo", attrs = { classes("mdc-icon-button", AppStylesheet.image) - onClick { } + onClick { } } ) }, navButtons = { From 8585cbb698672083927cae0d1d6c171c3d4bf0cf Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 15:14:23 +0200 Subject: [PATCH 031/325] Use snackbar when there is an error UiState feedback --- .../compose/dashboard/DashboardView.kt | 77 +++++++++---------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 7f30e6bc..b7375d37 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -73,56 +73,55 @@ fun DashboardView( MainFlexContainer { Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) - FeedbackSnackbar("haha test") - } - //Process new Category Data - when (categoriesViewState) { - is UiState.Success<*> -> { - //Updates Data - // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot - when (val element = (categoriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - categoryList = it + //Process new Category Data + when (categoriesViewState) { + is UiState.Success<*> -> { + //Updates Data + // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot + when (val element = (categoriesViewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + categoryList = it + } } - } + } } } + is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } } - is UiState.Error -> { - Text((categoriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } - //Process new Entry Data - when (entriesViewState) { - is UiState.Success<*> -> { - //Updates Data - when (val element = (entriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - entryList = it + //Process new Entry Data + when (entriesViewState) { + is UiState.Success<*> -> { + //Updates Data + when (val element = (entriesViewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + entryList = it + } } - } + } } } - } - is UiState.Error -> { - FeedbackSnackbar((entriesViewState as UiState.Error).error) //TODO: make it work - Text((entriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() + is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } } } + } @Composable From 28f9221e660b23335f1c3f6841c5e7af63984f4c Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 15:46:10 +0200 Subject: [PATCH 032/325] Show Category-Icon with category title and center title --- .../budgetBinder/compose/category/CategoryComponent.kt | 8 +++++++- .../hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 129c5f31..72e6d822 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -4,7 +4,9 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.domain.usecase.* +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel import kotlinx.coroutines.CoroutineScope @@ -85,7 +87,11 @@ fun BudgetBar(category: Category, entryList: List) { for (entry in entryList) { usedBudget -= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget } - H1(attrs={classes("mdc-typography--headline4")}) { Text("${category.name} - Budget") } + H1(attrs={classes("mdc-typography--headline4", AppStylesheet.flexContainer)}) { + CategoryImageToIcon(category.image) + Text("${category.name} - Budget") + } + Div { if (usedBudget <= budget && budget > 0) { //Normal not Spent Budget //Money Text diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index b7375d37..26d81ed1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -71,6 +71,7 @@ fun DashboardView( }) MainFlexContainer { + Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) //Process new Category Data From 6d115997464710b6d09c28bf5981bbf0eaca04ce Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Thu, 16 Jun 2022 16:21:46 +0200 Subject: [PATCH 033/325] Add DeleteDialog as composable and add Dialog on delete user in Settings --- .../hsfl/budgetBinder/compose/Composables.kt | 98 +++++++++++++++++++ .../compose/settings/SettingsView.kt | 9 +- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 26bf8c22..45eb88d6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.flex import org.jetbrains.compose.web.css.percent @@ -161,3 +162,100 @@ fun CategoryList(categoryList: List) { } } } + +@Composable +fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composable () -> Unit ){ + var hiddenValue by remember { mutableStateOf(hidden)} + Div( + attrs = { + when(hiddenValue){ + false -> classes("mdc-dialog", "mdc-dialog--open") + true -> classes("mdc-dialog") + } + } + ) { + Div( + attrs = { + classes("mdc-dialog__container") + } + ) { + Div( + attrs = { + classes("mdc-dialog__surface") + attr("role", "alertdialog") + attr("aria-modal", "true") + attr("aria-labelledby", "my-dialog-title") + attr("aria-describedby", "my-dialog-content") + } + ) { + Div( + attrs = { + classes("mdc-dialog__content") + id("my-dialog-content") + } + ) { + content() //Text in Dialog + } + Div( + attrs = { + classes("mdc-dialog__actions") + } + ) { + Button( + attrs = { + classes("mdc-button", "mdc-dialog__button") + attr("data-mdc-dialog-action", "cancel") + onClick { hiddenValue = true } + } + ) { + Div( + attrs = { + classes("mdc-button__ripple") + } + ) { + + } + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Cancel") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-dialog__button") + attr("data-mdc-dialog-action", "accept") + onClick { + buttonAction() + hiddenValue = true } + } + ) { + Div( + attrs = { + classes("mdc-button__ripple") + } + ) { + + } + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("OK") + } + } + } + } + } + Div( + attrs = { + classes("mdc-dialog__scrim") + } + ) { + + } + } +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt index 9583303b..6324485a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt @@ -1,6 +1,7 @@ package de.hsfl.budgetBinder.compose.settings import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet @@ -20,6 +21,7 @@ fun SettingsView( onDeleteButtonPressed: () -> Unit, onChangeButtonPressed: () -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } val viewState by remember { state } topBarMain( @@ -105,7 +107,9 @@ fun SettingsView( Button( attrs = { classes("mdc-button", "mdc-button--raised") - onClick { onDeleteButtonPressed() } + onClick { + deleteDialog = true + } style { flex(100.percent) } } ) { @@ -113,5 +117,8 @@ fun SettingsView( } } } + if (deleteDialog) { + DeleteDialog(false, {onDeleteButtonPressed}) { Text("Delete User?") } + } } } From 6e13ff86cc2afc81a529ca81c7bc9afb2e286ed7 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Thu, 16 Jun 2022 16:39:46 +0200 Subject: [PATCH 034/325] Add DeleteDialog on delete Category --- .../hsfl/budgetBinder/compose/Composables.kt | 24 ++++++++++++------- .../compose/category/CategorySummaryView.kt | 7 +++++- .../compose/settings/SettingsView.kt | 2 +- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 45eb88d6..613a7d63 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -109,7 +109,10 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun CategoryList(categoryList: List) { +fun CategoryList( + categoryList: List, + onOpenDeleteDialog: () -> Unit, +) { Div { console.log(categoryList.size) for (category in categoryList) @@ -147,13 +150,13 @@ fun CategoryList(categoryList: List) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) onClick { } - style { flex(25.percent)} + style { flex(25.percent) } }) { Text("Edit Category") } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { } + onClick { onOpenDeleteDialog() } style { flex(25.percent) } }) { Text("Delete Category") @@ -164,11 +167,11 @@ fun CategoryList(categoryList: List) { } @Composable -fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composable () -> Unit ){ - var hiddenValue by remember { mutableStateOf(hidden)} +fun DeleteDialog(hidden: Boolean, buttonAction: () -> Unit, resetDialog: () -> Unit, content: @Composable () -> Unit) { + var hiddenValue by remember { mutableStateOf(hidden) } Div( attrs = { - when(hiddenValue){ + when (hiddenValue) { false -> classes("mdc-dialog", "mdc-dialog--open") true -> classes("mdc-dialog") } @@ -205,7 +208,10 @@ fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composabl attrs = { classes("mdc-button", "mdc-dialog__button") attr("data-mdc-dialog-action", "cancel") - onClick { hiddenValue = true } + onClick { + hiddenValue = true + resetDialog() + } } ) { Div( @@ -229,7 +235,9 @@ fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composabl attr("data-mdc-dialog-action", "accept") onClick { buttonAction() - hiddenValue = true } + hiddenValue = true + resetDialog() + } } ) { Div( diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 93799a7b..5e05c425 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.CategoryList +import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain @@ -23,6 +24,7 @@ fun CategorySummaryView( onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -82,7 +84,7 @@ fun CategorySummaryView( }) { Text("Create Category") } - CategoryList(categoryList) + CategoryList(categoryList, {deleteDialog = true}) Div { when (viewState) { is UiState.Success<*> -> { @@ -106,5 +108,8 @@ fun CategorySummaryView( } } } + if (deleteDialog) { + DeleteDialog(false, {}, {deleteDialog = false}) { Text("Delete User?") } + } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt index 6324485a..8a9b0225 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt @@ -118,7 +118,7 @@ fun SettingsView( } } if (deleteDialog) { - DeleteDialog(false, {onDeleteButtonPressed}) { Text("Delete User?") } + DeleteDialog(false, {onDeleteButtonPressed()}, {deleteDialog = false}) { Text("Delete User?") } } } } From 5ecabc588e1063b7782489e83ba4f4ecfacc3830 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Thu, 16 Jun 2022 18:49:47 +0200 Subject: [PATCH 035/325] Change how categories ard displayed --- .../hsfl/budgetBinder/compose/Composables.kt | 57 +++++++++++++------ .../compose/theme/AppStylesheet.kt | 21 ++++++- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 613a7d63..8dc2a6c5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -1,14 +1,14 @@ package de.hsfl.budgetBinder.compose +import App import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.style import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi -import org.jetbrains.compose.web.css.flex -import org.jetbrains.compose.web.css.percent -import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg @@ -114,50 +114,71 @@ fun CategoryList( onOpenDeleteDialog: () -> Unit, ) { Div { - console.log(categoryList.size) for (category in categoryList) Div(attrs = { - classes("mdc-card", AppStylesheet.card, AppStylesheet.flexContainer) + classes("mdc-card", AppStylesheet.card) } ) { Div( attrs = { - classes(AppStylesheet.margin) - style { flex(100.percent) } + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) } ) { - Text("Name: ${category.name}") - Div(attrs = { style { width(3.percent) } }) { + Div( + attrs = { + classes(AppStylesheet.imageFlexContainer) + } + ) { + CategoryImageToIcon(category.image) + } + Div( + attrs = { + classes(AppStylesheet.categoryListElementText) + } + ) { + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(category.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Budget: ${category.budget}€") } + } + } + Div(attrs = { + classes(AppStylesheet.imageFlexContainer) + } + ) { Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in Rect(x = 0, y = 0, width = 1, height = 1, { attr("fill", "#${category.color}") }) } } - Div { - Text("Image: ") - CategoryImageToIcon(category.image) - } - Text("Budget: ${category.budget}€") } Div( attrs = { - style { flex(100.percent) } classes(AppStylesheet.flexContainer) } ) { - Div(attrs = { style { flex(75.percent) } }) { } Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) onClick { } - style { flex(25.percent) } + style { + flex(50.percent) + margin(1.5.percent) + } }) { Text("Edit Category") } Button(attrs = { classes("mdc-button", "mdc-button--raised") onClick { onOpenDeleteDialog() } - style { flex(25.percent) } + style { + flex(50.percent) + margin(1.5.percent) + backgroundColor(Color("#b00020")) + } }) { Text("Delete Category") } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 6bb759f2..bf77d757 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -1,6 +1,7 @@ package de.hsfl.budgetBinder.compose.theme import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.css.keywords.auto import org.jetbrains.compose.web.css.selectors.CSSSelector /*All Information found about Stylesheets: @@ -52,9 +53,25 @@ object AppStylesheet : StyleSheet() { flex("50%") } - //EntryList - val entryListElement by style{ + val categoryListElement by style{ + flexDirection(FlexDirection("row")) + alignItems(AlignItems.Center) + margin(10.px) + marginTop(0.px) + } + + val categoryListElementText by style{ + flex("2 2 90%") + } + + val imageFlexContainer by style { + flex("0.1 0.1 5%") + height(auto) + } + val text by style{ + textAlign("center") + padding(10.px) } val card by style { From 34076da6e9c436810d92d8c57192c2c723c48512 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 17 Jun 2022 14:58:50 +0200 Subject: [PATCH 036/325] Change how a color of a category is displayed from rect to circle --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 8dc2a6c5..24765deb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,12 +4,14 @@ import App import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.attr import de.hsfl.budgetBinder.compose.theme.AppStylesheet.style import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Circle import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg @@ -150,7 +152,7 @@ fun CategoryList( } ) { Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in - Rect(x = 0, y = 0, width = 1, height = 1, { + Circle(cx = 0.5, cy = 0.5, r=0.5, { attr("fill", "#${category.color}") }) } From 5a1d8db749a91c9d2bcb133da133dd3718146830 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 17 Jun 2022 16:04:49 +0200 Subject: [PATCH 037/325] Add edit and delete button functionality for categories summary --- .../de/hsfl/budgetBinder/compose/Composables.kt | 16 ++++++++-------- .../compose/category/CategoryComponent.kt | 2 ++ .../compose/category/CategorySummaryView.kt | 11 +++-------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 24765deb..5dbec237 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -1,18 +1,13 @@ package de.hsfl.budgetBinder.compose -import App import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.attr -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.style import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle -import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg @@ -113,8 +108,10 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { @Composable fun CategoryList( categoryList: List, - onOpenDeleteDialog: () -> Unit, + onEditButton: () -> Unit, + onDeleteButton: (Int) -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } Div { for (category in categoryList) Div(attrs = { @@ -165,7 +162,7 @@ fun CategoryList( ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { } + onClick { onEditButton() } style { flex(50.percent) margin(1.5.percent) @@ -175,7 +172,7 @@ fun CategoryList( } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { onOpenDeleteDialog() } + onClick { deleteDialog = true } style { flex(50.percent) margin(1.5.percent) @@ -185,6 +182,9 @@ fun CategoryList( Text("Delete Category") } } + if (deleteDialog) { + DeleteDialog(false, {onDeleteButton(category.id)}, {deleteDialog = false}) { Text("Delete Category?") } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 04422b2c..bcef65ba 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -43,6 +43,8 @@ fun CategoryComponent(screenState: MutableState) { Screen.CategorySummary -> CategorySummaryView( state = viewState, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, + onEditButton = { screenState.value = Screen.CategoryEdit}, + onDeleteButton = {id -> categoryViewModel.removeCategory(id)}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 5e05c425..2b704955 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -2,15 +2,12 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.css.flex import org.jetbrains.compose.web.css.margin import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* @@ -20,11 +17,12 @@ import org.jetbrains.compose.web.dom.* fun CategorySummaryView( state: State, onCategoryCreateButton: () -> Unit, + onEditButton: () -> Unit, + onDeleteButton: (id: Int) -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { - var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -84,7 +82,7 @@ fun CategorySummaryView( }) { Text("Create Category") } - CategoryList(categoryList, {deleteDialog = true}) + CategoryList(categoryList, onEditButton, onDeleteButton) Div { when (viewState) { is UiState.Success<*> -> { @@ -108,8 +106,5 @@ fun CategorySummaryView( } } } - if (deleteDialog) { - DeleteDialog(false, {}, {deleteDialog = false}) { Text("Delete User?") } - } } } From 2812b174b71a9d54a7ab3203f6766409e5a4c35c Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 12:03:09 +0200 Subject: [PATCH 038/325] Fix wrong images used. Fix padding of images. Set image container to justify-content center --- .../de/hsfl/budgetBinder/compose/Composables.kt | 2 +- .../compose/category/CategoryCreateView.kt | 5 +++++ .../budgetBinder/compose/theme/AppStylesheet.kt | 4 ++++ .../hsfl/budgetBinder/presentation/CategoryIcon.kt | 14 ++++++++------ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 66edb3f9..310b6826 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -142,7 +142,7 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { ) { Ul( attrs = { - classes("mdc-image-list", "my-image-list") + classes("mdc-image-list", AppStylesheet.categoryImageList) } ) { for (image in Category.Image.values()) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index 22d8391a..034566ca 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -89,6 +89,7 @@ fun CategoryCreateView( } } ) { + //Category Name Input Div( attrs = { classes(AppStylesheet.margin) @@ -127,6 +128,7 @@ fun CategoryCreateView( ) { } } } + //Category Color Input Div( attrs = { classes(AppStylesheet.margin) @@ -165,6 +167,7 @@ fun CategoryCreateView( ) { } } } + //Category Image Input Div( attrs = { classes(AppStylesheet.margin) @@ -184,6 +187,7 @@ fun CategoryCreateView( CategoryImagesToImageList(onClick = {categoryImageState = it}) } } + //Category Budget Input Div( attrs = { classes(AppStylesheet.margin) @@ -223,6 +227,7 @@ fun CategoryCreateView( ) { } } } + //Submit button Div( attrs = { classes(AppStylesheet.margin) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index a527c5b5..54ad4c47 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -74,6 +74,10 @@ object AppStylesheet : StyleSheet() { flex("2 2 90%") } + val categoryImageList by style{ + justifyContent(JustifyContent.Center) + } + val text by style { textAlign("center") padding(10.px) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt index f84b6cb5..cffd4de2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt @@ -3,8 +3,7 @@ package de.hsfl.budgetBinder.presentation import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import org.jetbrains.compose.web.css.padding -import org.jetbrains.compose.web.css.px +import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Span import org.jetbrains.compose.web.dom.Text @@ -15,7 +14,10 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Span( attrs = { classes("material-icons") - style { padding(8.px) } + style { + paddingTop(8.px) + paddingBottom(8.px) + } } ) { Text( @@ -27,7 +29,7 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Category.Image.WRONG -> "dangerous" Category.Image.HOME -> "home" Category.Image.FOOD -> "bakery_dining" - Category.Image.FASTFOOD -> "bakery_dining" + Category.Image.FASTFOOD -> "fastfood" Category.Image.RESTAURANT -> "restaurant" Category.Image.FAMILY -> "people" Category.Image.MONEY -> "payments" @@ -41,10 +43,10 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Category.Image.FLOWER -> "local_florist" Category.Image.PET -> "pets" Category.Image.BILLS -> "receipt" - Category.Image.KEYBOARD -> "redeem" + Category.Image.KEYBOARD -> "keyboard" Category.Image.PRINTER -> "print" Category.Image.WATER -> "water_drop" - Category.Image.FIRE -> "fire" + Category.Image.FIRE -> "local_fire_department" Category.Image.STAR -> "grade" Category.Image.SAVINGS -> "savings" Category.Image.CAR -> "minor_crash" From ee07b142226788b610861b0dd84d6107ddb9017f Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:11:52 +0200 Subject: [PATCH 039/325] Add EntryOverview Screen and open EntryOverview with corresponding ID when clicking on an entry in dashboard --- .../kotlin/de/hsfl/budgetBinder/presentation/Screen.kt | 1 + .../budgetBinder/compose/dashboard/DashboardComponent.kt | 2 +- .../hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 7 +++---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 11177659..cd863bba 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -11,6 +11,7 @@ sealed class Screen { object CategoryEdit : Screen() object CategoryCreate : Screen() object CategoryCreateOnRegister : Screen() + data class EntryOverview (val id: Int) : Screen() object EntryEdit : Screen() object EntryCreate : Screen() diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 5df2d38d..a05e21e4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -25,6 +25,6 @@ fun DashboardComponent(screenState: MutableState) { onCategorySummaryButton = { screenState.value = Screen.CategorySummary}, onSettingsButton = {screenState.value = Screen.Settings}, onEntryCreateButton = {screenState.value = Screen.EntryCreate}, - onEntryEditButton = {screenState.value = Screen.EntryEdit} + onEntryOverviewButton = {id -> screenState.value = Screen.EntryOverview(id)} ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 26d81ed1..a14ba26f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -12,9 +12,8 @@ import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.css.keywords.auto + import org.jetbrains.compose.web.dom.* @@ -25,7 +24,7 @@ fun DashboardView( onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, onEntryCreateButton: () -> Unit, - onEntryEditButton: (id:Int) -> Unit + onEntryOverviewButton: (id:Int) -> Unit ) { val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } @@ -72,7 +71,7 @@ fun DashboardView( MainFlexContainer { - Div { DashboardData(categoryList, entryList, onEntryEditButton) } + Div { DashboardData(categoryList, entryList, onEntryOverviewButton) } CreateNewEntryButton(onEntryCreateButton) //Process new Category Data when (categoriesViewState) { From 915b78a605d910281d2514ac5bc05454ddc55074 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:21:09 +0200 Subject: [PATCH 040/325] Fix Router routing per type and not per instance --- .../de/hsfl/budgetBinder/compose/Router.kt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 6c187b43..b03e6251 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -11,14 +11,17 @@ import de.hsfl.budgetBinder.compose.settings.SettingsComponent import de.hsfl.budgetBinder.presentation.Screen @Composable +//Id for cases where a specific entry or category needs to be opened fun Router(screenState: MutableState) { when (screenState.value) { - Screen.Welcome -> {} - Screen.Register -> RegisterComponent(screenState = screenState) - Screen.Login -> LoginComponent(screenState = screenState) - Screen.Dashboard -> DashboardComponent(screenState = screenState) - Screen.Settings, Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - Screen.CategorySummary,Screen.CategoryEdit,Screen.CategoryCreate, Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) - Screen.EntryCreate, Screen.EntryEdit -> EntryComponent(screenState = screenState) + is Screen.Welcome -> {} + is Screen.Register -> RegisterComponent(screenState = screenState) + is Screen.Login -> LoginComponent(screenState = screenState) + is Screen.Dashboard -> DashboardComponent(screenState = screenState) + is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) + is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, Screen.CategoryCreateOnRegister + -> CategoryComponent(screenState = screenState) + is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) + else -> {} } -} \ No newline at end of file +} From 9a78de57ebbbe10ecf31dba39b814cd299df31b0 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:43:59 +0200 Subject: [PATCH 041/325] Add EntryOverviewView and connect it in EntryComponent --- .../compose/entry/EntryOverviewView.kt | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt new file mode 100644 index 00000000..28ee388a --- /dev/null +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -0,0 +1,168 @@ +package de.hsfl.budgetBinder.compose.entry + +import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.CategoryList +import de.hsfl.budgetBinder.compose.DeleteDialog +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import de.hsfl.budgetBinder.presentation.UiState +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Circle +import org.jetbrains.compose.web.svg.Svg + + +@Composable +fun EntryOverviewView( + state: State, + onEditButton: () -> Unit, + onDeleteButton: (id: Int) -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToCategory: () -> Unit, + onChangeToSettings: () -> Unit +) { + var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } + val viewState by remember { state } + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } + } + }) + + MainFlexContainer { + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Entry") } + + EntryOverview(entry,onEditButton,onDeleteButton) + } + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is Entry -> entry = element + else -> {} + } + + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } +} + +@Composable +fun EntryOverview( + entry: Entry, + onEditButton: () -> Unit, + onDeleteButton: (Int) -> Unit +) { + var deleteDialog by remember { mutableStateOf(false) } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Div( + attrs = { + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) + } + ) { + + Div( + attrs = { + classes(AppStylesheet.categoryListElementText) + } + ) { + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(entry.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Amount: ${entry.amount}€") } + } + } + } + Div( + attrs = { + classes(AppStylesheet.flexContainer) + } + ) { + Button(attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + onClick { onEditButton() } + style { + flex(50.percent) + margin(1.5.percent) + } + }) { + Text("Edit Entry") + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { deleteDialog = true } + style { + flex(50.percent) + margin(1.5.percent) + backgroundColor(Color("#b00020")) + } + }) { + Text("Delete Entry") + } + } + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton(entry.id) }, + { deleteDialog = false }) { Text("Delete Entry?") } + } + } +} + From cce3a880189db111a258163914fe48ea490956b3 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:45:01 +0200 Subject: [PATCH 042/325] Add EntryComponent stuff for EntryOverview --- .../budgetBinder/compose/entry/EntryComponent.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 5c204a64..b6d03992 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -27,7 +27,7 @@ fun EntryComponent(screenState: MutableState) { val changeEntryByIdUseCase: ChangeEntryByIdUseCase by di.instance() val deleteEntryByIdUseCase: DeleteEntryByIdUseCase by di.instance() val createNewEntryUseCase: CreateNewEntryUseCase by di.instance() - val userViewModel = EntryViewModel( + val entryViewModel = EntryViewModel( getAllEntriesUseCase, getEntryByIdUseCase, createNewEntryUseCase, @@ -35,7 +35,7 @@ fun EntryComponent(screenState: MutableState) { deleteEntryByIdUseCase, scope ) - val viewState = userViewModel.state.collectAsState(scope) + val viewState = entryViewModel.state.collectAsState(scope) when (screenState.value) { Screen.EntryCreate -> EntryCreateView( @@ -47,6 +47,14 @@ fun EntryComponent(screenState: MutableState) { state = viewState, onBackButton = { screenState.value = Screen.Dashboard } ) + is Screen.EntryOverview -> EntryOverviewView( + state = viewState, + onEditButton = {}, + onDeleteButton = {id -> entryViewModel.removeEntry(id)}, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) else -> {} } } From 3e8577b1d61defb91428fdbe1da8e9cfcd29ca68 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:58:10 +0200 Subject: [PATCH 043/325] Load Entry-Data when EntryOverview is opened --- .../presentation/viewmodel/EntryViewModel.kt | 2 +- .../de/hsfl/budgetBinder/compose/Router.kt | 1 - .../compose/entry/EntryComponent.kt | 22 +++-- .../compose/entry/EntryOverviewView.kt | 94 +++++++++---------- 4 files changed, 58 insertions(+), 61 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt index fcac4160..770446b9 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt @@ -74,4 +74,4 @@ class EntryViewModel( } }.launchIn(scope) } -} \ No newline at end of file +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index b03e6251..067df92a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -11,7 +11,6 @@ import de.hsfl.budgetBinder.compose.settings.SettingsComponent import de.hsfl.budgetBinder.presentation.Screen @Composable -//Id for cases where a specific entry or category needs to be opened fun Router(screenState: MutableState) { when (screenState.value) { is Screen.Welcome -> {} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index b6d03992..85c268de 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -47,14 +47,17 @@ fun EntryComponent(screenState: MutableState) { state = viewState, onBackButton = { screenState.value = Screen.Dashboard } ) - is Screen.EntryOverview -> EntryOverviewView( - state = viewState, - onEditButton = {}, - onDeleteButton = {id -> entryViewModel.removeEntry(id)}, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) + is Screen.EntryOverview -> { + EntryOverviewView( + state = viewState, + onEditButton = {}, + onDeleteButton = { id -> entryViewModel.removeEntry(id) }, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) + entryViewModel.getEntryById((screenState.value as Screen.EntryOverview).id) + } else -> {} } } @@ -101,8 +104,7 @@ fun EntryList(list: List, categoryList: List, onEntry: (id: Int AppStylesheet.text ) }) { Text("No Entries in this category") } - } - else { + } else { for (entry in list) { EntryListElement(entry, categoryList, onEntry) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index 28ee388a..861308b2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -78,7 +78,7 @@ fun EntryOverviewView( } ) { Text(" Entry") } - EntryOverview(entry,onEditButton,onDeleteButton) + EntryOverview(entry, onEditButton, onDeleteButton) } when (viewState) { is UiState.Success<*> -> { @@ -105,64 +105,60 @@ fun EntryOverview( onDeleteButton: (Int) -> Unit ) { var deleteDialog by remember { mutableStateOf(false) } - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } + Div( + attrs = { + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) + } ) { - Div( - attrs = { - classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) - } - ) { - Div( - attrs = { - classes(AppStylesheet.categoryListElementText) - } - ) { - Div { - Div(attrs = { - classes("mdc-typography--headline4", AppStylesheet.text) - }) { Text(entry.name) } - Div(attrs = { - classes("mdc-typography--headline6", AppStylesheet.text) - }) { Text("Amount: ${entry.amount}€") } - } - } - } Div( attrs = { - classes(AppStylesheet.flexContainer) + classes(AppStylesheet.categoryListElementText) } ) { - Button(attrs = { - classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton() } - style { - flex(50.percent) - margin(1.5.percent) - } - }) { - Text("Edit Entry") + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(entry.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Amount: ${entry.amount}€") } } - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { deleteDialog = true } - style { - flex(50.percent) - margin(1.5.percent) - backgroundColor(Color("#b00020")) - } - }) { - Text("Delete Entry") + } + } + Div( + attrs = { + classes(AppStylesheet.flexContainer) + } + ) { + Button(attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + onClick { onEditButton() } + style { + flex(50.percent) + margin(1.5.percent) } + }) { + Text("Edit Entry") } - if (deleteDialog) { - DeleteDialog( - false, - { onDeleteButton(entry.id) }, - { deleteDialog = false }) { Text("Delete Entry?") } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { deleteDialog = true } + style { + flex(50.percent) + margin(1.5.percent) + backgroundColor(Color("#b00020")) + } + }) { + Text("Delete Entry") } } + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton(entry.id) }, + { deleteDialog = false }) { Text("Delete Entry?") } + } } + From 3ab3f5da1688c8588eea5fc80876c4c41c816e98 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 18:39:56 +0200 Subject: [PATCH 044/325] Make editEntry button go to EntryEdit:Screen --- .../compose/entry/EntryComponent.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 85c268de..05d81f23 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -38,19 +38,10 @@ fun EntryComponent(screenState: MutableState) { val viewState = entryViewModel.state.collectAsState(scope) when (screenState.value) { - Screen.EntryCreate -> EntryCreateView( - state = viewState, - onBackButton = { screenState.value = Screen.Dashboard }, - onCategoryCreateButton = { screenState.value = Screen.CategoryCreate } - ) - Screen.EntryEdit -> EntryEditView( - state = viewState, - onBackButton = { screenState.value = Screen.Dashboard } - ) is Screen.EntryOverview -> { EntryOverviewView( state = viewState, - onEditButton = {}, + onEditButton = {screenState.value = Screen.EntryEdit}, onDeleteButton = { id -> entryViewModel.removeEntry(id) }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, @@ -58,6 +49,15 @@ fun EntryComponent(screenState: MutableState) { ) entryViewModel.getEntryById((screenState.value as Screen.EntryOverview).id) } + Screen.EntryCreate -> EntryCreateView( + state = viewState, + onBackButton = { screenState.value = Screen.Dashboard }, + onCategoryCreateButton = { screenState.value = Screen.CategoryCreate } + ) + Screen.EntryEdit -> EntryEditView( + state = viewState, + onBackButton = { screenState.value = Screen.Dashboard } + ) else -> {} } } From cb316c877f60aef52591925d027b24cc36a5dfe6 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sat, 18 Jun 2022 18:51:48 +0200 Subject: [PATCH 045/325] Add entryCreate functionality and style, plus change that EntryCreateView gets the categoryList from DashboardView --- .../hsfl/budgetBinder/presentation/Screen.kt | 4 +- .../presentation/viewmodel/EntryViewModel.kt | 1 + .../hsfl/budgetBinder/compose/Composables.kt | 92 ++++- .../de/hsfl/budgetBinder/compose/Router.kt | 14 +- .../compose/category/CategoryCreateView.kt | 276 ++++++++------- .../compose/category/CategorySummaryView.kt | 59 ++-- .../compose/dashboard/DashboardComponent.kt | 2 +- .../compose/dashboard/DashboardView.kt | 4 +- .../compose/entry/EntryComponent.kt | 14 +- .../compose/entry/EntryCreateView.kt | 276 +++++++++++++-- .../budgetBinder/compose/login/LoginView.kt | 180 +++++----- .../compose/register/RegisterView.kt | 321 +++++++++--------- .../settings/SettingsChangeUserDataView.kt | 229 ++++++------- .../compose/settings/SettingsView.kt | 85 +++-- 14 files changed, 908 insertions(+), 649 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 11177659..a05d2792 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -1,5 +1,7 @@ package de.hsfl.budgetBinder.presentation +import de.hsfl.budgetBinder.common.Category + sealed class Screen { object Welcome : Screen() object Login : Screen() @@ -12,6 +14,6 @@ sealed class Screen { object CategoryCreate : Screen() object CategoryCreateOnRegister : Screen() object EntryEdit : Screen() - object EntryCreate : Screen() + data class EntryCreate (val categoryList :List): Screen() } diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt index fcac4160..72c787ea 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt @@ -74,4 +74,5 @@ class EntryViewModel( } }.launchIn(scope) } + } \ No newline at end of file diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 66edb3f9..895c49ca 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -3,11 +3,14 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.image import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.attributes.ButtonType +import org.jetbrains.compose.web.attributes.type +import org.jetbrains.compose.web.attributes.value import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* -import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.svg.Circle import org.jetbrains.compose.web.svg.Svg @@ -23,7 +26,12 @@ fun MainFlexContainer(content: @Composable () -> Unit) { Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) Div(attrs = { classes(AppStylesheet.contentFlexContainer) }) { - content() + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + content() + } } Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) } @@ -85,20 +93,20 @@ fun Icon(icon_name: String) { // Snackbar that shows msg @Composable fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { - var hiddenValue by remember { mutableStateOf(hidden)} + var hiddenValue by remember { mutableStateOf(hidden) } Aside( attrs = { - when(hiddenValue){ - false -> classes("mdc-snackbar","mdc-snackbar--open") - true -> classes("mdc-snackbar","maria") + when (hiddenValue) { + false -> classes("mdc-snackbar", "mdc-snackbar--open") + true -> classes("mdc-snackbar", "maria") } - onClick { - hiddenValue = true - console.log(this@Aside) - console.log("ldsadsad") + onClick { + hiddenValue = true + console.log(this@Aside) + console.log("ldsadsad") - } - }) { + } + }) { Div(attrs = { classes("mdc-snackbar__surface") attr(attr = "role", value = "status") @@ -130,8 +138,6 @@ fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { } - - @Composable fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } @@ -212,11 +218,11 @@ fun CategoryList( } } Div(attrs = { - classes(AppStylesheet.imageFlexContainer) - } + classes(AppStylesheet.imageFlexContainer) + } ) { Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in - Circle(cx = 0.5, cy = 0.5, r=0.5, { + Circle(cx = 0.5, cy = 0.5, r = 0.5, { attr("fill", "#${category.color}") }) } @@ -250,7 +256,10 @@ fun CategoryList( } } if (deleteDialog) { - DeleteDialog(false, {onDeleteButton(category.id)}, {deleteDialog = false}) { Text("Delete Category?") } + DeleteDialog( + false, + { onDeleteButton(category.id) }, + { deleteDialog = false }) { Text("Delete Category?") } } } } @@ -357,3 +366,50 @@ fun DeleteDialog(hidden: Boolean, buttonAction: () -> Unit, resetDialog: () -> U } } } + +@Composable +fun ChooseCategoryMenu( + categoryList: List, + getCategoryId: (Int) -> Unit +) { + var chosenCategory by remember { mutableStateOf(categoryList[0]) } + var showList by remember { mutableStateOf(false) } + + Button(attrs = { + classes("mdc-button", "mdc-dialog__button") + onClick { showList = !showList } + type(ButtonType.Button) + }) { + Div(attrs = { + when (showList) { + true -> classes("mdc-menu", "mdc-menu-surface", "mdc-menu-surface--open") + false -> classes("mdc-menu", "mdc-menu-surface") + } + }) { + Ul(attrs = { + classes("mdc-list") + attr("role", "menu") + attr("aria-hidden", "true") + attr("aria-orientation", "vertical") + attr("tabindex", "-1") + }) { + for (category in categoryList) { + Li(attrs = { + classes("mdc-list-item") + attr("role", "menuitem") + onClick { } + }) { + Span(attrs = { classes("mdc-list-item__ripple") }) { } + Span(attrs = { onClick { chosenCategory = category; getCategoryId(category.id) } }) { + Text( + category.name + ) + } + } + } + } + } + Text(chosenCategory.name) + } +} + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 6c187b43..acaae021 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -13,12 +13,12 @@ import de.hsfl.budgetBinder.presentation.Screen @Composable fun Router(screenState: MutableState) { when (screenState.value) { - Screen.Welcome -> {} - Screen.Register -> RegisterComponent(screenState = screenState) - Screen.Login -> LoginComponent(screenState = screenState) - Screen.Dashboard -> DashboardComponent(screenState = screenState) - Screen.Settings, Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - Screen.CategorySummary,Screen.CategoryEdit,Screen.CategoryCreate, Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) - Screen.EntryCreate, Screen.EntryEdit -> EntryComponent(screenState = screenState) + is Screen.Welcome -> {} + is Screen.Register -> RegisterComponent(screenState = screenState) + is Screen.Login -> LoginComponent(screenState = screenState) + is Screen.Dashboard -> DashboardComponent(screenState = screenState) + is Screen.Settings, Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) + is Screen.CategorySummary,Screen.CategoryEdit,Screen.CategoryCreate, Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) + is Screen.EntryCreate, Screen.EntryEdit -> EntryComponent(screenState = screenState) } } \ No newline at end of file diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index 22d8391a..2fefac50 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -10,10 +10,7 @@ import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.min import org.jetbrains.compose.web.attributes.required -import org.jetbrains.compose.web.css.marginBottom -import org.jetbrains.compose.web.css.marginLeft -import org.jetbrains.compose.web.css.percent -import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* @@ -28,7 +25,7 @@ fun CategoryCreateView( var categoryNameTextFieldState by remember { mutableStateOf("") } var categoryColorTextFieldState by remember { mutableStateOf("") } var categoryImageState by remember { mutableStateOf(Category.Image.DEFAULT) } - var categoryBudgetTextFieldState by remember { mutableStateOf("") } + var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } topBarMain( @@ -71,180 +68,179 @@ fun CategoryCreateView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Create a new Category") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onCreateCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() + } } ) { - H1 { Text("Create a new Category") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") - onCreateCategoryButtonPressed( - categoryNameTextFieldState, - categoryColorTextFieldState, - categoryImageState, - categoryBudgetTextFieldState.toFloat() - ) - it.preventDefault() + Div( + attrs = { + classes(AppStylesheet.margin) } - } ) { - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Category Name") } + Input( + type = InputType.Text ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Category Name") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(categoryNameTextFieldState) - required(true) - onInput { - categoryNameTextFieldState = it.value - } + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + required(true) + onInput { + categoryNameTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) } - Div( + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } ) { - Label( + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } } + ) { Text("Color") } + Input( + type = InputType.Color ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } - } - ) { Text("Color") } - Input( - type = InputType.Color - ) { - classes("mdc-text-field__input") - value(categoryColorTextFieldState) - onInput { - categoryColorTextFieldState = it.value - } + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + style { width(100.percent) } } ) { - Label( + Span( attrs = { - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent) } } - ) { - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent); marginLeft(2.percent)} - } - ) { Text("Image") } - CategoryImagesToImageList(onClick = {categoryImageState = it}) - } + ) { Text("Image") } + CategoryImagesToImageList(onClick = { categoryImageState = it }) + } + } + Div( + attrs = { + classes(AppStylesheet.margin) } - Div( + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Budget") } - Input( - type = InputType.Number - ) { - classes("mdc-text-field__input") - value(categoryBudgetTextFieldState) - required(true) - min("1") - onInput { - categoryBudgetTextFieldState = it.value.toString() - } + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + required(true) + min("1") + onInput { + categoryBudgetTextFieldState = it.value.toString() } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( attrs = { - classes(AppStylesheet.margin) + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + //Text((viewState as UiState.Success<*>).element.toString()) } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - Div { - when (viewState) { - is UiState.Success<*> -> { - //Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 2b704955..8bd83a2a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -66,43 +66,38 @@ fun CategorySummaryView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Category Summary") } - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onCategoryCreateButton() } + H1( + attrs = { style { margin(2.percent) } - }) { - Text("Create Category") } - CategoryList(categoryList, onEditButton, onDeleteButton) - Div { - when (viewState) { - is UiState.Success<*> -> { - when (val element = (viewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - categoryList = it - } + ) { Text(" Category Summary") } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onCategoryCreateButton() } + style { margin(2.percent) } + }) { + Text("Create Category") + } + CategoryList(categoryList, onEditButton, onDeleteButton) + Div { + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + categoryList = it } - } + } } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 5df2d38d..da048608 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -24,7 +24,7 @@ fun DashboardComponent(screenState: MutableState) { entriesState = entriesViewState, onCategorySummaryButton = { screenState.value = Screen.CategorySummary}, onSettingsButton = {screenState.value = Screen.Settings}, - onEntryCreateButton = {screenState.value = Screen.EntryCreate}, + onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, onEntryEditButton = {screenState.value = Screen.EntryEdit} ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 26d81ed1..c1b1e254 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -24,7 +24,7 @@ fun DashboardView( entriesState: State, onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, - onEntryCreateButton: () -> Unit, + onEntryCreateButton: (categoryList: List) -> Unit, onEntryEditButton: (id:Int) -> Unit ) { val categoriesViewState by remember { categoriesState } @@ -73,7 +73,7 @@ fun DashboardView( MainFlexContainer { Div { DashboardData(categoryList, entryList, onEntryEditButton) } - CreateNewEntryButton(onEntryCreateButton) + CreateNewEntryButton({ onEntryCreateButton(categoryList) }) //Process new Category Data when (categoriesViewState) { is UiState.Success<*> -> { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 5c204a64..f67304c7 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -38,12 +38,18 @@ fun EntryComponent(screenState: MutableState) { val viewState = userViewModel.state.collectAsState(scope) when (screenState.value) { - Screen.EntryCreate -> EntryCreateView( + is Screen.EntryCreate -> {EntryCreateView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard }, - onCategoryCreateButton = { screenState.value = Screen.CategoryCreate } + categoryList = (screenState.value as Screen.EntryCreate).categoryList, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onCreateEntryButtonPressed = { name, amount, repeat, category_id -> + userViewModel.createEntry(Entry.In(name, amount, repeat, category_id)) }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - Screen.EntryEdit -> EntryEditView( + + } + is Screen.EntryEdit -> EntryEditView( state = viewState, onBackButton = { screenState.value = Screen.Dashboard } ) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 40b47c7c..1495873d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -1,42 +1,270 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.* +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.id +import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.attributes.* +import org.jetbrains.compose.web.attributes.AutoComplete.Companion.off +import org.jetbrains.compose.web.attributes.AutoComplete.Companion.on +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Path +import org.jetbrains.compose.web.svg.Svg +@OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryCreateView( state: State, - onBackButton: () -> Unit, - onCategoryCreateButton: () -> Unit + categoryList: List, + onChangeToDashboard: () -> Unit, + onChangeToSettings: () -> Unit, + onChangeToCategory: () -> Unit, + onCreateEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category_id: Int) -> Unit, ) { + var switchState by remember { mutableStateOf(false) } + var entryNameTextFieldState by remember { mutableStateOf("") } + var entryAmountTextFieldState by remember { mutableStateOf("") } + var entryRepeatState by remember { mutableStateOf("") } + var entryCategoryIDTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("EntryCreate")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + }) + + MainFlexContainer { + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Create new Entry") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$entryNameTextFieldState, $entryAmountTextFieldState, $entryRepeatState, $entryCategoryIDTextFieldState") + onCreateEntryButtonPressed( + entryNameTextFieldState, + (if (!switchState) "-$entryAmountTextFieldState" else entryAmountTextFieldState).toFloat(), + entryRepeatState.toBoolean(), + entryCategoryIDTextFieldState.toInt() + ) + it.preventDefault() } } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Dashboard") - } - Button(attrs = { - onClick { onCategoryCreateButton() } - }) { - Text("Create new Category (Needs to be put as the last option when selecting a category for an entry)") + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Entry Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(entryNameTextFieldState) + required(true) + onInput { + entryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Amount") } + Div { + Button( + attrs = { + if (!switchState) classes("mdc-switch", "mdc-switch--unselected") + else classes("mdc-switch", "mdc-switch--selected") + id("basic-switch") + attr("role", "switch") + attr("aria-checked", "false") + type(ButtonType.Button) + onClick { switchState = !switchState } + } + ) { + Div(attrs = { classes("mdc-switch__track") }) { } + Div(attrs = { classes("mdc-switch__handle-track") }) { + Div(attrs = { classes("mdc-switch__handle") }) { + Div(attrs = { classes("mdc-switch__shadow") }) { + Div(attrs = { classes("mdc-elevation-overlay") }) { } + } + Div(attrs = { classes("mdc-switch__ripple") }) { } + Div(attrs = { classes("mdc-switch__icons") }) { + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") + } + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M20 13H4v-2h16v2z") + } + } + } + } + } + } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { + Text(if (switchState) "+" else "-") + } + Input( + type = InputType.Number + ) { + attr("step", "0.01") + classes("mdc-text-field__input") + onInput { + entryAmountTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) + } + ) { + Div(attrs = {style { flex(50.percent) }}) { + Div(attrs = { classes("mdc-form-field") }) { + Div(attrs = { classes("mdc-checkbox") }) { + Input(type = InputType.Checkbox) + { + classes("mdc-checkbox__native-control") + id("checkbox-1") + onInput { + entryRepeatState = it.value.toString() + } + } + Div(attrs = { classes("mdc-checkbox__background") }) { + Svg(attrs = { classes("mdc-checkbox__checkmark") }, viewBox = "0 0 24 24") { + Path("M1.73,12.91 8.1,19.28 22.79,4.59", attrs = { classes("mdc-checkbox__checkmark") }) + } + Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } + } + Div(attrs = { classes("mdc-checkbox__ripple") }) { } + } + Label(forId = "checkbox-1") { Text("repeat") } + } + } + Div(attrs = {style { flex(50.percent) }}) { + ChooseCategoryMenu(categoryList) { id -> entryCategoryIDTextFieldState = id.toString() } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt index 82e7ed1c..55e44092 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt @@ -69,119 +69,113 @@ fun LoginView( } } - MainFlexContainer{ + MainFlexContainer { // -- Login Form -- + H1 { Text(" Login") } + Form( + attrs = { + this.addEventListener("submit") { + console.log("${emailTextFieldState}, ${passwordTextFieldState}") + onLoginButtonPressed(emailTextFieldState, passwordTextFieldState) + it.preventDefault() + } + } + ) { Div( attrs = { - classes("mdc-card", AppStylesheet.card) + classes(AppStylesheet.margin) } ) { - H1 { Text(" Login") } - Form( + Label( attrs = { - this.addEventListener("submit") { - console.log("${emailTextFieldState}, ${passwordTextFieldState}") - onLoginButtonPressed(emailTextFieldState, passwordTextFieldState) - it.preventDefault() - } + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Div( + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field__ripple") } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Email") } - EmailInput(value = emailTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - emailTextFieldState = it.value - - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( + ) { } + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-floating-label", "mdc-floating-label--float-above") } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + ) { Text("Email") } + EmailInput(value = emailTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + emailTextFieldState = it.value + } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( + }) + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-line-ripple") } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - // -- Login Request Management -- - when (viewState) { - is UiState.Success<*> -> { - onLoginSuccess() + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { Text("Password") } + PasswordInput(value = passwordTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + passwordTextFieldState = it.value + } + }) + Span( + attrs = { + classes("mdc-line-ripple") } - else -> {} - } + ) { } } } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + // -- Login Request Management -- + when (viewState) { + is UiState.Success<*> -> { + onLoginSuccess() + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + else -> {} + } } + } } \ No newline at end of file diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt index 9cb0697a..4e7924bf 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt @@ -74,198 +74,191 @@ fun RegisterView( } } - MainFlexContainer{ + MainFlexContainer { // -- Register Form -- - Div( - attrs = { - classes("mdc-card", AppStylesheet.card) + H1 { Text(" Register") } + Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit + this.addEventListener("submit") { + console.log("$firstNameTextFieldState, $lastNameTextFieldState, $emailTextFieldState, $passwordTextFieldState") + onRegisterButtonPressed( + firstNameTextFieldState, + lastNameTextFieldState, + emailTextFieldState, + passwordTextFieldState + ) + it.preventDefault() } + } ) { - - H1 { Text(" Register") } - Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit - this.addEventListener("submit") { - console.log("$firstNameTextFieldState, $lastNameTextFieldState, $emailTextFieldState, $passwordTextFieldState") - onRegisterButtonPressed( - firstNameTextFieldState, - lastNameTextFieldState, - emailTextFieldState, - passwordTextFieldState - ) - it.preventDefault() - } + Div( + attrs = { + classes(AppStylesheet.margin) } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } ) { - Div( + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field__ripple") } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Firstname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(firstNameTextFieldState) - onInput { - firstNameTextFieldState = it.value - } - } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( + ) { } + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Firstname") } + Input( + type = InputType.Text ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Lastname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(lastNameTextFieldState) - onInput { - lastNameTextFieldState = it.value - } - } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } + classes("mdc-text-field__input") + value(firstNameTextFieldState) + onInput { + firstNameTextFieldState = it.value } } - Div( + Span( attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Email") } - EmailInput(value = emailTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - emailTextFieldState = it.value - - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } + classes("mdc-line-ripple") } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - Div( + ) { + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Lastname") } + Input( + type = InputType.Text ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } + classes("mdc-text-field__input") + value(lastNameTextFieldState) + onInput { + lastNameTextFieldState = it.value } } - Div( + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-line-ripple") } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - // -- Register Request Management -- - when (viewState) { - is UiState.Success<*> -> { - onChangeToLogin() + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { Text("Email") } + EmailInput(value = emailTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + emailTextFieldState = it.value + + } + }) + Span( + attrs = { + classes("mdc-line-ripple") } - else -> {} + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Password") } + PasswordInput(value = passwordTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + passwordTextFieldState = it.value + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + // -- Register Request Management -- + when (viewState) { + is UiState.Success<*> -> { + onChangeToLogin() + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + else -> {} + } } } } \ No newline at end of file diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt index 30b8488d..e9dcf578 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt @@ -64,155 +64,148 @@ fun SettingsChangeUserDataView( }) MainFlexContainer { - Div( - attrs = { - classes("mdc-card", AppStylesheet.card) + H1 { Text("Change User Data") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$firstNameTextFieldState, $lastNameTextFieldState, $passwordTextFieldState") + onChangeDataButtonPressed( + firstNameTextFieldState, + lastNameTextFieldState, + passwordTextFieldState + ) + it.preventDefault() } + } ) { - - H1 { Text("Change User Data") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$firstNameTextFieldState, $lastNameTextFieldState, $passwordTextFieldState") - onChangeDataButtonPressed( - firstNameTextFieldState, - lastNameTextFieldState, - passwordTextFieldState - ) - it.preventDefault() + Div( + attrs = { + classes(AppStylesheet.margin) } - } ) { - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Firstname") } + Input( + type = InputType.Text ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Firstname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(firstNameTextFieldState) - onInput { - firstNameTextFieldState = it.value - } + classes("mdc-text-field__input") + value(firstNameTextFieldState) + onInput { + firstNameTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Lastname") } + Input( + type = InputType.Text ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Lastname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(lastNameTextFieldState) - onInput { - lastNameTextFieldState = it.value - } + classes("mdc-text-field__input") + value(lastNameTextFieldState) + onInput { + lastNameTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Password") } + PasswordInput(value = passwordTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + passwordTextFieldState = it.value } - ) { } - } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) } - Div( + ) { + SubmitInput( attrs = { - classes(AppStylesheet.margin) - } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) } - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt index 8a9b0225..94e3eab8 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt @@ -64,61 +64,56 @@ fun SettingsView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) + H1( + attrs = { + style { marginLeft(2.percent) } + } + ) { Text("Settings") } + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } } - ) { - H1( - attrs = { - style { marginLeft(2.percent) } - } - ) { Text("Settings") } - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) } - Div( + ) { + Button( attrs = { - classes(AppStylesheet.margin, AppStylesheet.flexContainer) + classes("mdc-button", "mdc-button--raised") + onClick { onChangeButtonPressed() } + style { flex(100.percent) } } ) { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onChangeButtonPressed() } - style { flex(100.percent) } - } - ) { - Text("Change Userdata") - } + Text("Change Userdata") + } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) } - Div( + ) { + Button( attrs = { - classes(AppStylesheet.margin, AppStylesheet.flexContainer) - } - ) { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { - deleteDialog = true - } - style { flex(100.percent) } + classes("mdc-button", "mdc-button--raised") + onClick { + deleteDialog = true } - ) { - Text("Delete User") + style { flex(100.percent) } } + ) { + Text("Delete User") } } - if (deleteDialog) { - DeleteDialog(false, {onDeleteButtonPressed()}, {deleteDialog = false}) { Text("Delete User?") } - } + } + if (deleteDialog) { + DeleteDialog(false, { onDeleteButtonPressed() }, { deleteDialog = false }) { Text("Delete User?") } } } From 6c0c402db5143bf89ee6cf9a8db24bfd658e607a Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sat, 18 Jun 2022 18:52:51 +0200 Subject: [PATCH 046/325] Delete unused Imports --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt | 2 -- .../de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt | 4 ---- 2 files changed, 6 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 895c49ca..4e032ff7 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -3,12 +3,10 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.image import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType import org.jetbrains.compose.web.attributes.type -import org.jetbrains.compose.web.attributes.value import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 1495873d..691b2bb5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -4,13 +4,9 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.* import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.id -import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.* -import org.jetbrains.compose.web.attributes.AutoComplete.Companion.off -import org.jetbrains.compose.web.attributes.AutoComplete.Companion.on import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Path From 936cf8e3370a5d0b9682e97b069c867c29779126 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 18:53:46 +0200 Subject: [PATCH 047/325] Fetch the right entry data when loading EntryEdit:Screen --- .../de/hsfl/budgetBinder/presentation/Screen.kt | 2 +- .../budgetBinder/compose/entry/EntryComponent.kt | 13 ++++++++----- .../budgetBinder/compose/entry/EntryOverviewView.kt | 6 +++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index cd863bba..d0fb7670 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -12,7 +12,7 @@ sealed class Screen { object CategoryCreate : Screen() object CategoryCreateOnRegister : Screen() data class EntryOverview (val id: Int) : Screen() - object EntryEdit : Screen() + data class EntryEdit (val id: Int): Screen() object EntryCreate : Screen() } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 05d81f23..1fae10a2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -41,7 +41,7 @@ fun EntryComponent(screenState: MutableState) { is Screen.EntryOverview -> { EntryOverviewView( state = viewState, - onEditButton = {screenState.value = Screen.EntryEdit}, + onEditButton = {id -> screenState.value = Screen.EntryEdit(id)}, onDeleteButton = { id -> entryViewModel.removeEntry(id) }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, @@ -54,10 +54,13 @@ fun EntryComponent(screenState: MutableState) { onBackButton = { screenState.value = Screen.Dashboard }, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate } ) - Screen.EntryEdit -> EntryEditView( - state = viewState, - onBackButton = { screenState.value = Screen.Dashboard } - ) + is Screen.EntryEdit -> { + EntryEditView( + state = viewState, + onBackButton = { screenState.value = Screen.Dashboard } + ) + entryViewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) + } else -> {} } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index 861308b2..dbf22003 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -19,7 +19,7 @@ import org.jetbrains.compose.web.svg.Svg @Composable fun EntryOverviewView( state: State, - onEditButton: () -> Unit, + onEditButton: (id: Int) -> Unit, onDeleteButton: (id: Int) -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, @@ -101,7 +101,7 @@ fun EntryOverviewView( @Composable fun EntryOverview( entry: Entry, - onEditButton: () -> Unit, + onEditButton: (Int) -> Unit, onDeleteButton: (Int) -> Unit ) { var deleteDialog by remember { mutableStateOf(false) } @@ -133,7 +133,7 @@ fun EntryOverview( ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton() } + onClick { onEditButton(entry.id) } style { flex(50.percent) margin(1.5.percent) From a9c4199c3f759367bf58e207f956b88c4f93cedc Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 18:56:08 +0200 Subject: [PATCH 048/325] Go back to Dashboard when deleting an entry --- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 1fae10a2..7f201524 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -42,7 +42,9 @@ fun EntryComponent(screenState: MutableState) { EntryOverviewView( state = viewState, onEditButton = {id -> screenState.value = Screen.EntryEdit(id)}, - onDeleteButton = { id -> entryViewModel.removeEntry(id) }, + onDeleteButton = { id -> + entryViewModel.removeEntry(id) + screenState.value = Screen.Dashboard}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, From c47977fa45039d4e17fa1b9b1e563bc016ad04fd Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sat, 18 Jun 2022 21:55:41 +0200 Subject: [PATCH 049/325] add is to all screens --- .../src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 42cecb0d..99039343 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -17,8 +17,8 @@ fun Router(screenState: MutableState) { is Screen.Register -> RegisterComponent(screenState = screenState) is Screen.Login -> LoginComponent(screenState = screenState) is Screen.Dashboard -> DashboardComponent(screenState = screenState) - is Screen.Settings, Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - is Screen.CategorySummary,Screen.CategoryEdit,Screen.CategoryCreate, Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) + is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) + is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) } } From 3c7d3c772cf59165f90929a0b6bfcd1341d5d7cd Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sat, 18 Jun 2022 21:59:14 +0200 Subject: [PATCH 050/325] Add EntryOverviewView.kt --- .../compose/entry/EntryOverviewView.kt | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt new file mode 100644 index 00000000..dbf22003 --- /dev/null +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -0,0 +1,164 @@ +package de.hsfl.budgetBinder.compose.entry + +import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.CategoryList +import de.hsfl.budgetBinder.compose.DeleteDialog +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import de.hsfl.budgetBinder.presentation.UiState +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Circle +import org.jetbrains.compose.web.svg.Svg + + +@Composable +fun EntryOverviewView( + state: State, + onEditButton: (id: Int) -> Unit, + onDeleteButton: (id: Int) -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToCategory: () -> Unit, + onChangeToSettings: () -> Unit +) { + var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } + val viewState by remember { state } + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } + } + }) + + MainFlexContainer { + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Entry") } + + EntryOverview(entry, onEditButton, onDeleteButton) + } + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is Entry -> entry = element + else -> {} + } + + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } +} + +@Composable +fun EntryOverview( + entry: Entry, + onEditButton: (Int) -> Unit, + onDeleteButton: (Int) -> Unit +) { + var deleteDialog by remember { mutableStateOf(false) } + Div( + attrs = { + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) + } + ) { + + Div( + attrs = { + classes(AppStylesheet.categoryListElementText) + } + ) { + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(entry.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Amount: ${entry.amount}€") } + } + } + } + Div( + attrs = { + classes(AppStylesheet.flexContainer) + } + ) { + Button(attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + onClick { onEditButton(entry.id) } + style { + flex(50.percent) + margin(1.5.percent) + } + }) { + Text("Edit Entry") + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { deleteDialog = true } + style { + flex(50.percent) + margin(1.5.percent) + backgroundColor(Color("#b00020")) + } + }) { + Text("Delete Entry") + } + } + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton(entry.id) }, + { deleteDialog = false }) { Text("Delete Entry?") } + } +} + + From 7fdd49c681346230cf5a0490e710d8b806f9119b Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sun, 19 Jun 2022 14:33:14 +0200 Subject: [PATCH 051/325] Fix delete Category --- .../de/hsfl/budgetBinder/presentation/Screen.kt | 2 +- .../de/hsfl/budgetBinder/compose/Composables.kt | 13 +++---------- .../compose/category/CategoryComponent.kt | 10 +++++----- .../compose/category/CategoryEditView.kt | 5 +++-- .../compose/category/CategorySummaryView.kt | 11 +++++++++-- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 25833552..3653b6d3 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -10,7 +10,7 @@ sealed class Screen { object Settings : Screen() object SettingsChangeUserData : Screen() object CategorySummary : Screen() - object CategoryEdit : Screen() + data class CategoryEdit (val id: Int) : Screen() object CategoryCreate : Screen() object CategoryCreateOnRegister : Screen() data class EntryOverview (val id: Int) : Screen() diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index f6d9c328..a5520d69 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -179,10 +179,9 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { @Composable fun CategoryList( categoryList: List, - onEditButton: () -> Unit, + onEditButton: (Int) -> Unit, onDeleteButton: (Int) -> Unit ) { - var deleteDialog by remember { mutableStateOf(false) } Div { for (category in categoryList) Div(attrs = { @@ -233,7 +232,7 @@ fun CategoryList( ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton() } + onClick { onEditButton(category.id) } style { flex(50.percent) margin(1.5.percent) @@ -243,7 +242,7 @@ fun CategoryList( } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { deleteDialog = true } + onClick { onDeleteButton(category.id) } style { flex(50.percent) margin(1.5.percent) @@ -253,12 +252,6 @@ fun CategoryList( Text("Delete Category") } } - if (deleteDialog) { - DeleteDialog( - false, - { onDeleteButton(category.id) }, - { deleteDialog = false }) { Text("Delete Category?") } - } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 1331098c..4b29065c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -43,7 +43,7 @@ fun CategoryComponent(screenState: MutableState) { val viewState = categoryViewModel.state.collectAsState(scope) when (screenState.value) { - Screen.CategoryCreate -> CategoryCreateView( + is Screen.CategoryCreate -> CategoryCreateView( state = viewState, onCreateCategoryButtonPressed = { name, color, image, budget -> categoryViewModel.createCategory(Category.In(name, color.drop(1), image, budget)) }, @@ -51,20 +51,20 @@ fun CategoryComponent(screenState: MutableState) { onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - Screen.CategorySummary -> CategorySummaryView( + is Screen.CategorySummary -> CategorySummaryView( state = viewState, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, - onEditButton = { screenState.value = Screen.CategoryEdit}, + onEditButton = { id -> screenState.value = Screen.CategoryEdit(id)}, onDeleteButton = {id -> categoryViewModel.removeCategory(id)}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - Screen.CategoryEdit -> CategoryEditView( + is Screen.CategoryEdit -> CategoryEditView( state = viewState, onBackButton = { screenState.value = Screen.CategorySummary } ) - Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( + is Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( state = viewState, onFinishedButton = { screenState.value = Screen.Dashboard diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt index 892e8511..d2a714f3 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt @@ -14,11 +14,12 @@ fun CategoryEditView( onBackButton: () -> Unit ) { val viewState by remember { state } - H1{Text("CategoryEditView")} + H1{Text("Edit Category")} + console.log() Div { when (viewState) { is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + //Text((viewState as UiState.Success<*>).element.toString()) } is UiState.Error -> { Text((viewState as UiState.Error).error) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 8bd83a2a..4cd5c9a4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -17,12 +17,13 @@ import org.jetbrains.compose.web.dom.* fun CategorySummaryView( state: State, onCategoryCreateButton: () -> Unit, - onEditButton: () -> Unit, + onEditButton: (id: Int) -> Unit, onDeleteButton: (id: Int) -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -78,7 +79,13 @@ fun CategorySummaryView( }) { Text("Create Category") } - CategoryList(categoryList, onEditButton, onDeleteButton) + CategoryList(categoryList, {id -> onEditButton(id)}, {id -> onDeleteButton(id)}) + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton }, + { deleteDialog = false }) { Text("Delete Category?") } + } Div { when (viewState) { is UiState.Success<*> -> { From 0595f088ebdf294ee36472d813c1ba357029367e Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sun, 19 Jun 2022 15:02:15 +0200 Subject: [PATCH 052/325] Fix openDialog on delete Category --- .../de/hsfl/budgetBinder/compose/Composables.kt | 11 ++++++++++- .../compose/category/CategorySummaryView.kt | 8 +------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index a5520d69..bea80e8b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -182,7 +182,16 @@ fun CategoryList( onEditButton: (Int) -> Unit, onDeleteButton: (Int) -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } + var id by remember { mutableStateOf(0) } + Div { + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton(id) }, + { deleteDialog = false }) { Text("Delete Category?") } + } for (category in categoryList) Div(attrs = { classes("mdc-card", AppStylesheet.card) @@ -242,7 +251,7 @@ fun CategoryList( } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { onDeleteButton(category.id) } + onClick { deleteDialog = !deleteDialog; id = category.id } style { flex(50.percent) margin(1.5.percent) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 4cd5c9a4..7554dfe6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -23,7 +23,6 @@ fun CategorySummaryView( onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { - var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -80,12 +79,7 @@ fun CategorySummaryView( Text("Create Category") } CategoryList(categoryList, {id -> onEditButton(id)}, {id -> onDeleteButton(id)}) - if (deleteDialog) { - DeleteDialog( - false, - { onDeleteButton }, - { deleteDialog = false }) { Text("Delete Category?") } - } + Div { when (viewState) { is UiState.Success<*> -> { From b3aff9a9ae335c9432e130f1d61d24153bb8894c Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sun, 19 Jun 2022 19:12:43 +0200 Subject: [PATCH 053/325] Add form in edit category --- .../viewmodel/CategoryViewModel.kt | 4 - .../hsfl/budgetBinder/compose/Composables.kt | 11 +- .../compose/category/CategoryComponent.kt | 48 ++-- .../compose/category/CategoryCreateView.kt | 6 +- .../compose/category/CategoryEditView.kt | 262 ++++++++++++++++-- .../compose/category/CategorySummaryView.kt | 1 - 6 files changed, 284 insertions(+), 48 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt index 14ccdfe2..c8240a54 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt @@ -21,10 +21,6 @@ class CategoryViewModel( private val _state = MutableStateFlow(UiState.Empty) val state: StateFlow = _state - init { - getAllCategories() - } - fun getAllCategories() { getAllCategoriesUseCase.categories().onEach { when (it) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index bea80e8b..062be013 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -137,8 +137,11 @@ fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { @Composable -fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { - var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } +fun CategoryImagesToImageList( + inputImage: MutableState, + onClick: (Category.Image) -> Unit +) { + var highlightImage by remember { mutableStateOf(inputImage) } Div( attrs = { classes("mdc-card", AppStylesheet.card) @@ -157,14 +160,14 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { ) { Div( attrs = { - if (highlightImage == image) + if (highlightImage.value == image) classes( "mdc-image-list__image-aspect-container", "mdc-icon-button", "mdc-button--raised" ) else classes("mdc-image-list__image-aspect-container", "mdc-icon-button") - onClick { onClick(image); highlightImage = image } + onClick { onClick(image); highlightImage.value = image } } ) { CategoryImageToIcon(image) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 4b29065c..77435c08 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -12,7 +12,6 @@ import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob -import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* @@ -46,24 +45,38 @@ fun CategoryComponent(screenState: MutableState) { is Screen.CategoryCreate -> CategoryCreateView( state = viewState, onCreateCategoryButtonPressed = { name, color, image, budget -> - categoryViewModel.createCategory(Category.In(name, color.drop(1), image, budget)) }, + categoryViewModel.createCategory(Category.In(name, color.drop(1), image, budget)) + screenState.value = Screen.CategorySummary }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - is Screen.CategorySummary -> CategorySummaryView( - state = viewState, - onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, - onEditButton = { id -> screenState.value = Screen.CategoryEdit(id)}, - onDeleteButton = {id -> categoryViewModel.removeCategory(id)}, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) - is Screen.CategoryEdit -> CategoryEditView( - state = viewState, - onBackButton = { screenState.value = Screen.CategorySummary } - ) + is Screen.CategorySummary -> { + CategorySummaryView( + state = viewState, + onCategoryCreateButton = { screenState.value = Screen.CategoryCreate }, + onEditButton = { id -> screenState.value = Screen.CategoryEdit(id) }, + onDeleteButton = { id -> categoryViewModel.removeCategory(id) }, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) + categoryViewModel.getAllCategories() + } + is Screen.CategoryEdit -> { + CategoryEditView( + state = viewState, + onEditCategoryButtonPressed = { name, color, image, budget -> + categoryViewModel.changeCategory( + Category.Patch(name, color.drop(1), image, budget), + (screenState.value as Screen.CategoryEdit).id + ); screenState.value = Screen.CategorySummary }, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) + categoryViewModel.getCategoryById((screenState.value as Screen.CategoryEdit).id) + } is Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( state = viewState, onFinishedButton = { @@ -94,7 +107,7 @@ fun BudgetBar(category: Category, entryList: List) { for (entry in entryList) { usedBudget -= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget } - H1(attrs={classes("mdc-typography--headline4", AppStylesheet.flexContainer)}) { + H1(attrs = { classes("mdc-typography--headline4", AppStylesheet.flexContainer) }) { CategoryImageToIcon(category.image) Text("${category.name} - Budget") } @@ -104,7 +117,8 @@ fun BudgetBar(category: Category, entryList: List) { //Money Text MoneyTextDiv { Div(attrs = { - classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€") } + classes("mdc-typography--headline5") + }) { Text(usedBudget.toString() + "€") } Div(attrs = { classes("mdc-typography--headline5") }) { Text(budget.toString() + "€") } } Svg(viewBox = "0 0 $width $height") { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index 07906da2..06af894f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -24,7 +24,7 @@ fun CategoryCreateView( ) { var categoryNameTextFieldState by remember { mutableStateOf("") } var categoryColorTextFieldState by remember { mutableStateOf("") } - var categoryImageState by remember { mutableStateOf(Category.Image.DEFAULT) } + var categoryImageState = remember { mutableStateOf(Category.Image.DEFAULT) } var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } @@ -79,7 +79,7 @@ fun CategoryCreateView( onCreateCategoryButtonPressed( categoryNameTextFieldState, categoryColorTextFieldState, - categoryImageState, + categoryImageState.value, categoryBudgetTextFieldState.toFloat() ) it.preventDefault() @@ -181,7 +181,7 @@ fun CategoryCreateView( style { marginBottom(1.percent); marginLeft(2.percent) } } ) { Text("Image") } - CategoryImagesToImageList(onClick = { categoryImageState = it }) + CategoryImagesToImageList(categoryImageState, onClick = { categoryImageState.value = it }) } } //Category Budget Input diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt index d2a714f3..900dda55 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt @@ -1,37 +1,261 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.CategoryImagesToImageList +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.min +import org.jetbrains.compose.web.attributes.required +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* @Composable fun CategoryEditView( state: State, - onBackButton: () -> Unit + onEditCategoryButtonPressed: (name: String, color: String, image: Category.Image, budget: Float) -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToCategory: () -> Unit, + onChangeToSettings: () -> Unit ) { + var category by remember { mutableStateOf(Category(0, "", "", Category.Image.DEFAULT, 0f)) } + var categoryNameTextFieldState by remember { mutableStateOf("") } + var categoryColorTextFieldState by remember { mutableStateOf("") } + var categoryImageState = remember { mutableStateOf(Category.Image.DEFAULT) } + var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("Edit Category")} - console.log() - Div { - when (viewState) { - is UiState.Success<*> -> { - //Text((viewState as UiState.Success<*>).element.toString()) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + }) + + MainFlexContainer { + H1(attrs = { style { margin(2.percent) } }) { Text("Edit Category") } + + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onEditCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState.value, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() } } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Category Overview") + ) { + //Category Name Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Category Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + required(true) + onInput { + categoryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Category Color Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Color") } + Input( + type = InputType.Color + ) { + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Category Image Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent) } + } + ) { Text("Image") } + CategoryImagesToImageList(categoryImageState, onClick = { categoryImageState.value = it }) + } + } + //Category Budget Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number + ) { + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + required(true) + min("1") + onInput { + categoryBudgetTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Submit button + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + + Div { + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is Category -> { + category = element + categoryNameTextFieldState = category.name + categoryColorTextFieldState = "#" + category.color + categoryImageState.value = category.image + categoryBudgetTextFieldState = category.budget.toString() + } + } + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 7554dfe6..af48f680 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -3,7 +3,6 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.CategoryList -import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain From dd7df028362fa4295c33f978290711a316518f80 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 20 Jun 2022 09:54:25 +0200 Subject: [PATCH 054/325] Add form in entryEdit and add categoryList in entryEdit and entryOverview --- .../hsfl/budgetBinder/presentation/Screen.kt | 4 +- .../hsfl/budgetBinder/compose/Composables.kt | 12 +- .../compose/dashboard/DashboardComponent.kt | 2 +- .../compose/dashboard/DashboardView.kt | 4 +- .../compose/entry/EntryComponent.kt | 39 ++- .../compose/entry/EntryEditView.kt | 286 ++++++++++++++++-- .../compose/entry/EntryOverviewView.kt | 20 +- 7 files changed, 312 insertions(+), 55 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 3653b6d3..ea4c95e2 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -13,8 +13,8 @@ sealed class Screen { data class CategoryEdit (val id: Int) : Screen() object CategoryCreate : Screen() object CategoryCreateOnRegister : Screen() - data class EntryOverview (val id: Int) : Screen() - data class EntryEdit (val id: Int): Screen() + data class EntryOverview (val id: Int, val categoryList :List) : Screen() + data class EntryEdit (val id: Int, val categoryList :List): Screen() data class EntryCreate (val categoryList :List): Screen() } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 062be013..a63f1e05 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -2,8 +2,10 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import de.hsfl.budgetBinder.presentation.Screen import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType import org.jetbrains.compose.web.attributes.type @@ -373,7 +375,7 @@ fun DeleteDialog(hidden: Boolean, buttonAction: () -> Unit, resetDialog: () -> U @Composable fun ChooseCategoryMenu( categoryList: List, - getCategoryId: (Int) -> Unit + getCategoryId: (Int?) -> Unit ) { var chosenCategory by remember { mutableStateOf(categoryList[0]) } var showList by remember { mutableStateOf(false) } @@ -400,14 +402,10 @@ fun ChooseCategoryMenu( Li(attrs = { classes("mdc-list-item") attr("role", "menuitem") - onClick { } + onClick { chosenCategory = category; getCategoryId(category.id) } }) { Span(attrs = { classes("mdc-list-item__ripple") }) { } - Span(attrs = { onClick { chosenCategory = category; getCategoryId(category.id) } }) { - Text( - category.name - ) - } + Span(attrs = { }) { Text(category.name) } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 6470f36b..2597603f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -25,6 +25,6 @@ fun DashboardComponent(screenState: MutableState) { onCategorySummaryButton = { screenState.value = Screen.CategorySummary}, onSettingsButton = {screenState.value = Screen.Settings}, onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, - onEntryOverviewButton = {id -> screenState.value = Screen.EntryOverview(id)} + onEntryOverviewButton = {id, categoryList -> screenState.value = Screen.EntryOverview(id, categoryList)} ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 81bc5863..4f5cae76 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -24,7 +24,7 @@ fun DashboardView( onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, onEntryCreateButton: (categoryList: List) -> Unit, - onEntryOverviewButton: (id:Int) -> Unit + onEntryOverviewButton: (id:Int, categoryList: List) -> Unit ) { val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } @@ -71,7 +71,7 @@ fun DashboardView( MainFlexContainer { - Div { DashboardData(categoryList, entryList, onEntryOverviewButton) } + Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id, categoryList) } } CreateNewEntryButton({ onEntryCreateButton(categoryList) }) //Process new Category Data when (categoriesViewState) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 58181bda..cd1c6197 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -41,34 +41,49 @@ fun EntryComponent(screenState: MutableState) { is Screen.EntryOverview -> { EntryOverviewView( state = viewState, - onEditButton = {id -> screenState.value = Screen.EntryEdit(id)}, + onEditButton = { id -> + screenState.value = Screen.EntryEdit(id, (screenState.value as Screen.EntryOverview).categoryList) + }, onDeleteButton = { id -> entryViewModel.removeEntry(id) - screenState.value = Screen.Dashboard}, + screenState.value = Screen.Dashboard + }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) entryViewModel.getEntryById((screenState.value as Screen.EntryOverview).id) } - is Screen.EntryCreate -> {EntryCreateView( - state = viewState, - categoryList = (screenState.value as Screen.EntryCreate).categoryList, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onCreateEntryButtonPressed = { name, amount, repeat, category_id -> - entryViewModel.createEntry(Entry.In(name, amount, repeat, category_id)) }, - onChangeToSettings = { screenState.value = Screen.Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) + is Screen.EntryCreate -> { + EntryCreateView( + state = viewState, + categoryList = (screenState.value as Screen.EntryCreate).categoryList, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onCreateEntryButtonPressed = { name, amount, repeat, category_id -> + entryViewModel.createEntry(Entry.In(name, amount, repeat, category_id)) + }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) } is Screen.EntryEdit -> { EntryEditView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard } + categoryList = (screenState.value as Screen.EntryEdit).categoryList, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onEditEntryButtonPressed = { name, amount, repeat, category -> + entryViewModel.changeEntry( + Entry.Patch(name, amount, repeat, category), + (screenState.value as Screen.EntryEdit).id + ) + }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) entryViewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) } + else -> {} } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 0aac23a6..8622874e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -1,36 +1,286 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.ChooseCategoryMenu +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.category.categoryIdToCategory +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.attributes.ButtonType +import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.required +import org.jetbrains.compose.web.attributes.type +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Path +import org.jetbrains.compose.web.svg.Svg +@OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryEditView( state: State, - onBackButton: () -> Unit + categoryList: List, + onChangeToDashboard: () -> Unit, + onChangeToSettings: () -> Unit, + onChangeToCategory: () -> Unit, + onEditEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category: Entry.Category) -> Unit, ) { + var entry by remember { mutableStateOf(Entry(0, "", 0f, false, 0)) } + var switchState by remember { mutableStateOf(false) } + var entryNameTextFieldState by remember { mutableStateOf("") } + var entryAmountTextFieldState by remember { mutableStateOf("") } + var entryRepeatState by remember { mutableStateOf("") } + var entryCategoryIDTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("EntryEditView")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + }) + + MainFlexContainer { + H1( + attrs = { + style { margin(2.percent) } } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { Text("Edit Entry") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$entryNameTextFieldState, $entryAmountTextFieldState, $entryRepeatState, ${entryCategoryIDTextFieldState.toInt()}") + onEditEntryButtonPressed( + entryNameTextFieldState, + (if (!switchState) "-$entryAmountTextFieldState" else entryAmountTextFieldState).toFloat(), + entryRepeatState.toBoolean(), + Entry.Category(entryCategoryIDTextFieldState.toInt()) + ) + it.preventDefault() } } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Dashboard") + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Entry Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(entryNameTextFieldState) + required(true) + onInput { + entryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Amount") } + Div { + Button( + attrs = { + if (!switchState) classes("mdc-switch", "mdc-switch--unselected") + else classes("mdc-switch", "mdc-switch--selected") + id("basic-switch") + attr("role", "switch") + attr("aria-checked", "false") + type(ButtonType.Button) + onClick { switchState = !switchState } + } + ) { + Div(attrs = { classes("mdc-switch__track") }) { } + Div(attrs = { classes("mdc-switch__handle-track") }) { + Div(attrs = { classes("mdc-switch__handle") }) { + Div(attrs = { classes("mdc-switch__shadow") }) { + Div(attrs = { classes("mdc-elevation-overlay") }) { } + } + Div(attrs = { classes("mdc-switch__ripple") }) { } + Div(attrs = { classes("mdc-switch__icons") }) { + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") + } + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M20 13H4v-2h16v2z") + } + } + } + } + } + } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { + Text(if (switchState) "+" else "-") + } + Input( + type = InputType.Number + ) { + attr("step", "0.01") + classes("mdc-text-field__input") + onInput { + entryAmountTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) + } + ) { + Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { classes("mdc-form-field") }) { + Div(attrs = { classes("mdc-checkbox") }) { + Input(type = InputType.Checkbox) + { + classes("mdc-checkbox__native-control") + id("checkbox-1") + onInput { + entryRepeatState = it.value.toString() + } + } + Div(attrs = { classes("mdc-checkbox__background") }) { + Svg(attrs = { classes("mdc-checkbox__checkmark") }, viewBox = "0 0 24 24") { + Path( + "M1.73,12.91 8.1,19.28 22.79,4.59", + attrs = { classes("mdc-checkbox__checkmark") }) + } + Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } + } + Div(attrs = { classes("mdc-checkbox__ripple") }) { } + } + Label(forId = "checkbox-1") { Text("repeat") } + } + } + Div(attrs = { style { flex(50.percent) } }) { + ChooseCategoryMenu(categoryList) { id -> entryCategoryIDTextFieldState = id.toString() } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is Entry -> { + entry = element + entryNameTextFieldState = entry.name + entryAmountTextFieldState = entry.amount.toString() + switchState = !entry.amount.toString().startsWith("-") + entryRepeatState = entry.repeat.toString() + entryCategoryIDTextFieldState = entry.category_id.toString() + } + } + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index dbf22003..1d79a64a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -25,7 +25,7 @@ fun EntryOverviewView( onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { - var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } + var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } val viewState by remember { state } topBarMain( @@ -68,25 +68,19 @@ fun EntryOverviewView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Entry") } + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Entry") } - EntryOverview(entry, onEditButton, onDeleteButton) - } + EntryOverview(entry, onEditButton, onDeleteButton) when (viewState) { is UiState.Success<*> -> { when (val element = (viewState as UiState.Success<*>).element) { is Entry -> entry = element else -> {} } - } is UiState.Error -> { Text((viewState as UiState.Error).error) From 406631e14c0771057e95dab46e5478d696a65453 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 19:53:43 +0200 Subject: [PATCH 055/325] Add Form in CategoryCreateView and Buttonlogic in CategoryComponent --- .../compose/category/CategoryComponent.kt | 7 +- .../compose/category/CategoryCreateView.kt | 250 ++++++++++++++++-- 2 files changed, 237 insertions(+), 20 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 5df06015..3354ce6d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.common.User import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel @@ -42,7 +43,11 @@ fun CategoryComponent(screenState: MutableState) { when (screenState.value) { Screen.CategoryCreate -> CategoryCreateView( state = viewState, - onBackButton = { screenState.value = Screen.CategorySummary} + onCreateCategoryButtonPressed = { name, color, image, budget -> + categoryViewModel.createCategory(Category.In(name, color.drop(1), image, budget)) }, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) Screen.CategorySummary -> CategorySummaryView( state = viewState, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index a889b22d..efb46c63 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -1,36 +1,248 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.CategoryImagesToImageList +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.css.marginBottom +import org.jetbrains.compose.web.css.marginLeft +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.dom.* @Composable fun CategoryCreateView( state: State, - onBackButton: () -> Unit + onCreateCategoryButtonPressed: (name: String, color: String, image: Category.Image, budget: Float) -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToSettings: () -> Unit, + onChangeToCategory: () -> Unit, ) { + var categoryNameTextFieldState by remember { mutableStateOf("") } + var categoryColorTextFieldState by remember { mutableStateOf("") } + var categoryImageState by remember { mutableStateOf(Category.Image.DEFAULT) } + var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("CategoryCreateView")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } + }) + + MainFlexContainer { + Div(attrs = { + classes("mdc-card", AppStylesheet.card) } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to To Category Overview") + ) { + H1 { Text("Create a new Category") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onCreateCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() + } + } + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Category Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + onInput { + categoryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(50.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Color") } + Input( + type = InputType.Color + ) { + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent)} + } + ) { Text("Image") } + CategoryImagesToImageList(onClick = {categoryImageState = it}) + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number + ) { + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + onInput { + categoryBudgetTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } + } } } } From 210a63025e91b3b198f0b0711c41cc35aa265141 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 19:54:11 +0200 Subject: [PATCH 056/325] Add ImageList as Composable --- .../hsfl/budgetBinder/compose/Composables.kt | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index d31dcabe..4060e9bf 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -1,32 +1,33 @@ package de.hsfl.budgetBinder.compose +import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* /*Main Container for every mayor layout*/ @Composable -fun MainFlexContainer(content: @Composable () -> Unit){ - Div ( +fun MainFlexContainer(content: @Composable () -> Unit) { + Div( attrs = { classes("mdc-top-app-bar--fixed-adjust", AppStylesheet.flexContainer) } - ){ - Div (attrs = { classes(AppStylesheet.pufferFlexContainer) }) - Div (attrs = { classes(AppStylesheet.contentFlexContainer)}) + ) { + Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) + Div(attrs = { classes(AppStylesheet.contentFlexContainer) }) { content() } - Div (attrs = { classes(AppStylesheet.pufferFlexContainer)}) + Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) } } @Composable -fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit){ +fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit) { Header( attrs = { classes("mdc-top-app-bar") @@ -61,3 +62,35 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } } } + +@Composable +fun CategoryImagesToImageList(onClick : (Category.Image) -> Unit) { + Div( + attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Ul( + attrs = { + classes("mdc-image-list", "my-image-list") + } + ) { + for (image in Category.Image.values()) { + Li( + attrs = { + classes("mdc-image-list__item") + } + ) { + Div( + attrs = { + classes("mdc-image-list__image-aspect-container", "mdc-icon-button") + onClick { onClick } + } + ) { + CategoryImageToIcon(image) + } + } + } + } + } +} From 14b09c88cc60abb3d0053cebaa5e98635dca9a28 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 20:52:09 +0200 Subject: [PATCH 057/325] Add highlight when image is chosen and button functionality in composable --- .../de/hsfl/budgetBinder/compose/Composables.kt | 13 ++++++++++--- .../compose/category/CategoryComponent.kt | 1 - .../compose/category/CategoryCreateView.kt | 5 +++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 4060e9bf..b2100a2c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -64,7 +64,8 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } @Composable -fun CategoryImagesToImageList(onClick : (Category.Image) -> Unit) { +fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { + var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } Div( attrs = { classes("mdc-card", AppStylesheet.card) @@ -83,8 +84,14 @@ fun CategoryImagesToImageList(onClick : (Category.Image) -> Unit) { ) { Div( attrs = { - classes("mdc-image-list__image-aspect-container", "mdc-icon-button") - onClick { onClick } + if (highlightImage == image) + classes( + "mdc-image-list__image-aspect-container", + "mdc-icon-button", + "mdc-button--raised" + ) + else classes("mdc-image-list__image-aspect-container", "mdc-icon-button") + onClick { onClick(image); highlightImage = image } } ) { CategoryImageToIcon(image) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 3354ce6d..b805ac39 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -4,7 +4,6 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY import de.hsfl.budgetBinder.common.Entry -import de.hsfl.budgetBinder.common.User import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index efb46c63..91566936 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -8,6 +8,8 @@ import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.min +import org.jetbrains.compose.web.attributes.required import org.jetbrains.compose.web.css.marginBottom import org.jetbrains.compose.web.css.marginLeft import org.jetbrains.compose.web.css.percent @@ -113,6 +115,7 @@ fun CategoryCreateView( ) { classes("mdc-text-field__input") value(categoryNameTextFieldState) + required(true) onInput { categoryNameTextFieldState = it.value } @@ -207,6 +210,8 @@ fun CategoryCreateView( ) { classes("mdc-text-field__input") value(categoryBudgetTextFieldState) + required(true) + min("1") onInput { categoryBudgetTextFieldState = it.value.toString() } From 3d4418c0c66fcfc31f224407500439dca9404997 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 20:57:34 +0200 Subject: [PATCH 058/325] Change width of color input from 50% to 100% --- .../de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index 91566936..a63d68e4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -135,7 +135,7 @@ fun CategoryCreateView( Label( attrs = { classes("mdc-text-field", "mdc-text-field--outlined") - style { width(50.percent) } + style { width(100.percent) } } ) { Span( From 19aafa40ea07d22af6a6678214ed97a49392c97b Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 16:53:40 +0200 Subject: [PATCH 059/325] Add TopBar and MainContainer to CategorySummaryView --- .../compose/category/CategoryComponent.kt | 3 + .../compose/category/CategorySummaryView.kt | 132 ++++++++++++++---- 2 files changed, 106 insertions(+), 29 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index b805ac39..3ae0c602 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -53,6 +53,9 @@ fun CategoryComponent(screenState: MutableState) { onBackButton = { screenState.value = Screen.Dashboard}, onEditButton = { screenState.value = Screen.CategoryEdit}, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) Screen.CategoryEdit -> CategoryEditView( state = viewState, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index a9cefeff..8c1116cb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -1,11 +1,15 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.css.margin +import org.jetbrains.compose.web.css.marginBottom +import org.jetbrains.compose.web.css.marginLeft +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.dom.* @Composable @@ -13,36 +17,106 @@ fun CategorySummaryView( state: State, onBackButton: () -> Unit, onEditButton: () -> Unit, - onCategoryCreateButton: () -> Unit + onCategoryCreateButton: () -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToCategory: () -> Unit, + onChangeToSettings: () -> Unit ) { val viewState by remember { state } - H1{Text("CategorySummaryView")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } + }) + + MainFlexContainer { + Div(attrs = { + classes("mdc-card", AppStylesheet.card) } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Dashboard") - } - Button(attrs = { - onClick { onEditButton() } - }) { - Text("Edit Category (Needs to be set for each category)") - } - Button(attrs = { - onClick { onCategoryCreateButton() } - }) { - Text("Create Category") + ) { + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Category Summary") } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onCategoryCreateButton() } + style { margin(2.percent) } + }) { + Text("Create Category") + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Text("Kat 1") + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onEditButton() } + }) { + Text("Edit Category (Needs to be set for each category)") + } + } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Text("Kat 2") + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onEditButton() } + }) { + Text("Edit Category (Needs to be set for each category)") + } + } + } } } } From 712ba7dcc7e207f3a86c36673a11c75b9b495890 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 13:15:37 +0200 Subject: [PATCH 060/325] Add CategoryList as Composable --- .../hsfl/budgetBinder/compose/Composables.kt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index b2100a2c..0eeeb7cf 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* @@ -101,3 +102,29 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { } } } + +@Composable +fun CategoryList(categoryList : List){ + Div { + console.log(categoryList.size) + for (category in categoryList) + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Text("${category.name}") + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { } + }) { + Text("Edit Category") + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { } + }) { + Text("Delete Category") + } + } + } +} From f64f5e4c179e66c9be2e66520be9324d2b3b82bb Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 13:16:31 +0200 Subject: [PATCH 061/325] Add getAllCategories() at init --- .../budgetBinder/presentation/viewmodel/CategoryViewModel.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt index 10e8a5e3..2358ee3c 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt @@ -16,6 +16,10 @@ class CategoryViewModel( private val _state = MutableStateFlow(UiState.Empty) val state: StateFlow = _state + init { + getAllCategories() + } + fun getAllCategories() { categoryUseCases.getAllCategoriesUseCase.categories().onEach { when (it) { From 9b1ecdcc7a18b68e788e86178dae72deef8783da Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 13:16:53 +0200 Subject: [PATCH 062/325] Delete unused Buttons --- .../de/hsfl/budgetBinder/compose/category/CategoryComponent.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 3ae0c602..93651236 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -50,8 +50,6 @@ fun CategoryComponent(screenState: MutableState) { ) Screen.CategorySummary -> CategorySummaryView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard}, - onEditButton = { screenState.value = Screen.CategoryEdit}, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, From 2566fac1487d200979e29ce46d79212dfddfea0d Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 13:18:06 +0200 Subject: [PATCH 063/325] Delete unused Buttons and add CategoryList() from Composables --- .../compose/category/CategorySummaryView.kt | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 8c1116cb..07758e1a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -1,13 +1,13 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.css.margin -import org.jetbrains.compose.web.css.marginBottom -import org.jetbrains.compose.web.css.marginLeft import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* @@ -15,13 +15,12 @@ import org.jetbrains.compose.web.dom.* @Composable fun CategorySummaryView( state: State, - onBackButton: () -> Unit, - onEditButton: () -> Unit, onCategoryCreateButton: () -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { + var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } topBarMain( @@ -80,10 +79,20 @@ fun CategorySummaryView( }) { Text("Create Category") } + CategoryList(categoryList) Div { when (viewState) { is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + when (val element = (viewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + categoryList = it + } + } + } + } } is UiState.Error -> { Text((viewState as UiState.Error).error) @@ -92,30 +101,6 @@ fun CategorySummaryView( //CircularProgressIndicator() } } - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - Text("Kat 1") - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onEditButton() } - }) { - Text("Edit Category (Needs to be set for each category)") - } - } - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - Text("Kat 2") - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onEditButton() } - }) { - Text("Edit Category (Needs to be set for each category)") - } - } } } } From 304c5d3bc91ce864f9908b022dfbc622824f809f Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:14:40 +0200 Subject: [PATCH 064/325] Add marginRight --- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index b498f7f6..6bb759f2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -60,7 +60,6 @@ object AppStylesheet : StyleSheet() { val card by style { margin(10.px) marginTop(25.px) - } val image by style { @@ -70,4 +69,8 @@ object AppStylesheet : StyleSheet() { val margin by style { margin(10.px) } + + val marginRight by style { + marginRight(1.percent) + } } \ No newline at end of file From 9a3ed899b33e8f688fa0938b2959198a10b5c8c9 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:15:26 +0200 Subject: [PATCH 065/325] Change display of categoryList to not showing --- .../de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index a63d68e4..22d8391a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -237,7 +237,7 @@ fun CategoryCreateView( Div { when (viewState) { is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + //Text((viewState as UiState.Success<*>).element.toString()) } is UiState.Error -> { Text((viewState as UiState.Error).error) From c7d7282fe7d7707711f8d8a84bfd14d064a3a5ae Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:15:48 +0200 Subject: [PATCH 066/325] Delete unused imports --- .../hsfl/budgetBinder/compose/category/CategorySummaryView.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 07758e1a..93799a7b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -2,11 +2,14 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain +import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState +import org.jetbrains.compose.web.css.flex import org.jetbrains.compose.web.css.margin import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* From c4bc325a78bda9af50e899b7bf82b3b260651ff3 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:16:51 +0200 Subject: [PATCH 067/325] Add color, image and budget for each displayed category --- .../hsfl/budgetBinder/compose/Composables.kt | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 0eeeb7cf..cd086600 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,10 +4,12 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Rect +import org.jetbrains.compose.web.svg.Svg /*Main Container for every mayor layout*/ @@ -103,27 +105,57 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { } } +@OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun CategoryList(categoryList : List){ +fun CategoryList(categoryList: List) { Div { console.log(categoryList.size) for (category in categoryList) Div(attrs = { - classes("mdc-card", AppStylesheet.card) + classes("mdc-card", AppStylesheet.card, AppStylesheet.flexContainer) } ) { - Text("${category.name}") - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { } - }) { - Text("Edit Category") + Div( + attrs = { + classes(AppStylesheet.margin) + style { flex(100.percent) } + } + ) { + Text("Name: ${category.name}") + Div(attrs = { style { width(3.percent) } }) { + Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in + Rect(x = 0, y = 0, width = 1, height = 1, { + attr("fill", "#${category.color}") + }) + } + } + Div { + Text("Image: ") + CategoryImageToIcon(category.image) + } + Text("Budget: ${category.budget}€") } - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { } - }) { - Text("Delete Category") + Div( + attrs = { + style { flex(100.percent) } + classes(AppStylesheet.flexContainer) + } + ) { + Div(attrs = { style { flex(75.percent) } }) { } + Button(attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + onClick { } + style { flex(25.percent)} + }) { + Text("Edit Category") + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { } + style { flex(25.percent) } + }) { + Text("Delete Category") + } } } } From 24e6ddb95aed15d23d7956cf324bca58d9ca3026 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Thu, 16 Jun 2022 16:21:46 +0200 Subject: [PATCH 068/325] Add DeleteDialog as composable and add Dialog on delete user in Settings --- .../hsfl/budgetBinder/compose/Composables.kt | 98 +++++++++++++++++++ .../compose/settings/SettingsView.kt | 9 +- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index cd086600..2d861cfe 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -5,6 +5,7 @@ import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* @@ -160,3 +161,100 @@ fun CategoryList(categoryList: List) { } } } + +@Composable +fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composable () -> Unit ){ + var hiddenValue by remember { mutableStateOf(hidden)} + Div( + attrs = { + when(hiddenValue){ + false -> classes("mdc-dialog", "mdc-dialog--open") + true -> classes("mdc-dialog") + } + } + ) { + Div( + attrs = { + classes("mdc-dialog__container") + } + ) { + Div( + attrs = { + classes("mdc-dialog__surface") + attr("role", "alertdialog") + attr("aria-modal", "true") + attr("aria-labelledby", "my-dialog-title") + attr("aria-describedby", "my-dialog-content") + } + ) { + Div( + attrs = { + classes("mdc-dialog__content") + id("my-dialog-content") + } + ) { + content() //Text in Dialog + } + Div( + attrs = { + classes("mdc-dialog__actions") + } + ) { + Button( + attrs = { + classes("mdc-button", "mdc-dialog__button") + attr("data-mdc-dialog-action", "cancel") + onClick { hiddenValue = true } + } + ) { + Div( + attrs = { + classes("mdc-button__ripple") + } + ) { + + } + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Cancel") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-dialog__button") + attr("data-mdc-dialog-action", "accept") + onClick { + buttonAction() + hiddenValue = true } + } + ) { + Div( + attrs = { + classes("mdc-button__ripple") + } + ) { + + } + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("OK") + } + } + } + } + } + Div( + attrs = { + classes("mdc-dialog__scrim") + } + ) { + + } + } +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt index 9583303b..6324485a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt @@ -1,6 +1,7 @@ package de.hsfl.budgetBinder.compose.settings import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet @@ -20,6 +21,7 @@ fun SettingsView( onDeleteButtonPressed: () -> Unit, onChangeButtonPressed: () -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } val viewState by remember { state } topBarMain( @@ -105,7 +107,9 @@ fun SettingsView( Button( attrs = { classes("mdc-button", "mdc-button--raised") - onClick { onDeleteButtonPressed() } + onClick { + deleteDialog = true + } style { flex(100.percent) } } ) { @@ -113,5 +117,8 @@ fun SettingsView( } } } + if (deleteDialog) { + DeleteDialog(false, {onDeleteButtonPressed}) { Text("Delete User?") } + } } } From f498d953bfbbe0de50e26af3c81964b93ecd8161 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Thu, 16 Jun 2022 16:39:46 +0200 Subject: [PATCH 069/325] Add DeleteDialog on delete Category --- .../hsfl/budgetBinder/compose/Composables.kt | 24 ++++++++++++------- .../compose/category/CategorySummaryView.kt | 7 +++++- .../compose/settings/SettingsView.kt | 2 +- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 2d861cfe..6b4011d2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -108,7 +108,10 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun CategoryList(categoryList: List) { +fun CategoryList( + categoryList: List, + onOpenDeleteDialog: () -> Unit, +) { Div { console.log(categoryList.size) for (category in categoryList) @@ -146,13 +149,13 @@ fun CategoryList(categoryList: List) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) onClick { } - style { flex(25.percent)} + style { flex(25.percent) } }) { Text("Edit Category") } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { } + onClick { onOpenDeleteDialog() } style { flex(25.percent) } }) { Text("Delete Category") @@ -163,11 +166,11 @@ fun CategoryList(categoryList: List) { } @Composable -fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composable () -> Unit ){ - var hiddenValue by remember { mutableStateOf(hidden)} +fun DeleteDialog(hidden: Boolean, buttonAction: () -> Unit, resetDialog: () -> Unit, content: @Composable () -> Unit) { + var hiddenValue by remember { mutableStateOf(hidden) } Div( attrs = { - when(hiddenValue){ + when (hiddenValue) { false -> classes("mdc-dialog", "mdc-dialog--open") true -> classes("mdc-dialog") } @@ -204,7 +207,10 @@ fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composabl attrs = { classes("mdc-button", "mdc-dialog__button") attr("data-mdc-dialog-action", "cancel") - onClick { hiddenValue = true } + onClick { + hiddenValue = true + resetDialog() + } } ) { Div( @@ -228,7 +234,9 @@ fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composabl attr("data-mdc-dialog-action", "accept") onClick { buttonAction() - hiddenValue = true } + hiddenValue = true + resetDialog() + } } ) { Div( diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 93799a7b..5e05c425 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.CategoryList +import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain @@ -23,6 +24,7 @@ fun CategorySummaryView( onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -82,7 +84,7 @@ fun CategorySummaryView( }) { Text("Create Category") } - CategoryList(categoryList) + CategoryList(categoryList, {deleteDialog = true}) Div { when (viewState) { is UiState.Success<*> -> { @@ -106,5 +108,8 @@ fun CategorySummaryView( } } } + if (deleteDialog) { + DeleteDialog(false, {}, {deleteDialog = false}) { Text("Delete User?") } + } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt index 6324485a..8a9b0225 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt @@ -118,7 +118,7 @@ fun SettingsView( } } if (deleteDialog) { - DeleteDialog(false, {onDeleteButtonPressed}) { Text("Delete User?") } + DeleteDialog(false, {onDeleteButtonPressed()}, {deleteDialog = false}) { Text("Delete User?") } } } } From 807bffa8c027e01a54adc2b8b4fb80463fcf0d5e Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Thu, 16 Jun 2022 18:49:47 +0200 Subject: [PATCH 070/325] Change how categories ard displayed --- .../hsfl/budgetBinder/compose/Composables.kt | 53 +++++++++++++------ .../compose/theme/AppStylesheet.kt | 21 +++++++- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 6b4011d2..d2de4d69 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -1,9 +1,11 @@ package de.hsfl.budgetBinder.compose +import App import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.style import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi @@ -113,50 +115,71 @@ fun CategoryList( onOpenDeleteDialog: () -> Unit, ) { Div { - console.log(categoryList.size) for (category in categoryList) Div(attrs = { - classes("mdc-card", AppStylesheet.card, AppStylesheet.flexContainer) + classes("mdc-card", AppStylesheet.card) } ) { Div( attrs = { - classes(AppStylesheet.margin) - style { flex(100.percent) } + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) } ) { - Text("Name: ${category.name}") - Div(attrs = { style { width(3.percent) } }) { + Div( + attrs = { + classes(AppStylesheet.imageFlexContainer) + } + ) { + CategoryImageToIcon(category.image) + } + Div( + attrs = { + classes(AppStylesheet.categoryListElementText) + } + ) { + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(category.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Budget: ${category.budget}€") } + } + } + Div(attrs = { + classes(AppStylesheet.imageFlexContainer) + } + ) { Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in Rect(x = 0, y = 0, width = 1, height = 1, { attr("fill", "#${category.color}") }) } } - Div { - Text("Image: ") - CategoryImageToIcon(category.image) - } - Text("Budget: ${category.budget}€") } Div( attrs = { - style { flex(100.percent) } classes(AppStylesheet.flexContainer) } ) { - Div(attrs = { style { flex(75.percent) } }) { } Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) onClick { } - style { flex(25.percent) } + style { + flex(50.percent) + margin(1.5.percent) + } }) { Text("Edit Category") } Button(attrs = { classes("mdc-button", "mdc-button--raised") onClick { onOpenDeleteDialog() } - style { flex(25.percent) } + style { + flex(50.percent) + margin(1.5.percent) + backgroundColor(Color("#b00020")) + } }) { Text("Delete Category") } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 6bb759f2..bf77d757 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -1,6 +1,7 @@ package de.hsfl.budgetBinder.compose.theme import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.css.keywords.auto import org.jetbrains.compose.web.css.selectors.CSSSelector /*All Information found about Stylesheets: @@ -52,9 +53,25 @@ object AppStylesheet : StyleSheet() { flex("50%") } - //EntryList - val entryListElement by style{ + val categoryListElement by style{ + flexDirection(FlexDirection("row")) + alignItems(AlignItems.Center) + margin(10.px) + marginTop(0.px) + } + + val categoryListElementText by style{ + flex("2 2 90%") + } + + val imageFlexContainer by style { + flex("0.1 0.1 5%") + height(auto) + } + val text by style{ + textAlign("center") + padding(10.px) } val card by style { From 6028331411be1a55dda6ff8daad6fde1b4a6c41d Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 17 Jun 2022 14:58:50 +0200 Subject: [PATCH 071/325] Change how a color of a category is displayed from rect to circle --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index d2de4d69..dee600fa 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -5,12 +5,14 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.attr import de.hsfl.budgetBinder.compose.theme.AppStylesheet.style import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Circle import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg @@ -151,7 +153,7 @@ fun CategoryList( } ) { Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in - Rect(x = 0, y = 0, width = 1, height = 1, { + Circle(cx = 0.5, cy = 0.5, r=0.5, { attr("fill", "#${category.color}") }) } From e37f43d7aa666d3fb50d6874ce2b50d5d24b3673 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 17 Jun 2022 16:04:49 +0200 Subject: [PATCH 072/325] Add edit and delete button functionality for categories summary --- .../de/hsfl/budgetBinder/compose/Composables.kt | 16 ++++++++-------- .../compose/category/CategoryComponent.kt | 2 ++ .../compose/category/CategorySummaryView.kt | 11 +++-------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index dee600fa..9d70fddd 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -1,19 +1,14 @@ package de.hsfl.budgetBinder.compose -import App import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.attr -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.style import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle -import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg @@ -114,8 +109,10 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { @Composable fun CategoryList( categoryList: List, - onOpenDeleteDialog: () -> Unit, + onEditButton: () -> Unit, + onDeleteButton: (Int) -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } Div { for (category in categoryList) Div(attrs = { @@ -166,7 +163,7 @@ fun CategoryList( ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { } + onClick { onEditButton() } style { flex(50.percent) margin(1.5.percent) @@ -176,7 +173,7 @@ fun CategoryList( } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { onOpenDeleteDialog() } + onClick { deleteDialog = true } style { flex(50.percent) margin(1.5.percent) @@ -186,6 +183,9 @@ fun CategoryList( Text("Delete Category") } } + if (deleteDialog) { + DeleteDialog(false, {onDeleteButton(category.id)}, {deleteDialog = false}) { Text("Delete Category?") } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 93651236..fb405137 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -51,6 +51,8 @@ fun CategoryComponent(screenState: MutableState) { Screen.CategorySummary -> CategorySummaryView( state = viewState, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, + onEditButton = { screenState.value = Screen.CategoryEdit}, + onDeleteButton = {id -> categoryViewModel.removeCategory(id)}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 5e05c425..2b704955 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -2,15 +2,12 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.css.flex import org.jetbrains.compose.web.css.margin import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* @@ -20,11 +17,12 @@ import org.jetbrains.compose.web.dom.* fun CategorySummaryView( state: State, onCategoryCreateButton: () -> Unit, + onEditButton: () -> Unit, + onDeleteButton: (id: Int) -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { - var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -84,7 +82,7 @@ fun CategorySummaryView( }) { Text("Create Category") } - CategoryList(categoryList, {deleteDialog = true}) + CategoryList(categoryList, onEditButton, onDeleteButton) Div { when (viewState) { is UiState.Success<*> -> { @@ -108,8 +106,5 @@ fun CategorySummaryView( } } } - if (deleteDialog) { - DeleteDialog(false, {}, {deleteDialog = false}) { Text("Delete User?") } - } } } From fa397677ddee539a9a8f3d0859ac71face9220aa Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:14:52 +0200 Subject: [PATCH 073/325] Add function to get all entries that belong to a category_id --- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 2e78928f..49622ba2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -63,4 +63,7 @@ fun EntryList(list: List, categoryList : List){ for (entry in list){ EntryListElement(entry,categoryList) } -} \ No newline at end of file +} + +fun entriesFromCategory(list: List, category_id: Int?):List = + list.filter { it.category_id == category_id } \ No newline at end of file From 0ebabd441a1edd01826255df4f8baf6115b088ca Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:22:26 +0200 Subject: [PATCH 074/325] Rework Dashboard Logic, add logic to switch to different categories --- .../compose/dashboard/DashboardView.kt | 136 ++++++++++++++++-- 1 file changed, 121 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 9d91d87e..2fc01241 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -3,14 +3,15 @@ package de.hsfl.budgetBinder.compose.dashboard import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry -import de.hsfl.budgetBinder.compose.category.Bar +import de.hsfl.budgetBinder.compose.Icon +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.category.BudgetBar import de.hsfl.budgetBinder.compose.entry.EntryList +import de.hsfl.budgetBinder.compose.entry.entriesFromCategory +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text -import kotlin.math.log +import kotlinx.serialization.json.JsonNull.content +import org.jetbrains.compose.web.dom.* @Composable @@ -25,10 +26,9 @@ fun DashboardView( val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } var categoryList by remember { mutableStateOf>(emptyList()) } - var entryList by remember { mutableStateOf>(emptyList()) } - Div { + MainFlexContainer { H1 { Text("DashboardView") } Button(attrs = { onClick { onSettingsButton() } @@ -50,9 +50,10 @@ fun DashboardView( }) { Text("Edit Entry (Needs to be there for every Entry shown)") } - } - Div { - UpdateDashboardData(categoryList, entryList) + Div { + DashboardData(categoryList, entryList) + } + CreateNewEntryButton(onEntryCreateButton) } //Process new Category Data when (categoriesViewState) { @@ -100,13 +101,118 @@ fun DashboardView( //CircularProgressIndicator() } } + + } @Composable -fun UpdateDashboardData(categoryList: List, entryList: List) { +fun DashboardData(categoryList: List, entryList: List) { console.log("Category $categoryList and Entry $entryList") - if (categoryList.isNotEmpty() && entryList.isNotEmpty()) { - Bar(categoryList[0], entryList) //Bar for first Category, needs to be changed later - EntryList(entryList, categoryList) + var focusedCategory by remember { mutableStateOf(-1) } //Variable from -1 (all) to categoryList.size + console.log("Focus:${focusedCategory}") + fun changeFocusedCategory(increase: Boolean): Int { + var newFocus = focusedCategory + if (increase) newFocus++ + else newFocus-- + newFocus = + when { + (newFocus) < -1 -> -1 + (newFocus > categoryList.size) -> categoryList.size + else -> { + newFocus + } + } + return newFocus + } + + if (entryList.isNotEmpty()) { + when (focusedCategory) { + //Overall View + -1 -> { + var everyBudgetTogether = 0f + for (category in categoryList) { + everyBudgetTogether += category.budget + } + val fakeOverallBudget = + Category(0, "Overall", "111111", Category.Image.DEFAULT, everyBudgetTogether) + SwipeContainer ( + content = {BudgetBar(fakeOverallBudget, entryList)}, //Every CategoryBudget with every Entry's Budget + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + ) + + EntryList(entryList, categoryList) //List of Every Entry + } + //Normal Category View + in categoryList.indices -> { + val filteredEntryList = + entriesFromCategory(entryList, categoryList[focusedCategory].id) + SwipeContainer ( + content = {BudgetBar(categoryList[focusedCategory], filteredEntryList)}, //Every Category with their Entries' Budget + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + ) + EntryList( + filteredEntryList, + listOf(categoryList[focusedCategory]) + ) //Only gives CategoryData of selected category, as everything else seems unnecessary + } + + //No Category View + categoryList.size -> { + val filteredEntryList = entriesFromCategory(entryList, null) + val fakeNoCategory = + Category(0, "No Category", "111111", Category.Image.DEFAULT, 0f) + SwipeContainer ( + content = {BudgetBar(fakeNoCategory, filteredEntryList)}, //"No Category" with their Entries' Budget + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + ) + EntryList( + filteredEntryList, + emptyList() + ) //Needs no categoryList, as they have no category + } + } + } else { + //TODO: Show something like: NO DATA TO SHOW! + } + +} + + +@Composable +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { + Button(attrs = { + onClick { onEntryCreateButton() } + }) { + Text("Create Entry") + } +} + +@Composable +fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Boolean) -> Unit) { + Div( + attrs = { + classes(AppStylesheet.flexContainer) + }) { + Div(attrs = { + classes(AppStylesheet.arrowFlexContainer) + onClick{onFocusCategoryChange(false)} + }){ + Icon("arrow_back_ios_new") + } + Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) + { + content() + } + Div(attrs = { + classes(AppStylesheet.arrowFlexContainer) + onClick{onFocusCategoryChange(true)} + }) { + Icon("arrow_forward_ios_new") + } } } + + + + + From 5c50bb4ec08d5ccfddc8a2876548ed7eb4b65f2b Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:23:00 +0200 Subject: [PATCH 075/325] Add general Icon function to get an function with the namestring --- .../de/hsfl/budgetBinder/compose/Composables.kt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 9d70fddd..ff59ec39 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,8 +4,6 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle @@ -25,7 +23,7 @@ fun MainFlexContainer(content: @Composable () -> Unit) { { content() } - Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) + Div(attrs = { classes(AppStylesheet.pufferFlexContainer)}) } } @@ -66,6 +64,18 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } } +@Composable +fun Icon (icon_name: String){ + Span( + attrs = { + classes("material-icons") + style { + width(24.px) + height(24.px) } + } + ) {Text(icon_name)} +} + @Composable fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } From cc855feed0047dfabcb91b1f7729a20e16ce9419 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:23:39 +0200 Subject: [PATCH 076/325] Make slight style adjustments --- .../compose/category/CategoryComponent.kt | 11 +++++++---- .../hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 10 +++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index fb405137..1ae6b42c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -78,15 +78,18 @@ fun categoryIdToCategory(category_id: Int?,categoryList: List): Catego @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun Bar(category: Category, entryList: List){ +fun BudgetBar(category: Category, entryList: List){ + //category = Category we want to show + //entryList = List of entries //width and height are for aspect ratio - tries to fill out wherever its in, so its more like - val width = 200 - val height = 80 + val width = 20 + val height = 2 val budget = category.budget var usedBudget = 0f for (entry in entryList) { - usedBudget+= entry.amount + usedBudget-= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget } + H1{Text("${category.name} - Budget")} Div{ if (usedBudget < budget) { //Money Text diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index bf77d757..85caf44c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -37,6 +37,7 @@ object AppStylesheet : StyleSheet() { //Container for flex elements, used in MainFlexContainer val flexContainer by style { display(DisplayStyle.Flex) + justifyContent(JustifyContent.Center) } //Container for empty sides, used in MainFlexContainer val pufferFlexContainer by style { @@ -49,9 +50,16 @@ object AppStylesheet : StyleSheet() { } //Container for main content, used in MainFlexContainer val contentFlexContainer by style { - justifyContent(JustifyContent.Center) flex("50%") } + //Container for main content in BudgetBar + val budgetBarContainer by style { + flex("90%") + } + //Container for arrow in BudgetBar + val arrowFlexContainer by style { + flex("0.1 0.1 5%") + } val categoryListElement by style{ flexDirection(FlexDirection("row")) From 34939f5c03d28df0c43a957e4b3e2cafebb37015 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:30:38 +0200 Subject: [PATCH 077/325] Format dashboard category switch buttons --- .../de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 4 ++-- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 2fc01241..1b75ffd2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -194,7 +194,7 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool classes(AppStylesheet.flexContainer) }) { Div(attrs = { - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.arrowFlexContainer, "mdc-button") onClick{onFocusCategoryChange(false)} }){ Icon("arrow_back_ios_new") @@ -204,7 +204,7 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool content() } Div(attrs = { - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.arrowFlexContainer, "mdc-button") onClick{onFocusCategoryChange(true)} }) { Icon("arrow_forward_ios_new") diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 85caf44c..19d7a64c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -59,6 +59,7 @@ object AppStylesheet : StyleSheet() { //Container for arrow in BudgetBar val arrowFlexContainer by style { flex("0.1 0.1 5%") + height(auto) } val categoryListElement by style{ From 2c6f49141c65b0eadbbe66c6f34462ef6c256f1f Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 21:37:10 +0200 Subject: [PATCH 078/325] Add all cases to BudgetBar --- .../compose/category/CategoryComponent.kt | 75 +++++++++++-------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 1ae6b42c..f5270b1e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -11,6 +11,7 @@ import di import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob +import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* @@ -59,18 +60,20 @@ fun CategoryComponent(screenState: MutableState) { ) Screen.CategoryEdit -> CategoryEditView( state = viewState, - onBackButton = { screenState.value = Screen.CategorySummary} + onBackButton = { screenState.value = Screen.CategorySummary } ) Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( state = viewState, - onFinishedButton = { screenState.value = Screen.Dashboard} //Should go back to the previous Screen, which could be CategorySummary or EntryCreate. + onFinishedButton = { + screenState.value = Screen.Dashboard + } //Should go back to the previous Screen, which could be CategorySummary or EntryCreate. ) else -> {} } } -fun categoryIdToCategory(category_id: Int?,categoryList: List): Category { - for (category in categoryList){ +fun categoryIdToCategory(category_id: Int?, categoryList: List): Category { + for (category in categoryList) { if (category.id == category_id) return category } return DEFAULT_CATEGORY //If the category wasn't found (or is set to no category) return default @@ -78,7 +81,7 @@ fun categoryIdToCategory(category_id: Int?,categoryList: List): Catego @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun BudgetBar(category: Category, entryList: List){ +fun BudgetBar(category: Category, entryList: List) { //category = Category we want to show //entryList = List of entries //width and height are for aspect ratio - tries to fill out wherever its in, so its more like @@ -87,44 +90,56 @@ fun BudgetBar(category: Category, entryList: List){ val budget = category.budget var usedBudget = 0f for (entry in entryList) { - usedBudget-= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget + usedBudget -= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget } - H1{Text("${category.name} - Budget")} - Div{ - if (usedBudget < budget) { + H1 { Text("${category.name} - Budget") } + Div { + if (usedBudget <= budget && budget > 0) { //Normal not Spent Budget //Money Text - Div(attrs={style { - display(DisplayStyle.Flex) - justifyContent(JustifyContent("space-between")) - }}){ - Div{Text(usedBudget.toString()+"€")} - Div{Text(budget.toString()+"€")} + MoneyTextDiv { + Div { Text(usedBudget.toString() + "€") } + Div { Text(budget.toString() + "€") } } - //Bar - Svg(viewBox = "0 0 $width $height"){//For aspect ratio - tries to fill out wherever its in + Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { attr("fill", Color.lightgray.toString()) }) - Rect(x = 0, y = 0, width = usedBudget/budget*width, height = height, { - attr("fill", Color.darkred.toString()) + if (0 < usedBudget) // If there is used budget, draw it + Rect(x = 0, y = 0, width = usedBudget / budget * width, height = height, { + attr("fill", "#" + category.color) + }) + } + } else if (usedBudget > budget && budget > 0) { //Over Budget + MoneyTextDiv { + Div { Text("Budget limit for " + category.name + " reached! " + usedBudget.toString() + "€ of " + budget.toString() + "€ Budget spent") } + } + Svg(viewBox = "0 0 $width $height") { + Rect(x = 0, y = 0, width = width, height = height, { + attr("fill", "#b00020") }) } - } - else{ - //SpentBudget Text - Div(attrs={style { - display(DisplayStyle.Flex) - justifyContent(JustifyContent("center")) - }}){ - Div{Text("Budget limit for "+category.name+" reached! "+usedBudget.toString()+"€ of "+budget.toString()+"€ Budget spent")} + } else if (budget <= 0f) { //No Category View or other unpredictable case + MoneyTextDiv { + Div { Text(usedBudget.toString() + "€ without category spent") } } - //Bar - Svg(viewBox = "0 0 $width $height"){//For aspect ratio - tries to fill out wherever its in + Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { - attr("fill", Color.red.toString()) + attr("fill", "#" + category.color) }) } } } } +@Composable +fun MoneyTextDiv(content: @Composable () -> Unit) { + Div(attrs = { + style { + display(DisplayStyle.Flex) + justifyContent(JustifyContent("space-between")) + } + }) { + content() + } +} + From 012e545d5fa7e9949706bb337e565b4a2f050441 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 22:21:12 +0200 Subject: [PATCH 079/325] Don't show switch button when there is no other category in that direction. Add typography to BudgetBar's texts --- .../compose/category/CategoryComponent.kt | 10 ++--- .../compose/dashboard/DashboardView.kt | 42 +++++++++++++++---- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index f5270b1e..83b5c7e4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -92,13 +92,13 @@ fun BudgetBar(category: Category, entryList: List) { for (entry in entryList) { usedBudget -= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget } - H1 { Text("${category.name} - Budget") } + H1(attrs={classes("mdc-typography--headline4")}) { Text("${category.name} - Budget") } Div { if (usedBudget <= budget && budget > 0) { //Normal not Spent Budget //Money Text MoneyTextDiv { - Div { Text(usedBudget.toString() + "€") } - Div { Text(budget.toString() + "€") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(budget.toString() + "€") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { @@ -111,7 +111,7 @@ fun BudgetBar(category: Category, entryList: List) { } } else if (usedBudget > budget && budget > 0) { //Over Budget MoneyTextDiv { - Div { Text("Budget limit for " + category.name + " reached! " + usedBudget.toString() + "€ of " + budget.toString() + "€ Budget spent") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text("Budget limit for " + category.name + " reached! " + usedBudget.toString() + "€ of " + budget.toString() + "€ Budget spent") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { @@ -120,7 +120,7 @@ fun BudgetBar(category: Category, entryList: List) { } } else if (budget <= 0f) { //No Category View or other unpredictable case MoneyTextDiv { - Div { Text(usedBudget.toString() + "€ without category spent") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€ without category spent") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 1b75ffd2..3ebca113 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -11,6 +11,10 @@ import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState import kotlinx.serialization.json.JsonNull.content +import org.jetbrains.compose.web.css.paddingLeft +import org.jetbrains.compose.web.css.paddingRight +import org.jetbrains.compose.web.css.px +import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* @@ -137,7 +141,8 @@ fun DashboardData(categoryList: List, entryList: List) { Category(0, "Overall", "111111", Category.Image.DEFAULT, everyBudgetTogether) SwipeContainer ( content = {BudgetBar(fakeOverallBudget, entryList)}, //Every CategoryBudget with every Entry's Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)}, + leftOn = false ) EntryList(entryList, categoryList) //List of Every Entry @@ -163,7 +168,8 @@ fun DashboardData(categoryList: List, entryList: List) { Category(0, "No Category", "111111", Category.Image.DEFAULT, 0f) SwipeContainer ( content = {BudgetBar(fakeNoCategory, filteredEntryList)}, //"No Category" with their Entries' Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)}, + rightOn = false ) EntryList( filteredEntryList, @@ -188,26 +194,44 @@ fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { } @Composable -fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Boolean) -> Unit) { +fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Boolean) -> Unit, leftOn: Boolean = true, rightOn:Boolean = true) { Div( attrs = { classes(AppStylesheet.flexContainer) }) { Div(attrs = { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") - onClick{onFocusCategoryChange(false)} + if(leftOn) { + classes(AppStylesheet.arrowFlexContainer, "mdc-button") + onClick { onFocusCategoryChange(false) } + } + else{ + classes(AppStylesheet.arrowFlexContainer) + style{ + paddingLeft(8.px) + paddingRight(8.px) + } + } }){ - Icon("arrow_back_ios_new") + if(leftOn) Icon("arrow_back_ios_new") } Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) { content() } Div(attrs = { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") - onClick{onFocusCategoryChange(true)} + if(rightOn) { + classes(AppStylesheet.arrowFlexContainer, "mdc-button") + onClick { onFocusCategoryChange(true) } + } + else{ + classes(AppStylesheet.arrowFlexContainer) + style{ + paddingLeft(8.px) + paddingRight(8.px) + } + } }) { - Icon("arrow_forward_ios_new") + if(rightOn) Icon("arrow_forward_ios_new") } } } From 68f63d0dffd68fe2f9677d5291d651f6fb615c61 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 12:47:55 +0200 Subject: [PATCH 080/325] Add first form of style for entries on dashboard --- .../compose/dashboard/DashboardView.kt | 8 ++++---- .../budgetBinder/compose/entry/EntryComponent.kt | 12 +++++++----- .../budgetBinder/compose/theme/AppStylesheet.kt | 16 +++++++++++++++- .../budgetBinder/presentation/CategoryIcon.kt | 12 +++++++++--- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 3ebca113..f708b458 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -201,11 +201,11 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool }) { Div(attrs = { if(leftOn) { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") + classes(AppStylesheet.imageFlexContainer, "mdc-button") onClick { onFocusCategoryChange(false) } } else{ - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.imageFlexContainer) style{ paddingLeft(8.px) paddingRight(8.px) @@ -220,11 +220,11 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool } Div(attrs = { if(rightOn) { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") + classes(AppStylesheet.imageFlexContainer, "mdc-button") onClick { onFocusCategoryChange(true) } } else{ - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.imageFlexContainer) style{ paddingLeft(8.px) paddingRight(8.px) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 49622ba2..b10750ad 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.category.categoryIdToCategory +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen @@ -50,11 +51,12 @@ fun EntryComponent(screenState: MutableState) { //Should be put in own File @Composable fun EntryListElement(entry: Entry, categoryList : List){ - Div { + Div (attrs = { + classes("mdc-card","mdc-card--outlined", AppStylesheet.entryListElement) + }) { CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) - Text(entry.name) - Text(entry.amount.toString()+"€") - + Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} + Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.text) }){Text(entry.amount.toString()+"€")}} } } @@ -66,4 +68,4 @@ fun EntryList(list: List, categoryList : List){ } fun entriesFromCategory(list: List, category_id: Int?):List = - list.filter { it.category_id == category_id } \ No newline at end of file + list.filter { it.category_id == category_id } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 19d7a64c..54f6c6d6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -62,6 +62,20 @@ object AppStylesheet : StyleSheet() { height(auto) } + //EntryList + val entryListElement by style{ + flexDirection(FlexDirection("row")) + alignItems(AlignItems.Center) + margin(10.px) + marginTop(0.px) + } + val entryListElementText by style{ + flex("2 2 90%") + } + val text by style{ + textAlign("center") + padding(10.px) + } val categoryListElement by style{ flexDirection(FlexDirection("row")) alignItems(AlignItems.Center) @@ -99,4 +113,4 @@ object AppStylesheet : StyleSheet() { val marginRight by style { marginRight(1.percent) } -} \ No newline at end of file +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt index bedf3bb9..f84b6cb5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt @@ -2,14 +2,20 @@ package de.hsfl.budgetBinder.presentation import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import org.jetbrains.compose.web.css.padding +import org.jetbrains.compose.web.css.px +import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Span import org.jetbrains.compose.web.dom.Text @Composable actual fun CategoryImageToIcon(icon: Category.Image) { - Span( + Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){ + Span( attrs = { classes("material-icons") + style { padding(8.px) } } ) { Text( @@ -60,5 +66,5 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Category.Image.PEST -> "pest_control" } ) - } -} \ No newline at end of file + }} +} From 41ff48ce065dd680d4987b412ddc14ef6dc76984 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 14:47:17 +0200 Subject: [PATCH 081/325] Add first form of newEntry button style --- .../hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 7 +++++-- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 8 +++++++- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 6 ++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index f708b458..b9271e25 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -185,11 +185,14 @@ fun DashboardData(categoryList: List, entryList: List) { @Composable -fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { //TODO: endlich mal schön machen! Button(attrs = { + classes("mdc-fab","mdc-fab--touch") onClick { onEntryCreateButton() } }) { - Text("Create Entry") + Div(attrs= {classes("mdc-fab__ripple")} ) + Icon("add") + Div(attrs= {classes("mdc-fab__touch")} ) } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index b10750ad..9f6a0dc6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -17,6 +17,7 @@ import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Text import org.kodein.di.compose.localDI import org.kodein.di.instance +import kotlin.math.absoluteValue @Composable fun EntryComponent(screenState: MutableState) { @@ -56,9 +57,14 @@ fun EntryListElement(entry: Entry, categoryList : List){ }) { CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} - Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.text) }){Text(entry.amount.toString()+"€")}} + Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.moneyText) }){Text(amountToString(entry.amount))}} } } +fun amountToString(amount:Float):String{ + //This whole thing just so it's "- 10 €" and not "-10 €" + val x = if (amount < 0) "-" else "" + return "$x ${amount.absoluteValue} €" +} @Composable fun EntryList(list: List, categoryList : List){ diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 54f6c6d6..e4d4bdf1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -76,6 +76,12 @@ object AppStylesheet : StyleSheet() { textAlign("center") padding(10.px) } + val moneyText by style{ + textAlign("center") + padding(10.px) + whiteSpace("nowrap") + + } val categoryListElement by style{ flexDirection(FlexDirection("row")) alignItems(AlignItems.Center) From 0a0210df27d2059ec6a38cc39337f546057b3fa9 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 15:25:08 +0200 Subject: [PATCH 082/325] Fix position for newEntry button --- .../compose/dashboard/DashboardView.kt | 27 ++++++++++--------- .../compose/theme/AppStylesheet.kt | 7 ++++- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index b9271e25..90c43329 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -11,10 +11,8 @@ import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState import kotlinx.serialization.json.JsonNull.content -import org.jetbrains.compose.web.css.paddingLeft -import org.jetbrains.compose.web.css.paddingRight -import org.jetbrains.compose.web.css.px -import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.css.keywords.auto import org.jetbrains.compose.web.dom.* @@ -185,14 +183,19 @@ fun DashboardData(categoryList: List, entryList: List) { @Composable -fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { //TODO: endlich mal schön machen! - Button(attrs = { - classes("mdc-fab","mdc-fab--touch") - onClick { onEntryCreateButton() } - }) { - Div(attrs= {classes("mdc-fab__ripple")} ) - Icon("add") - Div(attrs= {classes("mdc-fab__touch")} ) +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { + Div (attrs = {style { + display(DisplayStyle.Flex) + justifyContent(JustifyContent.FlexEnd) + }}) { + Button(attrs = { + classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) + onClick { onEntryCreateButton() } + }) { + Div(attrs = { classes("mdc-fab__ripple") }) + Icon("add") + Div(attrs = { classes("mdc-fab__touch") }) + } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index e4d4bdf1..84f02957 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -51,6 +51,7 @@ object AppStylesheet : StyleSheet() { //Container for main content, used in MainFlexContainer val contentFlexContainer by style { flex("50%") + position(Position.Relative) } //Container for main content in BudgetBar val budgetBarContainer by style { @@ -80,7 +81,11 @@ object AppStylesheet : StyleSheet() { textAlign("center") padding(10.px) whiteSpace("nowrap") - + } + val newEntryButton by style{ + position(Position.Fixed) + bottom(16.px) + marginRight(20.px) } val categoryListElement by style{ flexDirection(FlexDirection("row")) From 88762007276255e290c6d302759c3c7440c7489b Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 15:47:58 +0200 Subject: [PATCH 083/325] Add topBar (change later!). Add newEntry-button click reference --- .../compose/dashboard/DashboardView.kt | 77 ++++++++++++------- .../compose/entry/EntryComponent.kt | 7 +- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 90c43329..19e8429f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -9,6 +9,7 @@ import de.hsfl.budgetBinder.compose.category.BudgetBar import de.hsfl.budgetBinder.compose.entry.EntryList import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.css.* @@ -23,38 +24,54 @@ fun DashboardView( onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, onEntryCreateButton: () -> Unit, - onEntryEditButton: () -> Unit + onEntryEditButton: (id:Int) -> Unit ) { val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } var categoryList by remember { mutableStateOf>(emptyList()) } var entryList by remember { mutableStateOf>(emptyList()) } + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onCategorySummaryButton() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onSettingsButton() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } + } + }) + MainFlexContainer { - H1 { Text("DashboardView") } - Button(attrs = { - onClick { onSettingsButton() } - }) { - Text("Open Settings") - } - Button(attrs = { - onClick { onCategorySummaryButton() } - }) { - Text("Open Category List (Summary of every Category)") - } - Button(attrs = { - onClick { onEntryCreateButton() } - }) { - Text("Create Entry") - } - Button(attrs = { - onClick { onEntryEditButton() } - }) { - Text("Edit Entry (Needs to be there for every Entry shown)") - } - Div { - DashboardData(categoryList, entryList) - } + Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) } //Process new Category Data @@ -108,7 +125,7 @@ fun DashboardView( } @Composable -fun DashboardData(categoryList: List, entryList: List) { +fun DashboardData(categoryList: List, entryList: List, onEntry: (id:Int) -> Unit) { console.log("Category $categoryList and Entry $entryList") var focusedCategory by remember { mutableStateOf(-1) } //Variable from -1 (all) to categoryList.size console.log("Focus:${focusedCategory}") @@ -143,7 +160,7 @@ fun DashboardData(categoryList: List, entryList: List) { leftOn = false ) - EntryList(entryList, categoryList) //List of Every Entry + EntryList(entryList, categoryList, onEntry) //List of Every Entry } //Normal Category View in categoryList.indices -> { @@ -155,7 +172,8 @@ fun DashboardData(categoryList: List, entryList: List) { ) EntryList( filteredEntryList, - listOf(categoryList[focusedCategory]) + listOf(categoryList[focusedCategory]), + onEntry ) //Only gives CategoryData of selected category, as everything else seems unnecessary } @@ -171,7 +189,8 @@ fun DashboardData(categoryList: List, entryList: List) { ) EntryList( filteredEntryList, - emptyList() + emptyList(), + onEntry ) //Needs no categoryList, as they have no category } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 9f6a0dc6..ace27eba 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -51,9 +51,10 @@ fun EntryComponent(screenState: MutableState) { //Should be put in own File @Composable -fun EntryListElement(entry: Entry, categoryList : List){ +fun EntryListElement(entry: Entry, categoryList : List, onEntry: (id:Int) -> Unit){ Div (attrs = { classes("mdc-card","mdc-card--outlined", AppStylesheet.entryListElement) + onClick { onEntry(entry.id) } }) { CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} @@ -67,9 +68,9 @@ fun amountToString(amount:Float):String{ } @Composable -fun EntryList(list: List, categoryList : List){ +fun EntryList(list: List, categoryList : List, onEntry: (id:Int) -> Unit){ for (entry in list){ - EntryListElement(entry,categoryList) + EntryListElement(entry,categoryList,onEntry) } } From 3f15ab69a08b83ce7f8b4706ebbc2805aca9e969 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 10:49:48 +0200 Subject: [PATCH 084/325] Format files --- .../compose/category/CategoryComponent.kt | 3 +- .../compose/entry/EntryComponent.kt | 39 +++++++++++++------ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 83b5c7e4..2a8412aa 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -97,7 +97,8 @@ fun BudgetBar(category: Category, entryList: List) { if (usedBudget <= budget && budget > 0) { //Normal not Spent Budget //Money Text MoneyTextDiv { - Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€") } + Div(attrs = { + classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€") } Div(attrs = { classes("mdc-typography--headline5") }) { Text(budget.toString() + "€") } } Svg(viewBox = "0 0 $width $height") { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index ace27eba..560f0308 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -43,7 +43,7 @@ fun EntryComponent(screenState: MutableState) { ) Screen.EntryEdit -> EntryEditView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard} + onBackButton = { screenState.value = Screen.Dashboard } ) else -> {} } @@ -51,28 +51,43 @@ fun EntryComponent(screenState: MutableState) { //Should be put in own File @Composable -fun EntryListElement(entry: Entry, categoryList : List, onEntry: (id:Int) -> Unit){ - Div (attrs = { - classes("mdc-card","mdc-card--outlined", AppStylesheet.entryListElement) +fun EntryListElement(entry: Entry, categoryList: List, onEntry: (id: Int) -> Unit) { + Div(attrs = { + classes("mdc-card", "mdc-card--outlined", AppStylesheet.entryListElement) onClick { onEntry(entry.id) } }) { - CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) - Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} - Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.moneyText) }){Text(amountToString(entry.amount))}} + CategoryImageToIcon(categoryIdToCategory(entry.category_id, categoryList).image) + Div(attrs = { classes(AppStylesheet.entryListElementText) }) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text(entry.name) } + } + Div(attrs = { classes(AppStylesheet.imageFlexContainer) }) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.moneyText + ) + }) { Text(amountToString(entry.amount)) } + } } } -fun amountToString(amount:Float):String{ + +fun amountToString(amount: Float): String { //This whole thing just so it's "- 10 €" and not "-10 €" val x = if (amount < 0) "-" else "" return "$x ${amount.absoluteValue} €" } @Composable -fun EntryList(list: List, categoryList : List, onEntry: (id:Int) -> Unit){ - for (entry in list){ - EntryListElement(entry,categoryList,onEntry) +fun EntryList(list: List, categoryList: List, onEntry: (id: Int) -> Unit) { + for (entry in list) { + EntryListElement(entry, categoryList, onEntry) } } -fun entriesFromCategory(list: List, category_id: Int?):List = +fun entriesFromCategory(list: List, category_id: Int?): List = list.filter { it.category_id == category_id } From 32bd4a925ba150a56f8a47171d86436506bf229f Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 11:54:28 +0200 Subject: [PATCH 085/325] Add first non-working version of snackbar-feedback --- .../hsfl/budgetBinder/compose/Composables.kt | 43 +++++++++++++++++-- .../compose/dashboard/DashboardView.kt | 4 +- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index ff59ec39..14291592 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -64,18 +64,55 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } } + +///* Gives a material icon based on the icon name*/// @Composable -fun Icon (icon_name: String){ +fun Icon(icon_name: String) { Span( attrs = { classes("material-icons") style { width(24.px) - height(24.px) } + height(24.px) + } + } + ) { Text(icon_name) } +} + + +// Snackbar that shows msg +@Composable +fun FeedbackSnackbar(msg: String) { + Aside(attrs = { classes("mdc-snackbar") }) { + Div(attrs = { + classes("mdc-snackbar__surface") + attr(attr = "role", value = "status") + attr(attr = "aria-relevant", value = "additions") + }) { + Div(attrs = { + classes("mdc-snackbar__label") + attr(attr = "aria-atomic", value = "false") + }) { + Text(msg) + } + Div(attrs = { + classes("mdc-snackbar__actions") + attr(attr = "aria-atomic", value = "true") + }) { + Button(attrs = { classes("mdc-button", "mdc-snackbar__action") }) { + Div(attrs = { + classes("mdc-button__ripple") + }) + Span(attrs = { classes("mdc-button__label") }) + { Text("Dismiss") } + } + } } - ) {Text(icon_name)} + } } + + @Composable fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 19e8429f..5d07678e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -3,6 +3,7 @@ package de.hsfl.budgetBinder.compose.dashboard import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.Icon import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.category.BudgetBar @@ -73,6 +74,7 @@ fun DashboardView( MainFlexContainer { Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) + FeedbackSnackbar("haha test") } //Process new Category Data when (categoriesViewState) { @@ -111,9 +113,9 @@ fun DashboardView( } } } - } is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) //TODO: make it work Text((entriesViewState as UiState.Error).error) } is UiState.Loading -> { From cb8daaf5caf559def6bf551b375be2ad2001f353 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 11:58:32 +0200 Subject: [PATCH 086/325] Give feedback when there are no entries to load --- .../compose/dashboard/DashboardView.kt | 7 ++++++- .../budgetBinder/compose/entry/EntryComponent.kt | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 5d07678e..1b817392 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -197,7 +197,12 @@ fun DashboardData(categoryList: List, entryList: List, onEntry: } } } else { - //TODO: Show something like: NO DATA TO SHOW! + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text("No data to load") } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 560f0308..e7d00bed 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -84,8 +84,18 @@ fun amountToString(amount: Float): String { @Composable fun EntryList(list: List, categoryList: List, onEntry: (id: Int) -> Unit) { - for (entry in list) { - EntryListElement(entry, categoryList, onEntry) + if (list.isEmpty()) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text("No Entries in this category") } + } + else { + for (entry in list) { + EntryListElement(entry, categoryList, onEntry) + } } } From 058f2e05ac0d85312587780e2afa3cd4a80e2113 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 12:05:19 +0200 Subject: [PATCH 087/325] Show BudgetBar when when there are no entries or categories --- .../hsfl/budgetBinder/compose/category/CategoryComponent.kt | 4 ++-- .../de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 2a8412aa..41ea647a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -119,9 +119,9 @@ fun BudgetBar(category: Category, entryList: List) { attr("fill", "#b00020") }) } - } else if (budget <= 0f) { //No Category View or other unpredictable case + } else if (budget <= 0f) { //No Category View or other unpredictable case (or no categories, overall screen) MoneyTextDiv { - Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€ without category spent") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€ spent") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 1b817392..3fffe916 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -146,7 +146,7 @@ fun DashboardData(categoryList: List, entryList: List, onEntry: return newFocus } - if (entryList.isNotEmpty()) { + //if (entryList.isNotEmpty()) { when (focusedCategory) { //Overall View -1 -> { @@ -196,14 +196,14 @@ fun DashboardData(categoryList: List, entryList: List, onEntry: ) //Needs no categoryList, as they have no category } } - } else { + /*} else { Div(attrs = { classes( "mdc-typography--headline5", AppStylesheet.text ) }) { Text("No data to load") } - } + }*/ } From 27a7b18775e12f1ebfc67031f74957e320ab18ac Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 15:02:43 +0200 Subject: [PATCH 088/325] Snackbar disappears when clicked on (this is a form of logic in view, may change later) --- .../hsfl/budgetBinder/compose/Composables.kt | 23 ++++++++++++++++--- .../compose/dashboard/DashboardView.kt | 3 +-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 14291592..8675ef06 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -82,12 +82,26 @@ fun Icon(icon_name: String) { // Snackbar that shows msg @Composable -fun FeedbackSnackbar(msg: String) { - Aside(attrs = { classes("mdc-snackbar") }) { +fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { + var hiddenValue by remember { mutableStateOf(hidden)} + Aside( + attrs = { + when(hiddenValue){ + false -> classes("mdc-snackbar","mdc-snackbar--open") + true -> classes("mdc-snackbar","maria") + } + onClick { + hiddenValue = true + console.log(this@Aside) + console.log("ldsadsad") + + } + }) { Div(attrs = { classes("mdc-snackbar__surface") attr(attr = "role", value = "status") attr(attr = "aria-relevant", value = "additions") + }) { Div(attrs = { classes("mdc-snackbar__label") @@ -99,7 +113,9 @@ fun FeedbackSnackbar(msg: String) { classes("mdc-snackbar__actions") attr(attr = "aria-atomic", value = "true") }) { - Button(attrs = { classes("mdc-button", "mdc-snackbar__action") }) { + Button(attrs = { + classes("mdc-button", "mdc-snackbar__action") + }) { Div(attrs = { classes("mdc-button__ripple") }) @@ -113,6 +129,7 @@ fun FeedbackSnackbar(msg: String) { + @Composable fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 3fffe916..7f30e6bc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -31,13 +31,12 @@ fun DashboardView( val entriesViewState by remember { entriesState } var categoryList by remember { mutableStateOf>(emptyList()) } var entryList by remember { mutableStateOf>(emptyList()) } - topBarMain( logoButton = { Img( src = "images/Logo.png", alt = "Logo", attrs = { classes("mdc-icon-button", AppStylesheet.image) - onClick { } + onClick { } } ) }, navButtons = { From 386a48c5d8d8f63a04c243b3854144243ee292ad Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 15:14:23 +0200 Subject: [PATCH 089/325] Use snackbar when there is an error UiState feedback --- .../compose/dashboard/DashboardView.kt | 77 +++++++++---------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 7f30e6bc..b7375d37 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -73,56 +73,55 @@ fun DashboardView( MainFlexContainer { Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) - FeedbackSnackbar("haha test") - } - //Process new Category Data - when (categoriesViewState) { - is UiState.Success<*> -> { - //Updates Data - // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot - when (val element = (categoriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - categoryList = it + //Process new Category Data + when (categoriesViewState) { + is UiState.Success<*> -> { + //Updates Data + // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot + when (val element = (categoriesViewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + categoryList = it + } } - } + } } } + is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } } - is UiState.Error -> { - Text((categoriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } - //Process new Entry Data - when (entriesViewState) { - is UiState.Success<*> -> { - //Updates Data - when (val element = (entriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - entryList = it + //Process new Entry Data + when (entriesViewState) { + is UiState.Success<*> -> { + //Updates Data + when (val element = (entriesViewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + entryList = it + } } - } + } } } - } - is UiState.Error -> { - FeedbackSnackbar((entriesViewState as UiState.Error).error) //TODO: make it work - Text((entriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() + is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } } } + } @Composable From eed87812f40f2d0bb25595a01c6c2741374d96e0 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 15:46:10 +0200 Subject: [PATCH 090/325] Show Category-Icon with category title and center title --- .../budgetBinder/compose/category/CategoryComponent.kt | 8 +++++++- .../hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 41ea647a..655ecadf 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -4,7 +4,9 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.domain.usecase.* +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel import di @@ -92,7 +94,11 @@ fun BudgetBar(category: Category, entryList: List) { for (entry in entryList) { usedBudget -= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget } - H1(attrs={classes("mdc-typography--headline4")}) { Text("${category.name} - Budget") } + H1(attrs={classes("mdc-typography--headline4", AppStylesheet.flexContainer)}) { + CategoryImageToIcon(category.image) + Text("${category.name} - Budget") + } + Div { if (usedBudget <= budget && budget > 0) { //Normal not Spent Budget //Money Text diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index b7375d37..26d81ed1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -71,6 +71,7 @@ fun DashboardView( }) MainFlexContainer { + Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) //Process new Category Data From 1176fed33f7683bc36b978b8b6eb6763a47677f6 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sat, 18 Jun 2022 18:51:48 +0200 Subject: [PATCH 091/325] Add entryCreate functionality and style, plus change that EntryCreateView gets the categoryList from DashboardView --- .../hsfl/budgetBinder/presentation/Screen.kt | 4 +- .../hsfl/budgetBinder/compose/Composables.kt | 92 ++++- .../de/hsfl/budgetBinder/compose/Router.kt | 16 +- .../compose/category/CategoryCreateView.kt | 276 ++++++++------- .../compose/category/CategorySummaryView.kt | 59 ++-- .../compose/dashboard/DashboardComponent.kt | 2 +- .../compose/dashboard/DashboardView.kt | 4 +- .../compose/entry/EntryComponent.kt | 14 +- .../compose/entry/EntryCreateView.kt | 276 +++++++++++++-- .../budgetBinder/compose/login/LoginView.kt | 180 +++++----- .../compose/register/RegisterView.kt | 321 +++++++++--------- .../settings/SettingsChangeUserDataView.kt | 229 ++++++------- .../compose/settings/SettingsView.kt | 85 +++-- 13 files changed, 909 insertions(+), 649 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 899b2dc1..8a7c333b 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -2,6 +2,8 @@ package de.hsfl.budgetBinder.presentation import de.hsfl.budgetBinder.domain.usecase.DeleteEntryByIdUseCase +import de.hsfl.budgetBinder.common.Category + sealed class Screen { sealed class Welcome: Screen() { object Screen1: Welcome() @@ -22,7 +24,7 @@ sealed class Screen { sealed class Entry: Screen() { data class Overview(val id: Int): Entry() object Edit: Entry() - object Create: Entry() + data class Create (val categoryList :List): Entry() } object Login : Screen() object Register : Screen() diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 8675ef06..2f0b8729 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,6 +4,11 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.image +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.attributes.ButtonType +import org.jetbrains.compose.web.attributes.type import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle @@ -21,7 +26,12 @@ fun MainFlexContainer(content: @Composable () -> Unit) { Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) Div(attrs = { classes(AppStylesheet.contentFlexContainer) }) { - content() + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + content() + } } Div(attrs = { classes(AppStylesheet.pufferFlexContainer)}) } @@ -83,20 +93,20 @@ fun Icon(icon_name: String) { // Snackbar that shows msg @Composable fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { - var hiddenValue by remember { mutableStateOf(hidden)} + var hiddenValue by remember { mutableStateOf(hidden) } Aside( attrs = { - when(hiddenValue){ - false -> classes("mdc-snackbar","mdc-snackbar--open") - true -> classes("mdc-snackbar","maria") + when (hiddenValue) { + false -> classes("mdc-snackbar", "mdc-snackbar--open") + true -> classes("mdc-snackbar", "maria") } - onClick { - hiddenValue = true - console.log(this@Aside) - console.log("ldsadsad") + onClick { + hiddenValue = true + console.log(this@Aside) + console.log("ldsadsad") - } - }) { + } + }) { Div(attrs = { classes("mdc-snackbar__surface") attr(attr = "role", value = "status") @@ -128,8 +138,6 @@ fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { } - - @Composable fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } @@ -210,11 +218,11 @@ fun CategoryList( } } Div(attrs = { - classes(AppStylesheet.imageFlexContainer) - } + classes(AppStylesheet.imageFlexContainer) + } ) { Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in - Circle(cx = 0.5, cy = 0.5, r=0.5, { + Circle(cx = 0.5, cy = 0.5, r = 0.5, { attr("fill", "#${category.color}") }) } @@ -248,7 +256,10 @@ fun CategoryList( } } if (deleteDialog) { - DeleteDialog(false, {onDeleteButton(category.id)}, {deleteDialog = false}) { Text("Delete Category?") } + DeleteDialog( + false, + { onDeleteButton(category.id) }, + { deleteDialog = false }) { Text("Delete Category?") } } } } @@ -355,3 +366,50 @@ fun DeleteDialog(hidden: Boolean, buttonAction: () -> Unit, resetDialog: () -> U } } } + +@Composable +fun ChooseCategoryMenu( + categoryList: List, + getCategoryId: (Int) -> Unit +) { + var chosenCategory by remember { mutableStateOf(categoryList[0]) } + var showList by remember { mutableStateOf(false) } + + Button(attrs = { + classes("mdc-button", "mdc-dialog__button") + onClick { showList = !showList } + type(ButtonType.Button) + }) { + Div(attrs = { + when (showList) { + true -> classes("mdc-menu", "mdc-menu-surface", "mdc-menu-surface--open") + false -> classes("mdc-menu", "mdc-menu-surface") + } + }) { + Ul(attrs = { + classes("mdc-list") + attr("role", "menu") + attr("aria-hidden", "true") + attr("aria-orientation", "vertical") + attr("tabindex", "-1") + }) { + for (category in categoryList) { + Li(attrs = { + classes("mdc-list-item") + attr("role", "menuitem") + onClick { } + }) { + Span(attrs = { classes("mdc-list-item__ripple") }) { } + Span(attrs = { onClick { chosenCategory = category; getCategoryId(category.id) } }) { + Text( + category.name + ) + } + } + } + } + } + Text(chosenCategory.name) + } +} + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 3f09cfb0..c24ec50d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -13,12 +13,12 @@ import de.hsfl.budgetBinder.presentation.Screen @Composable fun Router(screenState: MutableState) { when (screenState.value) { - Screen._Welcome -> {} - Screen.Register -> RegisterComponent(screenState = screenState) - Screen.Login -> LoginComponent(screenState = screenState) - Screen.Dashboard -> DashboardComponent(screenState = screenState) - Screen._Settings, Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - Screen.CategorySummary,Screen.CategoryEdit,Screen.CategoryCreate, Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) - Screen.EntryCreate, Screen.EntryEdit -> EntryComponent(screenState = screenState) + is Screen.Welcome -> {} + is Screen.Register -> RegisterComponent(screenState = screenState) + is Screen.Login -> LoginComponent(screenState = screenState) + is Screen.Dashboard -> DashboardComponent(screenState = screenState) + is Screen.Settings, Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) + is Screen.CategorySummary,Screen.CategoryEdit,Screen.CategoryCreate, Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) + is Screen.EntryCreate, Screen.EntryEdit -> EntryComponent(screenState = screenState) } -} \ No newline at end of file +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index 22d8391a..2fefac50 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -10,10 +10,7 @@ import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.min import org.jetbrains.compose.web.attributes.required -import org.jetbrains.compose.web.css.marginBottom -import org.jetbrains.compose.web.css.marginLeft -import org.jetbrains.compose.web.css.percent -import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* @@ -28,7 +25,7 @@ fun CategoryCreateView( var categoryNameTextFieldState by remember { mutableStateOf("") } var categoryColorTextFieldState by remember { mutableStateOf("") } var categoryImageState by remember { mutableStateOf(Category.Image.DEFAULT) } - var categoryBudgetTextFieldState by remember { mutableStateOf("") } + var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } topBarMain( @@ -71,180 +68,179 @@ fun CategoryCreateView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Create a new Category") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onCreateCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() + } } ) { - H1 { Text("Create a new Category") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") - onCreateCategoryButtonPressed( - categoryNameTextFieldState, - categoryColorTextFieldState, - categoryImageState, - categoryBudgetTextFieldState.toFloat() - ) - it.preventDefault() + Div( + attrs = { + classes(AppStylesheet.margin) } - } ) { - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Category Name") } + Input( + type = InputType.Text ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Category Name") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(categoryNameTextFieldState) - required(true) - onInput { - categoryNameTextFieldState = it.value - } + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + required(true) + onInput { + categoryNameTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) } - Div( + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } ) { - Label( + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } } + ) { Text("Color") } + Input( + type = InputType.Color ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } - } - ) { Text("Color") } - Input( - type = InputType.Color - ) { - classes("mdc-text-field__input") - value(categoryColorTextFieldState) - onInput { - categoryColorTextFieldState = it.value - } + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + style { width(100.percent) } } ) { - Label( + Span( attrs = { - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent) } } - ) { - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent); marginLeft(2.percent)} - } - ) { Text("Image") } - CategoryImagesToImageList(onClick = {categoryImageState = it}) - } + ) { Text("Image") } + CategoryImagesToImageList(onClick = { categoryImageState = it }) + } + } + Div( + attrs = { + classes(AppStylesheet.margin) } - Div( + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Budget") } - Input( - type = InputType.Number - ) { - classes("mdc-text-field__input") - value(categoryBudgetTextFieldState) - required(true) - min("1") - onInput { - categoryBudgetTextFieldState = it.value.toString() - } + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + required(true) + min("1") + onInput { + categoryBudgetTextFieldState = it.value.toString() } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( attrs = { - classes(AppStylesheet.margin) + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + //Text((viewState as UiState.Success<*>).element.toString()) } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - Div { - when (viewState) { - is UiState.Success<*> -> { - //Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 2b704955..8bd83a2a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -66,43 +66,38 @@ fun CategorySummaryView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Category Summary") } - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onCategoryCreateButton() } + H1( + attrs = { style { margin(2.percent) } - }) { - Text("Create Category") } - CategoryList(categoryList, onEditButton, onDeleteButton) - Div { - when (viewState) { - is UiState.Success<*> -> { - when (val element = (viewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - categoryList = it - } + ) { Text(" Category Summary") } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onCategoryCreateButton() } + style { margin(2.percent) } + }) { + Text("Create Category") + } + CategoryList(categoryList, onEditButton, onDeleteButton) + Div { + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + categoryList = it } - } + } } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index c7237976..2a691030 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -26,7 +26,7 @@ fun DashboardComponent(screenState: MutableState) { entriesState = entriesViewState, onCategorySummaryButton = { screenState.value = Screen.CategorySummary}, onSettingsButton = {screenState.value = Screen._Settings}, - onEntryCreateButton = {screenState.value = Screen.EntryCreate}, + onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, onEntryEditButton = {screenState.value = Screen.EntryEdit} ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 26d81ed1..c1b1e254 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -24,7 +24,7 @@ fun DashboardView( entriesState: State, onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, - onEntryCreateButton: () -> Unit, + onEntryCreateButton: (categoryList: List) -> Unit, onEntryEditButton: (id:Int) -> Unit ) { val categoriesViewState by remember { categoriesState } @@ -73,7 +73,7 @@ fun DashboardView( MainFlexContainer { Div { DashboardData(categoryList, entryList, onEntryEditButton) } - CreateNewEntryButton(onEntryCreateButton) + CreateNewEntryButton({ onEntryCreateButton(categoryList) }) //Process new Category Data when (categoriesViewState) { is UiState.Success<*> -> { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index e7d00bed..3686ee5f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -36,12 +36,18 @@ fun EntryComponent(screenState: MutableState) { val viewState = viewModel.state.collectAsState(scope.coroutineContext) when (screenState.value) { - Screen.EntryCreate -> EntryCreateView( + is Screen.EntryCreate -> {EntryCreateView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard }, - onCategoryCreateButton = { screenState.value = Screen.CategoryCreate } + categoryList = (screenState.value as Screen.EntryCreate).categoryList, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onCreateEntryButtonPressed = { name, amount, repeat, category_id -> + userViewModel.createEntry(Entry.In(name, amount, repeat, category_id)) }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - Screen.EntryEdit -> EntryEditView( + + } + is Screen.EntryEdit -> EntryEditView( state = viewState, onBackButton = { screenState.value = Screen.Dashboard } ) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 40b47c7c..1495873d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -1,42 +1,270 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.* +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.id +import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.attributes.* +import org.jetbrains.compose.web.attributes.AutoComplete.Companion.off +import org.jetbrains.compose.web.attributes.AutoComplete.Companion.on +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Path +import org.jetbrains.compose.web.svg.Svg +@OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryCreateView( state: State, - onBackButton: () -> Unit, - onCategoryCreateButton: () -> Unit + categoryList: List, + onChangeToDashboard: () -> Unit, + onChangeToSettings: () -> Unit, + onChangeToCategory: () -> Unit, + onCreateEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category_id: Int) -> Unit, ) { + var switchState by remember { mutableStateOf(false) } + var entryNameTextFieldState by remember { mutableStateOf("") } + var entryAmountTextFieldState by remember { mutableStateOf("") } + var entryRepeatState by remember { mutableStateOf("") } + var entryCategoryIDTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("EntryCreate")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + }) + + MainFlexContainer { + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Create new Entry") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$entryNameTextFieldState, $entryAmountTextFieldState, $entryRepeatState, $entryCategoryIDTextFieldState") + onCreateEntryButtonPressed( + entryNameTextFieldState, + (if (!switchState) "-$entryAmountTextFieldState" else entryAmountTextFieldState).toFloat(), + entryRepeatState.toBoolean(), + entryCategoryIDTextFieldState.toInt() + ) + it.preventDefault() } } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Dashboard") - } - Button(attrs = { - onClick { onCategoryCreateButton() } - }) { - Text("Create new Category (Needs to be put as the last option when selecting a category for an entry)") + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Entry Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(entryNameTextFieldState) + required(true) + onInput { + entryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Amount") } + Div { + Button( + attrs = { + if (!switchState) classes("mdc-switch", "mdc-switch--unselected") + else classes("mdc-switch", "mdc-switch--selected") + id("basic-switch") + attr("role", "switch") + attr("aria-checked", "false") + type(ButtonType.Button) + onClick { switchState = !switchState } + } + ) { + Div(attrs = { classes("mdc-switch__track") }) { } + Div(attrs = { classes("mdc-switch__handle-track") }) { + Div(attrs = { classes("mdc-switch__handle") }) { + Div(attrs = { classes("mdc-switch__shadow") }) { + Div(attrs = { classes("mdc-elevation-overlay") }) { } + } + Div(attrs = { classes("mdc-switch__ripple") }) { } + Div(attrs = { classes("mdc-switch__icons") }) { + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") + } + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M20 13H4v-2h16v2z") + } + } + } + } + } + } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { + Text(if (switchState) "+" else "-") + } + Input( + type = InputType.Number + ) { + attr("step", "0.01") + classes("mdc-text-field__input") + onInput { + entryAmountTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) + } + ) { + Div(attrs = {style { flex(50.percent) }}) { + Div(attrs = { classes("mdc-form-field") }) { + Div(attrs = { classes("mdc-checkbox") }) { + Input(type = InputType.Checkbox) + { + classes("mdc-checkbox__native-control") + id("checkbox-1") + onInput { + entryRepeatState = it.value.toString() + } + } + Div(attrs = { classes("mdc-checkbox__background") }) { + Svg(attrs = { classes("mdc-checkbox__checkmark") }, viewBox = "0 0 24 24") { + Path("M1.73,12.91 8.1,19.28 22.79,4.59", attrs = { classes("mdc-checkbox__checkmark") }) + } + Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } + } + Div(attrs = { classes("mdc-checkbox__ripple") }) { } + } + Label(forId = "checkbox-1") { Text("repeat") } + } + } + Div(attrs = {style { flex(50.percent) }}) { + ChooseCategoryMenu(categoryList) { id -> entryCategoryIDTextFieldState = id.toString() } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt index 82e7ed1c..55e44092 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt @@ -69,119 +69,113 @@ fun LoginView( } } - MainFlexContainer{ + MainFlexContainer { // -- Login Form -- + H1 { Text(" Login") } + Form( + attrs = { + this.addEventListener("submit") { + console.log("${emailTextFieldState}, ${passwordTextFieldState}") + onLoginButtonPressed(emailTextFieldState, passwordTextFieldState) + it.preventDefault() + } + } + ) { Div( attrs = { - classes("mdc-card", AppStylesheet.card) + classes(AppStylesheet.margin) } ) { - H1 { Text(" Login") } - Form( + Label( attrs = { - this.addEventListener("submit") { - console.log("${emailTextFieldState}, ${passwordTextFieldState}") - onLoginButtonPressed(emailTextFieldState, passwordTextFieldState) - it.preventDefault() - } + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Div( + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field__ripple") } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Email") } - EmailInput(value = emailTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - emailTextFieldState = it.value - - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( + ) { } + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-floating-label", "mdc-floating-label--float-above") } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + ) { Text("Email") } + EmailInput(value = emailTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + emailTextFieldState = it.value + } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( + }) + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-line-ripple") } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - // -- Login Request Management -- - when (viewState) { - is UiState.Success<*> -> { - onLoginSuccess() + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { Text("Password") } + PasswordInput(value = passwordTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + passwordTextFieldState = it.value + } + }) + Span( + attrs = { + classes("mdc-line-ripple") } - else -> {} - } + ) { } } } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + // -- Login Request Management -- + when (viewState) { + is UiState.Success<*> -> { + onLoginSuccess() + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + else -> {} + } } + } } \ No newline at end of file diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt index 9cb0697a..4e7924bf 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt @@ -74,198 +74,191 @@ fun RegisterView( } } - MainFlexContainer{ + MainFlexContainer { // -- Register Form -- - Div( - attrs = { - classes("mdc-card", AppStylesheet.card) + H1 { Text(" Register") } + Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit + this.addEventListener("submit") { + console.log("$firstNameTextFieldState, $lastNameTextFieldState, $emailTextFieldState, $passwordTextFieldState") + onRegisterButtonPressed( + firstNameTextFieldState, + lastNameTextFieldState, + emailTextFieldState, + passwordTextFieldState + ) + it.preventDefault() } + } ) { - - H1 { Text(" Register") } - Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit - this.addEventListener("submit") { - console.log("$firstNameTextFieldState, $lastNameTextFieldState, $emailTextFieldState, $passwordTextFieldState") - onRegisterButtonPressed( - firstNameTextFieldState, - lastNameTextFieldState, - emailTextFieldState, - passwordTextFieldState - ) - it.preventDefault() - } + Div( + attrs = { + classes(AppStylesheet.margin) } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } ) { - Div( + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field__ripple") } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Firstname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(firstNameTextFieldState) - onInput { - firstNameTextFieldState = it.value - } - } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( + ) { } + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Firstname") } + Input( + type = InputType.Text ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Lastname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(lastNameTextFieldState) - onInput { - lastNameTextFieldState = it.value - } - } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } + classes("mdc-text-field__input") + value(firstNameTextFieldState) + onInput { + firstNameTextFieldState = it.value } } - Div( + Span( attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Email") } - EmailInput(value = emailTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - emailTextFieldState = it.value - - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } + classes("mdc-line-ripple") } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - Div( + ) { + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Lastname") } + Input( + type = InputType.Text ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } + classes("mdc-text-field__input") + value(lastNameTextFieldState) + onInput { + lastNameTextFieldState = it.value } } - Div( + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-line-ripple") } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - // -- Register Request Management -- - when (viewState) { - is UiState.Success<*> -> { - onChangeToLogin() + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { Text("Email") } + EmailInput(value = emailTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + emailTextFieldState = it.value + + } + }) + Span( + attrs = { + classes("mdc-line-ripple") } - else -> {} + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Password") } + PasswordInput(value = passwordTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + passwordTextFieldState = it.value + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + // -- Register Request Management -- + when (viewState) { + is UiState.Success<*> -> { + onChangeToLogin() + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + else -> {} + } } } } \ No newline at end of file diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt index 30b8488d..e9dcf578 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt @@ -64,155 +64,148 @@ fun SettingsChangeUserDataView( }) MainFlexContainer { - Div( - attrs = { - classes("mdc-card", AppStylesheet.card) + H1 { Text("Change User Data") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$firstNameTextFieldState, $lastNameTextFieldState, $passwordTextFieldState") + onChangeDataButtonPressed( + firstNameTextFieldState, + lastNameTextFieldState, + passwordTextFieldState + ) + it.preventDefault() } + } ) { - - H1 { Text("Change User Data") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$firstNameTextFieldState, $lastNameTextFieldState, $passwordTextFieldState") - onChangeDataButtonPressed( - firstNameTextFieldState, - lastNameTextFieldState, - passwordTextFieldState - ) - it.preventDefault() + Div( + attrs = { + classes(AppStylesheet.margin) } - } ) { - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Firstname") } + Input( + type = InputType.Text ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Firstname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(firstNameTextFieldState) - onInput { - firstNameTextFieldState = it.value - } + classes("mdc-text-field__input") + value(firstNameTextFieldState) + onInput { + firstNameTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Lastname") } + Input( + type = InputType.Text ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Lastname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(lastNameTextFieldState) - onInput { - lastNameTextFieldState = it.value - } + classes("mdc-text-field__input") + value(lastNameTextFieldState) + onInput { + lastNameTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Password") } + PasswordInput(value = passwordTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + passwordTextFieldState = it.value } - ) { } - } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) } - Div( + ) { + SubmitInput( attrs = { - classes(AppStylesheet.margin) - } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) } - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt index 8a9b0225..94e3eab8 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt @@ -64,61 +64,56 @@ fun SettingsView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) + H1( + attrs = { + style { marginLeft(2.percent) } + } + ) { Text("Settings") } + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } } - ) { - H1( - attrs = { - style { marginLeft(2.percent) } - } - ) { Text("Settings") } - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) } - Div( + ) { + Button( attrs = { - classes(AppStylesheet.margin, AppStylesheet.flexContainer) + classes("mdc-button", "mdc-button--raised") + onClick { onChangeButtonPressed() } + style { flex(100.percent) } } ) { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onChangeButtonPressed() } - style { flex(100.percent) } - } - ) { - Text("Change Userdata") - } + Text("Change Userdata") + } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) } - Div( + ) { + Button( attrs = { - classes(AppStylesheet.margin, AppStylesheet.flexContainer) - } - ) { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { - deleteDialog = true - } - style { flex(100.percent) } + classes("mdc-button", "mdc-button--raised") + onClick { + deleteDialog = true } - ) { - Text("Delete User") + style { flex(100.percent) } } + ) { + Text("Delete User") } } - if (deleteDialog) { - DeleteDialog(false, {onDeleteButtonPressed()}, {deleteDialog = false}) { Text("Delete User?") } - } + } + if (deleteDialog) { + DeleteDialog(false, { onDeleteButtonPressed() }, { deleteDialog = false }) { Text("Delete User?") } } } From 10f3297e48c8876aff89eb7ff05deb6398c9de42 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sat, 18 Jun 2022 18:52:51 +0200 Subject: [PATCH 092/325] Delete unused Imports --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt | 1 - .../de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt | 4 ---- 2 files changed, 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 2f0b8729..62cb248b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,7 +4,6 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.image import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 1495873d..691b2bb5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -4,13 +4,9 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.* import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.id -import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.* -import org.jetbrains.compose.web.attributes.AutoComplete.Companion.off -import org.jetbrains.compose.web.attributes.AutoComplete.Companion.on import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Path From ad23c431427734523acf16b64293de61c0462126 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 12:03:09 +0200 Subject: [PATCH 093/325] Fix wrong images used. Fix padding of images. Set image container to justify-content center --- .../hsfl/budgetBinder/compose/Composables.kt | 2 +- .../compose/category/CategoryCreateView.kt | 274 +++++++++--------- .../compose/theme/AppStylesheet.kt | 19 +- .../budgetBinder/presentation/CategoryIcon.kt | 14 +- 4 files changed, 164 insertions(+), 145 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 62cb248b..ea360d49 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -147,7 +147,7 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { ) { Ul( attrs = { - classes("mdc-image-list", "my-image-list") + classes("mdc-image-list", AppStylesheet.categoryImageList) } ) { for (image in Category.Image.values()) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index 2fefac50..edf490e5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -68,179 +68,185 @@ fun CategoryCreateView( }) MainFlexContainer { - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text("Create a new Category") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") - onCreateCategoryButtonPressed( - categoryNameTextFieldState, - categoryColorTextFieldState, - categoryImageState, - categoryBudgetTextFieldState.toFloat() - ) - it.preventDefault() - } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) } ) { - Div( - attrs = { - classes(AppStylesheet.margin) + H1 { Text("Create a new Category") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onCreateCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() } + } ) { - Label( + //Category Name Input + Div( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes(AppStylesheet.margin) } ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( + Label( attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - ) { Text("Category Name") } - Input( - type = InputType.Text ) { - classes("mdc-text-field__input") - value(categoryNameTextFieldState) - required(true) - onInput { - categoryNameTextFieldState = it.value + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Category Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + required(true) + onInput { + categoryNameTextFieldState = it.value + } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) } - ) { - Label( + //Category Color Input + Div( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes(AppStylesheet.margin) } ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( + Label( attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } - ) { Text("Color") } - Input( - type = InputType.Color ) { - classes("mdc-text-field__input") - value(categoryColorTextFieldState) - onInput { - categoryColorTextFieldState = it.value + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Color") } + Input( + type = InputType.Color + ) { + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value + } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( + //Category Image Input + Div( attrs = { - style { width(100.percent) } + classes(AppStylesheet.margin) } ) { - Span( + Label( attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent); marginLeft(2.percent) } + style { width(100.percent) } } - ) { Text("Image") } - CategoryImagesToImageList(onClick = { categoryImageState = it }) - } - } - Div( - attrs = { - classes(AppStylesheet.margin) + ) { + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent)} + } + ) { Text("Image") } + CategoryImagesToImageList(onClick = {categoryImageState = it}) + } } - ) { - Label( + //Category Budget Input + Div( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes(AppStylesheet.margin) } ) { - Span( + Label( attrs = { - classes("mdc-text-field__ripple") + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Budget") } - Input( - type = InputType.Number ) { - classes("mdc-text-field__input") - value(categoryBudgetTextFieldState) - required(true) - min("1") - onInput { - categoryBudgetTextFieldState = it.value.toString() + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number + ) { + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + required(true) + min("1") + onInput { + categoryBudgetTextFieldState = it.value.toString() + } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - SubmitInput( + //Submit button + Div( attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - Div { - when (viewState) { - is UiState.Success<*> -> { - //Text((viewState as UiState.Success<*>).element.toString()) + classes(AppStylesheet.margin) } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + //Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 84f02957..5bcbcafe 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -63,6 +63,21 @@ object AppStylesheet : StyleSheet() { height(auto) } + val categoryListElement by style{ + flexDirection(FlexDirection("row")) + alignItems(AlignItems.Center) + margin(10.px) + marginTop(0.px) + } + + val categoryListElementText by style{ + flex("2 2 90%") + } + + val categoryImageList by style{ + justifyContent(JustifyContent.Center) + } + //EntryList val entryListElement by style{ flexDirection(FlexDirection("row")) @@ -73,10 +88,6 @@ object AppStylesheet : StyleSheet() { val entryListElementText by style{ flex("2 2 90%") } - val text by style{ - textAlign("center") - padding(10.px) - } val moneyText by style{ textAlign("center") padding(10.px) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt index f84b6cb5..cffd4de2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt @@ -3,8 +3,7 @@ package de.hsfl.budgetBinder.presentation import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import org.jetbrains.compose.web.css.padding -import org.jetbrains.compose.web.css.px +import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Span import org.jetbrains.compose.web.dom.Text @@ -15,7 +14,10 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Span( attrs = { classes("material-icons") - style { padding(8.px) } + style { + paddingTop(8.px) + paddingBottom(8.px) + } } ) { Text( @@ -27,7 +29,7 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Category.Image.WRONG -> "dangerous" Category.Image.HOME -> "home" Category.Image.FOOD -> "bakery_dining" - Category.Image.FASTFOOD -> "bakery_dining" + Category.Image.FASTFOOD -> "fastfood" Category.Image.RESTAURANT -> "restaurant" Category.Image.FAMILY -> "people" Category.Image.MONEY -> "payments" @@ -41,10 +43,10 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Category.Image.FLOWER -> "local_florist" Category.Image.PET -> "pets" Category.Image.BILLS -> "receipt" - Category.Image.KEYBOARD -> "redeem" + Category.Image.KEYBOARD -> "keyboard" Category.Image.PRINTER -> "print" Category.Image.WATER -> "water_drop" - Category.Image.FIRE -> "fire" + Category.Image.FIRE -> "local_fire_department" Category.Image.STAR -> "grade" Category.Image.SAVINGS -> "savings" Category.Image.CAR -> "minor_crash" From b9000168b5c12706877a64d73b58f8f9a6e922b8 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:11:52 +0200 Subject: [PATCH 094/325] Add EntryOverview Screen and open EntryOverview with corresponding ID when clicking on an entry in dashboard --- .../budgetBinder/compose/dashboard/DashboardComponent.kt | 1 + .../de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 2a691030..d0992b48 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -28,5 +28,6 @@ fun DashboardComponent(screenState: MutableState) { onSettingsButton = {screenState.value = Screen._Settings}, onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, onEntryEditButton = {screenState.value = Screen.EntryEdit} + onEntryOverviewButton = {id -> screenState.value = Screen.EntryOverview(id)} ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index c1b1e254..2cabe030 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -12,9 +12,7 @@ import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.css.keywords.auto import org.jetbrains.compose.web.dom.* @@ -25,7 +23,7 @@ fun DashboardView( onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, onEntryCreateButton: (categoryList: List) -> Unit, - onEntryEditButton: (id:Int) -> Unit + onEntryOverviewButton: (id:Int) -> Unit ) { val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } @@ -72,7 +70,7 @@ fun DashboardView( MainFlexContainer { - Div { DashboardData(categoryList, entryList, onEntryEditButton) } + Div { DashboardData(categoryList, entryList, onEntryOverviewButton) } CreateNewEntryButton({ onEntryCreateButton(categoryList) }) //Process new Category Data when (categoriesViewState) { From cb267e0a43db6e0d4469d3b4e76592c4dc40b36d Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:21:09 +0200 Subject: [PATCH 095/325] Fix Router routing per type and not per instance --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index c24ec50d..067df92a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -17,8 +17,10 @@ fun Router(screenState: MutableState) { is Screen.Register -> RegisterComponent(screenState = screenState) is Screen.Login -> LoginComponent(screenState = screenState) is Screen.Dashboard -> DashboardComponent(screenState = screenState) - is Screen.Settings, Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - is Screen.CategorySummary,Screen.CategoryEdit,Screen.CategoryCreate, Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) - is Screen.EntryCreate, Screen.EntryEdit -> EntryComponent(screenState = screenState) + is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) + is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, Screen.CategoryCreateOnRegister + -> CategoryComponent(screenState = screenState) + is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) + else -> {} } } From ebc1c25301d52b72a11d45160b79ac55048dc8de Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:43:59 +0200 Subject: [PATCH 096/325] Add EntryOverviewView and connect it in EntryComponent --- .../compose/entry/EntryOverviewView.kt | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt new file mode 100644 index 00000000..28ee388a --- /dev/null +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -0,0 +1,168 @@ +package de.hsfl.budgetBinder.compose.entry + +import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.CategoryList +import de.hsfl.budgetBinder.compose.DeleteDialog +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import de.hsfl.budgetBinder.presentation.UiState +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Circle +import org.jetbrains.compose.web.svg.Svg + + +@Composable +fun EntryOverviewView( + state: State, + onEditButton: () -> Unit, + onDeleteButton: (id: Int) -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToCategory: () -> Unit, + onChangeToSettings: () -> Unit +) { + var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } + val viewState by remember { state } + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } + } + }) + + MainFlexContainer { + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Entry") } + + EntryOverview(entry,onEditButton,onDeleteButton) + } + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is Entry -> entry = element + else -> {} + } + + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } +} + +@Composable +fun EntryOverview( + entry: Entry, + onEditButton: () -> Unit, + onDeleteButton: (Int) -> Unit +) { + var deleteDialog by remember { mutableStateOf(false) } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Div( + attrs = { + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) + } + ) { + + Div( + attrs = { + classes(AppStylesheet.categoryListElementText) + } + ) { + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(entry.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Amount: ${entry.amount}€") } + } + } + } + Div( + attrs = { + classes(AppStylesheet.flexContainer) + } + ) { + Button(attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + onClick { onEditButton() } + style { + flex(50.percent) + margin(1.5.percent) + } + }) { + Text("Edit Entry") + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { deleteDialog = true } + style { + flex(50.percent) + margin(1.5.percent) + backgroundColor(Color("#b00020")) + } + }) { + Text("Delete Entry") + } + } + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton(entry.id) }, + { deleteDialog = false }) { Text("Delete Entry?") } + } + } +} + From 4d21c1e0d79343db7e5d3c7b381f9fdfd8b7e6c7 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:45:01 +0200 Subject: [PATCH 097/325] Add EntryComponent stuff for EntryOverview --- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 3686ee5f..a746cf2c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -51,6 +51,14 @@ fun EntryComponent(screenState: MutableState) { state = viewState, onBackButton = { screenState.value = Screen.Dashboard } ) + is Screen.EntryOverview -> EntryOverviewView( + state = viewState, + onEditButton = {}, + onDeleteButton = {id -> entryViewModel.removeEntry(id)}, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) else -> {} } } From 0d702b9318425c24f1108af2e62bd3dac0eac34a Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:58:10 +0200 Subject: [PATCH 098/325] Load Entry-Data when EntryOverview is opened --- .../compose/entry/EntryComponent.kt | 22 +++-- .../compose/entry/EntryOverviewView.kt | 94 +++++++++---------- 2 files changed, 57 insertions(+), 59 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index a746cf2c..6ea574af 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -51,14 +51,17 @@ fun EntryComponent(screenState: MutableState) { state = viewState, onBackButton = { screenState.value = Screen.Dashboard } ) - is Screen.EntryOverview -> EntryOverviewView( - state = viewState, - onEditButton = {}, - onDeleteButton = {id -> entryViewModel.removeEntry(id)}, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) + is Screen.EntryOverview -> { + EntryOverviewView( + state = viewState, + onEditButton = {}, + onDeleteButton = { id -> entryViewModel.removeEntry(id) }, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) + entryViewModel.getEntryById((screenState.value as Screen.EntryOverview).id) + } else -> {} } } @@ -105,8 +108,7 @@ fun EntryList(list: List, categoryList: List, onEntry: (id: Int AppStylesheet.text ) }) { Text("No Entries in this category") } - } - else { + } else { for (entry in list) { EntryListElement(entry, categoryList, onEntry) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index 28ee388a..861308b2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -78,7 +78,7 @@ fun EntryOverviewView( } ) { Text(" Entry") } - EntryOverview(entry,onEditButton,onDeleteButton) + EntryOverview(entry, onEditButton, onDeleteButton) } when (viewState) { is UiState.Success<*> -> { @@ -105,64 +105,60 @@ fun EntryOverview( onDeleteButton: (Int) -> Unit ) { var deleteDialog by remember { mutableStateOf(false) } - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } + Div( + attrs = { + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) + } ) { - Div( - attrs = { - classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) - } - ) { - Div( - attrs = { - classes(AppStylesheet.categoryListElementText) - } - ) { - Div { - Div(attrs = { - classes("mdc-typography--headline4", AppStylesheet.text) - }) { Text(entry.name) } - Div(attrs = { - classes("mdc-typography--headline6", AppStylesheet.text) - }) { Text("Amount: ${entry.amount}€") } - } - } - } Div( attrs = { - classes(AppStylesheet.flexContainer) + classes(AppStylesheet.categoryListElementText) } ) { - Button(attrs = { - classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton() } - style { - flex(50.percent) - margin(1.5.percent) - } - }) { - Text("Edit Entry") + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(entry.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Amount: ${entry.amount}€") } } - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { deleteDialog = true } - style { - flex(50.percent) - margin(1.5.percent) - backgroundColor(Color("#b00020")) - } - }) { - Text("Delete Entry") + } + } + Div( + attrs = { + classes(AppStylesheet.flexContainer) + } + ) { + Button(attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + onClick { onEditButton() } + style { + flex(50.percent) + margin(1.5.percent) } + }) { + Text("Edit Entry") } - if (deleteDialog) { - DeleteDialog( - false, - { onDeleteButton(entry.id) }, - { deleteDialog = false }) { Text("Delete Entry?") } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { deleteDialog = true } + style { + flex(50.percent) + margin(1.5.percent) + backgroundColor(Color("#b00020")) + } + }) { + Text("Delete Entry") } } + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton(entry.id) }, + { deleteDialog = false }) { Text("Delete Entry?") } + } } + From 3d2308f344ac73bbf878a9e653298ab61559dd96 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 18:39:56 +0200 Subject: [PATCH 099/325] Make editEntry button go to EntryEdit:Screen --- .../kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 6ea574af..db70c0e1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -54,7 +54,7 @@ fun EntryComponent(screenState: MutableState) { is Screen.EntryOverview -> { EntryOverviewView( state = viewState, - onEditButton = {}, + onEditButton = {screenState.value = Screen.EntryEdit}, onDeleteButton = { id -> entryViewModel.removeEntry(id) }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, From 2d8812133e17fc5b3a7a733b510ddc4be39ab2fb Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 18:53:46 +0200 Subject: [PATCH 100/325] Fetch the right entry data when loading EntryEdit:Screen --- .../hsfl/budgetBinder/presentation/Screen.kt | 2 +- .../compose/entry/EntryComponent.kt | 33 +++++++++++-------- .../compose/entry/EntryOverviewView.kt | 6 ++-- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 8a7c333b..081c7026 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -23,7 +23,7 @@ sealed class Screen { } sealed class Entry: Screen() { data class Overview(val id: Int): Entry() - object Edit: Entry() + data class Edit(val id: Int): Entry() data class Create (val categoryList :List): Entry() } object Login : Screen() diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index db70c0e1..ebc8260d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -36,25 +36,30 @@ fun EntryComponent(screenState: MutableState) { val viewState = viewModel.state.collectAsState(scope.coroutineContext) when (screenState.value) { - is Screen.EntryCreate -> {EntryCreateView( - state = viewState, - categoryList = (screenState.value as Screen.EntryCreate).categoryList, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onCreateEntryButtonPressed = { name, amount, repeat, category_id -> - userViewModel.createEntry(Entry.In(name, amount, repeat, category_id)) }, - onChangeToSettings = { screenState.value = Screen.Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) + is Screen.EntryCreate -> { + EntryCreateView( + state = viewState, + categoryList = (screenState.value as Screen.EntryCreate).categoryList, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onCreateEntryButtonPressed = { name, amount, repeat, category_id -> + userViewModel.createEntry(Entry.In(name, amount, repeat, category_id)) + }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) } - is Screen.EntryEdit -> EntryEditView( - state = viewState, - onBackButton = { screenState.value = Screen.Dashboard } - ) + is Screen.EntryEdit -> { + EntryEditView( + state = viewState, + onBackButton = { screenState.value = Screen.Dashboard } + ) + entryViewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) + } is Screen.EntryOverview -> { EntryOverviewView( state = viewState, - onEditButton = {screenState.value = Screen.EntryEdit}, + onEditButton = {id -> screenState.value = Screen.EntryEdit(id)}, onDeleteButton = { id -> entryViewModel.removeEntry(id) }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index 861308b2..dbf22003 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -19,7 +19,7 @@ import org.jetbrains.compose.web.svg.Svg @Composable fun EntryOverviewView( state: State, - onEditButton: () -> Unit, + onEditButton: (id: Int) -> Unit, onDeleteButton: (id: Int) -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, @@ -101,7 +101,7 @@ fun EntryOverviewView( @Composable fun EntryOverview( entry: Entry, - onEditButton: () -> Unit, + onEditButton: (Int) -> Unit, onDeleteButton: (Int) -> Unit ) { var deleteDialog by remember { mutableStateOf(false) } @@ -133,7 +133,7 @@ fun EntryOverview( ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton() } + onClick { onEditButton(entry.id) } style { flex(50.percent) margin(1.5.percent) From 48f8d939e25ef26c2e0e1462620e0ff60347aeff Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 18:56:08 +0200 Subject: [PATCH 101/325] Go back to Dashboard when deleting an entry --- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index ebc8260d..68dfbda4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -60,7 +60,9 @@ fun EntryComponent(screenState: MutableState) { EntryOverviewView( state = viewState, onEditButton = {id -> screenState.value = Screen.EntryEdit(id)}, - onDeleteButton = { id -> entryViewModel.removeEntry(id) }, + onDeleteButton = { id -> + entryViewModel.removeEntry(id) + screenState.value = Screen.Dashboard}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, From c7560a33ea562ed7556fb695945fb6e1ad3544c9 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sat, 18 Jun 2022 21:55:41 +0200 Subject: [PATCH 102/325] add is to all screens --- .../src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 067df92a..94a6372f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -18,8 +18,7 @@ fun Router(screenState: MutableState) { is Screen.Login -> LoginComponent(screenState = screenState) is Screen.Dashboard -> DashboardComponent(screenState = screenState) is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, Screen.CategoryCreateOnRegister - -> CategoryComponent(screenState = screenState) + is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) else -> {} } From 3763229ae2b752347bc485056694182a6ffeb656 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sun, 19 Jun 2022 14:33:14 +0200 Subject: [PATCH 103/325] Fix delete Category --- .../de/hsfl/budgetBinder/presentation/Screen.kt | 2 +- .../de/hsfl/budgetBinder/compose/Composables.kt | 13 +++---------- .../compose/category/CategoryComponent.kt | 10 +++++----- .../compose/category/CategoryEditView.kt | 5 +++-- .../compose/category/CategorySummaryView.kt | 11 +++++++++-- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 081c7026..73849774 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -17,7 +17,7 @@ sealed class Screen { } sealed class Category: Screen() { object Summary: Category() - object Edit: Category() + data class Edit(val id: Int): Category() object Create: Category() object CreateOnRegister: Category() } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index ea360d49..b2064038 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -180,10 +180,9 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { @Composable fun CategoryList( categoryList: List, - onEditButton: () -> Unit, + onEditButton: (Int) -> Unit, onDeleteButton: (Int) -> Unit ) { - var deleteDialog by remember { mutableStateOf(false) } Div { for (category in categoryList) Div(attrs = { @@ -234,7 +233,7 @@ fun CategoryList( ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton() } + onClick { onEditButton(category.id) } style { flex(50.percent) margin(1.5.percent) @@ -244,7 +243,7 @@ fun CategoryList( } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { deleteDialog = true } + onClick { onDeleteButton(category.id) } style { flex(50.percent) margin(1.5.percent) @@ -254,12 +253,6 @@ fun CategoryList( Text("Delete Category") } } - if (deleteDialog) { - DeleteDialog( - false, - { onDeleteButton(category.id) }, - { deleteDialog = false }) { Text("Delete Category?") } - } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 655ecadf..c3dd6691 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -43,7 +43,7 @@ fun CategoryComponent(screenState: MutableState) { val viewState = viewModel.state.collectAsState(scope.coroutineContext) when (screenState.value) { - Screen.CategoryCreate -> CategoryCreateView( + is Screen.CategoryCreate -> CategoryCreateView( state = viewState, onCreateCategoryButtonPressed = { name, color, image, budget -> categoryViewModel.createCategory(Category.In(name, color.drop(1), image, budget)) }, @@ -51,20 +51,20 @@ fun CategoryComponent(screenState: MutableState) { onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - Screen.CategorySummary -> CategorySummaryView( + is Screen.CategorySummary -> CategorySummaryView( state = viewState, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, - onEditButton = { screenState.value = Screen.CategoryEdit}, + onEditButton = { id -> screenState.value = Screen.CategoryEdit(id)}, onDeleteButton = {id -> categoryViewModel.removeCategory(id)}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - Screen.CategoryEdit -> CategoryEditView( + is Screen.CategoryEdit -> CategoryEditView( state = viewState, onBackButton = { screenState.value = Screen.CategorySummary } ) - Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( + is Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( state = viewState, onFinishedButton = { screenState.value = Screen.Dashboard diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt index 892e8511..d2a714f3 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt @@ -14,11 +14,12 @@ fun CategoryEditView( onBackButton: () -> Unit ) { val viewState by remember { state } - H1{Text("CategoryEditView")} + H1{Text("Edit Category")} + console.log() Div { when (viewState) { is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + //Text((viewState as UiState.Success<*>).element.toString()) } is UiState.Error -> { Text((viewState as UiState.Error).error) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 8bd83a2a..4cd5c9a4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -17,12 +17,13 @@ import org.jetbrains.compose.web.dom.* fun CategorySummaryView( state: State, onCategoryCreateButton: () -> Unit, - onEditButton: () -> Unit, + onEditButton: (id: Int) -> Unit, onDeleteButton: (id: Int) -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -78,7 +79,13 @@ fun CategorySummaryView( }) { Text("Create Category") } - CategoryList(categoryList, onEditButton, onDeleteButton) + CategoryList(categoryList, {id -> onEditButton(id)}, {id -> onDeleteButton(id)}) + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton }, + { deleteDialog = false }) { Text("Delete Category?") } + } Div { when (viewState) { is UiState.Success<*> -> { From c095f47e7e5748cf9070e2cddb6f42786ac81ea7 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sun, 19 Jun 2022 15:02:15 +0200 Subject: [PATCH 104/325] Fix openDialog on delete Category --- .../de/hsfl/budgetBinder/compose/Composables.kt | 11 ++++++++++- .../compose/category/CategorySummaryView.kt | 8 +------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index b2064038..c3240a58 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -183,7 +183,16 @@ fun CategoryList( onEditButton: (Int) -> Unit, onDeleteButton: (Int) -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } + var id by remember { mutableStateOf(0) } + Div { + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton(id) }, + { deleteDialog = false }) { Text("Delete Category?") } + } for (category in categoryList) Div(attrs = { classes("mdc-card", AppStylesheet.card) @@ -243,7 +252,7 @@ fun CategoryList( } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { onDeleteButton(category.id) } + onClick { deleteDialog = !deleteDialog; id = category.id } style { flex(50.percent) margin(1.5.percent) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 4cd5c9a4..7554dfe6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -23,7 +23,6 @@ fun CategorySummaryView( onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { - var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -80,12 +79,7 @@ fun CategorySummaryView( Text("Create Category") } CategoryList(categoryList, {id -> onEditButton(id)}, {id -> onDeleteButton(id)}) - if (deleteDialog) { - DeleteDialog( - false, - { onDeleteButton }, - { deleteDialog = false }) { Text("Delete Category?") } - } + Div { when (viewState) { is UiState.Success<*> -> { From 7df22b8d8ea7b4cee5e3bbe2dafd0ac6c1e22096 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sun, 19 Jun 2022 19:12:43 +0200 Subject: [PATCH 105/325] Add form in edit category --- .../viewmodel/CategoryViewModel.kt | 4 - .../hsfl/budgetBinder/compose/Composables.kt | 11 +- .../compose/category/CategoryComponent.kt | 48 +-- .../compose/category/CategoryCreateView.kt | 281 +++++++++--------- .../compose/category/CategoryEditView.kt | 262 ++++++++++++++-- .../compose/category/CategorySummaryView.kt | 1 - 6 files changed, 421 insertions(+), 186 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt index 2358ee3c..10e8a5e3 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/CategoryViewModel.kt @@ -16,10 +16,6 @@ class CategoryViewModel( private val _state = MutableStateFlow(UiState.Empty) val state: StateFlow = _state - init { - getAllCategories() - } - fun getAllCategories() { categoryUseCases.getAllCategoriesUseCase.categories().onEach { when (it) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index c3240a58..04b2f2bc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -138,8 +138,11 @@ fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { @Composable -fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { - var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } +fun CategoryImagesToImageList( + inputImage: MutableState, + onClick: (Category.Image) -> Unit +) { + var highlightImage by remember { mutableStateOf(inputImage) } Div( attrs = { classes("mdc-card", AppStylesheet.card) @@ -158,14 +161,14 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { ) { Div( attrs = { - if (highlightImage == image) + if (highlightImage.value == image) classes( "mdc-image-list__image-aspect-container", "mdc-icon-button", "mdc-button--raised" ) else classes("mdc-image-list__image-aspect-container", "mdc-icon-button") - onClick { onClick(image); highlightImage = image } + onClick { onClick(image); highlightImage.value = image } } ) { CategoryImageToIcon(image) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index c3dd6691..a84bb41d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -13,7 +13,6 @@ import di import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob -import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* @@ -46,24 +45,38 @@ fun CategoryComponent(screenState: MutableState) { is Screen.CategoryCreate -> CategoryCreateView( state = viewState, onCreateCategoryButtonPressed = { name, color, image, budget -> - categoryViewModel.createCategory(Category.In(name, color.drop(1), image, budget)) }, + categoryViewModel.createCategory(Category.In(name, color.drop(1), image, budget)) + screenState.value = Screen.CategorySummary }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - is Screen.CategorySummary -> CategorySummaryView( - state = viewState, - onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, - onEditButton = { id -> screenState.value = Screen.CategoryEdit(id)}, - onDeleteButton = {id -> categoryViewModel.removeCategory(id)}, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) - is Screen.CategoryEdit -> CategoryEditView( - state = viewState, - onBackButton = { screenState.value = Screen.CategorySummary } - ) + is Screen.CategorySummary -> { + CategorySummaryView( + state = viewState, + onCategoryCreateButton = { screenState.value = Screen.CategoryCreate }, + onEditButton = { id -> screenState.value = Screen.CategoryEdit(id) }, + onDeleteButton = { id -> categoryViewModel.removeCategory(id) }, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) + categoryViewModel.getAllCategories() + } + is Screen.CategoryEdit -> { + CategoryEditView( + state = viewState, + onEditCategoryButtonPressed = { name, color, image, budget -> + categoryViewModel.changeCategory( + Category.Patch(name, color.drop(1), image, budget), + (screenState.value as Screen.CategoryEdit).id + ); screenState.value = Screen.CategorySummary }, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) + categoryViewModel.getCategoryById((screenState.value as Screen.CategoryEdit).id) + } is Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( state = viewState, onFinishedButton = { @@ -94,7 +107,7 @@ fun BudgetBar(category: Category, entryList: List) { for (entry in entryList) { usedBudget -= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget } - H1(attrs={classes("mdc-typography--headline4", AppStylesheet.flexContainer)}) { + H1(attrs = { classes("mdc-typography--headline4", AppStylesheet.flexContainer) }) { CategoryImageToIcon(category.image) Text("${category.name} - Budget") } @@ -104,7 +117,8 @@ fun BudgetBar(category: Category, entryList: List) { //Money Text MoneyTextDiv { Div(attrs = { - classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€") } + classes("mdc-typography--headline5") + }) { Text(usedBudget.toString() + "€") } Div(attrs = { classes("mdc-typography--headline5") }) { Text(budget.toString() + "€") } } Svg(viewBox = "0 0 $width $height") { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index edf490e5..06af894f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -24,7 +24,7 @@ fun CategoryCreateView( ) { var categoryNameTextFieldState by remember { mutableStateOf("") } var categoryColorTextFieldState by remember { mutableStateOf("") } - var categoryImageState by remember { mutableStateOf(Category.Image.DEFAULT) } + var categoryImageState = remember { mutableStateOf(Category.Image.DEFAULT) } var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } @@ -68,185 +68,184 @@ fun CategoryCreateView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Create a new Category") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onCreateCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState.value, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() + } } ) { - H1 { Text("Create a new Category") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") - onCreateCategoryButtonPressed( - categoryNameTextFieldState, - categoryColorTextFieldState, - categoryImageState, - categoryBudgetTextFieldState.toFloat() - ) - it.preventDefault() + //Category Name Input + Div( + attrs = { + classes(AppStylesheet.margin) } - } ) { - //Category Name Input - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Category Name") } + Input( + type = InputType.Text ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Category Name") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(categoryNameTextFieldState) - required(true) - onInput { - categoryNameTextFieldState = it.value - } + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + required(true) + onInput { + categoryNameTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Category Color Input + Div( + attrs = { + classes(AppStylesheet.margin) } - //Category Color Input - Div( + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } ) { - Label( + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } } + ) { Text("Color") } + Input( + type = InputType.Color ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } - } - ) { Text("Color") } - Input( - type = InputType.Color - ) { - classes("mdc-text-field__input") - value(categoryColorTextFieldState) - onInput { - categoryColorTextFieldState = it.value - } + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - //Category Image Input - Div( + } + //Category Image Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + style { width(100.percent) } } ) { - Label( + Span( attrs = { - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent) } } - ) { - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent); marginLeft(2.percent)} - } - ) { Text("Image") } - CategoryImagesToImageList(onClick = {categoryImageState = it}) - } + ) { Text("Image") } + CategoryImagesToImageList(categoryImageState, onClick = { categoryImageState.value = it }) + } + } + //Category Budget Input + Div( + attrs = { + classes(AppStylesheet.margin) } - //Category Budget Input - Div( + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Budget") } - Input( - type = InputType.Number - ) { - classes("mdc-text-field__input") - value(categoryBudgetTextFieldState) - required(true) - min("1") - onInput { - categoryBudgetTextFieldState = it.value.toString() - } + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + required(true) + min("1") + onInput { + categoryBudgetTextFieldState = it.value.toString() } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - //Submit button - Div( + } + //Submit button + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( attrs = { - classes(AppStylesheet.margin) + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + //Text((viewState as UiState.Success<*>).element.toString()) } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - Div { - when (viewState) { - is UiState.Success<*> -> { - //Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt index d2a714f3..900dda55 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt @@ -1,37 +1,261 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.CategoryImagesToImageList +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.min +import org.jetbrains.compose.web.attributes.required +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* @Composable fun CategoryEditView( state: State, - onBackButton: () -> Unit + onEditCategoryButtonPressed: (name: String, color: String, image: Category.Image, budget: Float) -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToCategory: () -> Unit, + onChangeToSettings: () -> Unit ) { + var category by remember { mutableStateOf(Category(0, "", "", Category.Image.DEFAULT, 0f)) } + var categoryNameTextFieldState by remember { mutableStateOf("") } + var categoryColorTextFieldState by remember { mutableStateOf("") } + var categoryImageState = remember { mutableStateOf(Category.Image.DEFAULT) } + var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("Edit Category")} - console.log() - Div { - when (viewState) { - is UiState.Success<*> -> { - //Text((viewState as UiState.Success<*>).element.toString()) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + }) + + MainFlexContainer { + H1(attrs = { style { margin(2.percent) } }) { Text("Edit Category") } + + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onEditCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState.value, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() } } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Category Overview") + ) { + //Category Name Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Category Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + required(true) + onInput { + categoryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Category Color Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Color") } + Input( + type = InputType.Color + ) { + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Category Image Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent) } + } + ) { Text("Image") } + CategoryImagesToImageList(categoryImageState, onClick = { categoryImageState.value = it }) + } + } + //Category Budget Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number + ) { + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + required(true) + min("1") + onInput { + categoryBudgetTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Submit button + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + + Div { + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is Category -> { + category = element + categoryNameTextFieldState = category.name + categoryColorTextFieldState = "#" + category.color + categoryImageState.value = category.image + categoryBudgetTextFieldState = category.budget.toString() + } + } + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 7554dfe6..af48f680 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -3,7 +3,6 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.CategoryList -import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain From 2bd3dc7959802049e682ce7240111e1fd8bc02f8 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 20 Jun 2022 09:54:25 +0200 Subject: [PATCH 106/325] Add form in entryEdit and add categoryList in entryEdit and entryOverview --- .../hsfl/budgetBinder/presentation/Screen.kt | 10 +- .../hsfl/budgetBinder/compose/Composables.kt | 12 +- .../compose/dashboard/DashboardComponent.kt | 3 +- .../compose/dashboard/DashboardView.kt | 4 +- .../compose/entry/EntryComponent.kt | 11 +- .../compose/entry/EntryEditView.kt | 286 ++++++++++++++++-- .../compose/entry/EntryOverviewView.kt | 20 +- 7 files changed, 299 insertions(+), 47 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 73849774..14e89793 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -22,8 +22,8 @@ sealed class Screen { object CreateOnRegister: Category() } sealed class Entry: Screen() { - data class Overview(val id: Int): Entry() - data class Edit(val id: Int): Entry() + data class Overview(val id: Int, val categoryList :List): Entry() + data class Edit(val id: Int, val categoryList :List): Entry() data class Create (val categoryList :List): Entry() } object Login : Screen() @@ -44,8 +44,10 @@ sealed class Screen { object CategoryCreate : Screen() @Deprecated(message = "use sealed class Category") object CategoryCreateOnRegister : Screen() + @Deprecated(message = "use sealed class Category") + data class EntryOverview (val id: Int, val categoryList :List) : Screen() @Deprecated(message = "use sealed class Entry") - object EntryEdit : Screen() + data class EntryEdit (val id: Int, val categoryList :List): Screen() @Deprecated(message = "use sealed class Entry") - object EntryCreate : Screen() + data class EntryCreate (val categoryList :List): Screen() } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 04b2f2bc..4587300c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -2,9 +2,11 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.StateManager.screenState import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import de.hsfl.budgetBinder.presentation.Screen import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType import org.jetbrains.compose.web.attributes.type @@ -374,7 +376,7 @@ fun DeleteDialog(hidden: Boolean, buttonAction: () -> Unit, resetDialog: () -> U @Composable fun ChooseCategoryMenu( categoryList: List, - getCategoryId: (Int) -> Unit + getCategoryId: (Int?) -> Unit ) { var chosenCategory by remember { mutableStateOf(categoryList[0]) } var showList by remember { mutableStateOf(false) } @@ -401,14 +403,10 @@ fun ChooseCategoryMenu( Li(attrs = { classes("mdc-list-item") attr("role", "menuitem") - onClick { } + onClick { chosenCategory = category; getCategoryId(category.id) } }) { Span(attrs = { classes("mdc-list-item__ripple") }) { } - Span(attrs = { onClick { chosenCategory = category; getCategoryId(category.id) } }) { - Text( - category.name - ) - } + Span(attrs = { }) { Text(category.name) } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index d0992b48..da1ae3cc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -27,7 +27,6 @@ fun DashboardComponent(screenState: MutableState) { onCategorySummaryButton = { screenState.value = Screen.CategorySummary}, onSettingsButton = {screenState.value = Screen._Settings}, onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, - onEntryEditButton = {screenState.value = Screen.EntryEdit} - onEntryOverviewButton = {id -> screenState.value = Screen.EntryOverview(id)} + onEntryOverviewButton = {id, categoryList -> screenState.value = Screen.EntryOverview(id, categoryList)} ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 2cabe030..7453e2a6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -23,7 +23,7 @@ fun DashboardView( onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, onEntryCreateButton: (categoryList: List) -> Unit, - onEntryOverviewButton: (id:Int) -> Unit + onEntryOverviewButton: (id:Int, categoryList: List) -> Unit ) { val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } @@ -70,7 +70,7 @@ fun DashboardView( MainFlexContainer { - Div { DashboardData(categoryList, entryList, onEntryOverviewButton) } + Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id, categoryList) } } CreateNewEntryButton({ onEntryCreateButton(categoryList) }) //Process new Category Data when (categoriesViewState) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 68dfbda4..64bcda05 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -52,7 +52,16 @@ fun EntryComponent(screenState: MutableState) { is Screen.EntryEdit -> { EntryEditView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard } + categoryList = (screenState.value as Screen.EntryEdit).categoryList, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onEditEntryButtonPressed = { name, amount, repeat, category -> + entryViewModel.changeEntry( + Entry.Patch(name, amount, repeat, category), + (screenState.value as Screen.EntryEdit).id + ) + }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) entryViewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 0aac23a6..8622874e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -1,36 +1,286 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.ChooseCategoryMenu +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.category.categoryIdToCategory +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.attributes.ButtonType +import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.required +import org.jetbrains.compose.web.attributes.type +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Path +import org.jetbrains.compose.web.svg.Svg +@OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryEditView( state: State, - onBackButton: () -> Unit + categoryList: List, + onChangeToDashboard: () -> Unit, + onChangeToSettings: () -> Unit, + onChangeToCategory: () -> Unit, + onEditEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category: Entry.Category) -> Unit, ) { + var entry by remember { mutableStateOf(Entry(0, "", 0f, false, 0)) } + var switchState by remember { mutableStateOf(false) } + var entryNameTextFieldState by remember { mutableStateOf("") } + var entryAmountTextFieldState by remember { mutableStateOf("") } + var entryRepeatState by remember { mutableStateOf("") } + var entryCategoryIDTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("EntryEditView")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + }) + + MainFlexContainer { + H1( + attrs = { + style { margin(2.percent) } } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { Text("Edit Entry") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$entryNameTextFieldState, $entryAmountTextFieldState, $entryRepeatState, ${entryCategoryIDTextFieldState.toInt()}") + onEditEntryButtonPressed( + entryNameTextFieldState, + (if (!switchState) "-$entryAmountTextFieldState" else entryAmountTextFieldState).toFloat(), + entryRepeatState.toBoolean(), + Entry.Category(entryCategoryIDTextFieldState.toInt()) + ) + it.preventDefault() } } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Dashboard") + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Entry Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(entryNameTextFieldState) + required(true) + onInput { + entryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Amount") } + Div { + Button( + attrs = { + if (!switchState) classes("mdc-switch", "mdc-switch--unselected") + else classes("mdc-switch", "mdc-switch--selected") + id("basic-switch") + attr("role", "switch") + attr("aria-checked", "false") + type(ButtonType.Button) + onClick { switchState = !switchState } + } + ) { + Div(attrs = { classes("mdc-switch__track") }) { } + Div(attrs = { classes("mdc-switch__handle-track") }) { + Div(attrs = { classes("mdc-switch__handle") }) { + Div(attrs = { classes("mdc-switch__shadow") }) { + Div(attrs = { classes("mdc-elevation-overlay") }) { } + } + Div(attrs = { classes("mdc-switch__ripple") }) { } + Div(attrs = { classes("mdc-switch__icons") }) { + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") + } + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M20 13H4v-2h16v2z") + } + } + } + } + } + } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { + Text(if (switchState) "+" else "-") + } + Input( + type = InputType.Number + ) { + attr("step", "0.01") + classes("mdc-text-field__input") + onInput { + entryAmountTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) + } + ) { + Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { classes("mdc-form-field") }) { + Div(attrs = { classes("mdc-checkbox") }) { + Input(type = InputType.Checkbox) + { + classes("mdc-checkbox__native-control") + id("checkbox-1") + onInput { + entryRepeatState = it.value.toString() + } + } + Div(attrs = { classes("mdc-checkbox__background") }) { + Svg(attrs = { classes("mdc-checkbox__checkmark") }, viewBox = "0 0 24 24") { + Path( + "M1.73,12.91 8.1,19.28 22.79,4.59", + attrs = { classes("mdc-checkbox__checkmark") }) + } + Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } + } + Div(attrs = { classes("mdc-checkbox__ripple") }) { } + } + Label(forId = "checkbox-1") { Text("repeat") } + } + } + Div(attrs = { style { flex(50.percent) } }) { + ChooseCategoryMenu(categoryList) { id -> entryCategoryIDTextFieldState = id.toString() } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is Entry -> { + entry = element + entryNameTextFieldState = entry.name + entryAmountTextFieldState = entry.amount.toString() + switchState = !entry.amount.toString().startsWith("-") + entryRepeatState = entry.repeat.toString() + entryCategoryIDTextFieldState = entry.category_id.toString() + } + } + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index dbf22003..1d79a64a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -25,7 +25,7 @@ fun EntryOverviewView( onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { - var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } + var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } val viewState by remember { state } topBarMain( @@ -68,25 +68,19 @@ fun EntryOverviewView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Entry") } + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Entry") } - EntryOverview(entry, onEditButton, onDeleteButton) - } + EntryOverview(entry, onEditButton, onDeleteButton) when (viewState) { is UiState.Success<*> -> { when (val element = (viewState as UiState.Success<*>).element) { is Entry -> entry = element else -> {} } - } is UiState.Error -> { Text((viewState as UiState.Error).error) From f6bfdd218e43f9ffd8c7a0070d708cf28e4addf8 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 20:04:57 +0200 Subject: [PATCH 107/325] Remove categoryList from Entry-Screens. Will get loaded via ViewModel later --- .../kotlin/de/hsfl/budgetBinder/presentation/Screen.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 14e89793..c9b79bad 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -22,9 +22,9 @@ sealed class Screen { object CreateOnRegister: Category() } sealed class Entry: Screen() { - data class Overview(val id: Int, val categoryList :List): Entry() - data class Edit(val id: Int, val categoryList :List): Entry() - data class Create (val categoryList :List): Entry() + data class Overview(val id: Int): Entry() + data class Edit(val id: Int): Entry() + object Create: Entry() } object Login : Screen() object Register : Screen() From 76c3f987b156a5422e448b789218562bf22ebfd4 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 20:10:55 +0200 Subject: [PATCH 108/325] Remove unnecessary imports in Composables and fix CategoryComponent --- .../hsfl/budgetBinder/compose/Composables.kt | 4 +--- .../compose/category/CategoryComponent.kt | 22 ++++++++----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 4587300c..5451397c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -2,11 +2,9 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.StateManager.screenState import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import de.hsfl.budgetBinder.presentation.Screen import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType import org.jetbrains.compose.web.attributes.type @@ -144,7 +142,7 @@ fun CategoryImagesToImageList( inputImage: MutableState, onClick: (Category.Image) -> Unit ) { - var highlightImage by remember { mutableStateOf(inputImage) } + val highlightImage by remember { mutableStateOf(inputImage) } Div( attrs = { classes("mdc-card", AppStylesheet.card) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index a84bb41d..3d81ea8f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -10,15 +10,11 @@ import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel import di -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg -import org.kodein.di.compose.localDI import org.kodein.di.instance @Composable @@ -45,37 +41,37 @@ fun CategoryComponent(screenState: MutableState) { is Screen.CategoryCreate -> CategoryCreateView( state = viewState, onCreateCategoryButtonPressed = { name, color, image, budget -> - categoryViewModel.createCategory(Category.In(name, color.drop(1), image, budget)) + viewModel.createCategory(Category.In(name, color.drop(1), image, budget)) screenState.value = Screen.CategorySummary }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) is Screen.CategorySummary -> { CategorySummaryView( state = viewState, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate }, - onEditButton = { id -> screenState.value = Screen.CategoryEdit(id) }, - onDeleteButton = { id -> categoryViewModel.removeCategory(id) }, + onEditButton = { id -> screenState.value = Screen.Category.Edit(id) }, + onDeleteButton = { id -> viewModel.removeCategory(id) }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - categoryViewModel.getAllCategories() + viewModel.getAllCategories() } is Screen.CategoryEdit -> { CategoryEditView( state = viewState, onEditCategoryButtonPressed = { name, color, image, budget -> - categoryViewModel.changeCategory( + viewModel.changeCategory( Category.Patch(name, color.drop(1), image, budget), (screenState.value as Screen.CategoryEdit).id ); screenState.value = Screen.CategorySummary }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - categoryViewModel.getCategoryById((screenState.value as Screen.CategoryEdit).id) + viewModel.getCategoryById((screenState.value as Screen.CategoryEdit).id) } is Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( state = viewState, From 4eba1305ce860e44693829ecf4f33dd7f5dfcfc0 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 20:16:18 +0200 Subject: [PATCH 109/325] Fix EntryComponent --- .../hsfl/budgetBinder/presentation/Screen.kt | 2 +- .../compose/entry/EntryComponent.kt | 24 ++++++++----------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index c9b79bad..af3594d5 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -39,7 +39,7 @@ sealed class Screen { @Deprecated(message = "use sealed class Category") object CategorySummary : Screen() @Deprecated(message = "use sealed class Category") - object CategoryEdit : Screen() + data class CategoryEdit(val id: Int) : Screen() @Deprecated(message = "use sealed class Category") object CategoryCreate : Screen() @Deprecated(message = "use sealed class Category") diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 64bcda05..cae054b1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -10,12 +10,8 @@ import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.viewmodel.EntryViewModel import di -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Text -import org.kodein.di.compose.localDI import org.kodein.di.instance import kotlin.math.absoluteValue @@ -41,10 +37,10 @@ fun EntryComponent(screenState: MutableState) { state = viewState, categoryList = (screenState.value as Screen.EntryCreate).categoryList, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onCreateEntryButtonPressed = { name, amount, repeat, category_id -> - userViewModel.createEntry(Entry.In(name, amount, repeat, category_id)) + onCreateEntryButtonPressed = { name:String, amount:Float, repeat:Boolean, category_id:Int -> + viewModel.createEntry(Entry.In(name, amount, repeat, category_id)) }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) @@ -54,29 +50,29 @@ fun EntryComponent(screenState: MutableState) { state = viewState, categoryList = (screenState.value as Screen.EntryEdit).categoryList, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onEditEntryButtonPressed = { name, amount, repeat, category -> - entryViewModel.changeEntry( + onEditEntryButtonPressed = { name:String, amount:Float, repeat:Boolean, category:Entry.Category? -> + viewModel.changeEntry( Entry.Patch(name, amount, repeat, category), (screenState.value as Screen.EntryEdit).id ) }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - entryViewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) + viewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) } is Screen.EntryOverview -> { EntryOverviewView( state = viewState, onEditButton = {id -> screenState.value = Screen.EntryEdit(id)}, onDeleteButton = { id -> - entryViewModel.removeEntry(id) + viewModel.removeEntry(id) screenState.value = Screen.Dashboard}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - entryViewModel.getEntryById((screenState.value as Screen.EntryOverview).id) + viewModel.getEntryById((screenState.value as Screen.EntryOverview).id) } else -> {} } From 55c9c20d12b29808caf7535e8668d76a89ffcbdf Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 20:54:46 +0200 Subject: [PATCH 110/325] Remove categoryList from EntryScreen-Views --- .../kotlin/de/hsfl/budgetBinder/presentation/Screen.kt | 4 ++-- .../hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt | 2 +- .../de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 4 ++-- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 3 +-- .../de/hsfl/budgetBinder/compose/entry/EntryEditView.kt | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index af3594d5..17e898a5 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -45,9 +45,9 @@ sealed class Screen { @Deprecated(message = "use sealed class Category") object CategoryCreateOnRegister : Screen() @Deprecated(message = "use sealed class Category") - data class EntryOverview (val id: Int, val categoryList :List) : Screen() + data class EntryOverview (val id: Int) : Screen() @Deprecated(message = "use sealed class Entry") - data class EntryEdit (val id: Int, val categoryList :List): Screen() + data class EntryEdit (val id: Int): Screen() @Deprecated(message = "use sealed class Entry") data class EntryCreate (val categoryList :List): Screen() } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index da1ae3cc..0881187e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -27,6 +27,6 @@ fun DashboardComponent(screenState: MutableState) { onCategorySummaryButton = { screenState.value = Screen.CategorySummary}, onSettingsButton = {screenState.value = Screen._Settings}, onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, - onEntryOverviewButton = {id, categoryList -> screenState.value = Screen.EntryOverview(id, categoryList)} + onEntryOverviewButton = {id -> screenState.value = Screen.EntryOverview(id)} ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 7453e2a6..0ec060a3 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -23,7 +23,7 @@ fun DashboardView( onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, onEntryCreateButton: (categoryList: List) -> Unit, - onEntryOverviewButton: (id:Int, categoryList: List) -> Unit + onEntryOverviewButton: (id:Int) -> Unit ) { val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } @@ -70,7 +70,7 @@ fun DashboardView( MainFlexContainer { - Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id, categoryList) } } + Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id) } } CreateNewEntryButton({ onEntryCreateButton(categoryList) }) //Process new Category Data when (categoriesViewState) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index cae054b1..0e704a15 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -48,7 +48,6 @@ fun EntryComponent(screenState: MutableState) { is Screen.EntryEdit -> { EntryEditView( state = viewState, - categoryList = (screenState.value as Screen.EntryEdit).categoryList, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onEditEntryButtonPressed = { name:String, amount:Float, repeat:Boolean, category:Entry.Category? -> viewModel.changeEntry( @@ -64,7 +63,7 @@ fun EntryComponent(screenState: MutableState) { is Screen.EntryOverview -> { EntryOverviewView( state = viewState, - onEditButton = {id -> screenState.value = Screen.EntryEdit(id)}, + onEditButton = {id, -> screenState.value = Screen.EntryEdit(id)}, onDeleteButton = { id -> viewModel.removeEntry(id) screenState.value = Screen.Dashboard}, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 8622874e..bc189082 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -24,13 +24,13 @@ import org.jetbrains.compose.web.svg.Svg @Composable fun EntryEditView( state: State, - categoryList: List, onChangeToDashboard: () -> Unit, onChangeToSettings: () -> Unit, onChangeToCategory: () -> Unit, onEditEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category: Entry.Category) -> Unit, ) { var entry by remember { mutableStateOf(Entry(0, "", 0f, false, 0)) } + var categoryList by remember { mutableStateOf>(emptyList()) } var switchState by remember { mutableStateOf(false) } var entryNameTextFieldState by remember { mutableStateOf("") } var entryAmountTextFieldState by remember { mutableStateOf("") } From 5654d2822959d3a5882f1e40d25596615754c02d Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 21:22:49 +0200 Subject: [PATCH 111/325] Update RegisterComponent.kt to work with new RegisterViewModel --- .../compose/register/RegisterComponent.kt | 270 ++++++++++++++++-- 1 file changed, 253 insertions(+), 17 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt index 58526f41..fae09b44 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt @@ -2,31 +2,267 @@ package de.hsfl.budgetBinder.compose.register import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.User +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.register.RegisterEvent import de.hsfl.budgetBinder.presentation.viewmodel.register.RegisterViewModel import di +import kotlinx.coroutines.flow.collectLatest +import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.dom.* import org.kodein.di.instance @Composable -fun RegisterComponent(screenState: MutableState) { - /*al scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - val registerUseCase: RegisterUseCase by di.instance() - val loginUseCase: LoginUseCase by di.instance() - val getMyUserUseCase : GetMyUserUseCase by di.instance() - val viewModel = RegisterViewModel(registerUseCase,loginUseCase,getMyUserUseCase, scope) - val viewState = viewModel.state.collectAsState(scope)*/ - val scope = rememberCoroutineScope() +fun RegisterComponent() { val viewModel: RegisterViewModel by di.instance() - val viewState = viewModel.state.collectAsState(scope.coroutineContext) + val firstNameTextState = viewModel.firstNameText.collectAsState() + val lastNameTextState = viewModel.lastNameText.collectAsState() + val emailTextState = viewModel.emailText.collectAsState() + val passwordTextState = viewModel.passwordText.collectAsState() + val confirmedPasswordTextState = viewModel.confirmedPasswordText.collectAsState() + val loadingState = remember { mutableStateOf(false) } + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> { + // TODO: Refactor this, it's working but ahh + loadingState.value = true + } + else -> loadingState.value = false + } + } + } + if (loadingState.value) { + Text("Loading") + //TODO: LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) + } + //Body + Header( + attrs = { + classes("mdc-top-app-bar") + } + ) { + Div( + attrs = { + classes("mdc-top-app-bar__row") + } + ) { + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") + } + ) { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + } + ) + Span( + attrs = { + classes("mdc-top-app-bar__title") + } + ) { + Text("Budget-Binder") + } + } + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") + } + ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(RegisterEvent.OnLoginScreen) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Login Instead") + } + } + } + } + } - RegisterView( - state = viewState, - onRegisterButtonPressed = { firstName, lastName, email, password -> - viewModel._register(User.In(firstName,lastName,email,password)) - }, - onChangeToLogin = { screenState.value = Screen.Login } - ) -} \ No newline at end of file + MainFlexContainer { + // -- Register Form -- + H1 { Text(" Register") } + Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit + this.addEventListener("submit") { + console.log("$firstNameTextState, $lastNameTextState, $emailTextState, $passwordTextState") + viewModel.onEvent(RegisterEvent.OnRegister) + it.preventDefault() + } + } + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Firstname") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(firstNameTextState.value.firstName) + onInput { + viewModel.onEvent(RegisterEvent.EnteredFirstname(it.value)) + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Lastname") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(lastNameTextState.value.firstName) + onInput { + viewModel.onEvent(RegisterEvent.EnteredLastname(it.value)) + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Email") } + EmailInput(value = emailTextState.value.email, + attrs = { + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(RegisterEvent.EnteredEmail(it.value)) + + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Password") } + PasswordInput(value = passwordTextState.value.password, + attrs = { + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(RegisterEvent.EnteredPassword(it.value)) + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + } + } +} From d5aa774e20526db9692986416b5203f2596aeda0 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 21:23:30 +0200 Subject: [PATCH 112/325] Delete previously used RegisterView (Now part of RegisterComponent --- .../compose/register/RegisterView.kt | 264 ------------------ 1 file changed, 264 deletions(-) delete mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt deleted file mode 100644 index 4e7924bf..00000000 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt +++ /dev/null @@ -1,264 +0,0 @@ -package de.hsfl.budgetBinder.compose.register - - -import androidx.compose.runtime.* -import de.hsfl.budgetBinder.compose.MainFlexContainer -import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.attributes.InputType -import org.jetbrains.compose.web.css.flex -import org.jetbrains.compose.web.css.percent -import org.jetbrains.compose.web.css.width -import org.jetbrains.compose.web.dom.* - -@Composable -fun RegisterView( - state: State, - onRegisterButtonPressed: (firstName: String, lastName: String, email: String, password: String) -> Unit, - onChangeToLogin: () -> Unit -) { - var firstNameTextFieldState by remember { mutableStateOf("") } - var lastNameTextFieldState by remember { mutableStateOf("") } - var emailTextFieldState by remember { mutableStateOf("") } - var passwordTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } - - Header( - attrs = { - classes("mdc-top-app-bar") - } - ) { - Div( - attrs = { - classes("mdc-top-app-bar__row") - } - ) { - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") - } - ) { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - } - ) - Span( - attrs = { - classes("mdc-top-app-bar__title") - } - ) { - Text("Budget-Binder") - } - } - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") - } - ) { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToLogin() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Login Instead") - } - } - } - } - } - - MainFlexContainer { - // -- Register Form -- - H1 { Text(" Register") } - Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit - this.addEventListener("submit") { - console.log("$firstNameTextFieldState, $lastNameTextFieldState, $emailTextFieldState, $passwordTextFieldState") - onRegisterButtonPressed( - firstNameTextFieldState, - lastNameTextFieldState, - emailTextFieldState, - passwordTextFieldState - ) - it.preventDefault() - } - } - ) { - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Firstname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(firstNameTextFieldState) - onInput { - firstNameTextFieldState = it.value - } - } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Lastname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(lastNameTextFieldState) - onInput { - lastNameTextFieldState = it.value - } - } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Email") } - EmailInput(value = emailTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - emailTextFieldState = it.value - - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - // -- Register Request Management -- - when (viewState) { - is UiState.Success<*> -> { - onChangeToLogin() - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - else -> {} - } - } - } -} \ No newline at end of file From a11c0d0a59d65851da8ee495a17186b973accdb4 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 21:49:11 +0200 Subject: [PATCH 113/325] Update LoginComponent to work with new LoginViewModel, change Router accordingly --- .../de/hsfl/budgetBinder/compose/Router.kt | 23 ++- .../compose/login/LoginComponent.kt | 192 ++++++++++++++++-- .../src/jsMain/kotlin/main.kt | 3 +- 3 files changed, 193 insertions(+), 25 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 94a6372f..dd87a630 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -2,6 +2,8 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.rememberCoroutineScope import de.hsfl.budgetBinder.compose.category.CategoryComponent import de.hsfl.budgetBinder.compose.dashboard.DashboardComponent import de.hsfl.budgetBinder.compose.entry.EntryComponent @@ -9,17 +11,24 @@ import de.hsfl.budgetBinder.compose.login.LoginComponent import de.hsfl.budgetBinder.compose.register.RegisterComponent import de.hsfl.budgetBinder.compose.settings.SettingsComponent import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.flow.RouterFlow +import di +import org.jetbrains.compose.web.dom.Text +import org.kodein.di.instance @Composable -fun Router(screenState: MutableState) { +fun Router() { + val scope = rememberCoroutineScope() + val routerFlow: RouterFlow by di.instance() + val screenState = routerFlow.state.collectAsState(scope.coroutineContext) when (screenState.value) { is Screen.Welcome -> {} - is Screen.Register -> RegisterComponent(screenState = screenState) - is Screen.Login -> LoginComponent(screenState = screenState) - is Screen.Dashboard -> DashboardComponent(screenState = screenState) - is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) - is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) + is Screen.Register -> RegisterComponent() + is Screen.Login -> LoginComponent() + is Screen.Dashboard -> Text("Dashboard")//DashboardComponent() + //is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) + //is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) + //is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) else -> {} } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt index 4bd513f8..59d859f5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt @@ -1,29 +1,189 @@ package de.hsfl.budgetBinder.compose.login import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginEvent import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginViewModel import di +import kotlinx.coroutines.flow.collectLatest +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.dom.* import org.kodein.di.compose.withDI import org.kodein.di.instance @Composable -fun LoginComponent(screenState: MutableState) = withDI(di) { - /*val scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - val loginUseCase: LoginUseCase by di.instance() - val getMyUserUseCase : GetMyUserUseCase by di.instance() - val viewModel = LoginViewModel(scope,loginUseCase, getMyUserUseCase) - val viewState = viewModel.state.collectAsState(scope)*/ +fun LoginComponent() { val scope = rememberCoroutineScope() val viewModel: LoginViewModel by di.instance() - val viewState = viewModel.state.collectAsState(scope) + val emailTextState = viewModel.emailText.collectAsState(scope.coroutineContext) + val passwordTextState = viewModel.passwordText.collectAsState(scope.coroutineContext) + val loadingState = remember { mutableStateOf(false) } - LoginView( - state = viewState, - onLoginButtonPressed = { email, password -> - viewModel.login(email, password) - }, - onLoginSuccess = { screenState.value = Screen.Dashboard }, - onChangeToRegister = { screenState.value = Screen.Register } - ) -} \ No newline at end of file + + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> loadingState.value = true + else -> loadingState.value = false + } + } + } + + if (loadingState.value) { + Text("Loading") + //LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) + } + //Body + Header( + attrs = { + classes("mdc-top-app-bar") + } + ) { + Div( + attrs = { + classes("mdc-top-app-bar__row") + } + ) { + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") + } + ) { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + } + ) + Span( + attrs = { + classes("mdc-top-app-bar__title") + } + ) { + Text("Budget-Binder") + } + } + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") + } + ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(LoginEvent.OnRegisterScreen) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Register Instead") + } + } + } + } + } + + MainFlexContainer { + // -- Login Form -- + H1 { Text(" Login") } + Form( + attrs = { + this.addEventListener("submit") { + console.log("$emailTextState, $passwordTextState") + viewModel.onEvent(LoginEvent.OnLogin) + it.preventDefault() + } + } + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Email") } + EmailInput(value = emailTextState.value.email, + attrs = { + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(LoginEvent.EnteredEmail(it.value)) + + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Password") } + PasswordInput(value = passwordTextState.value.password, + attrs = { + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(LoginEvent.EnteredPassword(it.value)) + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + } + } +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt index bdeb7a75..69ba53a0 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt @@ -19,6 +19,5 @@ val di = kodein(ktorEngine = Js.create()) @Composable fun App() = withDI(di) { - val screenState = remember { mutableStateOf(Screen.Login) } - Router(screenState = screenState) + Router() } From 484bea283b57be49c235b4f320614cc7134fbe48 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 22:05:27 +0200 Subject: [PATCH 114/325] Remove DashboardView and put content in DashboardComponent. Fix DashboardData and SwipeContainer --- .../de/hsfl/budgetBinder/compose/Router.kt | 2 +- .../compose/dashboard/DashboardComponent.kt | 189 ++++++++++-- .../compose/dashboard/DashboardView.kt | 271 ------------------ 3 files changed, 170 insertions(+), 292 deletions(-) delete mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index dd87a630..eb3c6d19 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -25,7 +25,7 @@ fun Router() { is Screen.Welcome -> {} is Screen.Register -> RegisterComponent() is Screen.Login -> LoginComponent() - is Screen.Dashboard -> Text("Dashboard")//DashboardComponent() + is Screen.Dashboard -> DashboardComponent() //is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) //is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) //is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 0881187e..2ae30c30 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -1,32 +1,181 @@ package de.hsfl.budgetBinder.compose.dashboard import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.FeedbackSnackbar +import de.hsfl.budgetBinder.compose.Icon +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.category.BudgetBar +import de.hsfl.budgetBinder.compose.entry.EntryList +import de.hsfl.budgetBinder.compose.entry.entriesFromCategory +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel import di +import kotlinx.coroutines.flow.collectLatest +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* import org.kodein.di.instance @Composable fun DashboardComponent(screenState: MutableState) { - //val scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - val scope = rememberCoroutineScope() - /*val di = localDI() - val getAllEntriesUseCase: GetAllEntriesUseCase by di.instance() - val getAllCategoriesUseCase: GetAllCategoriesUseCase by di.instance() - val dashboardViewModel = DashboardViewModel(getAllEntriesUseCase,getAllCategoriesUseCase, scope) - val categoriesViewState = dashboardViewModel.categoriesState.collectAsState(scope) - val entriesViewState = dashboardViewModel.entriesState.collectAsState(scope)*/ - val viewModel: DashboardViewModel by di.instance() - val categoriesViewState = viewModel.categoriesState.collectAsState(scope.coroutineContext) - val entriesViewState = viewModel.entriesState.collectAsState(scope.coroutineContext) - - DashboardView( - categoriesState = categoriesViewState, - entriesState = entriesViewState, - onCategorySummaryButton = { screenState.value = Screen.CategorySummary}, - onSettingsButton = {screenState.value = Screen._Settings}, - onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, - onEntryOverviewButton = {id -> screenState.value = Screen.EntryOverview(id)} - ) + val entryList = viewModel.entryListState.collectAsState() + val focusedCategory = viewModel.focusedCategoryState.collectAsState() + val totalSpendBudget = viewModel.spendBudgetOnCurrentCategory.collectAsState() + val olderEntries = viewModel.oldEntriesMapState.collectAsState() + val loadingState = remember { mutableStateOf(false) } + // val scaffoldState = rememberScaffoldState() + + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> loadingState.value = true + is UiEvent.HideSuccess -> loadingState.value = false + else -> loadingState.value = false + } + } + } + //TODO: TOPBAR + MainFlexContainer { + Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id) } } + CreateNewEntryButton({ onEntryCreateButton(categoryList) }) + //Process new Category Data + when (categoriesViewState) { + is UiState.Success<*> -> { + //Updates Data + // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot + when (val element = (categoriesViewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + categoryList = it + } + } + } + } + } + is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + //Process new Entry Data + when (entriesViewState) { + is UiState.Success<*> -> { + //Updates Data + when (val element = (entriesViewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + entryList = it + } + } + } + } + } + is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } + + + +} + +@Composable +fun DashboardData( + focusedCategory: Category, + totalSpendBudget: Float, + totalBudget: Float, + hasPrev: Boolean, + hasNext: Boolean, + onPrevClicked: () -> Unit, + onNextClicked: () -> Unit +) { + SwipeContainer ( + hasPrev, hasNext, onPrevClicked, onNextClicked + ){ + BudgetBar(categoryList[focusedCategory], filteredEntryList) + } } + + +@Composable +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { + Div (attrs = {style { + display(DisplayStyle.Flex) + justifyContent(JustifyContent.FlexEnd) + }}) { + Button(attrs = { + classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) + onClick { onEntryCreateButton() } + }) { + Div(attrs = { classes("mdc-fab__ripple") }) + Icon("add") + Div(attrs = { classes("mdc-fab__touch") }) + } + } +} + +@Composable +fun SwipeContainer( + hasPrev: Boolean, + hasNext: Boolean, + onPrevClicked: () -> Unit, + onNextClicked: () -> Unit, + content: @Composable () -> Unit +) { + Div( + attrs = { + classes(AppStylesheet.flexContainer) + }) { + Div(attrs = { + if(hasPrev) { + classes(AppStylesheet.imageFlexContainer, "mdc-button") + onClick { onPrevClicked() } + } + else{ + classes(AppStylesheet.imageFlexContainer) + style{ + paddingLeft(8.px) + paddingRight(8.px) + } + } + }){ + if(hasPrev) Icon("arrow_back_ios_new") + } + Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) + { + content() + } + Div(attrs = { + if(hasNext) { + classes(AppStylesheet.imageFlexContainer, "mdc-button") + onClick { onNextClicked() } + } + else{ + classes(AppStylesheet.imageFlexContainer) + style{ + paddingLeft(8.px) + paddingRight(8.px) + } + } + }) { + if(hasNext) Icon("arrow_forward_ios_new") + } + } +} + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt deleted file mode 100644 index 0ec060a3..00000000 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ /dev/null @@ -1,271 +0,0 @@ -package de.hsfl.budgetBinder.compose.dashboard - -import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.Entry -import de.hsfl.budgetBinder.compose.FeedbackSnackbar -import de.hsfl.budgetBinder.compose.Icon -import de.hsfl.budgetBinder.compose.MainFlexContainer -import de.hsfl.budgetBinder.compose.category.BudgetBar -import de.hsfl.budgetBinder.compose.entry.EntryList -import de.hsfl.budgetBinder.compose.entry.entriesFromCategory -import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.dom.* - - -@Composable -fun DashboardView( - categoriesState: State, - entriesState: State, - onCategorySummaryButton: () -> Unit, - onSettingsButton: () -> Unit, - onEntryCreateButton: (categoryList: List) -> Unit, - onEntryOverviewButton: (id:Int) -> Unit -) { - val categoriesViewState by remember { categoriesState } - val entriesViewState by remember { entriesState } - var categoryList by remember { mutableStateOf>(emptyList()) } - var entryList by remember { mutableStateOf>(emptyList()) } - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { } - } - ) - }, navButtons = { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onCategorySummaryButton() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onSettingsButton() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Settings") - } - } - }) - - MainFlexContainer { - - Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id) } } - CreateNewEntryButton({ onEntryCreateButton(categoryList) }) - //Process new Category Data - when (categoriesViewState) { - is UiState.Success<*> -> { - //Updates Data - // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot - when (val element = (categoriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - categoryList = it - } - } - } - } - } - is UiState.Error -> { - FeedbackSnackbar((entriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } - //Process new Entry Data - when (entriesViewState) { - is UiState.Success<*> -> { - //Updates Data - when (val element = (entriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - entryList = it - } - } - } - } - } - is UiState.Error -> { - FeedbackSnackbar((entriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } - } - - - -} - -@Composable -fun DashboardData(categoryList: List, entryList: List, onEntry: (id:Int) -> Unit) { - console.log("Category $categoryList and Entry $entryList") - var focusedCategory by remember { mutableStateOf(-1) } //Variable from -1 (all) to categoryList.size - console.log("Focus:${focusedCategory}") - fun changeFocusedCategory(increase: Boolean): Int { - var newFocus = focusedCategory - if (increase) newFocus++ - else newFocus-- - newFocus = - when { - (newFocus) < -1 -> -1 - (newFocus > categoryList.size) -> categoryList.size - else -> { - newFocus - } - } - return newFocus - } - - //if (entryList.isNotEmpty()) { - when (focusedCategory) { - //Overall View - -1 -> { - var everyBudgetTogether = 0f - for (category in categoryList) { - everyBudgetTogether += category.budget - } - val fakeOverallBudget = - Category(0, "Overall", "111111", Category.Image.DEFAULT, everyBudgetTogether) - SwipeContainer ( - content = {BudgetBar(fakeOverallBudget, entryList)}, //Every CategoryBudget with every Entry's Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)}, - leftOn = false - ) - - EntryList(entryList, categoryList, onEntry) //List of Every Entry - } - //Normal Category View - in categoryList.indices -> { - val filteredEntryList = - entriesFromCategory(entryList, categoryList[focusedCategory].id) - SwipeContainer ( - content = {BudgetBar(categoryList[focusedCategory], filteredEntryList)}, //Every Category with their Entries' Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} - ) - EntryList( - filteredEntryList, - listOf(categoryList[focusedCategory]), - onEntry - ) //Only gives CategoryData of selected category, as everything else seems unnecessary - } - - //No Category View - categoryList.size -> { - val filteredEntryList = entriesFromCategory(entryList, null) - val fakeNoCategory = - Category(0, "No Category", "111111", Category.Image.DEFAULT, 0f) - SwipeContainer ( - content = {BudgetBar(fakeNoCategory, filteredEntryList)}, //"No Category" with their Entries' Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)}, - rightOn = false - ) - EntryList( - filteredEntryList, - emptyList(), - onEntry - ) //Needs no categoryList, as they have no category - } - } - /*} else { - Div(attrs = { - classes( - "mdc-typography--headline5", - AppStylesheet.text - ) - }) { Text("No data to load") } - }*/ - -} - - -@Composable -fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { - Div (attrs = {style { - display(DisplayStyle.Flex) - justifyContent(JustifyContent.FlexEnd) - }}) { - Button(attrs = { - classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) - onClick { onEntryCreateButton() } - }) { - Div(attrs = { classes("mdc-fab__ripple") }) - Icon("add") - Div(attrs = { classes("mdc-fab__touch") }) - } - } -} - -@Composable -fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Boolean) -> Unit, leftOn: Boolean = true, rightOn:Boolean = true) { - Div( - attrs = { - classes(AppStylesheet.flexContainer) - }) { - Div(attrs = { - if(leftOn) { - classes(AppStylesheet.imageFlexContainer, "mdc-button") - onClick { onFocusCategoryChange(false) } - } - else{ - classes(AppStylesheet.imageFlexContainer) - style{ - paddingLeft(8.px) - paddingRight(8.px) - } - } - }){ - if(leftOn) Icon("arrow_back_ios_new") - } - Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) - { - content() - } - Div(attrs = { - if(rightOn) { - classes(AppStylesheet.imageFlexContainer, "mdc-button") - onClick { onFocusCategoryChange(true) } - } - else{ - classes(AppStylesheet.imageFlexContainer) - style{ - paddingLeft(8.px) - paddingRight(8.px) - } - } - }) { - if(rightOn) Icon("arrow_forward_ios_new") - } - } -} - - - - - From ae7863ecdcf4c9d37828b67ad41089757ea41782 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 22:19:28 +0200 Subject: [PATCH 115/325] Update Dashboards BudgetBar --- .../compose/category/CategoryComponent.kt | 40 +++++------ .../compose/dashboard/DashboardComponent.kt | 70 +++++-------------- 2 files changed, 36 insertions(+), 74 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 3d81ea8f..8a674a25 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -92,56 +92,54 @@ fun categoryIdToCategory(category_id: Int?, categoryList: List): Categ @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun BudgetBar(category: Category, entryList: List) { - //category = Category we want to show - //entryList = List of entries +fun BudgetBar( + focusedCategory: Category, + totalSpendBudget: Float, + totalBudget: Float, +) { //width and height are for aspect ratio - tries to fill out wherever its in, so its more like val width = 20 val height = 2 - val budget = category.budget - var usedBudget = 0f - for (entry in entryList) { - usedBudget -= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget - } + H1(attrs = { classes("mdc-typography--headline4", AppStylesheet.flexContainer) }) { - CategoryImageToIcon(category.image) - Text("${category.name} - Budget") + CategoryImageToIcon(focusedCategory.image) + Text("${focusedCategory.name} - Budget") } Div { - if (usedBudget <= budget && budget > 0) { //Normal not Spent Budget + if (totalSpendBudget <= totalBudget && totalBudget > 0) { //Normal not Spent Budget //Money Text MoneyTextDiv { Div(attrs = { classes("mdc-typography--headline5") - }) { Text(usedBudget.toString() + "€") } - Div(attrs = { classes("mdc-typography--headline5") }) { Text(budget.toString() + "€") } + }) { Text(totalSpendBudget.toString() + "€") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(totalBudget.toString() + "€") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { attr("fill", Color.lightgray.toString()) }) - if (0 < usedBudget) // If there is used budget, draw it - Rect(x = 0, y = 0, width = usedBudget / budget * width, height = height, { - attr("fill", "#" + category.color) + if (0 < totalSpendBudget) // If there is used budget, draw it + Rect(x = 0, y = 0, width = totalSpendBudget/ totalBudget * width, height = height, { + attr("fill", "#" + focusedCategory.color) }) } - } else if (usedBudget > budget && budget > 0) { //Over Budget + } else if (totalSpendBudget> totalBudget && totalBudget > 0) { //Over Budget MoneyTextDiv { - Div(attrs = { classes("mdc-typography--headline5") }) { Text("Budget limit for " + category.name + " reached! " + usedBudget.toString() + "€ of " + budget.toString() + "€ Budget spent") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text("Budget limit for " + focusedCategory.name + " reached! " + totalSpendBudget.toString() + "€ of " + totalBudget.toString() + "€ Budget spent") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { attr("fill", "#b00020") }) } - } else if (budget <= 0f) { //No Category View or other unpredictable case (or no categories, overall screen) + } else if (totalBudget <= 0f) { //No Category View or other unpredictable case (or no categories, overall screen) MoneyTextDiv { - Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€ spent") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(totalSpendBudget.toString() + "€ spent") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { - attr("fill", "#" + category.color) + attr("fill", "#" + focusedCategory.color) }) } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 2ae30c30..8924fc9c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -14,6 +14,7 @@ import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiEvent import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEvent import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel import di import kotlinx.coroutines.flow.collectLatest @@ -22,7 +23,7 @@ import org.jetbrains.compose.web.dom.* import org.kodein.di.instance @Composable -fun DashboardComponent(screenState: MutableState) { +fun DashboardComponent() { val viewModel: DashboardViewModel by di.instance() val entryList = viewModel.entryListState.collectAsState() val focusedCategory = viewModel.focusedCategoryState.collectAsState() @@ -42,57 +43,20 @@ fun DashboardComponent(screenState: MutableState) { } //TODO: TOPBAR MainFlexContainer { - Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id) } } - CreateNewEntryButton({ onEntryCreateButton(categoryList) }) - //Process new Category Data - when (categoriesViewState) { - is UiState.Success<*> -> { - //Updates Data - // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot - when (val element = (categoriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - categoryList = it - } - } - } - } - } - is UiState.Error -> { - FeedbackSnackbar((entriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + Div { + DashboardData( + focusedCategory = focusedCategory.value.category, + totalSpendBudget = totalSpendBudget.value.spendBudgetOnCurrentCategory, + totalBudget = focusedCategory.value.category.budget, + hasPrev = focusedCategory.value.hasPrev, + hasNext = focusedCategory.value.hasNext, + onPrevClicked = { viewModel.onEvent(DashboardEvent.OnPrevCategory) }, + onNextClicked = { viewModel.onEvent(DashboardEvent.OnNextCategory) } + ) } - //Process new Entry Data - when (entriesViewState) { - is UiState.Success<*> -> { - //Updates Data - when (val element = (entriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - entryList = it - } - } - } - } - } - is UiState.Error -> { - FeedbackSnackbar((entriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } - } - - + CreateNewEntryButton(viewModel.onEvent(DashboardEvent.OnEntryCreate)) + } } @Composable @@ -108,20 +72,20 @@ fun DashboardData( SwipeContainer ( hasPrev, hasNext, onPrevClicked, onNextClicked ){ - BudgetBar(categoryList[focusedCategory], filteredEntryList) + BudgetBar(focusedCategory,totalSpendBudget,totalBudget) } } @Composable -fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { +fun CreateNewEntryButton(onEntryCreateButton: Unit) { Div (attrs = {style { display(DisplayStyle.Flex) justifyContent(JustifyContent.FlexEnd) }}) { Button(attrs = { classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) - onClick { onEntryCreateButton() } + onClick { onEntryCreateButton } }) { Div(attrs = { classes("mdc-fab__ripple") }) Icon("add") From b2f28ed684c5d8ef335293e91dbda560ace6a1ed Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 22:41:37 +0200 Subject: [PATCH 116/325] Fix bug where dashboard automatically switches to EntryCreateScreen --- .../kotlin/de/hsfl/budgetBinder/compose/Router.kt | 11 +++++++---- .../compose/dashboard/DashboardComponent.kt | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index eb3c6d19..273337d0 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -21,14 +21,17 @@ fun Router() { val scope = rememberCoroutineScope() val routerFlow: RouterFlow by di.instance() val screenState = routerFlow.state.collectAsState(scope.coroutineContext) + console.log(screenState.value) when (screenState.value) { is Screen.Welcome -> {} is Screen.Register -> RegisterComponent() is Screen.Login -> LoginComponent() is Screen.Dashboard -> DashboardComponent() - //is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - //is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) - //is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) - else -> {} + is Screen.Settings, is Screen.SettingsChangeUserData -> Text("Settings")//SettingsComponent(screenState = screenState) + is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister ->Text("Old Category") //CategoryComponent(screenState = screenState) + is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> Text("Old Entry")//EntryComponent(screenState = screenState) + is Screen.Category -> Text("New Category") + is Screen.Entry -> Text("New Entry") + else -> {Text("No known Screen! Check if the screen you're trying to reach is in the ScreenRouter")} } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 8924fc9c..1f56cc92 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -55,7 +55,7 @@ fun DashboardComponent() { ) } - CreateNewEntryButton(viewModel.onEvent(DashboardEvent.OnEntryCreate)) + CreateNewEntryButton { viewModel.onEvent(DashboardEvent.OnEntryCreate) } } } @@ -78,14 +78,14 @@ fun DashboardData( @Composable -fun CreateNewEntryButton(onEntryCreateButton: Unit) { +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { Div (attrs = {style { display(DisplayStyle.Flex) justifyContent(JustifyContent.FlexEnd) }}) { Button(attrs = { classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) - onClick { onEntryCreateButton } + onClick { onEntryCreateButton() } }) { Div(attrs = { classes("mdc-fab__ripple") }) Icon("add") From a8392b5e5e632ab6b3866234d23857173dec56fe Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 22:58:27 +0200 Subject: [PATCH 117/325] Show current entries on Dashboard in their corresponding categories --- .../compose/dashboard/DashboardComponent.kt | 79 +++++++++++++++++-- .../compose/entry/EntryComponent.kt | 49 ------------ 2 files changed, 71 insertions(+), 57 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 1f56cc92..a27e8100 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -2,25 +2,22 @@ package de.hsfl.budgetBinder.compose.dashboard import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.Entry -import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.Icon import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.category.BudgetBar -import de.hsfl.budgetBinder.compose.entry.EntryList -import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.UiEvent -import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEntryState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEvent +import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.kodein.di.instance +import kotlin.math.absoluteValue @Composable fun DashboardComponent() { @@ -53,8 +50,13 @@ fun DashboardComponent() { onPrevClicked = { viewModel.onEvent(DashboardEvent.OnPrevCategory) }, onNextClicked = { viewModel.onEvent(DashboardEvent.OnNextCategory) } ) + EntryList(entryList = entryList.value.entryList, + oldEntries = olderEntries.value, + onItemClicked = { viewModel.onEvent(DashboardEvent.OnEntry(it)) }, + onLoadMore = { viewModel.onEvent(DashboardEvent.OnLoadMore) }, + onEntryDelete = { viewModel.onEvent(DashboardEvent.OnEntryDelete(it)) } + ) } - CreateNewEntryButton { viewModel.onEvent(DashboardEvent.OnEntryCreate) } } } @@ -143,3 +145,64 @@ fun SwipeContainer( } } + +//Should be put in own File +@Composable +fun EntryListElement( + entry: DashboardEntryState, + onItemClicked: (Int) -> Unit, + onEntryDelete: (Int) -> Unit +) { + Div(attrs = { + classes("mdc-card", "mdc-card--outlined", AppStylesheet.entryListElement) + onClick { onItemClicked(entry.entry.id) } + }) { + CategoryImageToIcon(entry.categoryImage) + Div(attrs = { classes(AppStylesheet.entryListElementText) }) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text(entry.entry.name) } + } + Div(attrs = { classes(AppStylesheet.imageFlexContainer) }) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.moneyText + ) + }) { Text(amountToString(entry.entry.amount)) } + } + } +} + +fun amountToString(amount: Float): String { + //This whole thing just so it's "- 10 €" and not "-10 €" + val x = if (amount < 0) "-" else "" + return "$x ${amount.absoluteValue} €" +} +//TODO: Load Old Data and old Entries +@Composable +fun EntryList( + entryList: List, + oldEntries: Map, + onItemClicked: (Int) -> Unit, + onLoadMore: () -> Unit, + onEntryDelete: (Int) -> Unit + +) { + if (entryList.isEmpty()) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text("This category has no entries. You can create an new entry.") } + } else { + for (entry in entryList) { + EntryListElement(entry, onItemClicked, onEntryDelete) + } + } +} + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 0e704a15..1b5e86f1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -77,54 +77,5 @@ fun EntryComponent(screenState: MutableState) { } } -//Should be put in own File -@Composable -fun EntryListElement(entry: Entry, categoryList: List, onEntry: (id: Int) -> Unit) { - Div(attrs = { - classes("mdc-card", "mdc-card--outlined", AppStylesheet.entryListElement) - onClick { onEntry(entry.id) } - }) { - CategoryImageToIcon(categoryIdToCategory(entry.category_id, categoryList).image) - Div(attrs = { classes(AppStylesheet.entryListElementText) }) { - Div(attrs = { - classes( - "mdc-typography--headline5", - AppStylesheet.text - ) - }) { Text(entry.name) } - } - Div(attrs = { classes(AppStylesheet.imageFlexContainer) }) { - Div(attrs = { - classes( - "mdc-typography--headline5", - AppStylesheet.moneyText - ) - }) { Text(amountToString(entry.amount)) } - } - } -} - -fun amountToString(amount: Float): String { - //This whole thing just so it's "- 10 €" and not "-10 €" - val x = if (amount < 0) "-" else "" - return "$x ${amount.absoluteValue} €" -} - -@Composable -fun EntryList(list: List, categoryList: List, onEntry: (id: Int) -> Unit) { - if (list.isEmpty()) { - Div(attrs = { - classes( - "mdc-typography--headline5", - AppStylesheet.text - ) - }) { Text("No Entries in this category") } - } else { - for (entry in list) { - EntryListElement(entry, categoryList, onEntry) - } - } -} - fun entriesFromCategory(list: List, category_id: Int?): List = list.filter { it.category_id == category_id } From a073a7e7e0ae7d2ec2897d3c3d13eac9e14c6022 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 23:49:56 +0200 Subject: [PATCH 118/325] Add basic logic to load older entries --- .../compose/dashboard/DashboardComponent.kt | 103 +++++++++++------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index a27e8100..acf2710e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -12,6 +12,7 @@ import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEntryState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEvent import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginEvent import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.* @@ -27,7 +28,7 @@ fun DashboardComponent() { val totalSpendBudget = viewModel.spendBudgetOnCurrentCategory.collectAsState() val olderEntries = viewModel.oldEntriesMapState.collectAsState() val loadingState = remember { mutableStateOf(false) } - // val scaffoldState = rememberScaffoldState() + // val scaffoldState = rememberScaffoldState() LaunchedEffect(key1 = true) { viewModel.eventFlow.collectLatest { event -> @@ -71,20 +72,22 @@ fun DashboardData( onPrevClicked: () -> Unit, onNextClicked: () -> Unit ) { - SwipeContainer ( + SwipeContainer( hasPrev, hasNext, onPrevClicked, onNextClicked - ){ - BudgetBar(focusedCategory,totalSpendBudget,totalBudget) + ) { + BudgetBar(focusedCategory, totalSpendBudget, totalBudget) } } @Composable fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { - Div (attrs = {style { - display(DisplayStyle.Flex) - justifyContent(JustifyContent.FlexEnd) - }}) { + Div(attrs = { + style { + display(DisplayStyle.Flex) + justifyContent(JustifyContent.FlexEnd) + } + }) { Button(attrs = { classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) onClick { onEntryCreateButton() } @@ -109,44 +112,81 @@ fun SwipeContainer( classes(AppStylesheet.flexContainer) }) { Div(attrs = { - if(hasPrev) { + if (hasPrev) { classes(AppStylesheet.imageFlexContainer, "mdc-button") onClick { onPrevClicked() } - } - else{ + } else { classes(AppStylesheet.imageFlexContainer) - style{ + style { paddingLeft(8.px) paddingRight(8.px) } } - }){ - if(hasPrev) Icon("arrow_back_ios_new") + }) { + if (hasPrev) Icon("arrow_back_ios_new") } Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) { content() } Div(attrs = { - if(hasNext) { + if (hasNext) { classes(AppStylesheet.imageFlexContainer, "mdc-button") onClick { onNextClicked() } - } - else{ + } else { classes(AppStylesheet.imageFlexContainer) - style{ + style { paddingLeft(8.px) paddingRight(8.px) } } }) { - if(hasNext) Icon("arrow_forward_ios_new") + if (hasNext) Icon("arrow_forward_ios_new") + } + } +} + +//TODO: Load Old Data and old Entries +@Composable +fun EntryList( + entryList: List, + oldEntries: Map, + onItemClicked: (Int) -> Unit, + onLoadMore: () -> Unit, + onEntryDelete: (Int) -> Unit + +) { + if (entryList.isEmpty()) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text("This category has no entries. You can create an new entry.") } + } else { + for (entry in entryList) { + EntryListElement(entry, onItemClicked, onEntryDelete) + } + Text("Older entries...") + for ((date, dashboardState) in oldEntries) { + Text(date) //TODO-WEB: Sticky? + for (entry in dashboardState.entryList) { + EntryListElement(entry, onItemClicked, onEntryDelete) + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onLoadMore() } + } + ) { + Span(attrs = { classes("mdc-button__label") } + ) { Text("Load more Entries") } } } } -//Should be put in own File @Composable fun EntryListElement( entry: DashboardEntryState, @@ -182,27 +222,6 @@ fun amountToString(amount: Float): String { val x = if (amount < 0) "-" else "" return "$x ${amount.absoluteValue} €" } -//TODO: Load Old Data and old Entries -@Composable -fun EntryList( - entryList: List, - oldEntries: Map, - onItemClicked: (Int) -> Unit, - onLoadMore: () -> Unit, - onEntryDelete: (Int) -> Unit -) { - if (entryList.isEmpty()) { - Div(attrs = { - classes( - "mdc-typography--headline5", - AppStylesheet.text - ) - }) { Text("This category has no entries. You can create an new entry.") } - } else { - for (entry in entryList) { - EntryListElement(entry, onItemClicked, onEntryDelete) - } - } -} + From ed985dee975b9030464664f67ab93e35406bc938 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 23:59:05 +0200 Subject: [PATCH 119/325] Add NavBar --- .../hsfl/budgetBinder/compose/Composables.kt | 36 ------ .../de/hsfl/budgetBinder/compose/NavBar.kt | 110 ++++++++++++++++++ 2 files changed, 110 insertions(+), 36 deletions(-) create mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 5451397c..d87c55c2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -36,42 +36,6 @@ fun MainFlexContainer(content: @Composable () -> Unit) { } } -@Composable -fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit) { - Header( - attrs = { - classes("mdc-top-app-bar") - } - ) { - Div( - attrs = { - classes("mdc-top-app-bar__row") - } - ) { - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") - } - ) { - logoButton() - Span( - attrs = { - classes("mdc-top-app-bar__title") - } - ) { - Text("Budget-Binder") - } - } - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") - } - ) { - navButtons() - } - } - } -} ///* Gives a material icon based on the icon name*/// diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt new file mode 100644 index 00000000..58219f78 --- /dev/null +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt @@ -0,0 +1,110 @@ +package de.hsfl.budgetBinder.compose + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerEvent +import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerViewModel +import di +import org.jetbrains.compose.web.dom.* +import org.kodein.di.instance + +//Top Navigation Bar +@Composable +fun NavBar(content: @Composable () -> Unit) { + val viewModel: NavDrawerViewModel by di.instance() + Header( + attrs = { + classes("mdc-top-app-bar") + } + ) { + Div( + attrs = { + classes("mdc-top-app-bar__row") + } + ) { + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") + } + ) { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { viewModel.onEvent(NavDrawerEvent.OnDashboard) } + } + ) + Span( + attrs = { + classes("mdc-top-app-bar__title") + } + ) { + Text("Budget-Binder") + } + } + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") + } + ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(NavDrawerEvent.OnCreateEntry) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("New Entry") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(NavDrawerEvent.OnCategory) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(NavDrawerEvent.OnSettings) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(NavDrawerEvent.OnLogout) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Logout") + } + } + } + } + } + content() +} From 1b9186523b145b1aad2c563c4c587095f93687a6 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 00:04:13 +0200 Subject: [PATCH 120/325] Add new NavBar to Dashboard --- .../hsfl/budgetBinder/compose/Composables.kt | 37 +++++++++++++++++++ .../compose/dashboard/DashboardComponent.kt | 3 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index d87c55c2..fcc5331b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -36,6 +36,43 @@ fun MainFlexContainer(content: @Composable () -> Unit) { } } +@Deprecated("Use new NavBar instead! just write NavBar{} over your MainFlexContainer!") +@Composable +fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit) { + Header( + attrs = { + classes("mdc-top-app-bar") + } + ) { + Div( + attrs = { + classes("mdc-top-app-bar__row") + } + ) { + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") + } + ) { + logoButton() + Span( + attrs = { + classes("mdc-top-app-bar__title") + } + ) { + Text("Budget-Binder") + } + } + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") + } + ) { + navButtons() + } + } + } +} ///* Gives a material icon based on the icon name*/// diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index acf2710e..d1ed8bc8 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.Icon import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.category.BudgetBar import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon @@ -39,7 +40,7 @@ fun DashboardComponent() { } } } - //TODO: TOPBAR + NavBar{} MainFlexContainer { Div { DashboardData( From 2e428403c052d73a65af98d4295b70147646d328 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 00:07:50 +0200 Subject: [PATCH 121/325] Format files and remove unnecessary imports --- .../hsfl/budgetBinder/compose/Composables.kt | 16 +++++++++--- .../de/hsfl/budgetBinder/compose/NavBar.kt | 25 +++++++++++++++---- .../de/hsfl/budgetBinder/compose/Router.kt | 17 +++++++------ .../compose/dashboard/DashboardComponent.kt | 2 +- .../compose/login/LoginComponent.kt | 10 +++++--- .../src/jsMain/kotlin/main.kt | 1 - .../kotlin/de/hsfl/budgetBinder/Root.kt | 12 ++++++--- identifier.sqlite | 0 8 files changed, 57 insertions(+), 26 deletions(-) create mode 100644 identifier.sqlite diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index fcc5331b..ba902a66 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -32,7 +32,7 @@ fun MainFlexContainer(content: @Composable () -> Unit) { content() } } - Div(attrs = { classes(AppStylesheet.pufferFlexContainer)}) + Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) } } @@ -168,7 +168,10 @@ fun CategoryImagesToImageList( "mdc-icon-button", "mdc-button--raised" ) - else classes("mdc-image-list__image-aspect-container", "mdc-icon-button") + else classes( + "mdc-image-list__image-aspect-container", + "mdc-icon-button" + ) onClick { onClick(image); highlightImage.value = image } } ) { @@ -271,7 +274,12 @@ fun CategoryList( } @Composable -fun DeleteDialog(hidden: Boolean, buttonAction: () -> Unit, resetDialog: () -> Unit, content: @Composable () -> Unit) { +fun DeleteDialog( + hidden: Boolean, + buttonAction: () -> Unit, + resetDialog: () -> Unit, + content: @Composable () -> Unit +) { var hiddenValue by remember { mutableStateOf(hidden) } Div( attrs = { @@ -405,7 +413,7 @@ fun ChooseCategoryMenu( onClick { chosenCategory = category; getCategoryId(category.id) } }) { Span(attrs = { classes("mdc-list-item__ripple") }) { } - Span(attrs = { }) { Text(category.name) } + Span(attrs = { }) { Text(category.name) } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt index 58219f78..e3d7263a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt @@ -1,7 +1,6 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.Composable -import androidx.compose.runtime.rememberCoroutineScope import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerEvent import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerViewModel @@ -49,7 +48,11 @@ fun NavBar(content: @Composable () -> Unit) { ) { Button( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + classes( + "mdc-button", + "mdc-button--raised", + "mdc-top-app-bar__navigation-icon" + ) onClick { viewModel.onEvent(NavDrawerEvent.OnCreateEntry) } } ) { @@ -63,7 +66,11 @@ fun NavBar(content: @Composable () -> Unit) { } Button( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + classes( + "mdc-button", + "mdc-button--raised", + "mdc-top-app-bar__navigation-icon" + ) onClick { viewModel.onEvent(NavDrawerEvent.OnCategory) } } ) { @@ -77,7 +84,11 @@ fun NavBar(content: @Composable () -> Unit) { } Button( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + classes( + "mdc-button", + "mdc-button--raised", + "mdc-top-app-bar__navigation-icon" + ) onClick { viewModel.onEvent(NavDrawerEvent.OnSettings) } } ) { @@ -91,7 +102,11 @@ fun NavBar(content: @Composable () -> Unit) { } Button( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + classes( + "mdc-button", + "mdc-button--raised", + "mdc-top-app-bar__navigation-icon" + ) onClick { viewModel.onEvent(NavDrawerEvent.OnLogout) } } ) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 273337d0..b79632be 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -1,15 +1,11 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState import androidx.compose.runtime.collectAsState import androidx.compose.runtime.rememberCoroutineScope -import de.hsfl.budgetBinder.compose.category.CategoryComponent import de.hsfl.budgetBinder.compose.dashboard.DashboardComponent -import de.hsfl.budgetBinder.compose.entry.EntryComponent import de.hsfl.budgetBinder.compose.login.LoginComponent import de.hsfl.budgetBinder.compose.register.RegisterComponent -import de.hsfl.budgetBinder.compose.settings.SettingsComponent import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.flow.RouterFlow import di @@ -27,11 +23,16 @@ fun Router() { is Screen.Register -> RegisterComponent() is Screen.Login -> LoginComponent() is Screen.Dashboard -> DashboardComponent() - is Screen.Settings, is Screen.SettingsChangeUserData -> Text("Settings")//SettingsComponent(screenState = screenState) - is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister ->Text("Old Category") //CategoryComponent(screenState = screenState) - is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> Text("Old Entry")//EntryComponent(screenState = screenState) + is Screen.Settings, is Screen.SettingsChangeUserData + -> Text("Settings")//SettingsComponent(screenState = screenState) + is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister + -> Text("Old Category") //CategoryComponent(screenState = screenState) + is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview + -> Text("Old Entry")//EntryComponent(screenState = screenState) is Screen.Category -> Text("New Category") is Screen.Entry -> Text("New Entry") - else -> {Text("No known Screen! Check if the screen you're trying to reach is in the ScreenRouter")} + else -> { + Text("No known Screen! Check if the screen you're trying to reach is in the ScreenRouter") + } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index d1ed8bc8..8b34b215 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -40,7 +40,7 @@ fun DashboardComponent() { } } } - NavBar{} + NavBar {} MainFlexContainer { Div { DashboardData( diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt index 59d859f5..17a053fc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt @@ -1,10 +1,9 @@ package de.hsfl.budgetBinder.compose.login + import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiEvent -import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginEvent import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginViewModel import di @@ -12,7 +11,6 @@ import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* -import org.kodein.di.compose.withDI import org.kodein.di.instance @@ -74,7 +72,11 @@ fun LoginComponent() { ) { Button( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + classes( + "mdc-button", + "mdc-button--raised", + "mdc-top-app-bar__navigation-icon" + ) onClick { viewModel.onEvent(LoginEvent.OnRegisterScreen) } } ) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt index 69ba53a0..797d4749 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt @@ -2,7 +2,6 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.Router import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.di.kodein -import de.hsfl.budgetBinder.presentation.Screen import io.ktor.client.engine.js.* import org.jetbrains.compose.web.css.Style import org.jetbrains.compose.web.renderComposable diff --git a/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/Root.kt b/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/Root.kt index 64546390..b351545f 100644 --- a/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/Root.kt +++ b/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/Root.kt @@ -7,7 +7,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import de.hsfl.budgetBinder.common.User import de.hsfl.budgetBinder.di.kodein import de.hsfl.budgetBinder.presentation.UiEvent import de.hsfl.budgetBinder.presentation.flow.DataFlow @@ -36,12 +35,19 @@ fun App() = withDI(di) { is UiEvent.ShowLoading -> loadingState.value = true is UiEvent.ShowError -> { loadingState.value = false - scaffoldState.snackbarHostState.showSnackbar(message = event.msg, actionLabel = "Dismiss") + scaffoldState.snackbarHostState.showSnackbar( + message = event.msg, + actionLabel = "Dismiss" + ) } is UiEvent.ShowSuccess -> { loadingState.value = false - scaffoldState.snackbarHostState.showSnackbar(message = event.msg, actionLabel = "Dismiss") + scaffoldState.snackbarHostState.showSnackbar( + message = event.msg, + actionLabel = "Dismiss" + ) } + else -> {} } } } diff --git a/identifier.sqlite b/identifier.sqlite new file mode 100644 index 00000000..e69de29b From 45f93eebacf5a385065b3da8c26fcc621c5350cd Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 00:18:15 +0200 Subject: [PATCH 122/325] Fix Login (LoginViewModel isn't complete, add todo for it) --- .../presentation/viewmodel/login/LoginViewModel.kt | 3 +++ .../de/hsfl/budgetBinder/compose/login/LoginComponent.kt | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/login/LoginViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/login/LoginViewModel.kt index 9f414177..287a4538 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/login/LoginViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/login/LoginViewModel.kt @@ -69,6 +69,9 @@ class LoginViewModel( serverUrlText.value.copy(serverAddress = event.value) is LoginEvent.OnLogin -> { if (validateEmail(email = emailText.value.email)) { + //TODO: Check what frontend this is opened from. + // Web -> auth(...), + // everyone else -> toggleDialog() toggleDialog() } else { _emailText.value = emailText.value.copy(emailValid = false) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt index 17a053fc..316720bb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt @@ -99,7 +99,7 @@ fun LoginComponent() { attrs = { this.addEventListener("submit") { console.log("$emailTextState, $passwordTextState") - viewModel.onEvent(LoginEvent.OnLogin) + viewModel.onEvent(LoginEvent.OnServerUrlDialogConfirm) //TODO: Change to OnLogin as soon as LoginViewModel has corresponding logic it.preventDefault() } } From b78d5873f2eebae67bc5bb7607afa72f450018a2 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 00:25:15 +0200 Subject: [PATCH 123/325] Delete unused LoginView --- .../budgetBinder/compose/login/LoginView.kt | 181 ------------------ 1 file changed, 181 deletions(-) delete mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt deleted file mode 100644 index 55e44092..00000000 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt +++ /dev/null @@ -1,181 +0,0 @@ -package de.hsfl.budgetBinder.compose.login - -import androidx.compose.runtime.* -import de.hsfl.budgetBinder.compose.MainFlexContainer -import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.dom.* - -@Composable -fun LoginView( - state: State, - onLoginButtonPressed: (email: String, password: String) -> Unit, - onLoginSuccess: () -> Unit, - onChangeToRegister: () -> Unit -) { - var emailTextFieldState by remember { mutableStateOf("") } - var passwordTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } - - Header( - attrs = { - classes("mdc-top-app-bar") - } - ) { - Div( - attrs = { - classes("mdc-top-app-bar__row") - } - ) { - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") - } - ) { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - } - ) - Span( - attrs = { - classes("mdc-top-app-bar__title") - } - ) { - Text("Budget-Binder") - } - } - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") - } - ) { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToRegister() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Register Instead") - } - } - } - } - } - - MainFlexContainer { - // -- Login Form -- - H1 { Text(" Login") } - Form( - attrs = { - this.addEventListener("submit") { - console.log("${emailTextFieldState}, ${passwordTextFieldState}") - onLoginButtonPressed(emailTextFieldState, passwordTextFieldState) - it.preventDefault() - } - } - ) { - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Email") } - EmailInput(value = emailTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - emailTextFieldState = it.value - - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - // -- Login Request Management -- - when (viewState) { - is UiState.Success<*> -> { - onLoginSuccess() - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - else -> {} - } - } - } -} \ No newline at end of file From d7f130e5491a0d90c6d80764054fac33b937a178 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 22:57:54 +0200 Subject: [PATCH 124/325] Create basis for new EntryViewModel --- .../entryViewModel/EntryViewModel.kt | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt new file mode 100644 index 00000000..ad6ee5fb --- /dev/null +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -0,0 +1,41 @@ +package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel + +import de.hsfl.budgetBinder.common.DataResponse +import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.domain.usecase.* +import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.flow.DataFlow +import de.hsfl.budgetBinder.presentation.flow.RouterFlow +import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.flow.* + +class EntryViewModel( + private val loginUseCases: LoginUseCases, + private val routerFlow: RouterFlow, + private val dataFlow: DataFlow, + private val scope: CoroutineScope + ) { + /* *** Variables *** */ + + //Dialog used to confirm deletion + private val _dialogState = MutableStateFlow(false) + val dialogState: StateFlow = _dialogState + private val _eventFlow = UiEventSharedFlow.mutableEventFlow + val eventFlow = UiEventSharedFlow.eventFlow + + + init{ + //Do we need something to init? + } + + fun onEvent(event: EntryEvent){ + //TODO Event action + } + + private fun toggleDialog() { + _dialogState.value = !dialogState.value + } +} From 7a8dc0bbcbd1c8de59ab6886bd414e0058907c5b Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:02:00 +0200 Subject: [PATCH 125/325] Add boiler use case functions --- .../viewmodel/entryViewModel/EntryViewModel.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index ad6ee5fb..0582e0e6 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -31,10 +31,19 @@ class EntryViewModel( //Do we need something to init? } + /* *** Event Handling *** */ fun onEvent(event: EntryEvent){ //TODO Event action } + + /* *** Use Case usages *** */ + fun getEntryById(id: Int) {} + fun createEntry(entry: Entry.In) {} + fun changeEntry(entry: Entry.Patch, id: Int) {} + fun removeEntry(id: Int) {} + + /* *** Helper *** */ private fun toggleDialog() { _dialogState.value = !dialogState.value } From 719a18ac3d7a31b1946bcb7c0b74733c72d91b87 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:14:57 +0200 Subject: [PATCH 126/325] Add EntryEvents --- .../viewmodel/entryViewModel/EntryEvent.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt new file mode 100644 index 00000000..3ae90ace --- /dev/null +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -0,0 +1,19 @@ +package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel + +// View is not allowed to declare what should be done, only notify what has happened, names are assigned as such + +sealed class EntryEvent { + data class EnteredName(val value: String) : EntryEvent() + + //If the amount will be added or subtracted from the current spent sum + data class EnteredAmountInputType(val value: Boolean) : EntryEvent() + data class EnteredAmount(val value: Float) : EntryEvent() + data class EnteredRepeatState(val value: Boolean) : EntryEvent() + data class EnteredCategoryID(val value: Int) : EntryEvent() + object OnCreateEntry : EntryEvent() + object OnEditEntry : EntryEvent() + object OnDeleteEntry : EntryEvent() + object OnDeleteDialogConfirm : EntryEvent() + object OnDeleteDialogDismiss : EntryEvent() + +} From 1fb42decfc4aa71caf32a040607c357628185beb Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:23:59 +0200 Subject: [PATCH 127/325] Add boiler for each event in onEvent --- .../entryViewModel/EntryViewModel.kt | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 0582e0e6..ef9c6390 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -17,7 +17,7 @@ class EntryViewModel( private val routerFlow: RouterFlow, private val dataFlow: DataFlow, private val scope: CoroutineScope - ) { +) { /* *** Variables *** */ //Dialog used to confirm deletion @@ -27,13 +27,28 @@ class EntryViewModel( val eventFlow = UiEventSharedFlow.eventFlow - init{ + init { //Do we need something to init? } /* *** Event Handling *** */ - fun onEvent(event: EntryEvent){ - //TODO Event action + fun onEvent(event: EntryEvent) { + when (event) { + is EntryEvent.EnteredName -> {} + is EntryEvent.EnteredAmount -> {} + is EntryEvent.EnteredRepeatState -> {} + is EntryEvent.EnteredCategoryID -> {} + is EntryEvent.EnteredAmountInputType -> {} + is EntryEvent.OnCreateEntry -> {} + is EntryEvent.OnEditEntry -> {} + is EntryEvent.OnDeleteEntry -> {} + is EntryEvent.OnDeleteDialogConfirm -> {} + is EntryEvent.OnDeleteDialogDismiss -> {} + else -> { + throw Exception("Unhandled EntryEvent in EntryViewModel") + } + } + } From 5fcb061cf48c917bcff2b6a279ce8b5ea4a29204 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:35:12 +0200 Subject: [PATCH 128/325] Rename EnteredAmountInputType to EnteredAmountSign and EnteredRepeatState to EnteredRepeat --- .../presentation/viewmodel/entryViewModel/EntryEvent.kt | 8 ++++---- .../viewmodel/entryViewModel/EntryViewModel.kt | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt index 3ae90ace..3fa91208 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -4,12 +4,12 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel sealed class EntryEvent { data class EnteredName(val value: String) : EntryEvent() - - //If the amount will be added or subtracted from the current spent sum - data class EnteredAmountInputType(val value: Boolean) : EntryEvent() data class EnteredAmount(val value: Float) : EntryEvent() - data class EnteredRepeatState(val value: Boolean) : EntryEvent() + data class EnteredRepeat(val value: Boolean) : EntryEvent() data class EnteredCategoryID(val value: Int) : EntryEvent() + data class EnteredAmountSign(val value: Boolean) : + EntryEvent() //If the amount will be added or subtracted from the current spent sum + object OnCreateEntry : EntryEvent() object OnEditEntry : EntryEvent() object OnDeleteEntry : EntryEvent() diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index ef9c6390..342cf682 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -7,6 +7,7 @@ import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow +import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginTextFieldState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -20,7 +21,8 @@ class EntryViewModel( ) { /* *** Variables *** */ - //Dialog used to confirm deletion + + //Default ViewModel Variables private val _dialogState = MutableStateFlow(false) val dialogState: StateFlow = _dialogState private val _eventFlow = UiEventSharedFlow.mutableEventFlow @@ -36,9 +38,9 @@ class EntryViewModel( when (event) { is EntryEvent.EnteredName -> {} is EntryEvent.EnteredAmount -> {} - is EntryEvent.EnteredRepeatState -> {} + is EntryEvent.EnteredRepeat -> {} is EntryEvent.EnteredCategoryID -> {} - is EntryEvent.EnteredAmountInputType -> {} + is EntryEvent.EnteredAmountSign -> {} is EntryEvent.OnCreateEntry -> {} is EntryEvent.OnEditEntry -> {} is EntryEvent.OnDeleteEntry -> {} From 95e8552aed2ff14d0a9ea234a16e847e54593641 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:36:28 +0200 Subject: [PATCH 129/325] Add EntryInputState --- .../viewmodel/entryViewModel/EntryInputState.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt new file mode 100644 index 00000000..5cc9feb0 --- /dev/null +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt @@ -0,0 +1,9 @@ +package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel + +data class EntryInputState( + val name: String = "", + val amount: String = "", + val repeat: Boolean = false, + val categoryID: Int? = null, + val amountSign: Boolean = false +) From b23b68477d69d6f9de4aa383a575e9e5f04adb76 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:53:26 +0200 Subject: [PATCH 130/325] Add StateFlows for data inputs --- .../viewmodel/entryViewModel/EntryViewModel.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 342cf682..499211f2 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -20,6 +20,20 @@ class EntryViewModel( private val scope: CoroutineScope ) { /* *** Variables *** */ + private val _nameText = MutableStateFlow(EntryInputState()) + val nameText: StateFlow = _nameText + + private val _amountText = MutableStateFlow(EntryInputState()) + val amountText: StateFlow = _amountText + + private val _repeatText = MutableStateFlow(EntryInputState()) + val repeatText: StateFlow = _repeatText + + private val _categoryIDText = MutableStateFlow(EntryInputState()) + val categoryIDText: StateFlow = _categoryIDText + + private val _amountSignText = MutableStateFlow(EntryInputState()) + val amountSignText: StateFlow = _amountSignText //Default ViewModel Variables From 911bf79b6327a93caf5b049e107f116759fa7e2e Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 00:10:51 +0200 Subject: [PATCH 131/325] Add button events, rename some data input variable names --- .../viewmodel/entryViewModel/EntryEvent.kt | 3 +- .../entryViewModel/EntryViewModel.kt | 41 +++++++++++++------ 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt index 3fa91208..f6b492f9 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -7,8 +7,7 @@ sealed class EntryEvent { data class EnteredAmount(val value: Float) : EntryEvent() data class EnteredRepeat(val value: Boolean) : EntryEvent() data class EnteredCategoryID(val value: Int) : EntryEvent() - data class EnteredAmountSign(val value: Boolean) : - EntryEvent() //If the amount will be added or subtracted from the current spent sum + data class EnteredAmountSign(val value: Boolean) : EntryEvent() object OnCreateEntry : EntryEvent() object OnEditEntry : EntryEvent() diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 499211f2..890c467c 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -3,6 +3,7 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel import de.hsfl.budgetBinder.common.DataResponse import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.domain.usecase.* +import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow @@ -20,28 +21,30 @@ class EntryViewModel( private val scope: CoroutineScope ) { /* *** Variables *** */ + + // ---- Data Input Variables ---- private val _nameText = MutableStateFlow(EntryInputState()) val nameText: StateFlow = _nameText private val _amountText = MutableStateFlow(EntryInputState()) val amountText: StateFlow = _amountText - private val _repeatText = MutableStateFlow(EntryInputState()) - val repeatText: StateFlow = _repeatText + private val _repeatState = MutableStateFlow(EntryInputState()) + val repeatState: StateFlow = _repeatState - private val _categoryIDText = MutableStateFlow(EntryInputState()) - val categoryIDText: StateFlow = _categoryIDText + private val _categoryIDState = MutableStateFlow(EntryInputState()) + val categoryIDState: StateFlow = _categoryIDState - private val _amountSignText = MutableStateFlow(EntryInputState()) - val amountSignText: StateFlow = _amountSignText + private val _amountSignState = MutableStateFlow(EntryInputState()) + val amountSignState: StateFlow = _amountSignState - //Default ViewModel Variables + // --- Default ViewModel Variables ---- private val _dialogState = MutableStateFlow(false) val dialogState: StateFlow = _dialogState private val _eventFlow = UiEventSharedFlow.mutableEventFlow val eventFlow = UiEventSharedFlow.eventFlow - + // ---- init { //Do we need something to init? @@ -55,11 +58,23 @@ class EntryViewModel( is EntryEvent.EnteredRepeat -> {} is EntryEvent.EnteredCategoryID -> {} is EntryEvent.EnteredAmountSign -> {} - is EntryEvent.OnCreateEntry -> {} - is EntryEvent.OnEditEntry -> {} - is EntryEvent.OnDeleteEntry -> {} - is EntryEvent.OnDeleteDialogConfirm -> {} - is EntryEvent.OnDeleteDialogDismiss -> {} + is EntryEvent.OnCreateEntry -> { + when (routerFlow.state.value) { + is Screen.Entry.Create -> createEntry( + Entry.In( + nameText, + amountState, + repeatState, + categoryIDState + ) + ) + else -> routerFlow.navigateTo(Screen.Entry.Create) + } + } + is EntryEvent.OnEditEntry -> routerFlow.navigateTo(Screen.Settings.Server) + is EntryEvent.OnDeleteEntry -> _dialogState.value = true + is EntryEvent.OnDeleteDialogConfirm -> removeEntry()//TODO Entry ID + is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") } From bc7c4b4cc4dbb07a3536efa0f56bd36bd0f3d1a4 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 00:15:01 +0200 Subject: [PATCH 132/325] Change data input variable structure to have a more precise type --- .../entryViewModel/EntryInputState.kt | 2 +- .../entryViewModel/EntryViewModel.kt | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt index 5cc9feb0..7debc864 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt @@ -2,7 +2,7 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel data class EntryInputState( val name: String = "", - val amount: String = "", + val amount: Float = 0f, val repeat: Boolean = false, val categoryID: Int? = null, val amountSign: Boolean = false diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 890c467c..622ac5dc 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -23,20 +23,20 @@ class EntryViewModel( /* *** Variables *** */ // ---- Data Input Variables ---- - private val _nameText = MutableStateFlow(EntryInputState()) - val nameText: StateFlow = _nameText + private val _nameText = MutableStateFlow(EntryInputState().name) + val nameText: StateFlow = _nameText - private val _amountText = MutableStateFlow(EntryInputState()) - val amountText: StateFlow = _amountText + private val _amountText = MutableStateFlow(EntryInputState().amount) + val amountText: StateFlow = _amountText - private val _repeatState = MutableStateFlow(EntryInputState()) - val repeatState: StateFlow = _repeatState + private val _repeatState = MutableStateFlow(EntryInputState().repeat) + val repeatState: StateFlow = _repeatState - private val _categoryIDState = MutableStateFlow(EntryInputState()) - val categoryIDState: StateFlow = _categoryIDState + private val _categoryIDState = MutableStateFlow(EntryInputState().categoryID) + val categoryIDState: StateFlow = _categoryIDState - private val _amountSignState = MutableStateFlow(EntryInputState()) - val amountSignState: StateFlow = _amountSignState + private val _amountSignState = MutableStateFlow(EntryInputState().amountSign) + val amountSignState: StateFlow = _amountSignState // --- Default ViewModel Variables ---- @@ -62,10 +62,10 @@ class EntryViewModel( when (routerFlow.state.value) { is Screen.Entry.Create -> createEntry( Entry.In( - nameText, - amountState, - repeatState, - categoryIDState + nameText.value, + amountText.value, + repeatState.value, + categoryIDState.value ) ) else -> routerFlow.navigateTo(Screen.Entry.Create) From 4773ed41ecbec95efb812342d29d15f80cba98eb Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 00:22:56 +0200 Subject: [PATCH 133/325] Add SelectedEntry --- .../presentation/viewmodel/entryViewModel/EntryEvent.kt | 2 ++ .../presentation/viewmodel/entryViewModel/EntryViewModel.kt | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt index f6b492f9..9e306f6c 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -3,12 +3,14 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel // View is not allowed to declare what should be done, only notify what has happened, names are assigned as such sealed class EntryEvent { + //User-made Data Input data class EnteredName(val value: String) : EntryEvent() data class EnteredAmount(val value: Float) : EntryEvent() data class EnteredRepeat(val value: Boolean) : EntryEvent() data class EnteredCategoryID(val value: Int) : EntryEvent() data class EnteredAmountSign(val value: Boolean) : EntryEvent() + //Action object OnCreateEntry : EntryEvent() object OnEditEntry : EntryEvent() object OnDeleteEntry : EntryEvent() diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 622ac5dc..550d713d 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -38,6 +38,8 @@ class EntryViewModel( private val _amountSignState = MutableStateFlow(EntryInputState().amountSign) val amountSignState: StateFlow = _amountSignState + private val _selectedEntry = MutableStateFlow(EntryState().selectedEntry) + val selectedEntry: StateFlow = _selectedEntry // --- Default ViewModel Variables ---- private val _dialogState = MutableStateFlow(false) @@ -73,7 +75,7 @@ class EntryViewModel( } is EntryEvent.OnEditEntry -> routerFlow.navigateTo(Screen.Settings.Server) is EntryEvent.OnDeleteEntry -> _dialogState.value = true - is EntryEvent.OnDeleteDialogConfirm -> removeEntry()//TODO Entry ID + is EntryEvent.OnDeleteDialogConfirm -> removeEntry(selectedEntry.value.id)//TODO Entry ID is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") From 731e2805a7cc2e8c38c285729c96e4eb9603c96c Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 00:26:27 +0200 Subject: [PATCH 134/325] Add data input eventhandling in viewmodel --- .../viewmodel/entryViewModel/EntryViewModel.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 550d713d..9024e664 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -55,11 +55,11 @@ class EntryViewModel( /* *** Event Handling *** */ fun onEvent(event: EntryEvent) { when (event) { - is EntryEvent.EnteredName -> {} - is EntryEvent.EnteredAmount -> {} - is EntryEvent.EnteredRepeat -> {} - is EntryEvent.EnteredCategoryID -> {} - is EntryEvent.EnteredAmountSign -> {} + is EntryEvent.EnteredName -> _nameText.value = nameText.value + is EntryEvent.EnteredAmount -> _amountText.value = amountText.value + is EntryEvent.EnteredRepeat -> _repeatState.value = repeatState.value + is EntryEvent.EnteredCategoryID -> _categoryIDState.value = categoryIDState.value + is EntryEvent.EnteredAmountSign -> _amountSignState.value = amountSignState.value is EntryEvent.OnCreateEntry -> { when (routerFlow.state.value) { is Screen.Entry.Create -> createEntry( From ecfa4d573636c1dc217d5a1202964445a164e7dc Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 00:40:04 +0200 Subject: [PATCH 135/325] Add OnEditEntry Event --- .../viewmodel/entryViewModel/EntryViewModel.kt | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 9024e664..09224408 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -60,7 +60,7 @@ class EntryViewModel( is EntryEvent.EnteredRepeat -> _repeatState.value = repeatState.value is EntryEvent.EnteredCategoryID -> _categoryIDState.value = categoryIDState.value is EntryEvent.EnteredAmountSign -> _amountSignState.value = amountSignState.value - is EntryEvent.OnCreateEntry -> { + is EntryEvent.OnCreateEntry -> when (routerFlow.state.value) { is Screen.Entry.Create -> createEntry( Entry.In( @@ -72,8 +72,19 @@ class EntryViewModel( ) else -> routerFlow.navigateTo(Screen.Entry.Create) } - } - is EntryEvent.OnEditEntry -> routerFlow.navigateTo(Screen.Settings.Server) + + is EntryEvent.OnEditEntry -> + when (routerFlow.state.value) { + is Screen.Entry.Edit -> changeEntry( + Entry.Patch( + nameText.value, + amountText.value, + repeatState.value, + Entry.Category(categoryIDState.value) + ), selectedEntry.value.id + ) + else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntry.value.id)) //using ID seems... unnecessary? + } is EntryEvent.OnDeleteEntry -> _dialogState.value = true is EntryEvent.OnDeleteDialogConfirm -> removeEntry(selectedEntry.value.id)//TODO Entry ID is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false From 037e93a15d9ddaf3de95879189b5b8b175e2c1ff Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 01:00:58 +0200 Subject: [PATCH 136/325] Get SelectedEntry when Screen is Edit or Overview --- .../viewmodel/entryViewModel/EntryViewModel.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 09224408..6b4093a0 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -49,7 +49,11 @@ class EntryViewModel( // ---- init { - //Do we need something to init? + when (routerFlow.state.value) { + is Screen.Entry.Overview -> getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) + is Screen.Entry.Edit -> getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) + else -> {} + } } /* *** Event Handling *** */ @@ -86,7 +90,7 @@ class EntryViewModel( else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntry.value.id)) //using ID seems... unnecessary? } is EntryEvent.OnDeleteEntry -> _dialogState.value = true - is EntryEvent.OnDeleteDialogConfirm -> removeEntry(selectedEntry.value.id)//TODO Entry ID + is EntryEvent.OnDeleteDialogConfirm -> removeEntry(selectedEntry.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") @@ -96,7 +100,7 @@ class EntryViewModel( } - /* *** Use Case usages *** */ + /* *** Use Case usages *** */ //TODO Implement use cases fun getEntryById(id: Int) {} fun createEntry(entry: Entry.In) {} fun changeEntry(entry: Entry.Patch, id: Int) {} From 055505ed1c98cc7671c6d5f6f5cab6b523ff7f4a Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 01:01:25 +0200 Subject: [PATCH 137/325] Add EntryState with selectedEntry --- .../presentation/viewmodel/entryViewModel/EntryState.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt new file mode 100644 index 00000000..d87cca04 --- /dev/null +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt @@ -0,0 +1,7 @@ +package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel + +import de.hsfl.budgetBinder.common.Entry + +data class EntryState( + val selectedEntry: Entry = Entry(0,"",0f,false,null) +) From e442932f097dbbdcc8f6845ca022dd2129668e21 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 14:44:34 +0200 Subject: [PATCH 138/325] Rename EntriesUseCases to EntryUseCases --- .../domain/usecase/{EntriesUseCases.kt => EntryUseCases.kt} | 2 +- .../presentation/viewmodel/entryViewModel/EntryViewModel.kt | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) rename budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/{EntriesUseCases.kt => EntryUseCases.kt} (91%) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntriesUseCases.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt similarity index 91% rename from budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntriesUseCases.kt rename to budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt index 0f914830..7233f2a2 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntriesUseCases.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt @@ -1,6 +1,6 @@ package de.hsfl.budgetBinder.domain.usecase -data class EntriesUseCases( +data class EntryUseCases( val getAllEntriesUseCase: GetAllEntriesUseCase, val getEntryByIdUseCase: GetEntryByIdUseCase, val createNewEntryUseCase: CreateNewEntryUseCase, diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 6b4093a0..998dab5a 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -15,7 +15,7 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.* class EntryViewModel( - private val loginUseCases: LoginUseCases, + private val entryUseCases: EntryUseCases, private val routerFlow: RouterFlow, private val dataFlow: DataFlow, private val scope: CoroutineScope @@ -101,7 +101,9 @@ class EntryViewModel( /* *** Use Case usages *** */ //TODO Implement use cases - fun getEntryById(id: Int) {} + fun getEntryById(id: Int) { + + } fun createEntry(entry: Entry.In) {} fun changeEntry(entry: Entry.Patch, id: Int) {} fun removeEntry(id: Int) {} From 9622046291022948bbe4cc724decc25bfd7fe6aa Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 14:50:47 +0200 Subject: [PATCH 139/325] Add getEntryById UseCase to EntryViewModel --- .../viewmodel/entryViewModel/EntryViewModel.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 998dab5a..264575c1 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -4,6 +4,7 @@ import de.hsfl.budgetBinder.common.DataResponse import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.UiEvent import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow @@ -102,7 +103,16 @@ class EntryViewModel( /* *** Use Case usages *** */ //TODO Implement use cases fun getEntryById(id: Int) { - + entryUseCases.getEntryByIdUseCase(id).onEach { + when (it){ + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + is DataResponse.Success<*> -> { + _selectedEntry.value = it.data!! + } + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + } + } } fun createEntry(entry: Entry.In) {} fun changeEntry(entry: Entry.Patch, id: Int) {} From e8b51e4a6b25aec1360f9bc0b5823f3d86e58379 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 14:55:32 +0200 Subject: [PATCH 140/325] Add createEntry UseCase to EntryViewModel --- .../viewmodel/entryViewModel/EntryViewModel.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 264575c1..dab96316 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -114,7 +114,16 @@ class EntryViewModel( } } } - fun createEntry(entry: Entry.In) {} + fun createEntry(entry: Entry.In) { + entryUseCases.createNewEntryUseCase(entry).onEach { + when (it){ + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + } + } + } fun changeEntry(entry: Entry.Patch, id: Int) {} fun removeEntry(id: Int) {} From 64d3b668f92e05a463af57c4cb4e40559e7bb791 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 14:56:31 +0200 Subject: [PATCH 141/325] Add changeEntry UseCase to EntryViewModel --- .../viewmodel/entryViewModel/EntryViewModel.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index dab96316..f3d98c9a 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -124,7 +124,16 @@ class EntryViewModel( } } } - fun changeEntry(entry: Entry.Patch, id: Int) {} + fun changeEntry(entry: Entry.Patch, id: Int) { + entryUseCases.changeEntryByIdUseCase(entry,id).onEach { + when (it){ + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully changed")) //TODO?: Change the msg + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + } + } + } fun removeEntry(id: Int) {} /* *** Helper *** */ From f0b43735b23dc07cb1619b2e667208b6dc77a139 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 14:59:56 +0200 Subject: [PATCH 142/325] Add removeEntry UseCase to EntryViewModel --- .../entryViewModel/EntryViewModel.kt | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index f3d98c9a..aa8b1f5a 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -104,7 +104,7 @@ class EntryViewModel( /* *** Use Case usages *** */ //TODO Implement use cases fun getEntryById(id: Int) { entryUseCases.getEntryByIdUseCase(id).onEach { - when (it){ + when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) is DataResponse.Success<*> -> { @@ -114,9 +114,10 @@ class EntryViewModel( } } } + fun createEntry(entry: Entry.In) { entryUseCases.createNewEntryUseCase(entry).onEach { - when (it){ + when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg @@ -124,9 +125,10 @@ class EntryViewModel( } } } + fun changeEntry(entry: Entry.Patch, id: Int) { - entryUseCases.changeEntryByIdUseCase(entry,id).onEach { - when (it){ + entryUseCases.changeEntryByIdUseCase(entry, id).onEach { + when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully changed")) //TODO?: Change the msg @@ -134,10 +136,15 @@ class EntryViewModel( } } } - fun removeEntry(id: Int) {} - /* *** Helper *** */ - private fun toggleDialog() { - _dialogState.value = !dialogState.value + fun removeEntry(id: Int) { + entryUseCases.deleteEntryByIdUseCase(id).onEach { + when (it) { + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully deleted")) //TODO?: Change the msg + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + } + } } } From 682f9b6680df038d69b4ccde15fd58eda8638235 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 15:01:22 +0200 Subject: [PATCH 143/325] Do small renaming --- .../viewmodel/entryViewModel/EntryViewModel.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index aa8b1f5a..c8c58810 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -80,7 +80,7 @@ class EntryViewModel( is EntryEvent.OnEditEntry -> when (routerFlow.state.value) { - is Screen.Entry.Edit -> changeEntry( + is Screen.Entry.Edit -> updateEntry( Entry.Patch( nameText.value, amountText.value, @@ -91,7 +91,7 @@ class EntryViewModel( else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntry.value.id)) //using ID seems... unnecessary? } is EntryEvent.OnDeleteEntry -> _dialogState.value = true - is EntryEvent.OnDeleteDialogConfirm -> removeEntry(selectedEntry.value.id) + is EntryEvent.OnDeleteDialogConfirm -> deleteEntry(selectedEntry.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") @@ -126,7 +126,7 @@ class EntryViewModel( } } - fun changeEntry(entry: Entry.Patch, id: Int) { + fun updateEntry(entry: Entry.Patch, id: Int) { entryUseCases.changeEntryByIdUseCase(entry, id).onEach { when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) @@ -137,7 +137,7 @@ class EntryViewModel( } } - fun removeEntry(id: Int) { + fun deleteEntry(id: Int) { entryUseCases.deleteEntryByIdUseCase(id).onEach { when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) From 2c99cfd0c9008b54ce1c75e586fafcd009fdbd0a Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 15:16:20 +0200 Subject: [PATCH 144/325] Add basic variables to web EntryComponent --- .../entryViewModel/EntryViewModel.kt | 14 ++++++------ .../compose/entry/EntryComponent.kt | 22 +++++++------------ 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index c8c58810..0a9791c5 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -39,8 +39,8 @@ class EntryViewModel( private val _amountSignState = MutableStateFlow(EntryInputState().amountSign) val amountSignState: StateFlow = _amountSignState - private val _selectedEntry = MutableStateFlow(EntryState().selectedEntry) - val selectedEntry: StateFlow = _selectedEntry + private val _selectedEntryState = MutableStateFlow(EntryState().selectedEntry) + val selectedEntryState: StateFlow = _selectedEntryState // --- Default ViewModel Variables ---- private val _dialogState = MutableStateFlow(false) @@ -86,12 +86,12 @@ class EntryViewModel( amountText.value, repeatState.value, Entry.Category(categoryIDState.value) - ), selectedEntry.value.id + ), selectedEntryState.value.id ) - else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntry.value.id)) //using ID seems... unnecessary? + else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntryState.value.id)) //using ID seems... unnecessary? } is EntryEvent.OnDeleteEntry -> _dialogState.value = true - is EntryEvent.OnDeleteDialogConfirm -> deleteEntry(selectedEntry.value.id) + is EntryEvent.OnDeleteDialogConfirm -> deleteEntry(selectedEntryState.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") @@ -101,14 +101,14 @@ class EntryViewModel( } - /* *** Use Case usages *** */ //TODO Implement use cases + /* *** Use Case usages *** */ fun getEntryById(id: Int) { entryUseCases.getEntryByIdUseCase(id).onEach { when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) is DataResponse.Success<*> -> { - _selectedEntry.value = it.data!! + _selectedEntryState.value = it.data!! } is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 1b5e86f1..409ef23e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -8,7 +8,9 @@ import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.viewmodel.EntryViewModel + +import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel import di import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Text @@ -16,20 +18,12 @@ import org.kodein.di.instance import kotlin.math.absoluteValue @Composable -fun EntryComponent(screenState: MutableState) { - //val scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - val scope = rememberCoroutineScope() - /*val di = localDI() - val getAllEntriesUseCase: GetAllEntriesUseCase by di.instance() - val getEntryByIdUseCase: GetEntryByIdUseCase by di.instance() - val changeEntryByIdUseCase: ChangeEntryByIdUseCase by di.instance() - val deleteEntryByIdUseCase: DeleteEntryByIdUseCase by di.instance() - val createNewEntryUseCase: CreateNewEntryUseCase by di.instance() - val userViewModel = EntryViewModel(getAllEntriesUseCase, getEntryByIdUseCase, createNewEntryUseCase,changeEntryByIdUseCase,deleteEntryByIdUseCase, scope) - val viewState = userViewModel.state.collectAsState(scope)*/ - +fun EntryComponent() { val viewModel: EntryViewModel by di.instance() - val viewState = viewModel.state.collectAsState(scope.coroutineContext) + //Data to load + val entry = viewModel.selectedEntryState.collectAsState() + val loadingState = remember { mutableStateOf(false) } + when (screenState.value) { is Screen.EntryCreate -> { From b0b9d873817e0fa57c2874b60e0e3155efea50a6 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 15:22:22 +0200 Subject: [PATCH 145/325] Remove old data parts from web entrycomponent --- .../compose/entry/EntryComponent.kt | 95 ++++++++++--------- 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 409ef23e..321b2bf0 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -3,15 +3,20 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.category.categoryIdToCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel import di +import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Text import org.kodein.di.instance @@ -19,55 +24,59 @@ import kotlin.math.absoluteValue @Composable fun EntryComponent() { + val viewModel: EntryViewModel by di.instance() + val routerFlow: RouterFlow by di.instance() + val screenState = routerFlow.state.collectAsState() + val loadingState = remember { mutableStateOf(false) } //Data to load val entry = viewModel.selectedEntryState.collectAsState() - val loadingState = remember { mutableStateOf(false) } - + val categoryList = viewModel.categoryListState.collectAsState() - when (screenState.value) { - is Screen.EntryCreate -> { - EntryCreateView( - state = viewState, - categoryList = (screenState.value as Screen.EntryCreate).categoryList, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onCreateEntryButtonPressed = { name:String, amount:Float, repeat:Boolean, category_id:Int -> - viewModel.createEntry(Entry.In(name, amount, repeat, category_id)) - }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) - - } - is Screen.EntryEdit -> { - EntryEditView( - state = viewState, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onEditEntryButtonPressed = { name:String, amount:Float, repeat:Boolean, category:Entry.Category? -> - viewModel.changeEntry( - Entry.Patch(name, amount, repeat, category), - (screenState.value as Screen.EntryEdit).id - ) - }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) - viewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> loadingState.value = true + is UiEvent.HideSuccess -> loadingState.value = false + else -> loadingState.value = false + } } - is Screen.EntryOverview -> { - EntryOverviewView( - state = viewState, - onEditButton = {id, -> screenState.value = Screen.EntryEdit(id)}, - onDeleteButton = { id -> - viewModel.removeEntry(id) - screenState.value = Screen.Dashboard}, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) - viewModel.getEntryById((screenState.value as Screen.EntryOverview).id) + } + NavBar {} + MainFlexContainer { + when (screenState.value) { + is Screen.EntryCreate -> { + EntryCreateView( + categoryList = (screenState.value as Screen.EntryCreate).categoryList, + onCreateEntryButtonPressed = { name: String, amount: Float, repeat: Boolean, category_id: Int -> + viewModel.createEntry(Entry.In(name, amount, repeat, category_id)) + } + ) + + } + is Screen.EntryEdit -> { + EntryEditView( + onEditEntryButtonPressed = { name: String, amount: Float, repeat: Boolean, category: Entry.Category? -> + viewModel.changeEntry( + Entry.Patch(name, amount, repeat, category), + (screenState.value as Screen.EntryEdit).id + ) + } + ) + viewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) + } + is Screen.EntryOverview -> { + EntryOverviewView( + onEditButton = { id, -> screenState.value = Screen.EntryEdit(id) }, + onDeleteButton = { id -> + viewModel.removeEntry(id) + screenState.value = Screen.Dashboard + } + ) + viewModel.getEntryById((screenState.value as Screen.EntryOverview).id) + } + else -> {} } - else -> {} } } From b4083dbfc316aa259b5df4823e902709da353501 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 15:34:08 +0200 Subject: [PATCH 146/325] Add getCategoryList to EntryViewModel --- .../domain/usecase/EntryUseCases.kt | 1 + .../viewmodel/entryViewModel/EntryState.kt | 4 ++- .../entryViewModel/EntryViewModel.kt | 33 +++++++++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt index 7233f2a2..2ccc8b09 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt @@ -2,6 +2,7 @@ package de.hsfl.budgetBinder.domain.usecase data class EntryUseCases( val getAllEntriesUseCase: GetAllEntriesUseCase, + val getCategoryListUseCase : GetAllCategoriesUseCase, val getEntryByIdUseCase: GetEntryByIdUseCase, val createNewEntryUseCase: CreateNewEntryUseCase, val changeEntryByIdUseCase: ChangeEntryByIdUseCase, diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt index d87cca04..883fb485 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt @@ -1,7 +1,9 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry data class EntryState( - val selectedEntry: Entry = Entry(0,"",0f,false,null) + val selectedEntry: Entry = Entry(0,"",0f,false,null), + val categoryList: List = listOf() ) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 0a9791c5..1238772e 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -1,5 +1,6 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.DataResponse import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.domain.usecase.* @@ -14,6 +15,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch class EntryViewModel( private val entryUseCases: EntryUseCases, @@ -42,6 +44,9 @@ class EntryViewModel( private val _selectedEntryState = MutableStateFlow(EntryState().selectedEntry) val selectedEntryState: StateFlow = _selectedEntryState + private val _categoryListState = MutableStateFlow(EntryState().categoryList) + val categoryListState: StateFlow> = _categoryListState + // --- Default ViewModel Variables ---- private val _dialogState = MutableStateFlow(false) val dialogState: StateFlow = _dialogState @@ -51,8 +56,14 @@ class EntryViewModel( init { when (routerFlow.state.value) { - is Screen.Entry.Overview -> getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) - is Screen.Entry.Edit -> getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) + is Screen.Entry.Overview -> { + getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) + getCategoryList() + } + is Screen.Entry.Edit -> { + getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) + getCategoryList() + } else -> {} } } @@ -114,6 +125,10 @@ class EntryViewModel( } } } + private fun getCategoryList() = scope.launch { + entryUseCases.getCategoryListUseCase.categories() + .collect { handleDataResponse(response = it, onSuccess = {cl -> _categoryListState.value = cl}) } + } fun createEntry(entry: Entry.In) { entryUseCases.createNewEntryUseCase(entry).onEach { @@ -147,4 +162,18 @@ class EntryViewModel( } } } + private suspend fun handleDataResponse(response: DataResponse, onSuccess: (T) -> Unit) { + when (response) { + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + is DataResponse.Success -> { + _eventFlow.emit(UiEvent.HideSuccess) + onSuccess(response.data!!) + } + is DataResponse.Unauthorized -> { + _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + routerFlow.navigateTo(Screen.Login) + } + } + } } From c0b59b776f8e49b6dc3eeaedb4baa346eb03ea0d Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 15:44:02 +0200 Subject: [PATCH 147/325] Update entryCreate usage in entryComponent --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt | 3 ++- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 9 ++++----- .../hsfl/budgetBinder/compose/entry/EntryCreateView.kt | 6 +----- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index b79632be..bee63303 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.rememberCoroutineScope import de.hsfl.budgetBinder.compose.dashboard.DashboardComponent +import de.hsfl.budgetBinder.compose.entry.EntryComponent import de.hsfl.budgetBinder.compose.login.LoginComponent import de.hsfl.budgetBinder.compose.register.RegisterComponent import de.hsfl.budgetBinder.presentation.Screen @@ -23,6 +24,7 @@ fun Router() { is Screen.Register -> RegisterComponent() is Screen.Login -> LoginComponent() is Screen.Dashboard -> DashboardComponent() + is Screen.Entry -> EntryComponent() is Screen.Settings, is Screen.SettingsChangeUserData -> Text("Settings")//SettingsComponent(screenState = screenState) is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister @@ -30,7 +32,6 @@ fun Router() { is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> Text("Old Entry")//EntryComponent(screenState = screenState) is Screen.Category -> Text("New Category") - is Screen.Entry -> Text("New Entry") else -> { Text("No known Screen! Check if the screen you're trying to reach is in the ScreenRouter") } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 321b2bf0..c4069a34 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -14,6 +14,7 @@ import de.hsfl.budgetBinder.presentation.UiEvent import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel import di import kotlinx.coroutines.flow.collectLatest @@ -45,12 +46,10 @@ fun EntryComponent() { NavBar {} MainFlexContainer { when (screenState.value) { - is Screen.EntryCreate -> { + is Screen.Entry.Create -> { EntryCreateView( - categoryList = (screenState.value as Screen.EntryCreate).categoryList, - onCreateEntryButtonPressed = { name: String, amount: Float, repeat: Boolean, category_id: Int -> - viewModel.createEntry(Entry.In(name, amount, repeat, category_id)) - } + categoryList = categoryList.value, + onCreateEntryButtonPressed = { viewModel.onEvent(EntryEvent.OnCreateEntry) } ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 691b2bb5..1ca4a5dc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -16,12 +16,8 @@ import org.jetbrains.compose.web.svg.Svg @OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryCreateView( - state: State, categoryList: List, - onChangeToDashboard: () -> Unit, - onChangeToSettings: () -> Unit, - onChangeToCategory: () -> Unit, - onCreateEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category_id: Int) -> Unit, + onCreateEntryButtonPressed: () -> Unit, ) { var switchState by remember { mutableStateOf(false) } var entryNameTextFieldState by remember { mutableStateOf("") } From f4884594dedd044ee7ff651cf31e3f9f0b9ececd Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 16:09:25 +0200 Subject: [PATCH 148/325] Update parts of entryCreate --- .../compose/entry/EntryComponent.kt | 4 +- .../compose/entry/EntryCreateView.kt | 354 ++++++++---------- 2 files changed, 163 insertions(+), 195 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index c4069a34..9a91041c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -33,6 +33,7 @@ fun EntryComponent() { //Data to load val entry = viewModel.selectedEntryState.collectAsState() val categoryList = viewModel.categoryListState.collectAsState() + //Inputs LaunchedEffect(key1 = true) { viewModel.eventFlow.collectLatest { event -> @@ -48,7 +49,8 @@ fun EntryComponent() { when (screenState.value) { is Screen.Entry.Create -> { EntryCreateView( - categoryList = categoryList.value, + onRepeatClicked = { input -> viewModel.onEvent(EntryEvent.EnteredRepeat(input))}, + onAmountTypeSwitched = { input -> viewModel.onEvent(EntryEvent.EnteredAmountSign(input))}, onCreateEntryButtonPressed = { viewModel.onEvent(EntryEvent.OnCreateEntry) } ) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 1ca4a5dc..1aaf9a1f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -5,258 +5,224 @@ import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.* import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditUserViewModel +import di import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.* import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Path import org.jetbrains.compose.web.svg.Svg +import org.kodein.di.instance @OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryCreateView( - categoryList: List, + onRepeatClicked: (Boolean) -> Unit, + onAmountTypeSwitched: (Boolean) -> Unit, onCreateEntryButtonPressed: () -> Unit, ) { - var switchState by remember { mutableStateOf(false) } - var entryNameTextFieldState by remember { mutableStateOf("") } - var entryAmountTextFieldState by remember { mutableStateOf("") } - var entryRepeatState by remember { mutableStateOf("") } - var entryCategoryIDTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } + val viewModel: EntryViewModel by di.instance() + val entryNameTextField by viewModel.nameText.collectAsState() + val entryAmountTextField by viewModel.amountText.collectAsState() + val entryRepeat by viewModel.repeatState.collectAsState() + val entryCategoryIDTextField by viewModel.repeatState.collectAsState() + val amountSign by viewModel.amountSignState.collectAsState() - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Create new Entry") } + Form(attrs = { + this.addEventListener("submit") { + onCreateEntryButtonPressed() + it.preventDefault() + } + } + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { Span( attrs = { - classes("mdc-button__label") + classes("mdc-text-field__ripple") } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { + ) { } Span( attrs = { - classes("mdc-button__label") + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Entry Name") } + Input( + type = InputType.Text ) { - Text("Settings") + classes("mdc-text-field__input") + value(entryNameTextFieldState) + required(true) + onInput { + entryNameTextFieldState = it.value + } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - }) - - MainFlexContainer { - H1( + } + Div( attrs = { - style { margin(2.percent) } - } - ) { Text("Create new Entry") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$entryNameTextFieldState, $entryAmountTextFieldState, $entryRepeatState, $entryCategoryIDTextFieldState") - onCreateEntryButtonPressed( - entryNameTextFieldState, - (if (!switchState) "-$entryAmountTextFieldState" else entryAmountTextFieldState).toFloat(), - entryRepeatState.toBoolean(), - entryCategoryIDTextFieldState.toInt() - ) - it.preventDefault() + classes(AppStylesheet.margin) } - } ) { - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Entry Name") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(entryNameTextFieldState) - required(true) - onInput { - entryNameTextFieldState = it.value - } + classes("mdc-text-field__ripple") } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } } - ) { - Span( + ) { Text("Amount") } + Div { + Button( attrs = { - classes("mdc-text-field__ripple") + if (!switchState) classes("mdc-switch", "mdc-switch--unselected") + else classes("mdc-switch", "mdc-switch--selected") + id("basic-switch") + attr("role", "switch") + attr("aria-checked", "false") + type(ButtonType.Button) + onClick { switchState = !switchState } } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } - } - ) { Text("Amount") } - Div { - Button( - attrs = { - if (!switchState) classes("mdc-switch", "mdc-switch--unselected") - else classes("mdc-switch", "mdc-switch--selected") - id("basic-switch") - attr("role", "switch") - attr("aria-checked", "false") - type(ButtonType.Button) - onClick { switchState = !switchState } - } - ) { - Div(attrs = { classes("mdc-switch__track") }) { } - Div(attrs = { classes("mdc-switch__handle-track") }) { - Div(attrs = { classes("mdc-switch__handle") }) { - Div(attrs = { classes("mdc-switch__shadow") }) { - Div(attrs = { classes("mdc-elevation-overlay") }) { } + ) { + Div(attrs = { classes("mdc-switch__track") }) { } + Div(attrs = { classes("mdc-switch__handle-track") }) { + Div(attrs = { classes("mdc-switch__handle") }) { + Div(attrs = { classes("mdc-switch__shadow") }) { + Div(attrs = { classes("mdc-elevation-overlay") }) { } + } + Div(attrs = { classes("mdc-switch__ripple") }) { } + Div(attrs = { classes("mdc-switch__icons") }) { + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") } - Div(attrs = { classes("mdc-switch__ripple") }) { } - Div(attrs = { classes("mdc-switch__icons") }) { - Svg( - attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, - viewBox = "0 0 24 24" - ) { - Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") - } - Svg( - attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, - viewBox = "0 0 24 24" - ) { - Path("M20 13H4v-2h16v2z") - } + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M20 13H4v-2h16v2z") } } } } } - Div(attrs = { - classes("mdc-typography--headline6", AppStylesheet.text) - }) { - Text(if (switchState) "+" else "-") - } - Input( - type = InputType.Number - ) { - attr("step", "0.01") - classes("mdc-text-field__input") - onInput { - entryAmountTextFieldState = it.value.toString() - } + } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { + Text(if (switchState) "+" else "-") + } + Input( + type = InputType.Number + ) { + attr("step", "0.01") + classes("mdc-text-field__input") + onInput { + entryAmountTextFieldState = it.value.toString() } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( - attrs = { - classes(AppStylesheet.margin, AppStylesheet.flexContainer) - } - ) { - Div(attrs = {style { flex(50.percent) }}) { - Div(attrs = { classes("mdc-form-field") }) { - Div(attrs = { classes("mdc-checkbox") }) { - Input(type = InputType.Checkbox) - { - classes("mdc-checkbox__native-control") - id("checkbox-1") - onInput { - entryRepeatState = it.value.toString() - } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) + } + ) { + Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { classes("mdc-form-field") }) { + Div(attrs = { classes("mdc-checkbox") }) { + Input(type = InputType.Checkbox) + { + classes("mdc-checkbox__native-control") + id("checkbox-1") + onInput { + entryRepeatState = it.value.toString() } - Div(attrs = { classes("mdc-checkbox__background") }) { - Svg(attrs = { classes("mdc-checkbox__checkmark") }, viewBox = "0 0 24 24") { - Path("M1.73,12.91 8.1,19.28 22.79,4.59", attrs = { classes("mdc-checkbox__checkmark") }) - } - Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } + } + Div(attrs = { classes("mdc-checkbox__background") }) { + Svg( + attrs = { classes("mdc-checkbox__checkmark") }, + viewBox = "0 0 24 24" + ) { + Path( + "M1.73,12.91 8.1,19.28 22.79,4.59", + attrs = { classes("mdc-checkbox__checkmark") }) } - Div(attrs = { classes("mdc-checkbox__ripple") }) { } + Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } } - Label(forId = "checkbox-1") { Text("repeat") } + Div(attrs = { classes("mdc-checkbox__ripple") }) { } } + Label(forId = "checkbox-1") { Text("repeat") } } - Div(attrs = {style { flex(50.percent) }}) { - ChooseCategoryMenu(categoryList) { id -> entryCategoryIDTextFieldState = id.toString() } + } + Div(attrs = { style { flex(50.percent) } }) { + ChooseCategoryMenu(categoryList) { id -> + entryCategoryIDTextFieldState = id.toString() } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( attrs = { - classes(AppStylesheet.margin) + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } } } + From edb9b82c03d68603857d8b586c09ac9f3cc82f6a Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 16:24:26 +0200 Subject: [PATCH 149/325] Update EntryCreateView --- .../viewmodel/entryViewModel/EntryEvent.kt | 6 +-- .../entryViewModel/EntryViewModel.kt | 4 +- .../compose/entry/EntryComponent.kt | 2 - .../compose/entry/EntryCreateView.kt | 39 +++++++------------ 4 files changed, 18 insertions(+), 33 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt index 9e306f6c..b71a37d1 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -6,9 +6,9 @@ sealed class EntryEvent { //User-made Data Input data class EnteredName(val value: String) : EntryEvent() data class EnteredAmount(val value: Float) : EntryEvent() - data class EnteredRepeat(val value: Boolean) : EntryEvent() - data class EnteredCategoryID(val value: Int) : EntryEvent() - data class EnteredAmountSign(val value: Boolean) : EntryEvent() + object EnteredRepeat : EntryEvent() + data class EnteredCategoryID(val value: Int?) : EntryEvent() + object EnteredAmountSign : EntryEvent() //Action object OnCreateEntry : EntryEvent() diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 1238772e..a6696638 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -73,9 +73,9 @@ class EntryViewModel( when (event) { is EntryEvent.EnteredName -> _nameText.value = nameText.value is EntryEvent.EnteredAmount -> _amountText.value = amountText.value - is EntryEvent.EnteredRepeat -> _repeatState.value = repeatState.value + is EntryEvent.EnteredRepeat -> _repeatState.value = !repeatState.value is EntryEvent.EnteredCategoryID -> _categoryIDState.value = categoryIDState.value - is EntryEvent.EnteredAmountSign -> _amountSignState.value = amountSignState.value + is EntryEvent.EnteredAmountSign -> _amountSignState.value = !amountSignState.value is EntryEvent.OnCreateEntry -> when (routerFlow.state.value) { is Screen.Entry.Create -> createEntry( diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 9a91041c..3c5dd3d6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -49,8 +49,6 @@ fun EntryComponent() { when (screenState.value) { is Screen.Entry.Create -> { EntryCreateView( - onRepeatClicked = { input -> viewModel.onEvent(EntryEvent.EnteredRepeat(input))}, - onAmountTypeSwitched = { input -> viewModel.onEvent(EntryEvent.EnteredAmountSign(input))}, onCreateEntryButtonPressed = { viewModel.onEvent(EntryEvent.OnCreateEntry) } ) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 1aaf9a1f..92dff5ed 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -1,12 +1,10 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.* import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel -import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditUserViewModel import di import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.* @@ -20,16 +18,17 @@ import org.kodein.di.instance @OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryCreateView( - onRepeatClicked: (Boolean) -> Unit, - onAmountTypeSwitched: (Boolean) -> Unit, onCreateEntryButtonPressed: () -> Unit, ) { val viewModel: EntryViewModel by di.instance() + //Input val entryNameTextField by viewModel.nameText.collectAsState() val entryAmountTextField by viewModel.amountText.collectAsState() val entryRepeat by viewModel.repeatState.collectAsState() val entryCategoryIDTextField by viewModel.repeatState.collectAsState() val amountSign by viewModel.amountSignState.collectAsState() + //Data + val categoryList by viewModel.categoryListState.collectAsState() H1( attrs = { @@ -68,10 +67,10 @@ fun EntryCreateView( type = InputType.Text ) { classes("mdc-text-field__input") - value(entryNameTextFieldState) + value(entryNameTextField) required(true) onInput { - entryNameTextFieldState = it.value + viewModel.onEvent(EntryEvent.EnteredName(it.value)) } } Span( @@ -106,13 +105,13 @@ fun EntryCreateView( Div { Button( attrs = { - if (!switchState) classes("mdc-switch", "mdc-switch--unselected") + if (!amountSign) classes("mdc-switch", "mdc-switch--unselected") else classes("mdc-switch", "mdc-switch--selected") id("basic-switch") attr("role", "switch") attr("aria-checked", "false") type(ButtonType.Button) - onClick { switchState = !switchState } + onClick { viewModel.onEvent(EntryEvent.EnteredAmountSign) } } ) { Div(attrs = { classes("mdc-switch__track") }) { } @@ -143,15 +142,16 @@ fun EntryCreateView( Div(attrs = { classes("mdc-typography--headline6", AppStylesheet.text) }) { - Text(if (switchState) "+" else "-") + Text(if (amountSign) "+" else "-") } Input( type = InputType.Number ) { attr("step", "0.01") + value(entryAmountTextField) classes("mdc-text-field__input") onInput { - entryAmountTextFieldState = it.value.toString() + viewModel.onEvent(EntryEvent.EnteredAmount(it.value!!.toFloat())) } } Span( @@ -174,7 +174,7 @@ fun EntryCreateView( classes("mdc-checkbox__native-control") id("checkbox-1") onInput { - entryRepeatState = it.value.toString() + viewModel.onEvent(EntryEvent.EnteredRepeat) } } Div(attrs = { classes("mdc-checkbox__background") }) { @@ -195,7 +195,7 @@ fun EntryCreateView( } Div(attrs = { style { flex(50.percent) } }) { ChooseCategoryMenu(categoryList) { id -> - entryCategoryIDTextFieldState = id.toString() + viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) } } } @@ -210,19 +210,6 @@ fun EntryCreateView( value("Submit") }) } - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } - } } } From b7bfd680e956bf65cf31d4c360e4d55411d2c59d Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 16:37:57 +0200 Subject: [PATCH 150/325] Add space between Buttons --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt index e3d7263a..61cdebde 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt @@ -51,7 +51,8 @@ fun NavBar(content: @Composable () -> Unit) { classes( "mdc-button", "mdc-button--raised", - "mdc-top-app-bar__navigation-icon" + "mdc-top-app-bar__navigation-icon", + AppStylesheet.marginRight ) onClick { viewModel.onEvent(NavDrawerEvent.OnCreateEntry) } } @@ -69,7 +70,8 @@ fun NavBar(content: @Composable () -> Unit) { classes( "mdc-button", "mdc-button--raised", - "mdc-top-app-bar__navigation-icon" + "mdc-top-app-bar__navigation-icon", + AppStylesheet.marginRight ) onClick { viewModel.onEvent(NavDrawerEvent.OnCategory) } } @@ -87,7 +89,8 @@ fun NavBar(content: @Composable () -> Unit) { classes( "mdc-button", "mdc-button--raised", - "mdc-top-app-bar__navigation-icon" + "mdc-top-app-bar__navigation-icon", + AppStylesheet.marginRight ) onClick { viewModel.onEvent(NavDrawerEvent.OnSettings) } } From 6574dd4fb32bf2634bcec3d9e8a634341428af19 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 17:07:02 +0200 Subject: [PATCH 151/325] Add new viewModel logic --- .../de/hsfl/budgetBinder/compose/Router.kt | 4 +- .../settings/SettingsChangeUserDataView.kt | 151 +++++++++--------- .../compose/settings/SettingsComponent.kt | 50 +++--- .../compose/settings/SettingsView.kt | 98 ++++-------- 4 files changed, 130 insertions(+), 173 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index b79632be..d2ed2537 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.rememberCoroutineScope import de.hsfl.budgetBinder.compose.dashboard.DashboardComponent import de.hsfl.budgetBinder.compose.login.LoginComponent import de.hsfl.budgetBinder.compose.register.RegisterComponent +import de.hsfl.budgetBinder.compose.settings.SettingsComponent import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.flow.RouterFlow import di @@ -23,8 +24,7 @@ fun Router() { is Screen.Register -> RegisterComponent() is Screen.Login -> LoginComponent() is Screen.Dashboard -> DashboardComponent() - is Screen.Settings, is Screen.SettingsChangeUserData - -> Text("Settings")//SettingsComponent(screenState = screenState) + is Screen.Settings, Screen.Settings.User -> SettingsComponent() is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> Text("Old Category") //CategoryComponent(screenState = screenState) is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt index e9dcf578..73eb02a4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt @@ -1,78 +1,50 @@ package de.hsfl.budgetBinder.compose.settings import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.viewmodel.settings.EditUserEvent +import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditUserViewModel +import di +import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.required import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* +import org.kodein.di.instance @Composable -fun SettingsChangeUserDataView( - state: State, - onChangeToDashboard: () -> Unit, - onChangeToSettings: () -> Unit, - onChangeToCategory: () -> Unit, - onChangeDataButtonPressed: (firstName: String, lastName: String, password: String) -> Unit -) { - var firstNameTextFieldState by remember { mutableStateOf("") } - var lastNameTextFieldState by remember { mutableStateOf("") } - var passwordTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } +fun SettingsChangeUserDataView() { + val viewModel: SettingsEditUserViewModel by di.instance() + val loadingState = remember { mutableStateOf(false) } + val firstNameText = viewModel.firstNameText.collectAsState() + val lastNameText = viewModel.lastNameText.collectAsState() + val passwordText = viewModel.passwordText.collectAsState() + val confirmedPasswordText = viewModel.confirmedPassword.collectAsState() + var checkPassword by remember { mutableStateOf(true) } - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Settings") - } + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> loadingState.value = true + is UiEvent.HideSuccess -> loadingState.value = false + else -> loadingState.value = false } - }) - + } + } + NavBar {} MainFlexContainer { H1 { Text("Change User Data") } Form(attrs = { this.addEventListener("submit") { - console.log("$firstNameTextFieldState, $lastNameTextFieldState, $passwordTextFieldState") - onChangeDataButtonPressed( - firstNameTextFieldState, - lastNameTextFieldState, - passwordTextFieldState - ) + checkPassword = passwordText == confirmedPasswordText + console.log(checkPassword) + if (checkPassword) viewModel.onEvent(EditUserEvent.OnUpdate) it.preventDefault() } } @@ -101,10 +73,11 @@ fun SettingsChangeUserDataView( Input( type = InputType.Text ) { + required() classes("mdc-text-field__input") - value(firstNameTextFieldState) + value(firstNameText.value.firstName) onInput { - firstNameTextFieldState = it.value + viewModel.onEvent(EditUserEvent.EnteredFirstName(it.value)) } } Span( @@ -138,10 +111,11 @@ fun SettingsChangeUserDataView( Input( type = InputType.Text ) { + required() classes("mdc-text-field__input") - value(lastNameTextFieldState) + value(lastNameText.value.lastName) onInput { - lastNameTextFieldState = it.value + viewModel.onEvent(EditUserEvent.EnteredLastName(it.value)) } } Span( @@ -172,11 +146,48 @@ fun SettingsChangeUserDataView( classes("mdc-floating-label", "mdc-floating-label--float-above") } ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, + PasswordInput(value = passwordText.value.password, + attrs = { + required() + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(EditUserEvent.EnteredPassword(it.value)) + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Repeat Password") } + PasswordInput(value = confirmedPasswordText.value.confirmedPassword, attrs = { + required() classes("mdc-text-field__input") onInput { - passwordTextFieldState = it.value + viewModel.onEvent(EditUserEvent.EnteredConfirmedPassword(it.value)) } }) Span( @@ -197,17 +208,9 @@ fun SettingsChangeUserDataView( value("Submit") }) } - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } } } + if (!checkPassword) { + FeedbackSnackbar("Passwords do not match") + } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt index a52e7127..46f900c9 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt @@ -3,42 +3,34 @@ package de.hsfl.budgetBinder.compose.settings import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.User import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.flow.DataFlow +import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsViewModel import di +import kotlinx.coroutines.flow.collectLatest import org.kodein.di.instance @Composable -fun SettingsComponent(screenState: MutableState) { - /*val scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - val di = localDI() - val changeMyUserUseCase: ChangeMyUserUseCase by di.instance() - val deleteMyUserUseCase: DeleteMyUserUseCase by di.instance() - val settingsViewModel = SettingsViewModel(changeMyUserUseCase, deleteMyUserUseCase, scope) - val viewState = settingsViewModel.state.collectAsState(scope)*/ - val scope = rememberCoroutineScope() - val settingsViewModel: SettingsViewModel by di.instance() - val viewState = settingsViewModel.state.collectAsState(scope) - +fun SettingsComponent() { + val viewModel: SettingsViewModel by di.instance() + val dataFlow: DataFlow by di.instance() + val routerFlow: RouterFlow by di.instance() + val userState = dataFlow.userState.collectAsState() + val screenState = routerFlow.state.collectAsState() + val loadingState = remember { mutableStateOf(false) } + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { + when (it) { + is UiEvent.ShowLoading -> loadingState.value = true + else -> loadingState.value = false + } + } + } when (screenState.value) { - Screen._Settings -> SettingsView( - state = viewState, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - onDeleteButtonPressed = { settingsViewModel.deleteMyUser(); screenState.value = Screen.Login }, - onChangeButtonPressed = { screenState.value = Screen.SettingsChangeUserData } - ) - Screen.SettingsChangeUserData -> SettingsChangeUserDataView( - state = viewState, - onChangeDataButtonPressed = { firstName, lastName, password -> - settingsViewModel.changeMyUser(User.Patch(firstName, lastName, password)); screenState.value = - Screen._Settings - }, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) + is Screen.Settings.Menu -> SettingsView() + is Screen.Settings.User -> SettingsChangeUserDataView() else -> {} } } \ No newline at end of file diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt index 94e3eab8..325f3af4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt @@ -2,82 +2,42 @@ package de.hsfl.budgetBinder.compose.settings import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.DeleteDialog -import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import org.jetbrains.compose.web.css.flex -import org.jetbrains.compose.web.css.marginLeft -import org.jetbrains.compose.web.css.percent +import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEvent +import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsViewModel +import di +import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* +import org.kodein.di.instance @Composable -fun SettingsView( - state: State, - onChangeToDashboard: () -> Unit, - onChangeToSettings: () -> Unit, - onChangeToCategory: () -> Unit, - onDeleteButtonPressed: () -> Unit, - onChangeButtonPressed: () -> Unit -) { +fun SettingsView() { + val viewModel: SettingsViewModel by di.instance() var deleteDialog by remember { mutableStateOf(false) } - val viewState by remember { state } - - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Settings") - } - } - }) + NavBar { } MainFlexContainer { H1( attrs = { style { marginLeft(2.percent) } } ) { Text("Settings") } - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { viewModel.onEvent(SettingsEvent.OnChangeToSettingsUserEdit) } + style { flex(100.percent) } + } + ) { + Text("Change Userdata") } } Div( @@ -88,11 +48,11 @@ fun SettingsView( Button( attrs = { classes("mdc-button", "mdc-button--raised") - onClick { onChangeButtonPressed() } + onClick { viewModel.onEvent(SettingsEvent.OnLogoutAllDevices) } style { flex(100.percent) } } ) { - Text("Change Userdata") + Text("Logout on all device") } } Div( @@ -103,10 +63,9 @@ fun SettingsView( Button( attrs = { classes("mdc-button", "mdc-button--raised") - onClick { - deleteDialog = true - } - style { flex(100.percent) } + onClick { deleteDialog = true } + style { flex(100.percent) + backgroundColor(Color("#b00020"))} } ) { Text("Delete User") @@ -114,6 +73,9 @@ fun SettingsView( } } if (deleteDialog) { - DeleteDialog(false, { onDeleteButtonPressed() }, { deleteDialog = false }) { Text("Delete User?") } + DeleteDialog( + false, + { viewModel.onEvent(SettingsEvent.OnDeleteDialogConfirm) }, + { deleteDialog = false }) { Text("Delete User?") } } } From 649a7bcfb0da1b36c677573f64ed9b68e58edb20 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 17:07:36 +0200 Subject: [PATCH 152/325] Fix lastnameText field --- .../de/hsfl/budgetBinder/compose/register/RegisterComponent.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt index fae09b44..ac16bdb1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt @@ -169,7 +169,7 @@ fun RegisterComponent() { type = InputType.Text ) { classes("mdc-text-field__input") - value(lastNameTextState.value.firstName) + value(lastNameTextState.value.lastName) onInput { viewModel.onEvent(RegisterEvent.EnteredLastname(it.value)) } From 056adfe8d5986ad6d5c2c11f4aa76dc323a03dfb Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 17:08:45 +0200 Subject: [PATCH 153/325] Try to fix entryCreate --- .../kotlin/de/hsfl/budgetBinder/di/DI.kt | 7 ++-- .../presentation/viewmodel/EntryViewModel.kt | 12 +++--- .../viewmodel/entryViewModel/EntryState.kt | 2 +- .../entryViewModel/EntryViewModel.kt | 16 ++++---- .../hsfl/budgetBinder/compose/Composables.kt | 14 ++++++- .../compose/entry/EntryComponent.kt | 37 ------------------- .../compose/entry/EntryCreateView.kt | 4 +- .../compose/entry/EntryEditView.kt | 2 +- 8 files changed, 36 insertions(+), 58 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt index 9fa387e6..d921d702 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt @@ -16,10 +16,11 @@ import de.hsfl.budgetBinder.domain.usecase.storage.StoreUserStateUseCase import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow +import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginViewModel import de.hsfl.budgetBinder.presentation.viewmodel.register.RegisterViewModel -import de.hsfl.budgetBinder.presentation.viewmodel.* import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerViewModel import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditServerUrlViewModel import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditUserViewModel @@ -74,7 +75,7 @@ fun kodein(ktorEngine: HttpClientEngine) = DI { bindSingleton { StoreUserStateUseCase() } bindSingleton { StoreServerUrlUseCase() } bindSingleton { StoreDarkModeUseCase() } - bindSingleton { EntriesUseCases(instance(), instance(), instance(), instance(), instance()) } + bindSingleton { EntryUseCases(instance(), instance(), instance(), instance(), instance(), instance()) } bindSingleton { CategoriesUseCases(instance(), instance(), instance(), instance(), instance(), instance()) } bindSingleton { SettingsUseCases(instance(), instance(), instance()) } bindSingleton { LoginUseCases(instance(), instance()) } @@ -94,7 +95,7 @@ fun kodein(ktorEngine: HttpClientEngine) = DI { bindSingleton { SettingsEditUserViewModel(instance(), instance(), instance(), instance()) } bindSingleton { SettingsEditServerUrlViewModel(instance(), instance(), instance()) } bindSingleton { CategoryViewModel(instance(), instance()) } - bindSingleton { EntryViewModel(instance(), instance()) } + bindSingleton { EntryViewModel(instance(), instance(), instance(), instance()) } bindSingleton { DashboardViewModel(instance(), instance(), instance(), instance()) } bindSingleton { NavDrawerViewModel(instance(), instance()) } } diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt index 3bd198ca..774d292f 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt @@ -10,14 +10,14 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.* class EntryViewModel( - private val entriesUseCases: EntriesUseCases, + private val entryUseCases: EntryUseCases, private val scope: CoroutineScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) ) { private val _state = MutableStateFlow(UiState.Empty) val state: StateFlow = _state fun getAllEntries() { - entriesUseCases.getAllEntriesUseCase.entries().onEach { + entryUseCases.getAllEntriesUseCase.entries().onEach { when (it) { is DataResponse.Success -> _state.value = UiState.Success(it.data) is DataResponse.Error -> _state.value = UiState.Error(it.error!!.message) @@ -28,7 +28,7 @@ class EntryViewModel( } fun getEntryById(id: Int) { - entriesUseCases.getEntryByIdUseCase(id).onEach { + entryUseCases.getEntryByIdUseCase(id).onEach { when (it) { is DataResponse.Success -> _state.value = UiState.Success(it.data) is DataResponse.Error -> _state.value = UiState.Error(it.error!!.message) @@ -39,7 +39,7 @@ class EntryViewModel( } fun createEntry(entry: Entry.In) { - entriesUseCases.createNewEntryUseCase(entry).onEach { + entryUseCases.createNewEntryUseCase(entry).onEach { when (it) { is DataResponse.Success -> _state.value = UiState.Success(it.data) is DataResponse.Error -> _state.value = UiState.Error(it.error!!.message) @@ -50,7 +50,7 @@ class EntryViewModel( } fun changeEntry(entry: Entry.Patch, id: Int) { - entriesUseCases.changeEntryByIdUseCase(entry, id).onEach { + entryUseCases.changeEntryByIdUseCase(entry, id).onEach { when (it) { is DataResponse.Success -> _state.value = UiState.Success(it.data) is DataResponse.Error -> _state.value = UiState.Error(it.error!!.message) @@ -61,7 +61,7 @@ class EntryViewModel( } fun removeEntry(id: Int) { - entriesUseCases.deleteEntryByIdUseCase(id).onEach { + entryUseCases.deleteEntryByIdUseCase(id).onEach { when (it) { is DataResponse.Success -> _state.value = UiState.Success(it.data) is DataResponse.Error -> _state.value = UiState.Error(it.error!!.message) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt index 883fb485..28cb3b67 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt @@ -5,5 +5,5 @@ import de.hsfl.budgetBinder.common.Entry data class EntryState( val selectedEntry: Entry = Entry(0,"",0f,false,null), - val categoryList: List = listOf() + val categoryList: List = listOf(Category(0,"","ffffff",Category.Image.DEFAULT,0f)) ) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index a6696638..c47cc0c4 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -55,14 +55,13 @@ class EntryViewModel( // ---- init { + getCategoryList() when (routerFlow.state.value) { is Screen.Entry.Overview -> { getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) - getCategoryList() } is Screen.Entry.Edit -> { getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) - getCategoryList() } else -> {} } @@ -71,10 +70,10 @@ class EntryViewModel( /* *** Event Handling *** */ fun onEvent(event: EntryEvent) { when (event) { - is EntryEvent.EnteredName -> _nameText.value = nameText.value - is EntryEvent.EnteredAmount -> _amountText.value = amountText.value + is EntryEvent.EnteredName -> _nameText.value = event.value + is EntryEvent.EnteredAmount -> _amountText.value = event.value is EntryEvent.EnteredRepeat -> _repeatState.value = !repeatState.value - is EntryEvent.EnteredCategoryID -> _categoryIDState.value = categoryIDState.value + is EntryEvent.EnteredCategoryID -> _categoryIDState.value = event.value is EntryEvent.EnteredAmountSign -> _amountSignState.value = !amountSignState.value is EntryEvent.OnCreateEntry -> when (routerFlow.state.value) { @@ -125,7 +124,7 @@ class EntryViewModel( } } } - private fun getCategoryList() = scope.launch { + fun getCategoryList() = scope.launch { entryUseCases.getCategoryListUseCase.categories() .collect { handleDataResponse(response = it, onSuccess = {cl -> _categoryListState.value = cl}) } } @@ -135,7 +134,10 @@ class EntryViewModel( when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) - is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg + is DataResponse.Success<*> -> { + _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg + routerFlow.navigateTo(Screen.Dashboard) + } is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index ba902a66..b264465e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -8,6 +8,7 @@ import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType import org.jetbrains.compose.web.attributes.type +import org.jetbrains.compose.web.attributes.value import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle @@ -383,9 +384,20 @@ fun DeleteDialog( @Composable fun ChooseCategoryMenu( categoryList: List, + selectedCategory: Int?, getCategoryId: (Int?) -> Unit ) { - var chosenCategory by remember { mutableStateOf(categoryList[0]) } + var chosenCategory by remember { + mutableStateOf( + if (selectedCategory == null) { + categoryList[0] + } else { + categoryList[selectedCategory] + } + ) + } + + var showList by remember { mutableStateOf(false) } Button(attrs = { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 3c5dd3d6..7a22fd76 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -5,23 +5,14 @@ import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.NavBar -import de.hsfl.budgetBinder.compose.category.categoryIdToCategory -import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.domain.usecase.* -import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiEvent import de.hsfl.budgetBinder.presentation.flow.RouterFlow - -import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel import di import kotlinx.coroutines.flow.collectLatest -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.Text import org.kodein.di.instance -import kotlin.math.absoluteValue @Composable fun EntryComponent() { @@ -30,10 +21,6 @@ fun EntryComponent() { val routerFlow: RouterFlow by di.instance() val screenState = routerFlow.state.collectAsState() val loadingState = remember { mutableStateOf(false) } - //Data to load - val entry = viewModel.selectedEntryState.collectAsState() - val categoryList = viewModel.categoryListState.collectAsState() - //Inputs LaunchedEffect(key1 = true) { viewModel.eventFlow.collectLatest { event -> @@ -53,31 +40,7 @@ fun EntryComponent() { ) } - is Screen.EntryEdit -> { - EntryEditView( - onEditEntryButtonPressed = { name: String, amount: Float, repeat: Boolean, category: Entry.Category? -> - viewModel.changeEntry( - Entry.Patch(name, amount, repeat, category), - (screenState.value as Screen.EntryEdit).id - ) - } - ) - viewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) - } - is Screen.EntryOverview -> { - EntryOverviewView( - onEditButton = { id, -> screenState.value = Screen.EntryEdit(id) }, - onDeleteButton = { id -> - viewModel.removeEntry(id) - screenState.value = Screen.Dashboard - } - ) - viewModel.getEntryById((screenState.value as Screen.EntryOverview).id) - } else -> {} } } } - -fun entriesFromCategory(list: List, category_id: Int?): List = - list.filter { it.category_id == category_id } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 92dff5ed..fa8e84c3 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -25,7 +25,7 @@ fun EntryCreateView( val entryNameTextField by viewModel.nameText.collectAsState() val entryAmountTextField by viewModel.amountText.collectAsState() val entryRepeat by viewModel.repeatState.collectAsState() - val entryCategoryIDTextField by viewModel.repeatState.collectAsState() + val entryCategoryIDTextField by viewModel.categoryIDState.collectAsState() val amountSign by viewModel.amountSignState.collectAsState() //Data val categoryList by viewModel.categoryListState.collectAsState() @@ -194,7 +194,7 @@ fun EntryCreateView( } } Div(attrs = { style { flex(50.percent) } }) { - ChooseCategoryMenu(categoryList) { id -> + ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index bc189082..5067a17e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -244,7 +244,7 @@ fun EntryEditView( } } Div(attrs = { style { flex(50.percent) } }) { - ChooseCategoryMenu(categoryList) { id -> entryCategoryIDTextFieldState = id.toString() } + //ChooseCategoryMenu(categoryList, ) { id -> entryCategoryIDTextFieldState = id.toString() } } } Div( From e44aa9f816edadb9a9bb90539a8f1e3f719014d1 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 17:39:22 +0200 Subject: [PATCH 154/325] Add reset to FeedbackSnackbar --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index ba902a66..f98e3122 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -92,7 +92,7 @@ fun Icon(icon_name: String) { // Snackbar that shows msg @Composable -fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { +fun FeedbackSnackbar(msg: String, hidden: Boolean = false, resetSnackbar: () -> Unit) { var hiddenValue by remember { mutableStateOf(hidden) } Aside( attrs = { @@ -125,6 +125,7 @@ fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { }) { Button(attrs = { classes("mdc-button", "mdc-snackbar__action") + onClick { resetSnackbar() } }) { Div(attrs = { classes("mdc-button__ripple") From 49a9996f46576db356ae67f5abc9c6bb274c8aef Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 17:39:43 +0200 Subject: [PATCH 155/325] Add FeedbackSnackbar when passwords do not match in SettingsChangeUserDataView --- .../compose/settings/SettingsChangeUserDataView.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt index 73eb02a4..e9b8427b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt @@ -26,7 +26,7 @@ fun SettingsChangeUserDataView() { val lastNameText = viewModel.lastNameText.collectAsState() val passwordText = viewModel.passwordText.collectAsState() val confirmedPasswordText = viewModel.confirmedPassword.collectAsState() - var checkPassword by remember { mutableStateOf(true) } + var openSnackbar by remember { mutableStateOf(false) } LaunchedEffect(key1 = true) { viewModel.eventFlow.collectLatest { event -> @@ -42,9 +42,10 @@ fun SettingsChangeUserDataView() { H1 { Text("Change User Data") } Form(attrs = { this.addEventListener("submit") { - checkPassword = passwordText == confirmedPasswordText - console.log(checkPassword) - if (checkPassword) viewModel.onEvent(EditUserEvent.OnUpdate) + if (passwordText != confirmedPasswordText) { + openSnackbar = true + } + viewModel.onEvent(EditUserEvent.OnUpdate) it.preventDefault() } } @@ -210,7 +211,7 @@ fun SettingsChangeUserDataView() { } } } - if (!checkPassword) { - FeedbackSnackbar("Passwords do not match") + if (openSnackbar) { + FeedbackSnackbar("Passwords do not match") { openSnackbar = false } } } From 15fd8a0475e53fc8ae91a241d22616dc336287b1 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 17:42:29 +0200 Subject: [PATCH 156/325] Add FeedbackSnackbar when passwords do not match in RegisterComponent and add required to all inputs --- .../compose/register/RegisterComponent.kt | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt index ac16bdb1..1c984eb1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt @@ -2,6 +2,7 @@ package de.hsfl.budgetBinder.compose.register import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.User +import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet @@ -13,6 +14,7 @@ import de.hsfl.budgetBinder.presentation.viewmodel.register.RegisterViewModel import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.required import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* @@ -28,6 +30,7 @@ fun RegisterComponent() { val passwordTextState = viewModel.passwordText.collectAsState() val confirmedPasswordTextState = viewModel.confirmedPasswordText.collectAsState() val loadingState = remember { mutableStateOf(false) } + var openSnackbar by remember { mutableStateOf(false) } LaunchedEffect(key1 = true) { viewModel.eventFlow.collectLatest { event -> @@ -101,7 +104,9 @@ fun RegisterComponent() { H1 { Text(" Register") } Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit this.addEventListener("submit") { - console.log("$firstNameTextState, $lastNameTextState, $emailTextState, $passwordTextState") + if (passwordTextState != confirmedPasswordTextState) { + openSnackbar = true + } viewModel.onEvent(RegisterEvent.OnRegister) it.preventDefault() } @@ -132,6 +137,7 @@ fun RegisterComponent() { type = InputType.Text ) { classes("mdc-text-field__input") + required() value(firstNameTextState.value.firstName) onInput { viewModel.onEvent(RegisterEvent.EnteredFirstname(it.value)) @@ -169,6 +175,7 @@ fun RegisterComponent() { type = InputType.Text ) { classes("mdc-text-field__input") + required() value(lastNameTextState.value.lastName) onInput { viewModel.onEvent(RegisterEvent.EnteredLastname(it.value)) @@ -204,6 +211,7 @@ fun RegisterComponent() { ) { Text("Email") } EmailInput(value = emailTextState.value.email, attrs = { + required() classes("mdc-text-field__input") onInput { viewModel.onEvent(RegisterEvent.EnteredEmail(it.value)) @@ -240,6 +248,7 @@ fun RegisterComponent() { ) { Text("Password") } PasswordInput(value = passwordTextState.value.password, attrs = { + required() classes("mdc-text-field__input") onInput { viewModel.onEvent(RegisterEvent.EnteredPassword(it.value)) @@ -252,6 +261,42 @@ fun RegisterComponent() { ) { } } } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Repeat Password") } + PasswordInput(value = confirmedPasswordTextState.value.confirmedPassword, + attrs = { + required() + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(RegisterEvent.EnteredConfirmedPassword(it.value)) + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } Div( attrs = { classes(AppStylesheet.margin) @@ -265,4 +310,7 @@ fun RegisterComponent() { } } } + if (openSnackbar) { + FeedbackSnackbar("Passwords do not match") { openSnackbar = false } + } } From d40d688afbaf4e5f3400139bd7a799e72f7994c5 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 18:12:50 +0200 Subject: [PATCH 157/325] Add confirmedPasswordValid for if Snackbar should open or not --- .../budgetBinder/compose/register/RegisterComponent.kt | 10 ++++++++-- .../compose/settings/SettingsChangeUserDataView.kt | 9 +++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt index 1c984eb1..91bda546 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt @@ -15,6 +15,7 @@ import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.required +import org.jetbrains.compose.web.css.marginLeft import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* @@ -101,10 +102,15 @@ fun RegisterComponent() { MainFlexContainer { // -- Register Form -- - H1 { Text(" Register") } + H1( + attrs = { + style { marginLeft(2.percent) } + } + ) { Text("Register") } Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit this.addEventListener("submit") { - if (passwordTextState != confirmedPasswordTextState) { + console.log("$firstNameTextState, $lastNameTextState, $emailTextState, $passwordTextState") + if (!confirmedPasswordTextState.value.confirmedPasswordValid) { openSnackbar = true } viewModel.onEvent(RegisterEvent.OnRegister) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt index e9b8427b..085ae1c4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt @@ -12,6 +12,7 @@ import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.required +import org.jetbrains.compose.web.css.marginLeft import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* @@ -39,10 +40,14 @@ fun SettingsChangeUserDataView() { } NavBar {} MainFlexContainer { - H1 { Text("Change User Data") } + H1( + attrs = { + style { marginLeft(2.percent) } + } + ) { Text("Change User Data") } Form(attrs = { this.addEventListener("submit") { - if (passwordText != confirmedPasswordText) { + if (!confirmedPasswordText.value.confirmedPasswordIsValid) { openSnackbar = true } viewModel.onEvent(EditUserEvent.OnUpdate) From 92a14cd7ea2fcf8cd3097d3e5e26f32a2701328e Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 18:56:23 +0200 Subject: [PATCH 158/325] Add first version of snackbar UiEvent feedback --- .../viewmodel/entryViewModel/EntryState.kt | 2 +- .../entryViewModel/EntryViewModel.kt | 43 +++++++++++++------ .../hsfl/budgetBinder/compose/Composables.kt | 30 +++++++------ .../src/jsMain/kotlin/main.kt | 36 ++++++++++++++++ 4 files changed, 84 insertions(+), 27 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt index 28cb3b67..183cde42 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt @@ -5,5 +5,5 @@ import de.hsfl.budgetBinder.common.Entry data class EntryState( val selectedEntry: Entry = Entry(0,"",0f,false,null), - val categoryList: List = listOf(Category(0,"","ffffff",Category.Image.DEFAULT,0f)) + val categoryList: List = listOf(Category(0,"No category","ffffff",Category.Image.DEFAULT,0f)) ) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index c47cc0c4..5aeca5d4 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -75,18 +75,22 @@ class EntryViewModel( is EntryEvent.EnteredRepeat -> _repeatState.value = !repeatState.value is EntryEvent.EnteredCategoryID -> _categoryIDState.value = event.value is EntryEvent.EnteredAmountSign -> _amountSignState.value = !amountSignState.value - is EntryEvent.OnCreateEntry -> + is EntryEvent.OnCreateEntry -> { when (routerFlow.state.value) { is Screen.Entry.Create -> createEntry( Entry.In( nameText.value, - amountText.value, + buildAmount(), repeatState.value, categoryIDState.value ) ) - else -> routerFlow.navigateTo(Screen.Entry.Create) + + else -> { + routerFlow.navigateTo(Screen.Entry.Create) + } } + } is EntryEvent.OnEditEntry -> when (routerFlow.state.value) { @@ -124,21 +128,28 @@ class EntryViewModel( } } } + fun getCategoryList() = scope.launch { entryUseCases.getCategoryListUseCase.categories() - .collect { handleDataResponse(response = it, onSuccess = {cl -> _categoryListState.value = cl}) } + .collect { + handleDataResponse( + response = it, + onSuccess = { cl -> _categoryListState.value = cl }) + } } fun createEntry(entry: Entry.In) { - entryUseCases.createNewEntryUseCase(entry).onEach { - when (it) { - is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) - is DataResponse.Success<*> -> { - _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg - routerFlow.navigateTo(Screen.Dashboard) + scope.launch { + entryUseCases.createNewEntryUseCase(entry).collect { response -> + when (response) { + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + is DataResponse.Success<*> -> { + _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg + routerFlow.navigateTo(Screen.Dashboard) + } + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) } - is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) } } } @@ -164,6 +175,7 @@ class EntryViewModel( } } } + private suspend fun handleDataResponse(response: DataResponse, onSuccess: (T) -> Unit) { when (response) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) @@ -178,4 +190,11 @@ class EntryViewModel( } } } + private fun buildAmount(): Float{ + return if(_amountSignState.value){ + _amountText.value + }else{ + _amountText.value*-1 + } + } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index b264465e..713c342a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -93,19 +93,15 @@ fun Icon(icon_name: String) { // Snackbar that shows msg @Composable -fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { - var hiddenValue by remember { mutableStateOf(hidden) } +fun FeedbackSnackbar(msg: String, hidden: Boolean = false, onDismiss: () -> Unit) { Aside( attrs = { - when (hiddenValue) { + when (hidden) { false -> classes("mdc-snackbar", "mdc-snackbar--open") true -> classes("mdc-snackbar", "maria") } onClick { - hiddenValue = true - console.log(this@Aside) - console.log("ldsadsad") - + onDismiss() } }) { Div(attrs = { @@ -387,15 +383,20 @@ fun ChooseCategoryMenu( selectedCategory: Int?, getCategoryId: (Int?) -> Unit ) { + console.log(categoryList) + var choseCat = categoryList[0] + + for (category in categoryList) { + if (category.id == selectedCategory) { + choseCat = category + break + } + } + var chosenCategory by remember { - mutableStateOf( - if (selectedCategory == null) { - categoryList[0] - } else { - categoryList[selectedCategory] - } - ) + mutableStateOf(choseCat) } + console.log(chosenCategory) var showList by remember { mutableStateOf(false) } @@ -434,3 +435,4 @@ fun ChooseCategoryMenu( } } + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt index 797d4749..210b3a1b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt @@ -1,11 +1,16 @@ import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.Router import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.di.kodein +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow import io.ktor.client.engine.js.* +import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.Style import org.jetbrains.compose.web.renderComposable import org.kodein.di.compose.withDI +import org.kodein.di.instance fun main() { renderComposable("root") { @@ -18,5 +23,36 @@ val di = kodein(ktorEngine = Js.create()) @Composable fun App() = withDI(di) { + val uiEventFlow: UiEventSharedFlow by di.instance() + val loadingState = remember { mutableStateOf(false) } + val snackBarText = remember { mutableStateOf("") } + val snackBarHidden = remember { mutableStateOf(true) } + LaunchedEffect(key1 = true) { + uiEventFlow.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> loadingState.value = true + is UiEvent.ShowError -> { + loadingState.value = false + snackBarText.value = event.msg + snackBarHidden.value = false + } + is UiEvent.ShowSuccess -> { + loadingState.value = false + snackBarText.value = event.msg + snackBarHidden.value = false + } + else -> {} + } + } + } + if (loadingState.value && snackBarHidden.value) { + snackBarText.value = "Loading" + snackBarHidden.value = false + console.log("loading now! ${snackBarHidden.value}") + } + FeedbackSnackbar(snackBarText.value,snackBarHidden.value) { + snackBarHidden.value = true + loadingState.value = false + } Router() } From 3b76d4c0daebf9230744da6cdac020817854dfbf Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 18:59:45 +0200 Subject: [PATCH 159/325] Fix EntryViewModels usage of UseCases --- .../entryViewModel/EntryViewModel.kt | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 5aeca5d4..f33b123a 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -155,23 +155,33 @@ class EntryViewModel( } fun updateEntry(entry: Entry.Patch, id: Int) { - entryUseCases.changeEntryByIdUseCase(entry, id).onEach { - when (it) { - is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) - is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully changed")) //TODO?: Change the msg - is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + scope.launch { + entryUseCases.changeEntryByIdUseCase(entry, id).collect { response -> + when (response) { + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + is DataResponse.Success<*> -> { + _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully updated")) //TODO?: Change the msg + routerFlow.navigateTo(Screen.Dashboard) + } + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + } } } } fun deleteEntry(id: Int) { - entryUseCases.deleteEntryByIdUseCase(id).onEach { - when (it) { - is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) - is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully deleted")) //TODO?: Change the msg - is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + scope.launch { + entryUseCases.deleteEntryByIdUseCase(id).collect { response -> + when (response) { + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + is DataResponse.Success<*> -> { + _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully deleted")) //TODO?: Change the msg + routerFlow.navigateTo(Screen.Dashboard) + } + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + } } } } @@ -190,11 +200,12 @@ class EntryViewModel( } } } - private fun buildAmount(): Float{ - return if(_amountSignState.value){ + + private fun buildAmount(): Float { + return if (_amountSignState.value) { _amountText.value - }else{ - _amountText.value*-1 + } else { + _amountText.value * -1 } } } From 173a5cf974c420d0d3c631288602fa04179c9785 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 19:54:32 +0200 Subject: [PATCH 160/325] Restructure init to loadEvents, reset data inputs in load --- .../viewmodel/entryViewModel/EntryEvent.kt | 5 ++ .../entryViewModel/EntryViewModel.kt | 48 +++++++++++++------ .../compose/entry/EntryComponent.kt | 2 +- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt index b71a37d1..463668d9 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -17,4 +17,9 @@ sealed class EntryEvent { object OnDeleteDialogConfirm : EntryEvent() object OnDeleteDialogDismiss : EntryEvent() + //Load Data for Screen (has some problems when done in init) + object LoadCreate : EntryEvent() + object LoadOverview : EntryEvent() + object LoadEdit : EntryEvent() + } diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index f33b123a..96101604 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -54,18 +54,6 @@ class EntryViewModel( val eventFlow = UiEventSharedFlow.eventFlow // ---- - init { - getCategoryList() - when (routerFlow.state.value) { - is Screen.Entry.Overview -> { - getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) - } - is Screen.Entry.Edit -> { - getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) - } - else -> {} - } - } /* *** Event Handling *** */ fun onEvent(event: EntryEvent) { @@ -88,6 +76,7 @@ class EntryViewModel( else -> { routerFlow.navigateTo(Screen.Entry.Create) + } } } @@ -102,16 +91,32 @@ class EntryViewModel( Entry.Category(categoryIDState.value) ), selectedEntryState.value.id ) - else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntryState.value.id)) //using ID seems... unnecessary? + else -> { + resetFlows() + routerFlow.navigateTo(Screen.Entry.Edit(selectedEntryState.value.id)) + } //using ID seems... unnecessary?} } is EntryEvent.OnDeleteEntry -> _dialogState.value = true is EntryEvent.OnDeleteDialogConfirm -> deleteEntry(selectedEntryState.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false + is EntryEvent.LoadCreate -> { + resetFlows() + getCategoryList() + } + is EntryEvent.LoadOverview -> { + resetFlows() + getCategoryList() + getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) + } + is EntryEvent.LoadEdit -> { + resetFlows() + getCategoryList() + getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) + } else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") } } - } @@ -201,6 +206,9 @@ class EntryViewModel( } } + /** + * Negates amount if amountSign is false + * */ private fun buildAmount(): Float { return if (_amountSignState.value) { _amountText.value @@ -208,4 +216,16 @@ class EntryViewModel( _amountText.value * -1 } } + + /** + * Resets Data Input Variables + */ + private fun resetFlows(){ + _nameText.value = EntryInputState().name + _amountText.value = EntryInputState().amount + _amountSignState.value = EntryInputState().amountSign + _repeatState.value = EntryInputState().repeat + _categoryIDState.value = EntryInputState().categoryID + } + } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 7a22fd76..8fa1b36b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -38,7 +38,7 @@ fun EntryComponent() { EntryCreateView( onCreateEntryButtonPressed = { viewModel.onEvent(EntryEvent.OnCreateEntry) } ) - + viewModel.onEvent(EntryEvent.LoadCreate) } else -> {} } From fa59b95308e4d102e3d5bae4252b880bf659ed6a Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 22:48:57 +0200 Subject: [PATCH 161/325] Overhaul EntryOverviewView with new ViewModel features --- .../entryViewModel/EntryViewModel.kt | 8 +- .../compose/entry/EntryComponent.kt | 9 ++ .../compose/entry/EntryOverviewView.kt | 112 ++++++------------ 3 files changed, 46 insertions(+), 83 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 96101604..bf13e935 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -105,7 +105,6 @@ class EntryViewModel( } is EntryEvent.LoadOverview -> { resetFlows() - getCategoryList() getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) } is EntryEvent.LoadEdit -> { @@ -113,16 +112,13 @@ class EntryViewModel( getCategoryList() getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) } - else -> { - throw Exception("Unhandled EntryEvent in EntryViewModel") - } } } /* *** Use Case usages *** */ - fun getEntryById(id: Int) { - entryUseCases.getEntryByIdUseCase(id).onEach { + fun getEntryById(id: Int) = scope.launch { + entryUseCases.getEntryByIdUseCase(id).collect { when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 8fa1b36b..eb13f870 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -40,6 +40,15 @@ fun EntryComponent() { ) viewModel.onEvent(EntryEvent.LoadCreate) } + is Screen.Entry.Overview -> { + EntryOverviewView( + onEditButton = { viewModel.onEvent(EntryEvent.OnEditEntry) }, + onDeleteButton = { viewModel.onEvent(EntryEvent.OnDeleteEntry) }, + onDeleteDialogConfirmButton = { viewModel.onEvent(EntryEvent.OnDeleteDialogConfirm) }, + onDeleteDialogDismissButton = { viewModel.onEvent(EntryEvent.OnDeleteDialogDismiss) } + ) + viewModel.onEvent(EntryEvent.LoadOverview) + } else -> {} } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index 1d79a64a..66c0c8c5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -10,95 +10,52 @@ import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import di import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle import org.jetbrains.compose.web.svg.Svg +import org.kodein.di.instance @Composable fun EntryOverviewView( - state: State, - onEditButton: (id: Int) -> Unit, - onDeleteButton: (id: Int) -> Unit, - onChangeToDashboard: () -> Unit, - onChangeToCategory: () -> Unit, - onChangeToSettings: () -> Unit + onEditButton: () -> Unit, + onDeleteButton: () -> Unit, + onDeleteDialogConfirmButton: () -> Unit, + onDeleteDialogDismissButton: () -> Unit ) { - var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } - val viewState by remember { state } - - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Settings") - } - } - }) - - MainFlexContainer { - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Entry") } - - EntryOverview(entry, onEditButton, onDeleteButton) - when (viewState) { - is UiState.Success<*> -> { - when (val element = (viewState as UiState.Success<*>).element) { - is Entry -> entry = element - else -> {} - } - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + val viewModel: EntryViewModel by di.instance() + //Data + val entry by viewModel.selectedEntryState.collectAsState() + console.log("Our Entry is $entry") + val deleteDialog by viewModel.dialogState.collectAsState() + H1( + attrs = { + style { margin(2.percent) } } - } + ) { Text(" Entry") } + + EntryOverview( + entry, + deleteDialog, + onEditButton, + onDeleteButton, + onDeleteDialogConfirmButton, + onDeleteDialogDismissButton + ) } @Composable fun EntryOverview( entry: Entry, - onEditButton: (Int) -> Unit, - onDeleteButton: (Int) -> Unit + deleteDialog: Boolean, + onEditButton: () -> Unit, + onDeleteButton: () -> Unit, + onDeleteDialogConfirmButton: () -> Unit, + onDeleteDialogDismissButton: () -> Unit ) { - var deleteDialog by remember { mutableStateOf(false) } Div( attrs = { classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) @@ -127,7 +84,7 @@ fun EntryOverview( ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton(entry.id) } + onClick { onEditButton() } style { flex(50.percent) margin(1.5.percent) @@ -137,7 +94,7 @@ fun EntryOverview( } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { deleteDialog = true } + onClick { onDeleteButton() } style { flex(50.percent) margin(1.5.percent) @@ -150,8 +107,9 @@ fun EntryOverview( if (deleteDialog) { DeleteDialog( false, - { onDeleteButton(entry.id) }, - { deleteDialog = false }) { Text("Delete Entry?") } + { onDeleteDialogConfirmButton() }, + { onDeleteDialogDismissButton() }) + { Text("Delete Entry?") } } } From f5192ee827cf2a314d7edc0a885ec42e896acc3d Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 23:42:30 +0200 Subject: [PATCH 162/325] Overhaul EntryEditView with new ViewModel structure and fix some small stuff --- .../compose/entry/EntryComponent.kt | 9 +- .../compose/entry/EntryCreateView.kt | 5 +- .../compose/entry/EntryEditView.kt | 365 ++++++++---------- 3 files changed, 161 insertions(+), 218 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index eb13f870..38016c5e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -36,7 +36,7 @@ fun EntryComponent() { when (screenState.value) { is Screen.Entry.Create -> { EntryCreateView( - onCreateEntryButtonPressed = { viewModel.onEvent(EntryEvent.OnCreateEntry) } + onCreateButton = { viewModel.onEvent(EntryEvent.OnCreateEntry) } ) viewModel.onEvent(EntryEvent.LoadCreate) } @@ -49,6 +49,13 @@ fun EntryComponent() { ) viewModel.onEvent(EntryEvent.LoadOverview) } + is Screen.Entry.Edit -> { + EntryEditView( + onEditButton = { viewModel.onEvent(EntryEvent.OnEditEntry)} + ) + viewModel.onEvent(EntryEvent.LoadEdit) + + } else -> {} } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index fa8e84c3..fc383ee4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -18,13 +18,12 @@ import org.kodein.di.instance @OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryCreateView( - onCreateEntryButtonPressed: () -> Unit, + onCreateButton: () -> Unit, ) { val viewModel: EntryViewModel by di.instance() //Input val entryNameTextField by viewModel.nameText.collectAsState() val entryAmountTextField by viewModel.amountText.collectAsState() - val entryRepeat by viewModel.repeatState.collectAsState() val entryCategoryIDTextField by viewModel.categoryIDState.collectAsState() val amountSign by viewModel.amountSignState.collectAsState() //Data @@ -37,7 +36,7 @@ fun EntryCreateView( ) { Text("Create new Entry") } Form(attrs = { this.addEventListener("submit") { - onCreateEntryButtonPressed() + onCreateButton() it.preventDefault() } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 5067a17e..f1d58c14 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -9,6 +9,9 @@ import de.hsfl.budgetBinder.compose.category.categoryIdToCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import di import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType import org.jetbrains.compose.web.attributes.InputType @@ -18,269 +21,203 @@ import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Path import org.jetbrains.compose.web.svg.Svg +import org.kodein.di.instance @OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryEditView( - state: State, - onChangeToDashboard: () -> Unit, - onChangeToSettings: () -> Unit, - onChangeToCategory: () -> Unit, - onEditEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category: Entry.Category) -> Unit, + onEditButton: () -> Unit, ) { - var entry by remember { mutableStateOf(Entry(0, "", 0f, false, 0)) } - var categoryList by remember { mutableStateOf>(emptyList()) } - var switchState by remember { mutableStateOf(false) } - var entryNameTextFieldState by remember { mutableStateOf("") } - var entryAmountTextFieldState by remember { mutableStateOf("") } - var entryRepeatState by remember { mutableStateOf("") } - var entryCategoryIDTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } + val viewModel: EntryViewModel by di.instance() + //Input + val entryNameTextField by viewModel.nameText.collectAsState() + val entryAmountTextField by viewModel.amountText.collectAsState() + val entryRepeat by viewModel.repeatState.collectAsState() + val entryCategoryIDTextField by viewModel.categoryIDState.collectAsState() + val amountSign by viewModel.amountSignState.collectAsState() + //Data + val categoryList by viewModel.categoryListState.collectAsState() + val entry by viewModel.selectedEntryState.collectAsState() - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Edit Entry") } + Form(attrs = { + this.addEventListener("submit") { + onEditButton() + it.preventDefault() + } + } + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { Span( attrs = { - classes("mdc-button__label") + classes("mdc-text-field__ripple") } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { + ) { } Span( attrs = { - classes("mdc-button__label") + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Entry Name") } + Input( + type = InputType.Text ) { - Text("Settings") + classes("mdc-text-field__input") + value(entryNameTextField) + required(true) + onInput { + viewModel.onEvent(EntryEvent.EnteredName(it.value)) + } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - }) - - MainFlexContainer { - H1( + } + Div( attrs = { - style { margin(2.percent) } - } - ) { Text("Edit Entry") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$entryNameTextFieldState, $entryAmountTextFieldState, $entryRepeatState, ${entryCategoryIDTextFieldState.toInt()}") - onEditEntryButtonPressed( - entryNameTextFieldState, - (if (!switchState) "-$entryAmountTextFieldState" else entryAmountTextFieldState).toFloat(), - entryRepeatState.toBoolean(), - Entry.Category(entryCategoryIDTextFieldState.toInt()) - ) - it.preventDefault() + classes(AppStylesheet.margin) } - } ) { - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Entry Name") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(entryNameTextFieldState) - required(true) - onInput { - entryNameTextFieldState = it.value - } + classes("mdc-text-field__ripple") } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } } - ) { - Span( + ) { Text("Amount") } + Div { + Button( attrs = { - classes("mdc-text-field__ripple") + if (!amountSign) classes("mdc-switch", "mdc-switch--unselected") + else classes("mdc-switch", "mdc-switch--selected") + id("basic-switch") + attr("role", "switch") + attr("aria-checked", "false") + type(ButtonType.Button) + onClick { viewModel.onEvent(EntryEvent.EnteredAmountSign) } } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } - } - ) { Text("Amount") } - Div { - Button( - attrs = { - if (!switchState) classes("mdc-switch", "mdc-switch--unselected") - else classes("mdc-switch", "mdc-switch--selected") - id("basic-switch") - attr("role", "switch") - attr("aria-checked", "false") - type(ButtonType.Button) - onClick { switchState = !switchState } - } - ) { - Div(attrs = { classes("mdc-switch__track") }) { } - Div(attrs = { classes("mdc-switch__handle-track") }) { - Div(attrs = { classes("mdc-switch__handle") }) { - Div(attrs = { classes("mdc-switch__shadow") }) { - Div(attrs = { classes("mdc-elevation-overlay") }) { } + ) { + Div(attrs = { classes("mdc-switch__track") }) { } + Div(attrs = { classes("mdc-switch__handle-track") }) { + Div(attrs = { classes("mdc-switch__handle") }) { + Div(attrs = { classes("mdc-switch__shadow") }) { + Div(attrs = { classes("mdc-elevation-overlay") }) { } + } + Div(attrs = { classes("mdc-switch__ripple") }) { } + Div(attrs = { classes("mdc-switch__icons") }) { + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") } - Div(attrs = { classes("mdc-switch__ripple") }) { } - Div(attrs = { classes("mdc-switch__icons") }) { - Svg( - attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, - viewBox = "0 0 24 24" - ) { - Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") - } - Svg( - attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, - viewBox = "0 0 24 24" - ) { - Path("M20 13H4v-2h16v2z") - } + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M20 13H4v-2h16v2z") } } } } } - Div(attrs = { - classes("mdc-typography--headline6", AppStylesheet.text) - }) { - Text(if (switchState) "+" else "-") - } - Input( - type = InputType.Number - ) { - attr("step", "0.01") - classes("mdc-text-field__input") - onInput { - entryAmountTextFieldState = it.value.toString() - } + } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { + Text(if (amountSign) "+" else "-") + } + Input( + type = InputType.Number + ) { + attr("step", "0.01") + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(EntryEvent.EnteredAmount(it.value as Float)) } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( - attrs = { - classes(AppStylesheet.margin, AppStylesheet.flexContainer) - } - ) { - Div(attrs = { style { flex(50.percent) } }) { - Div(attrs = { classes("mdc-form-field") }) { - Div(attrs = { classes("mdc-checkbox") }) { - Input(type = InputType.Checkbox) - { - classes("mdc-checkbox__native-control") - id("checkbox-1") - onInput { - entryRepeatState = it.value.toString() - } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) + } + ) { + Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { classes("mdc-form-field") }) { + Div(attrs = { classes("mdc-checkbox") }) { + Input(type = InputType.Checkbox) + { + classes("mdc-checkbox__native-control") + id("checkbox-1") + onInput { + viewModel.onEvent(EntryEvent.EnteredRepeat) } - Div(attrs = { classes("mdc-checkbox__background") }) { - Svg(attrs = { classes("mdc-checkbox__checkmark") }, viewBox = "0 0 24 24") { - Path( - "M1.73,12.91 8.1,19.28 22.79,4.59", - attrs = { classes("mdc-checkbox__checkmark") }) - } - Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } + } + Div(attrs = { classes("mdc-checkbox__background") }) { + Svg( + attrs = { classes("mdc-checkbox__checkmark") }, + viewBox = "0 0 24 24" + ) { + Path( + "M1.73,12.91 8.1,19.28 22.79,4.59", + attrs = { classes("mdc-checkbox__checkmark") }) } - Div(attrs = { classes("mdc-checkbox__ripple") }) { } + Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } } - Label(forId = "checkbox-1") { Text("repeat") } + Div(attrs = { classes("mdc-checkbox__ripple") }) { } } - } - Div(attrs = { style { flex(50.percent) } }) { - //ChooseCategoryMenu(categoryList, ) { id -> entryCategoryIDTextFieldState = id.toString() } + Label(forId = "checkbox-1") { Text("repeat") } } } - Div( - attrs = { - classes(AppStylesheet.margin) + Div(attrs = { style { flex(50.percent) } }) { + ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> + viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) } - Div { - when (viewState) { - is UiState.Success<*> -> { - when (val element = (viewState as UiState.Success<*>).element) { - is Entry -> { - entry = element - entryNameTextFieldState = entry.name - entryAmountTextFieldState = entry.amount.toString() - switchState = !entry.amount.toString().startsWith("-") - entryRepeatState = entry.repeat.toString() - entryCategoryIDTextFieldState = entry.category_id.toString() - } - } - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } + } + Div( + attrs = { + classes(AppStylesheet.margin) } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) } } } From 93719f60eb0f8b514cce0b480086af014b8ce90d Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 00:26:31 +0200 Subject: [PATCH 163/325] Load EntryEditView with data from selected entry (except amount) --- .../viewmodel/entryViewModel/EntryViewModel.kt | 13 +++++++++++-- .../budgetBinder/compose/entry/EntryEditView.kt | 5 +++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index bf13e935..6cc2e3ed 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -16,6 +16,9 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch +import kotlin.math.absoluteValue +import kotlin.math.sign +import kotlin.math.withSign class EntryViewModel( private val entryUseCases: EntryUseCases, @@ -124,6 +127,12 @@ class EntryViewModel( is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) is DataResponse.Success<*> -> { _selectedEntryState.value = it.data!! + //Load data into variables for edit + _nameText.value = _selectedEntryState.value.name + _amountText.value = _selectedEntryState.value.amount.absoluteValue + _amountSignState.value = _selectedEntryState.value.amount >= 0 + _repeatState.value = _selectedEntryState.value.repeat + _categoryIDState.value = _selectedEntryState.value.category_id } is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) } @@ -173,7 +182,7 @@ class EntryViewModel( fun deleteEntry(id: Int) { scope.launch { - entryUseCases.deleteEntryByIdUseCase(id).collect { response -> + entryUseCases.deleteEntryByIdUseCase(id).collect { response -> when (response) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) @@ -216,7 +225,7 @@ class EntryViewModel( /** * Resets Data Input Variables */ - private fun resetFlows(){ + private fun resetFlows() { _nameText.value = EntryInputState().name _amountText.value = EntryInputState().amount _amountSignState.value = EntryInputState().amountSign diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index f1d58c14..7763e54a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -178,14 +178,15 @@ fun EntryEditView( Div(attrs = { style { flex(50.percent) } }) { Div(attrs = { classes("mdc-form-field") }) { Div(attrs = { classes("mdc-checkbox") }) { - Input(type = InputType.Checkbox) + CheckboxInput (attrs = { + checked(entryRepeat) classes("mdc-checkbox__native-control") id("checkbox-1") onInput { viewModel.onEvent(EntryEvent.EnteredRepeat) } - } + }) Div(attrs = { classes("mdc-checkbox__background") }) { Svg( attrs = { classes("mdc-checkbox__checkmark") }, From 33b85ad2e48581b533513eb7bb4002aed970f152 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 00:36:45 +0200 Subject: [PATCH 164/325] Load EntryEditView with amount data from selected entry --- .../kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 7763e54a..c57e1213 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -159,6 +159,7 @@ fun EntryEditView( ) { attr("step", "0.01") classes("mdc-text-field__input") + value(entryAmountTextField) onInput { viewModel.onEvent(EntryEvent.EnteredAmount(it.value as Float)) } From 2abd426538315615b5c76988479b03840a269c35 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 00:59:11 +0200 Subject: [PATCH 165/325] Add some padding and nowrap to Categories in ChooseCategoryMenu --- .../de/hsfl/budgetBinder/compose/Composables.kt | 2 +- .../hsfl/budgetBinder/compose/entry/EntryEditView.kt | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 713c342a..e6c4b967 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -426,7 +426,7 @@ fun ChooseCategoryMenu( onClick { chosenCategory = category; getCategoryId(category.id) } }) { Span(attrs = { classes("mdc-list-item__ripple") }) { } - Span(attrs = { }) { Text(category.name) } + Span(attrs = { classes(AppStylesheet.moneyText)}) { Text(category.name) } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index c57e1213..4929d7bb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -1,14 +1,8 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.ChooseCategoryMenu -import de.hsfl.budgetBinder.compose.MainFlexContainer -import de.hsfl.budgetBinder.compose.category.categoryIdToCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel import di @@ -204,7 +198,10 @@ fun EntryEditView( Label(forId = "checkbox-1") { Text("repeat") } } } - Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { style { + flex(50.percent) + alignItems(AlignItems.Stretch) + } }) { ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) } From fc3e30a12fc7b52713fd3fe468ba3df8eded1bab Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 12:26:06 +0200 Subject: [PATCH 166/325] Change folder name entryViewModel to entry --- .../commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt | 2 +- .../viewmodel/{entryViewModel => entry}/EntryEvent.kt | 2 +- .../{entryViewModel => entry}/EntryInputState.kt | 2 +- .../viewmodel/{entryViewModel => entry}/EntryState.kt | 2 +- .../{entryViewModel => entry}/EntryViewModel.kt | 8 +------- .../hsfl/budgetBinder/compose/entry/EntryComponent.kt | 6 ++---- .../hsfl/budgetBinder/compose/entry/EntryCreateView.kt | 4 ++-- .../hsfl/budgetBinder/compose/entry/EntryEditView.kt | 4 ++-- .../budgetBinder/compose/entry/EntryOverviewView.kt | 10 +--------- 9 files changed, 12 insertions(+), 28 deletions(-) rename budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/{entryViewModel => entry}/EntryEvent.kt (92%) rename budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/{entryViewModel => entry}/EntryInputState.kt (73%) rename budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/{entryViewModel => entry}/EntryState.kt (80%) rename budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/{entryViewModel => entry}/EntryViewModel.kt (96%) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt index d921d702..9fc7a5d8 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt @@ -20,7 +20,7 @@ import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginViewModel import de.hsfl.budgetBinder.presentation.viewmodel.register.RegisterViewModel import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerViewModel import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditServerUrlViewModel import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditUserViewModel diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt similarity index 92% rename from budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt rename to budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt index 463668d9..00a691f1 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +package de.hsfl.budgetBinder.presentation.viewmodel.entry // View is not allowed to declare what should be done, only notify what has happened, names are assigned as such diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryInputState.kt similarity index 73% rename from budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt rename to budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryInputState.kt index 7debc864..db25b34e 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryInputState.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +package de.hsfl.budgetBinder.presentation.viewmodel.entry data class EntryInputState( val name: String = "", diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryState.kt similarity index 80% rename from budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt rename to budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryState.kt index 183cde42..b3486a6a 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryState.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +package de.hsfl.budgetBinder.presentation.viewmodel.entry import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt similarity index 96% rename from budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt rename to budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index 6cc2e3ed..e9b4188f 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +package de.hsfl.budgetBinder.presentation.viewmodel.entry import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.DataResponse @@ -6,19 +6,13 @@ import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiEvent -import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow -import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginTextFieldState import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import kotlin.math.absoluteValue -import kotlin.math.sign -import kotlin.math.withSign class EntryViewModel( private val entryUseCases: EntryUseCases, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 38016c5e..6684fc74 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -1,15 +1,13 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiEvent import de.hsfl.budgetBinder.presentation.flow.RouterFlow -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di import kotlinx.coroutines.flow.collectLatest import org.kodein.di.instance diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index fc383ee4..1391c7db 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -3,8 +3,8 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.* import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.* diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 4929d7bb..4bab291c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -3,8 +3,8 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.ChooseCategoryMenu import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index 66c0c8c5..9cac0722 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -1,21 +1,13 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry -import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.DeleteDialog -import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import de.hsfl.budgetBinder.presentation.UiState -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* -import org.jetbrains.compose.web.svg.Circle -import org.jetbrains.compose.web.svg.Svg import org.kodein.di.instance From 06f6d3fb4599adaf07f0ee8473feba459efa7db2 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 19:53:43 +0200 Subject: [PATCH 167/325] Add Form in CategoryCreateView and Buttonlogic in CategoryComponent --- .../compose/category/CategoryCreateView.kt | 250 ++++++++++++++++-- 1 file changed, 231 insertions(+), 19 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index a889b22d..efb46c63 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -1,36 +1,248 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.CategoryImagesToImageList +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.css.marginBottom +import org.jetbrains.compose.web.css.marginLeft +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.dom.* @Composable fun CategoryCreateView( state: State, - onBackButton: () -> Unit + onCreateCategoryButtonPressed: (name: String, color: String, image: Category.Image, budget: Float) -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToSettings: () -> Unit, + onChangeToCategory: () -> Unit, ) { + var categoryNameTextFieldState by remember { mutableStateOf("") } + var categoryColorTextFieldState by remember { mutableStateOf("") } + var categoryImageState by remember { mutableStateOf(Category.Image.DEFAULT) } + var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("CategoryCreateView")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } + }) + + MainFlexContainer { + Div(attrs = { + classes("mdc-card", AppStylesheet.card) } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to To Category Overview") + ) { + H1 { Text("Create a new Category") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onCreateCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() + } + } + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Category Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + onInput { + categoryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(50.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Color") } + Input( + type = InputType.Color + ) { + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent)} + } + ) { Text("Image") } + CategoryImagesToImageList(onClick = {categoryImageState = it}) + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number + ) { + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + onInput { + categoryBudgetTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } + } } } } From 25b8769f6b10bb9ec9bed2462627452821810576 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 19:54:11 +0200 Subject: [PATCH 168/325] Add ImageList as Composable --- .../hsfl/budgetBinder/compose/Composables.kt | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index d31dcabe..4060e9bf 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -1,32 +1,33 @@ package de.hsfl.budgetBinder.compose +import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* /*Main Container for every mayor layout*/ @Composable -fun MainFlexContainer(content: @Composable () -> Unit){ - Div ( +fun MainFlexContainer(content: @Composable () -> Unit) { + Div( attrs = { classes("mdc-top-app-bar--fixed-adjust", AppStylesheet.flexContainer) } - ){ - Div (attrs = { classes(AppStylesheet.pufferFlexContainer) }) - Div (attrs = { classes(AppStylesheet.contentFlexContainer)}) + ) { + Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) + Div(attrs = { classes(AppStylesheet.contentFlexContainer) }) { content() } - Div (attrs = { classes(AppStylesheet.pufferFlexContainer)}) + Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) } } @Composable -fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit){ +fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit) { Header( attrs = { classes("mdc-top-app-bar") @@ -61,3 +62,35 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } } } + +@Composable +fun CategoryImagesToImageList(onClick : (Category.Image) -> Unit) { + Div( + attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Ul( + attrs = { + classes("mdc-image-list", "my-image-list") + } + ) { + for (image in Category.Image.values()) { + Li( + attrs = { + classes("mdc-image-list__item") + } + ) { + Div( + attrs = { + classes("mdc-image-list__image-aspect-container", "mdc-icon-button") + onClick { onClick } + } + ) { + CategoryImageToIcon(image) + } + } + } + } + } +} From e1e03667225ed9ebbae3d3d4c7dc4cd6f08a378e Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 20:52:09 +0200 Subject: [PATCH 169/325] Add highlight when image is chosen and button functionality in composable --- .../de/hsfl/budgetBinder/compose/Composables.kt | 13 ++++++++++--- .../compose/category/CategoryCreateView.kt | 5 +++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 4060e9bf..b2100a2c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -64,7 +64,8 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } @Composable -fun CategoryImagesToImageList(onClick : (Category.Image) -> Unit) { +fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { + var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } Div( attrs = { classes("mdc-card", AppStylesheet.card) @@ -83,8 +84,14 @@ fun CategoryImagesToImageList(onClick : (Category.Image) -> Unit) { ) { Div( attrs = { - classes("mdc-image-list__image-aspect-container", "mdc-icon-button") - onClick { onClick } + if (highlightImage == image) + classes( + "mdc-image-list__image-aspect-container", + "mdc-icon-button", + "mdc-button--raised" + ) + else classes("mdc-image-list__image-aspect-container", "mdc-icon-button") + onClick { onClick(image); highlightImage = image } } ) { CategoryImageToIcon(image) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index efb46c63..91566936 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -8,6 +8,8 @@ import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.min +import org.jetbrains.compose.web.attributes.required import org.jetbrains.compose.web.css.marginBottom import org.jetbrains.compose.web.css.marginLeft import org.jetbrains.compose.web.css.percent @@ -113,6 +115,7 @@ fun CategoryCreateView( ) { classes("mdc-text-field__input") value(categoryNameTextFieldState) + required(true) onInput { categoryNameTextFieldState = it.value } @@ -207,6 +210,8 @@ fun CategoryCreateView( ) { classes("mdc-text-field__input") value(categoryBudgetTextFieldState) + required(true) + min("1") onInput { categoryBudgetTextFieldState = it.value.toString() } From 9a6aa563e9894119bbfd5b413e416ba84b36a08c Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 20:57:34 +0200 Subject: [PATCH 170/325] Change width of color input from 50% to 100% --- .../de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index 91566936..a63d68e4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -135,7 +135,7 @@ fun CategoryCreateView( Label( attrs = { classes("mdc-text-field", "mdc-text-field--outlined") - style { width(50.percent) } + style { width(100.percent) } } ) { Span( From db5a0632a9be62fcb1830cb5a61322f788d92251 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 13 Jun 2022 16:53:40 +0200 Subject: [PATCH 171/325] Add TopBar and MainContainer to CategorySummaryView --- .../compose/category/CategoryComponent.kt | 3 + .../compose/category/CategorySummaryView.kt | 132 ++++++++++++++---- 2 files changed, 106 insertions(+), 29 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 8d483556..53c7b474 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -44,6 +44,9 @@ fun CategoryComponent(screenState: MutableState) { onBackButton = { screenState.value = Screen.Dashboard}, onEditButton = { screenState.value = Screen.CategoryEdit}, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) Screen.CategoryEdit -> CategoryEditView( state = viewState, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index a9cefeff..8c1116cb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -1,11 +1,15 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.css.margin +import org.jetbrains.compose.web.css.marginBottom +import org.jetbrains.compose.web.css.marginLeft +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.dom.* @Composable @@ -13,36 +17,106 @@ fun CategorySummaryView( state: State, onBackButton: () -> Unit, onEditButton: () -> Unit, - onCategoryCreateButton: () -> Unit + onCategoryCreateButton: () -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToCategory: () -> Unit, + onChangeToSettings: () -> Unit ) { val viewState by remember { state } - H1{Text("CategorySummaryView")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } + }) + + MainFlexContainer { + Div(attrs = { + classes("mdc-card", AppStylesheet.card) } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Dashboard") - } - Button(attrs = { - onClick { onEditButton() } - }) { - Text("Edit Category (Needs to be set for each category)") - } - Button(attrs = { - onClick { onCategoryCreateButton() } - }) { - Text("Create Category") + ) { + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Category Summary") } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onCategoryCreateButton() } + style { margin(2.percent) } + }) { + Text("Create Category") + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Text("Kat 1") + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onEditButton() } + }) { + Text("Edit Category (Needs to be set for each category)") + } + } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Text("Kat 2") + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onEditButton() } + }) { + Text("Edit Category (Needs to be set for each category)") + } + } + } } } } From 9033d43508424a983a0032ab53e870ea284d2254 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 13:15:37 +0200 Subject: [PATCH 172/325] Add CategoryList as Composable --- .../hsfl/budgetBinder/compose/Composables.kt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index b2100a2c..0eeeb7cf 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* @@ -101,3 +102,29 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { } } } + +@Composable +fun CategoryList(categoryList : List){ + Div { + console.log(categoryList.size) + for (category in categoryList) + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Text("${category.name}") + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { } + }) { + Text("Edit Category") + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { } + }) { + Text("Delete Category") + } + } + } +} From 9acc5cdf028b9ce9b28c957f4501676bea7e130f Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 13:16:53 +0200 Subject: [PATCH 173/325] Delete unused Buttons --- .../de/hsfl/budgetBinder/compose/category/CategoryComponent.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 53c7b474..749b7b61 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -41,8 +41,6 @@ fun CategoryComponent(screenState: MutableState) { ) Screen.CategorySummary -> CategorySummaryView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard}, - onEditButton = { screenState.value = Screen.CategoryEdit}, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, From 8f7307204cf8cbd2da7675208c6f7940c6602f11 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 13:18:06 +0200 Subject: [PATCH 174/325] Delete unused Buttons and add CategoryList() from Composables --- .../compose/category/CategorySummaryView.kt | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 8c1116cb..07758e1a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -1,13 +1,13 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.css.margin -import org.jetbrains.compose.web.css.marginBottom -import org.jetbrains.compose.web.css.marginLeft import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* @@ -15,13 +15,12 @@ import org.jetbrains.compose.web.dom.* @Composable fun CategorySummaryView( state: State, - onBackButton: () -> Unit, - onEditButton: () -> Unit, onCategoryCreateButton: () -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { + var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } topBarMain( @@ -80,10 +79,20 @@ fun CategorySummaryView( }) { Text("Create Category") } + CategoryList(categoryList) Div { when (viewState) { is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + when (val element = (viewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + categoryList = it + } + } + } + } } is UiState.Error -> { Text((viewState as UiState.Error).error) @@ -92,30 +101,6 @@ fun CategorySummaryView( //CircularProgressIndicator() } } - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - Text("Kat 1") - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onEditButton() } - }) { - Text("Edit Category (Needs to be set for each category)") - } - } - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - Text("Kat 2") - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onEditButton() } - }) { - Text("Edit Category (Needs to be set for each category)") - } - } } } } From f673bf3ac2a6f41418edace3e89814c7da3bec71 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:14:40 +0200 Subject: [PATCH 175/325] Add marginRight --- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index b498f7f6..6bb759f2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -60,7 +60,6 @@ object AppStylesheet : StyleSheet() { val card by style { margin(10.px) marginTop(25.px) - } val image by style { @@ -70,4 +69,8 @@ object AppStylesheet : StyleSheet() { val margin by style { margin(10.px) } + + val marginRight by style { + marginRight(1.percent) + } } \ No newline at end of file From 7b2d3152b816d422e9292e2bf32db8786ebae780 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:15:26 +0200 Subject: [PATCH 176/325] Change display of categoryList to not showing --- .../de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index a63d68e4..22d8391a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -237,7 +237,7 @@ fun CategoryCreateView( Div { when (viewState) { is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + //Text((viewState as UiState.Success<*>).element.toString()) } is UiState.Error -> { Text((viewState as UiState.Error).error) From 81a162effb75fdbf0af43e2201bbd84fefa12780 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:15:48 +0200 Subject: [PATCH 177/325] Delete unused imports --- .../hsfl/budgetBinder/compose/category/CategorySummaryView.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 07758e1a..93799a7b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -2,11 +2,14 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain +import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState +import org.jetbrains.compose.web.css.flex import org.jetbrains.compose.web.css.margin import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* From 3f341731a97e9b0291a258fd7c9e2051721fb40b Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:16:51 +0200 Subject: [PATCH 178/325] Add color, image and budget for each displayed category --- .../hsfl/budgetBinder/compose/Composables.kt | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 0eeeb7cf..cd086600 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,10 +4,12 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Rect +import org.jetbrains.compose.web.svg.Svg /*Main Container for every mayor layout*/ @@ -103,27 +105,57 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { } } +@OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun CategoryList(categoryList : List){ +fun CategoryList(categoryList: List) { Div { console.log(categoryList.size) for (category in categoryList) Div(attrs = { - classes("mdc-card", AppStylesheet.card) + classes("mdc-card", AppStylesheet.card, AppStylesheet.flexContainer) } ) { - Text("${category.name}") - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { } - }) { - Text("Edit Category") + Div( + attrs = { + classes(AppStylesheet.margin) + style { flex(100.percent) } + } + ) { + Text("Name: ${category.name}") + Div(attrs = { style { width(3.percent) } }) { + Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in + Rect(x = 0, y = 0, width = 1, height = 1, { + attr("fill", "#${category.color}") + }) + } + } + Div { + Text("Image: ") + CategoryImageToIcon(category.image) + } + Text("Budget: ${category.budget}€") } - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { } - }) { - Text("Delete Category") + Div( + attrs = { + style { flex(100.percent) } + classes(AppStylesheet.flexContainer) + } + ) { + Div(attrs = { style { flex(75.percent) } }) { } + Button(attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + onClick { } + style { flex(25.percent)} + }) { + Text("Edit Category") + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { } + style { flex(25.percent) } + }) { + Text("Delete Category") + } } } } From 1a537520edbfd120d903bd5b0a496bff6d369c53 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Thu, 16 Jun 2022 16:21:46 +0200 Subject: [PATCH 179/325] Add DeleteDialog as composable and add Dialog on delete user in Settings --- .../hsfl/budgetBinder/compose/Composables.kt | 98 +++++++++++++++++++ .../compose/settings/SettingsView.kt | 9 +- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index cd086600..2d861cfe 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -5,6 +5,7 @@ import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* @@ -160,3 +161,100 @@ fun CategoryList(categoryList: List) { } } } + +@Composable +fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composable () -> Unit ){ + var hiddenValue by remember { mutableStateOf(hidden)} + Div( + attrs = { + when(hiddenValue){ + false -> classes("mdc-dialog", "mdc-dialog--open") + true -> classes("mdc-dialog") + } + } + ) { + Div( + attrs = { + classes("mdc-dialog__container") + } + ) { + Div( + attrs = { + classes("mdc-dialog__surface") + attr("role", "alertdialog") + attr("aria-modal", "true") + attr("aria-labelledby", "my-dialog-title") + attr("aria-describedby", "my-dialog-content") + } + ) { + Div( + attrs = { + classes("mdc-dialog__content") + id("my-dialog-content") + } + ) { + content() //Text in Dialog + } + Div( + attrs = { + classes("mdc-dialog__actions") + } + ) { + Button( + attrs = { + classes("mdc-button", "mdc-dialog__button") + attr("data-mdc-dialog-action", "cancel") + onClick { hiddenValue = true } + } + ) { + Div( + attrs = { + classes("mdc-button__ripple") + } + ) { + + } + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Cancel") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-dialog__button") + attr("data-mdc-dialog-action", "accept") + onClick { + buttonAction() + hiddenValue = true } + } + ) { + Div( + attrs = { + classes("mdc-button__ripple") + } + ) { + + } + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("OK") + } + } + } + } + } + Div( + attrs = { + classes("mdc-dialog__scrim") + } + ) { + + } + } +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt index 9583303b..6324485a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt @@ -1,6 +1,7 @@ package de.hsfl.budgetBinder.compose.settings import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet @@ -20,6 +21,7 @@ fun SettingsView( onDeleteButtonPressed: () -> Unit, onChangeButtonPressed: () -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } val viewState by remember { state } topBarMain( @@ -105,7 +107,9 @@ fun SettingsView( Button( attrs = { classes("mdc-button", "mdc-button--raised") - onClick { onDeleteButtonPressed() } + onClick { + deleteDialog = true + } style { flex(100.percent) } } ) { @@ -113,5 +117,8 @@ fun SettingsView( } } } + if (deleteDialog) { + DeleteDialog(false, {onDeleteButtonPressed}) { Text("Delete User?") } + } } } From 5dfb970000dc02cdaaa33339e4c73028c2f736d4 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Thu, 16 Jun 2022 16:39:46 +0200 Subject: [PATCH 180/325] Add DeleteDialog on delete Category --- .../hsfl/budgetBinder/compose/Composables.kt | 24 ++++++++++++------- .../compose/category/CategorySummaryView.kt | 7 +++++- .../compose/settings/SettingsView.kt | 2 +- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 2d861cfe..6b4011d2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -108,7 +108,10 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun CategoryList(categoryList: List) { +fun CategoryList( + categoryList: List, + onOpenDeleteDialog: () -> Unit, +) { Div { console.log(categoryList.size) for (category in categoryList) @@ -146,13 +149,13 @@ fun CategoryList(categoryList: List) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) onClick { } - style { flex(25.percent)} + style { flex(25.percent) } }) { Text("Edit Category") } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { } + onClick { onOpenDeleteDialog() } style { flex(25.percent) } }) { Text("Delete Category") @@ -163,11 +166,11 @@ fun CategoryList(categoryList: List) { } @Composable -fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composable () -> Unit ){ - var hiddenValue by remember { mutableStateOf(hidden)} +fun DeleteDialog(hidden: Boolean, buttonAction: () -> Unit, resetDialog: () -> Unit, content: @Composable () -> Unit) { + var hiddenValue by remember { mutableStateOf(hidden) } Div( attrs = { - when(hiddenValue){ + when (hiddenValue) { false -> classes("mdc-dialog", "mdc-dialog--open") true -> classes("mdc-dialog") } @@ -204,7 +207,10 @@ fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composabl attrs = { classes("mdc-button", "mdc-dialog__button") attr("data-mdc-dialog-action", "cancel") - onClick { hiddenValue = true } + onClick { + hiddenValue = true + resetDialog() + } } ) { Div( @@ -228,7 +234,9 @@ fun DeleteDialog( hidden: Boolean, buttonAction: () -> Unit, content: @Composabl attr("data-mdc-dialog-action", "accept") onClick { buttonAction() - hiddenValue = true } + hiddenValue = true + resetDialog() + } } ) { Div( diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 93799a7b..5e05c425 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.CategoryList +import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain @@ -23,6 +24,7 @@ fun CategorySummaryView( onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -82,7 +84,7 @@ fun CategorySummaryView( }) { Text("Create Category") } - CategoryList(categoryList) + CategoryList(categoryList, {deleteDialog = true}) Div { when (viewState) { is UiState.Success<*> -> { @@ -106,5 +108,8 @@ fun CategorySummaryView( } } } + if (deleteDialog) { + DeleteDialog(false, {}, {deleteDialog = false}) { Text("Delete User?") } + } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt index 6324485a..8a9b0225 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt @@ -118,7 +118,7 @@ fun SettingsView( } } if (deleteDialog) { - DeleteDialog(false, {onDeleteButtonPressed}) { Text("Delete User?") } + DeleteDialog(false, {onDeleteButtonPressed()}, {deleteDialog = false}) { Text("Delete User?") } } } } From e8024ba4ef7072c0660d5a67b90eb3ad0dc026e7 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Thu, 16 Jun 2022 18:49:47 +0200 Subject: [PATCH 181/325] Change how categories ard displayed --- .../hsfl/budgetBinder/compose/Composables.kt | 53 +++++++++++++------ .../compose/theme/AppStylesheet.kt | 21 +++++++- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 6b4011d2..d2de4d69 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -1,9 +1,11 @@ package de.hsfl.budgetBinder.compose +import App import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.style import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi @@ -113,50 +115,71 @@ fun CategoryList( onOpenDeleteDialog: () -> Unit, ) { Div { - console.log(categoryList.size) for (category in categoryList) Div(attrs = { - classes("mdc-card", AppStylesheet.card, AppStylesheet.flexContainer) + classes("mdc-card", AppStylesheet.card) } ) { Div( attrs = { - classes(AppStylesheet.margin) - style { flex(100.percent) } + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) } ) { - Text("Name: ${category.name}") - Div(attrs = { style { width(3.percent) } }) { + Div( + attrs = { + classes(AppStylesheet.imageFlexContainer) + } + ) { + CategoryImageToIcon(category.image) + } + Div( + attrs = { + classes(AppStylesheet.categoryListElementText) + } + ) { + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(category.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Budget: ${category.budget}€") } + } + } + Div(attrs = { + classes(AppStylesheet.imageFlexContainer) + } + ) { Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in Rect(x = 0, y = 0, width = 1, height = 1, { attr("fill", "#${category.color}") }) } } - Div { - Text("Image: ") - CategoryImageToIcon(category.image) - } - Text("Budget: ${category.budget}€") } Div( attrs = { - style { flex(100.percent) } classes(AppStylesheet.flexContainer) } ) { - Div(attrs = { style { flex(75.percent) } }) { } Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) onClick { } - style { flex(25.percent) } + style { + flex(50.percent) + margin(1.5.percent) + } }) { Text("Edit Category") } Button(attrs = { classes("mdc-button", "mdc-button--raised") onClick { onOpenDeleteDialog() } - style { flex(25.percent) } + style { + flex(50.percent) + margin(1.5.percent) + backgroundColor(Color("#b00020")) + } }) { Text("Delete Category") } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 6bb759f2..bf77d757 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -1,6 +1,7 @@ package de.hsfl.budgetBinder.compose.theme import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.css.keywords.auto import org.jetbrains.compose.web.css.selectors.CSSSelector /*All Information found about Stylesheets: @@ -52,9 +53,25 @@ object AppStylesheet : StyleSheet() { flex("50%") } - //EntryList - val entryListElement by style{ + val categoryListElement by style{ + flexDirection(FlexDirection("row")) + alignItems(AlignItems.Center) + margin(10.px) + marginTop(0.px) + } + + val categoryListElementText by style{ + flex("2 2 90%") + } + + val imageFlexContainer by style { + flex("0.1 0.1 5%") + height(auto) + } + val text by style{ + textAlign("center") + padding(10.px) } val card by style { From 40ab2c82d79706f133507f24dac0a88926a166e4 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 17 Jun 2022 14:58:50 +0200 Subject: [PATCH 182/325] Change how a color of a category is displayed from rect to circle --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index d2de4d69..dee600fa 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -5,12 +5,14 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.attr import de.hsfl.budgetBinder.compose.theme.AppStylesheet.style import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Circle import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg @@ -151,7 +153,7 @@ fun CategoryList( } ) { Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in - Rect(x = 0, y = 0, width = 1, height = 1, { + Circle(cx = 0.5, cy = 0.5, r=0.5, { attr("fill", "#${category.color}") }) } From 55013fdea965b9ace4f21486d1bbb44513f93080 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 17 Jun 2022 16:04:49 +0200 Subject: [PATCH 183/325] Add edit and delete button functionality for categories summary --- .../de/hsfl/budgetBinder/compose/Composables.kt | 16 ++++++++-------- .../compose/category/CategoryComponent.kt | 2 ++ .../compose/category/CategorySummaryView.kt | 11 +++-------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index dee600fa..9d70fddd 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -1,19 +1,14 @@ package de.hsfl.budgetBinder.compose -import App import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.attr -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.style import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle -import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg @@ -114,8 +109,10 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { @Composable fun CategoryList( categoryList: List, - onOpenDeleteDialog: () -> Unit, + onEditButton: () -> Unit, + onDeleteButton: (Int) -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } Div { for (category in categoryList) Div(attrs = { @@ -166,7 +163,7 @@ fun CategoryList( ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { } + onClick { onEditButton() } style { flex(50.percent) margin(1.5.percent) @@ -176,7 +173,7 @@ fun CategoryList( } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { onOpenDeleteDialog() } + onClick { deleteDialog = true } style { flex(50.percent) margin(1.5.percent) @@ -186,6 +183,9 @@ fun CategoryList( Text("Delete Category") } } + if (deleteDialog) { + DeleteDialog(false, {onDeleteButton(category.id)}, {deleteDialog = false}) { Text("Delete Category?") } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 749b7b61..ac0586e7 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -42,6 +42,8 @@ fun CategoryComponent(screenState: MutableState) { Screen.CategorySummary -> CategorySummaryView( state = viewState, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, + onEditButton = { screenState.value = Screen.CategoryEdit}, + onDeleteButton = {id -> categoryViewModel.removeCategory(id)}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 5e05c425..2b704955 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -2,15 +2,12 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.css.flex import org.jetbrains.compose.web.css.margin import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* @@ -20,11 +17,12 @@ import org.jetbrains.compose.web.dom.* fun CategorySummaryView( state: State, onCategoryCreateButton: () -> Unit, + onEditButton: () -> Unit, + onDeleteButton: (id: Int) -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { - var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -84,7 +82,7 @@ fun CategorySummaryView( }) { Text("Create Category") } - CategoryList(categoryList, {deleteDialog = true}) + CategoryList(categoryList, onEditButton, onDeleteButton) Div { when (viewState) { is UiState.Success<*> -> { @@ -108,8 +106,5 @@ fun CategorySummaryView( } } } - if (deleteDialog) { - DeleteDialog(false, {}, {deleteDialog = false}) { Text("Delete User?") } - } } } From bc62f8de2dfa6617c1d6bfb2dc82227428a8fd53 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:14:52 +0200 Subject: [PATCH 184/325] Add function to get all entries that belong to a category_id --- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 2e78928f..49622ba2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -63,4 +63,7 @@ fun EntryList(list: List, categoryList : List){ for (entry in list){ EntryListElement(entry,categoryList) } -} \ No newline at end of file +} + +fun entriesFromCategory(list: List, category_id: Int?):List = + list.filter { it.category_id == category_id } \ No newline at end of file From 8a4688213d4aa2f3697f15397d7bcd8edd6ff301 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:22:26 +0200 Subject: [PATCH 185/325] Rework Dashboard Logic, add logic to switch to different categories --- .../compose/dashboard/DashboardView.kt | 136 ++++++++++++++++-- 1 file changed, 121 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 9d91d87e..2fc01241 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -3,14 +3,15 @@ package de.hsfl.budgetBinder.compose.dashboard import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry -import de.hsfl.budgetBinder.compose.category.Bar +import de.hsfl.budgetBinder.compose.Icon +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.category.BudgetBar import de.hsfl.budgetBinder.compose.entry.EntryList +import de.hsfl.budgetBinder.compose.entry.entriesFromCategory +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text -import kotlin.math.log +import kotlinx.serialization.json.JsonNull.content +import org.jetbrains.compose.web.dom.* @Composable @@ -25,10 +26,9 @@ fun DashboardView( val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } var categoryList by remember { mutableStateOf>(emptyList()) } - var entryList by remember { mutableStateOf>(emptyList()) } - Div { + MainFlexContainer { H1 { Text("DashboardView") } Button(attrs = { onClick { onSettingsButton() } @@ -50,9 +50,10 @@ fun DashboardView( }) { Text("Edit Entry (Needs to be there for every Entry shown)") } - } - Div { - UpdateDashboardData(categoryList, entryList) + Div { + DashboardData(categoryList, entryList) + } + CreateNewEntryButton(onEntryCreateButton) } //Process new Category Data when (categoriesViewState) { @@ -100,13 +101,118 @@ fun DashboardView( //CircularProgressIndicator() } } + + } @Composable -fun UpdateDashboardData(categoryList: List, entryList: List) { +fun DashboardData(categoryList: List, entryList: List) { console.log("Category $categoryList and Entry $entryList") - if (categoryList.isNotEmpty() && entryList.isNotEmpty()) { - Bar(categoryList[0], entryList) //Bar for first Category, needs to be changed later - EntryList(entryList, categoryList) + var focusedCategory by remember { mutableStateOf(-1) } //Variable from -1 (all) to categoryList.size + console.log("Focus:${focusedCategory}") + fun changeFocusedCategory(increase: Boolean): Int { + var newFocus = focusedCategory + if (increase) newFocus++ + else newFocus-- + newFocus = + when { + (newFocus) < -1 -> -1 + (newFocus > categoryList.size) -> categoryList.size + else -> { + newFocus + } + } + return newFocus + } + + if (entryList.isNotEmpty()) { + when (focusedCategory) { + //Overall View + -1 -> { + var everyBudgetTogether = 0f + for (category in categoryList) { + everyBudgetTogether += category.budget + } + val fakeOverallBudget = + Category(0, "Overall", "111111", Category.Image.DEFAULT, everyBudgetTogether) + SwipeContainer ( + content = {BudgetBar(fakeOverallBudget, entryList)}, //Every CategoryBudget with every Entry's Budget + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + ) + + EntryList(entryList, categoryList) //List of Every Entry + } + //Normal Category View + in categoryList.indices -> { + val filteredEntryList = + entriesFromCategory(entryList, categoryList[focusedCategory].id) + SwipeContainer ( + content = {BudgetBar(categoryList[focusedCategory], filteredEntryList)}, //Every Category with their Entries' Budget + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + ) + EntryList( + filteredEntryList, + listOf(categoryList[focusedCategory]) + ) //Only gives CategoryData of selected category, as everything else seems unnecessary + } + + //No Category View + categoryList.size -> { + val filteredEntryList = entriesFromCategory(entryList, null) + val fakeNoCategory = + Category(0, "No Category", "111111", Category.Image.DEFAULT, 0f) + SwipeContainer ( + content = {BudgetBar(fakeNoCategory, filteredEntryList)}, //"No Category" with their Entries' Budget + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + ) + EntryList( + filteredEntryList, + emptyList() + ) //Needs no categoryList, as they have no category + } + } + } else { + //TODO: Show something like: NO DATA TO SHOW! + } + +} + + +@Composable +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { + Button(attrs = { + onClick { onEntryCreateButton() } + }) { + Text("Create Entry") + } +} + +@Composable +fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Boolean) -> Unit) { + Div( + attrs = { + classes(AppStylesheet.flexContainer) + }) { + Div(attrs = { + classes(AppStylesheet.arrowFlexContainer) + onClick{onFocusCategoryChange(false)} + }){ + Icon("arrow_back_ios_new") + } + Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) + { + content() + } + Div(attrs = { + classes(AppStylesheet.arrowFlexContainer) + onClick{onFocusCategoryChange(true)} + }) { + Icon("arrow_forward_ios_new") + } } } + + + + + From 53254b6e3614a821c718bc7c2c24355684a24a69 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:23:00 +0200 Subject: [PATCH 186/325] Add general Icon function to get an function with the namestring --- .../de/hsfl/budgetBinder/compose/Composables.kt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 9d70fddd..ff59ec39 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,8 +4,6 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle @@ -25,7 +23,7 @@ fun MainFlexContainer(content: @Composable () -> Unit) { { content() } - Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) + Div(attrs = { classes(AppStylesheet.pufferFlexContainer)}) } } @@ -66,6 +64,18 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } } +@Composable +fun Icon (icon_name: String){ + Span( + attrs = { + classes("material-icons") + style { + width(24.px) + height(24.px) } + } + ) {Text(icon_name)} +} + @Composable fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } From eebdbaed7295b18e51de28737548f6f564d35478 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:23:39 +0200 Subject: [PATCH 187/325] Make slight style adjustments --- .../compose/category/CategoryComponent.kt | 11 +++++++---- .../hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 10 +++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index ac0586e7..18a0b59f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -69,15 +69,18 @@ fun categoryIdToCategory(category_id: Int?,categoryList: List): Catego @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun Bar(category: Category, entryList: List){ +fun BudgetBar(category: Category, entryList: List){ + //category = Category we want to show + //entryList = List of entries //width and height are for aspect ratio - tries to fill out wherever its in, so its more like - val width = 200 - val height = 80 + val width = 20 + val height = 2 val budget = category.budget var usedBudget = 0f for (entry in entryList) { - usedBudget+= entry.amount + usedBudget-= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget } + H1{Text("${category.name} - Budget")} Div{ if (usedBudget < budget) { //Money Text diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index bf77d757..85caf44c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -37,6 +37,7 @@ object AppStylesheet : StyleSheet() { //Container for flex elements, used in MainFlexContainer val flexContainer by style { display(DisplayStyle.Flex) + justifyContent(JustifyContent.Center) } //Container for empty sides, used in MainFlexContainer val pufferFlexContainer by style { @@ -49,9 +50,16 @@ object AppStylesheet : StyleSheet() { } //Container for main content, used in MainFlexContainer val contentFlexContainer by style { - justifyContent(JustifyContent.Center) flex("50%") } + //Container for main content in BudgetBar + val budgetBarContainer by style { + flex("90%") + } + //Container for arrow in BudgetBar + val arrowFlexContainer by style { + flex("0.1 0.1 5%") + } val categoryListElement by style{ flexDirection(FlexDirection("row")) From 667dd7a8a3de3a501d7c2254186da2ad9a46b041 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:30:38 +0200 Subject: [PATCH 188/325] Format dashboard category switch buttons --- .../de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 4 ++-- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 2fc01241..1b75ffd2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -194,7 +194,7 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool classes(AppStylesheet.flexContainer) }) { Div(attrs = { - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.arrowFlexContainer, "mdc-button") onClick{onFocusCategoryChange(false)} }){ Icon("arrow_back_ios_new") @@ -204,7 +204,7 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool content() } Div(attrs = { - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.arrowFlexContainer, "mdc-button") onClick{onFocusCategoryChange(true)} }) { Icon("arrow_forward_ios_new") diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 85caf44c..19d7a64c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -59,6 +59,7 @@ object AppStylesheet : StyleSheet() { //Container for arrow in BudgetBar val arrowFlexContainer by style { flex("0.1 0.1 5%") + height(auto) } val categoryListElement by style{ From e76b1ead1dbced2d4fd7729a9d26e4715ddf0471 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 22:21:12 +0200 Subject: [PATCH 189/325] Don't show switch button when there is no other category in that direction. Add typography to BudgetBar's texts --- .../compose/dashboard/DashboardView.kt | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 1b75ffd2..3ebca113 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -11,6 +11,10 @@ import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState import kotlinx.serialization.json.JsonNull.content +import org.jetbrains.compose.web.css.paddingLeft +import org.jetbrains.compose.web.css.paddingRight +import org.jetbrains.compose.web.css.px +import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* @@ -137,7 +141,8 @@ fun DashboardData(categoryList: List, entryList: List) { Category(0, "Overall", "111111", Category.Image.DEFAULT, everyBudgetTogether) SwipeContainer ( content = {BudgetBar(fakeOverallBudget, entryList)}, //Every CategoryBudget with every Entry's Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)}, + leftOn = false ) EntryList(entryList, categoryList) //List of Every Entry @@ -163,7 +168,8 @@ fun DashboardData(categoryList: List, entryList: List) { Category(0, "No Category", "111111", Category.Image.DEFAULT, 0f) SwipeContainer ( content = {BudgetBar(fakeNoCategory, filteredEntryList)}, //"No Category" with their Entries' Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} + onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)}, + rightOn = false ) EntryList( filteredEntryList, @@ -188,26 +194,44 @@ fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { } @Composable -fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Boolean) -> Unit) { +fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Boolean) -> Unit, leftOn: Boolean = true, rightOn:Boolean = true) { Div( attrs = { classes(AppStylesheet.flexContainer) }) { Div(attrs = { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") - onClick{onFocusCategoryChange(false)} + if(leftOn) { + classes(AppStylesheet.arrowFlexContainer, "mdc-button") + onClick { onFocusCategoryChange(false) } + } + else{ + classes(AppStylesheet.arrowFlexContainer) + style{ + paddingLeft(8.px) + paddingRight(8.px) + } + } }){ - Icon("arrow_back_ios_new") + if(leftOn) Icon("arrow_back_ios_new") } Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) { content() } Div(attrs = { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") - onClick{onFocusCategoryChange(true)} + if(rightOn) { + classes(AppStylesheet.arrowFlexContainer, "mdc-button") + onClick { onFocusCategoryChange(true) } + } + else{ + classes(AppStylesheet.arrowFlexContainer) + style{ + paddingLeft(8.px) + paddingRight(8.px) + } + } }) { - Icon("arrow_forward_ios_new") + if(rightOn) Icon("arrow_forward_ios_new") } } } From 673bd008cbd5f4a181860e4681dac178bf02b0e2 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 12:47:55 +0200 Subject: [PATCH 190/325] Add first form of style for entries on dashboard --- .../compose/dashboard/DashboardView.kt | 8 ++++---- .../budgetBinder/compose/entry/EntryComponent.kt | 12 +++++++----- .../budgetBinder/compose/theme/AppStylesheet.kt | 16 +++++++++++++++- .../budgetBinder/presentation/CategoryIcon.kt | 12 +++++++++--- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 3ebca113..f708b458 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -201,11 +201,11 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool }) { Div(attrs = { if(leftOn) { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") + classes(AppStylesheet.imageFlexContainer, "mdc-button") onClick { onFocusCategoryChange(false) } } else{ - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.imageFlexContainer) style{ paddingLeft(8.px) paddingRight(8.px) @@ -220,11 +220,11 @@ fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Bool } Div(attrs = { if(rightOn) { - classes(AppStylesheet.arrowFlexContainer, "mdc-button") + classes(AppStylesheet.imageFlexContainer, "mdc-button") onClick { onFocusCategoryChange(true) } } else{ - classes(AppStylesheet.arrowFlexContainer) + classes(AppStylesheet.imageFlexContainer) style{ paddingLeft(8.px) paddingRight(8.px) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 49622ba2..b10750ad 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.category.categoryIdToCategory +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen @@ -50,11 +51,12 @@ fun EntryComponent(screenState: MutableState) { //Should be put in own File @Composable fun EntryListElement(entry: Entry, categoryList : List){ - Div { + Div (attrs = { + classes("mdc-card","mdc-card--outlined", AppStylesheet.entryListElement) + }) { CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) - Text(entry.name) - Text(entry.amount.toString()+"€") - + Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} + Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.text) }){Text(entry.amount.toString()+"€")}} } } @@ -66,4 +68,4 @@ fun EntryList(list: List, categoryList : List){ } fun entriesFromCategory(list: List, category_id: Int?):List = - list.filter { it.category_id == category_id } \ No newline at end of file + list.filter { it.category_id == category_id } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 19d7a64c..54f6c6d6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -62,6 +62,20 @@ object AppStylesheet : StyleSheet() { height(auto) } + //EntryList + val entryListElement by style{ + flexDirection(FlexDirection("row")) + alignItems(AlignItems.Center) + margin(10.px) + marginTop(0.px) + } + val entryListElementText by style{ + flex("2 2 90%") + } + val text by style{ + textAlign("center") + padding(10.px) + } val categoryListElement by style{ flexDirection(FlexDirection("row")) alignItems(AlignItems.Center) @@ -99,4 +113,4 @@ object AppStylesheet : StyleSheet() { val marginRight by style { marginRight(1.percent) } -} \ No newline at end of file +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt index bedf3bb9..f84b6cb5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt @@ -2,14 +2,20 @@ package de.hsfl.budgetBinder.presentation import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import org.jetbrains.compose.web.css.padding +import org.jetbrains.compose.web.css.px +import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Span import org.jetbrains.compose.web.dom.Text @Composable actual fun CategoryImageToIcon(icon: Category.Image) { - Span( + Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){ + Span( attrs = { classes("material-icons") + style { padding(8.px) } } ) { Text( @@ -60,5 +66,5 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Category.Image.PEST -> "pest_control" } ) - } -} \ No newline at end of file + }} +} From 62d4871cc19934aecbeb729ac9ad39164fa2f1a1 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 14:47:17 +0200 Subject: [PATCH 191/325] Add first form of newEntry button style --- .../hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 7 +++++-- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 8 +++++++- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 6 ++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index f708b458..b9271e25 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -185,11 +185,14 @@ fun DashboardData(categoryList: List, entryList: List) { @Composable -fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { //TODO: endlich mal schön machen! Button(attrs = { + classes("mdc-fab","mdc-fab--touch") onClick { onEntryCreateButton() } }) { - Text("Create Entry") + Div(attrs= {classes("mdc-fab__ripple")} ) + Icon("add") + Div(attrs= {classes("mdc-fab__touch")} ) } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index b10750ad..9f6a0dc6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -17,6 +17,7 @@ import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Text import org.kodein.di.compose.localDI import org.kodein.di.instance +import kotlin.math.absoluteValue @Composable fun EntryComponent(screenState: MutableState) { @@ -56,9 +57,14 @@ fun EntryListElement(entry: Entry, categoryList : List){ }) { CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} - Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.text) }){Text(entry.amount.toString()+"€")}} + Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.moneyText) }){Text(amountToString(entry.amount))}} } } +fun amountToString(amount:Float):String{ + //This whole thing just so it's "- 10 €" and not "-10 €" + val x = if (amount < 0) "-" else "" + return "$x ${amount.absoluteValue} €" +} @Composable fun EntryList(list: List, categoryList : List){ diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 54f6c6d6..e4d4bdf1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -76,6 +76,12 @@ object AppStylesheet : StyleSheet() { textAlign("center") padding(10.px) } + val moneyText by style{ + textAlign("center") + padding(10.px) + whiteSpace("nowrap") + + } val categoryListElement by style{ flexDirection(FlexDirection("row")) alignItems(AlignItems.Center) From a2ec4ff0fca8f23981e441d09e3a172391565e66 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 15:25:08 +0200 Subject: [PATCH 192/325] Fix position for newEntry button --- .../compose/dashboard/DashboardView.kt | 27 ++++++++++--------- .../compose/theme/AppStylesheet.kt | 7 ++++- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index b9271e25..90c43329 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -11,10 +11,8 @@ import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState import kotlinx.serialization.json.JsonNull.content -import org.jetbrains.compose.web.css.paddingLeft -import org.jetbrains.compose.web.css.paddingRight -import org.jetbrains.compose.web.css.px -import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.css.keywords.auto import org.jetbrains.compose.web.dom.* @@ -185,14 +183,19 @@ fun DashboardData(categoryList: List, entryList: List) { @Composable -fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { //TODO: endlich mal schön machen! - Button(attrs = { - classes("mdc-fab","mdc-fab--touch") - onClick { onEntryCreateButton() } - }) { - Div(attrs= {classes("mdc-fab__ripple")} ) - Icon("add") - Div(attrs= {classes("mdc-fab__touch")} ) +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { + Div (attrs = {style { + display(DisplayStyle.Flex) + justifyContent(JustifyContent.FlexEnd) + }}) { + Button(attrs = { + classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) + onClick { onEntryCreateButton() } + }) { + Div(attrs = { classes("mdc-fab__ripple") }) + Icon("add") + Div(attrs = { classes("mdc-fab__touch") }) + } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index e4d4bdf1..84f02957 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -51,6 +51,7 @@ object AppStylesheet : StyleSheet() { //Container for main content, used in MainFlexContainer val contentFlexContainer by style { flex("50%") + position(Position.Relative) } //Container for main content in BudgetBar val budgetBarContainer by style { @@ -80,7 +81,11 @@ object AppStylesheet : StyleSheet() { textAlign("center") padding(10.px) whiteSpace("nowrap") - + } + val newEntryButton by style{ + position(Position.Fixed) + bottom(16.px) + marginRight(20.px) } val categoryListElement by style{ flexDirection(FlexDirection("row")) From 2176b85fe5e6e2f180bf7b9c01206ad4359349d9 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 15:47:58 +0200 Subject: [PATCH 193/325] Add topBar (change later!). Add newEntry-button click reference --- .../compose/dashboard/DashboardView.kt | 77 ++++++++++++------- .../compose/entry/EntryComponent.kt | 7 +- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 90c43329..19e8429f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -9,6 +9,7 @@ import de.hsfl.budgetBinder.compose.category.BudgetBar import de.hsfl.budgetBinder.compose.entry.EntryList import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.css.* @@ -23,38 +24,54 @@ fun DashboardView( onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, onEntryCreateButton: () -> Unit, - onEntryEditButton: () -> Unit + onEntryEditButton: (id:Int) -> Unit ) { val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } var categoryList by remember { mutableStateOf>(emptyList()) } var entryList by remember { mutableStateOf>(emptyList()) } + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onCategorySummaryButton() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onSettingsButton() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } + } + }) + MainFlexContainer { - H1 { Text("DashboardView") } - Button(attrs = { - onClick { onSettingsButton() } - }) { - Text("Open Settings") - } - Button(attrs = { - onClick { onCategorySummaryButton() } - }) { - Text("Open Category List (Summary of every Category)") - } - Button(attrs = { - onClick { onEntryCreateButton() } - }) { - Text("Create Entry") - } - Button(attrs = { - onClick { onEntryEditButton() } - }) { - Text("Edit Entry (Needs to be there for every Entry shown)") - } - Div { - DashboardData(categoryList, entryList) - } + Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) } //Process new Category Data @@ -108,7 +125,7 @@ fun DashboardView( } @Composable -fun DashboardData(categoryList: List, entryList: List) { +fun DashboardData(categoryList: List, entryList: List, onEntry: (id:Int) -> Unit) { console.log("Category $categoryList and Entry $entryList") var focusedCategory by remember { mutableStateOf(-1) } //Variable from -1 (all) to categoryList.size console.log("Focus:${focusedCategory}") @@ -143,7 +160,7 @@ fun DashboardData(categoryList: List, entryList: List) { leftOn = false ) - EntryList(entryList, categoryList) //List of Every Entry + EntryList(entryList, categoryList, onEntry) //List of Every Entry } //Normal Category View in categoryList.indices -> { @@ -155,7 +172,8 @@ fun DashboardData(categoryList: List, entryList: List) { ) EntryList( filteredEntryList, - listOf(categoryList[focusedCategory]) + listOf(categoryList[focusedCategory]), + onEntry ) //Only gives CategoryData of selected category, as everything else seems unnecessary } @@ -171,7 +189,8 @@ fun DashboardData(categoryList: List, entryList: List) { ) EntryList( filteredEntryList, - emptyList() + emptyList(), + onEntry ) //Needs no categoryList, as they have no category } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 9f6a0dc6..ace27eba 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -51,9 +51,10 @@ fun EntryComponent(screenState: MutableState) { //Should be put in own File @Composable -fun EntryListElement(entry: Entry, categoryList : List){ +fun EntryListElement(entry: Entry, categoryList : List, onEntry: (id:Int) -> Unit){ Div (attrs = { classes("mdc-card","mdc-card--outlined", AppStylesheet.entryListElement) + onClick { onEntry(entry.id) } }) { CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} @@ -67,9 +68,9 @@ fun amountToString(amount:Float):String{ } @Composable -fun EntryList(list: List, categoryList : List){ +fun EntryList(list: List, categoryList : List, onEntry: (id:Int) -> Unit){ for (entry in list){ - EntryListElement(entry,categoryList) + EntryListElement(entry,categoryList,onEntry) } } From fe2dab3607f4195959e924acae3bd080dee42631 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 10:49:48 +0200 Subject: [PATCH 194/325] Format files --- .../compose/entry/EntryComponent.kt | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index ace27eba..560f0308 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -43,7 +43,7 @@ fun EntryComponent(screenState: MutableState) { ) Screen.EntryEdit -> EntryEditView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard} + onBackButton = { screenState.value = Screen.Dashboard } ) else -> {} } @@ -51,28 +51,43 @@ fun EntryComponent(screenState: MutableState) { //Should be put in own File @Composable -fun EntryListElement(entry: Entry, categoryList : List, onEntry: (id:Int) -> Unit){ - Div (attrs = { - classes("mdc-card","mdc-card--outlined", AppStylesheet.entryListElement) +fun EntryListElement(entry: Entry, categoryList: List, onEntry: (id: Int) -> Unit) { + Div(attrs = { + classes("mdc-card", "mdc-card--outlined", AppStylesheet.entryListElement) onClick { onEntry(entry.id) } }) { - CategoryImageToIcon(categoryIdToCategory(entry.category_id,categoryList).image) - Div(attrs = {classes(AppStylesheet.entryListElementText)}){Div(attrs = { classes("mdc-typography--headline5", AppStylesheet.text) }) {Text(entry.name)}} - Div(attrs = {classes(AppStylesheet.imageFlexContainer)}){Div(attrs = { classes("mdc-typography--headline5",AppStylesheet.moneyText) }){Text(amountToString(entry.amount))}} + CategoryImageToIcon(categoryIdToCategory(entry.category_id, categoryList).image) + Div(attrs = { classes(AppStylesheet.entryListElementText) }) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text(entry.name) } + } + Div(attrs = { classes(AppStylesheet.imageFlexContainer) }) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.moneyText + ) + }) { Text(amountToString(entry.amount)) } + } } } -fun amountToString(amount:Float):String{ + +fun amountToString(amount: Float): String { //This whole thing just so it's "- 10 €" and not "-10 €" val x = if (amount < 0) "-" else "" return "$x ${amount.absoluteValue} €" } @Composable -fun EntryList(list: List, categoryList : List, onEntry: (id:Int) -> Unit){ - for (entry in list){ - EntryListElement(entry,categoryList,onEntry) +fun EntryList(list: List, categoryList: List, onEntry: (id: Int) -> Unit) { + for (entry in list) { + EntryListElement(entry, categoryList, onEntry) } } -fun entriesFromCategory(list: List, category_id: Int?):List = +fun entriesFromCategory(list: List, category_id: Int?): List = list.filter { it.category_id == category_id } From 562d61d9ee21a213ab106a82333da7599a161a29 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 11:54:28 +0200 Subject: [PATCH 195/325] Add first non-working version of snackbar-feedback --- .../hsfl/budgetBinder/compose/Composables.kt | 43 +++++++++++++++++-- .../compose/dashboard/DashboardView.kt | 4 +- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index ff59ec39..14291592 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -64,18 +64,55 @@ fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> } } + +///* Gives a material icon based on the icon name*/// @Composable -fun Icon (icon_name: String){ +fun Icon(icon_name: String) { Span( attrs = { classes("material-icons") style { width(24.px) - height(24.px) } + height(24.px) + } + } + ) { Text(icon_name) } +} + + +// Snackbar that shows msg +@Composable +fun FeedbackSnackbar(msg: String) { + Aside(attrs = { classes("mdc-snackbar") }) { + Div(attrs = { + classes("mdc-snackbar__surface") + attr(attr = "role", value = "status") + attr(attr = "aria-relevant", value = "additions") + }) { + Div(attrs = { + classes("mdc-snackbar__label") + attr(attr = "aria-atomic", value = "false") + }) { + Text(msg) + } + Div(attrs = { + classes("mdc-snackbar__actions") + attr(attr = "aria-atomic", value = "true") + }) { + Button(attrs = { classes("mdc-button", "mdc-snackbar__action") }) { + Div(attrs = { + classes("mdc-button__ripple") + }) + Span(attrs = { classes("mdc-button__label") }) + { Text("Dismiss") } + } + } } - ) {Text(icon_name)} + } } + + @Composable fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 19e8429f..5d07678e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -3,6 +3,7 @@ package de.hsfl.budgetBinder.compose.dashboard import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.Icon import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.category.BudgetBar @@ -73,6 +74,7 @@ fun DashboardView( MainFlexContainer { Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) + FeedbackSnackbar("haha test") } //Process new Category Data when (categoriesViewState) { @@ -111,9 +113,9 @@ fun DashboardView( } } } - } is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) //TODO: make it work Text((entriesViewState as UiState.Error).error) } is UiState.Loading -> { From db5123e328100ec46355ba9d51b343fbb1114c6f Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 11:58:32 +0200 Subject: [PATCH 196/325] Give feedback when there are no entries to load --- .../compose/dashboard/DashboardView.kt | 7 ++++++- .../budgetBinder/compose/entry/EntryComponent.kt | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 5d07678e..1b817392 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -197,7 +197,12 @@ fun DashboardData(categoryList: List, entryList: List, onEntry: } } } else { - //TODO: Show something like: NO DATA TO SHOW! + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text("No data to load") } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 560f0308..e7d00bed 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -84,8 +84,18 @@ fun amountToString(amount: Float): String { @Composable fun EntryList(list: List, categoryList: List, onEntry: (id: Int) -> Unit) { - for (entry in list) { - EntryListElement(entry, categoryList, onEntry) + if (list.isEmpty()) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text("No Entries in this category") } + } + else { + for (entry in list) { + EntryListElement(entry, categoryList, onEntry) + } } } From 307c8f1085e417d4aaa18fa4143152db8625f4bc Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 12:05:19 +0200 Subject: [PATCH 197/325] Show BudgetBar when when there are no entries or categories --- .../de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 1b817392..3fffe916 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -146,7 +146,7 @@ fun DashboardData(categoryList: List, entryList: List, onEntry: return newFocus } - if (entryList.isNotEmpty()) { + //if (entryList.isNotEmpty()) { when (focusedCategory) { //Overall View -1 -> { @@ -196,14 +196,14 @@ fun DashboardData(categoryList: List, entryList: List, onEntry: ) //Needs no categoryList, as they have no category } } - } else { + /*} else { Div(attrs = { classes( "mdc-typography--headline5", AppStylesheet.text ) }) { Text("No data to load") } - } + }*/ } From 11e792d000e6f3a216241fcb69de8e71d1f2487a Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 15:02:43 +0200 Subject: [PATCH 198/325] Snackbar disappears when clicked on (this is a form of logic in view, may change later) --- .../hsfl/budgetBinder/compose/Composables.kt | 23 ++++++++++++++++--- .../compose/dashboard/DashboardView.kt | 3 +-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 14291592..8675ef06 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -82,12 +82,26 @@ fun Icon(icon_name: String) { // Snackbar that shows msg @Composable -fun FeedbackSnackbar(msg: String) { - Aside(attrs = { classes("mdc-snackbar") }) { +fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { + var hiddenValue by remember { mutableStateOf(hidden)} + Aside( + attrs = { + when(hiddenValue){ + false -> classes("mdc-snackbar","mdc-snackbar--open") + true -> classes("mdc-snackbar","maria") + } + onClick { + hiddenValue = true + console.log(this@Aside) + console.log("ldsadsad") + + } + }) { Div(attrs = { classes("mdc-snackbar__surface") attr(attr = "role", value = "status") attr(attr = "aria-relevant", value = "additions") + }) { Div(attrs = { classes("mdc-snackbar__label") @@ -99,7 +113,9 @@ fun FeedbackSnackbar(msg: String) { classes("mdc-snackbar__actions") attr(attr = "aria-atomic", value = "true") }) { - Button(attrs = { classes("mdc-button", "mdc-snackbar__action") }) { + Button(attrs = { + classes("mdc-button", "mdc-snackbar__action") + }) { Div(attrs = { classes("mdc-button__ripple") }) @@ -113,6 +129,7 @@ fun FeedbackSnackbar(msg: String) { + @Composable fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 3fffe916..7f30e6bc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -31,13 +31,12 @@ fun DashboardView( val entriesViewState by remember { entriesState } var categoryList by remember { mutableStateOf>(emptyList()) } var entryList by remember { mutableStateOf>(emptyList()) } - topBarMain( logoButton = { Img( src = "images/Logo.png", alt = "Logo", attrs = { classes("mdc-icon-button", AppStylesheet.image) - onClick { } + onClick { } } ) }, navButtons = { From 4e772f637360d578486d8967f4247a324dc00bbe Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 15:14:23 +0200 Subject: [PATCH 199/325] Use snackbar when there is an error UiState feedback --- .../compose/dashboard/DashboardView.kt | 77 +++++++++---------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 7f30e6bc..b7375d37 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -73,56 +73,55 @@ fun DashboardView( MainFlexContainer { Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) - FeedbackSnackbar("haha test") - } - //Process new Category Data - when (categoriesViewState) { - is UiState.Success<*> -> { - //Updates Data - // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot - when (val element = (categoriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - categoryList = it + //Process new Category Data + when (categoriesViewState) { + is UiState.Success<*> -> { + //Updates Data + // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot + when (val element = (categoriesViewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + categoryList = it + } } - } + } } } + is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } } - is UiState.Error -> { - Text((categoriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } - //Process new Entry Data - when (entriesViewState) { - is UiState.Success<*> -> { - //Updates Data - when (val element = (entriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - entryList = it + //Process new Entry Data + when (entriesViewState) { + is UiState.Success<*> -> { + //Updates Data + when (val element = (entriesViewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + entryList = it + } } - } + } } } - } - is UiState.Error -> { - FeedbackSnackbar((entriesViewState as UiState.Error).error) //TODO: make it work - Text((entriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() + is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } } } + } @Composable From 85a15678d4da59cf33f63b7c3e5124a581e05852 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 16 Jun 2022 15:46:10 +0200 Subject: [PATCH 200/325] Show Category-Icon with category title and center title --- .../de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index b7375d37..26d81ed1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -71,6 +71,7 @@ fun DashboardView( }) MainFlexContainer { + Div { DashboardData(categoryList, entryList, onEntryEditButton) } CreateNewEntryButton(onEntryCreateButton) //Process new Category Data From 994822c8715f1a84398e604c16571c26eb4d311f Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sat, 18 Jun 2022 18:51:48 +0200 Subject: [PATCH 201/325] Add entryCreate functionality and style, plus change that EntryCreateView gets the categoryList from DashboardView --- .../hsfl/budgetBinder/presentation/Screen.kt | 4 +- .../hsfl/budgetBinder/compose/Composables.kt | 92 ++++- .../de/hsfl/budgetBinder/compose/Router.kt | 16 +- .../compose/category/CategoryCreateView.kt | 276 ++++++++------- .../compose/category/CategorySummaryView.kt | 59 ++-- .../compose/dashboard/DashboardComponent.kt | 2 +- .../compose/dashboard/DashboardView.kt | 4 +- .../compose/entry/EntryComponent.kt | 14 +- .../compose/entry/EntryCreateView.kt | 276 +++++++++++++-- .../budgetBinder/compose/login/LoginView.kt | 180 +++++----- .../compose/register/RegisterView.kt | 321 +++++++++--------- .../settings/SettingsChangeUserDataView.kt | 229 ++++++------- .../compose/settings/SettingsView.kt | 85 +++-- 13 files changed, 909 insertions(+), 649 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index c4a63e2b..33852673 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -1,6 +1,8 @@ package de.hsfl.budgetBinder.presentation +import de.hsfl.budgetBinder.common.Category + sealed class Screen { sealed class Welcome: Screen() { object Screen1: Welcome() @@ -22,7 +24,7 @@ sealed class Screen { sealed class Entry: Screen() { data class Overview(val id: Int): Entry() object Edit: Entry() - object Create: Entry() + data class Create (val categoryList :List): Entry() } object Login : Screen() object Register : Screen() diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 8675ef06..2f0b8729 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,6 +4,11 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.image +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.attributes.ButtonType +import org.jetbrains.compose.web.attributes.type import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle @@ -21,7 +26,12 @@ fun MainFlexContainer(content: @Composable () -> Unit) { Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) Div(attrs = { classes(AppStylesheet.contentFlexContainer) }) { - content() + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + content() + } } Div(attrs = { classes(AppStylesheet.pufferFlexContainer)}) } @@ -83,20 +93,20 @@ fun Icon(icon_name: String) { // Snackbar that shows msg @Composable fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { - var hiddenValue by remember { mutableStateOf(hidden)} + var hiddenValue by remember { mutableStateOf(hidden) } Aside( attrs = { - when(hiddenValue){ - false -> classes("mdc-snackbar","mdc-snackbar--open") - true -> classes("mdc-snackbar","maria") + when (hiddenValue) { + false -> classes("mdc-snackbar", "mdc-snackbar--open") + true -> classes("mdc-snackbar", "maria") } - onClick { - hiddenValue = true - console.log(this@Aside) - console.log("ldsadsad") + onClick { + hiddenValue = true + console.log(this@Aside) + console.log("ldsadsad") - } - }) { + } + }) { Div(attrs = { classes("mdc-snackbar__surface") attr(attr = "role", value = "status") @@ -128,8 +138,6 @@ fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { } - - @Composable fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } @@ -210,11 +218,11 @@ fun CategoryList( } } Div(attrs = { - classes(AppStylesheet.imageFlexContainer) - } + classes(AppStylesheet.imageFlexContainer) + } ) { Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in - Circle(cx = 0.5, cy = 0.5, r=0.5, { + Circle(cx = 0.5, cy = 0.5, r = 0.5, { attr("fill", "#${category.color}") }) } @@ -248,7 +256,10 @@ fun CategoryList( } } if (deleteDialog) { - DeleteDialog(false, {onDeleteButton(category.id)}, {deleteDialog = false}) { Text("Delete Category?") } + DeleteDialog( + false, + { onDeleteButton(category.id) }, + { deleteDialog = false }) { Text("Delete Category?") } } } } @@ -355,3 +366,50 @@ fun DeleteDialog(hidden: Boolean, buttonAction: () -> Unit, resetDialog: () -> U } } } + +@Composable +fun ChooseCategoryMenu( + categoryList: List, + getCategoryId: (Int) -> Unit +) { + var chosenCategory by remember { mutableStateOf(categoryList[0]) } + var showList by remember { mutableStateOf(false) } + + Button(attrs = { + classes("mdc-button", "mdc-dialog__button") + onClick { showList = !showList } + type(ButtonType.Button) + }) { + Div(attrs = { + when (showList) { + true -> classes("mdc-menu", "mdc-menu-surface", "mdc-menu-surface--open") + false -> classes("mdc-menu", "mdc-menu-surface") + } + }) { + Ul(attrs = { + classes("mdc-list") + attr("role", "menu") + attr("aria-hidden", "true") + attr("aria-orientation", "vertical") + attr("tabindex", "-1") + }) { + for (category in categoryList) { + Li(attrs = { + classes("mdc-list-item") + attr("role", "menuitem") + onClick { } + }) { + Span(attrs = { classes("mdc-list-item__ripple") }) { } + Span(attrs = { onClick { chosenCategory = category; getCategoryId(category.id) } }) { + Text( + category.name + ) + } + } + } + } + } + Text(chosenCategory.name) + } +} + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 3f09cfb0..c24ec50d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -13,12 +13,12 @@ import de.hsfl.budgetBinder.presentation.Screen @Composable fun Router(screenState: MutableState) { when (screenState.value) { - Screen._Welcome -> {} - Screen.Register -> RegisterComponent(screenState = screenState) - Screen.Login -> LoginComponent(screenState = screenState) - Screen.Dashboard -> DashboardComponent(screenState = screenState) - Screen._Settings, Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - Screen.CategorySummary,Screen.CategoryEdit,Screen.CategoryCreate, Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) - Screen.EntryCreate, Screen.EntryEdit -> EntryComponent(screenState = screenState) + is Screen.Welcome -> {} + is Screen.Register -> RegisterComponent(screenState = screenState) + is Screen.Login -> LoginComponent(screenState = screenState) + is Screen.Dashboard -> DashboardComponent(screenState = screenState) + is Screen.Settings, Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) + is Screen.CategorySummary,Screen.CategoryEdit,Screen.CategoryCreate, Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) + is Screen.EntryCreate, Screen.EntryEdit -> EntryComponent(screenState = screenState) } -} \ No newline at end of file +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index 22d8391a..2fefac50 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -10,10 +10,7 @@ import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.min import org.jetbrains.compose.web.attributes.required -import org.jetbrains.compose.web.css.marginBottom -import org.jetbrains.compose.web.css.marginLeft -import org.jetbrains.compose.web.css.percent -import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* @@ -28,7 +25,7 @@ fun CategoryCreateView( var categoryNameTextFieldState by remember { mutableStateOf("") } var categoryColorTextFieldState by remember { mutableStateOf("") } var categoryImageState by remember { mutableStateOf(Category.Image.DEFAULT) } - var categoryBudgetTextFieldState by remember { mutableStateOf("") } + var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } topBarMain( @@ -71,180 +68,179 @@ fun CategoryCreateView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Create a new Category") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onCreateCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() + } } ) { - H1 { Text("Create a new Category") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") - onCreateCategoryButtonPressed( - categoryNameTextFieldState, - categoryColorTextFieldState, - categoryImageState, - categoryBudgetTextFieldState.toFloat() - ) - it.preventDefault() + Div( + attrs = { + classes(AppStylesheet.margin) } - } ) { - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Category Name") } + Input( + type = InputType.Text ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Category Name") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(categoryNameTextFieldState) - required(true) - onInput { - categoryNameTextFieldState = it.value - } + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + required(true) + onInput { + categoryNameTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) } - Div( + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } ) { - Label( + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } } + ) { Text("Color") } + Input( + type = InputType.Color ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } - } - ) { Text("Color") } - Input( - type = InputType.Color - ) { - classes("mdc-text-field__input") - value(categoryColorTextFieldState) - onInput { - categoryColorTextFieldState = it.value - } + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + style { width(100.percent) } } ) { - Label( + Span( attrs = { - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent) } } - ) { - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent); marginLeft(2.percent)} - } - ) { Text("Image") } - CategoryImagesToImageList(onClick = {categoryImageState = it}) - } + ) { Text("Image") } + CategoryImagesToImageList(onClick = { categoryImageState = it }) + } + } + Div( + attrs = { + classes(AppStylesheet.margin) } - Div( + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Budget") } - Input( - type = InputType.Number - ) { - classes("mdc-text-field__input") - value(categoryBudgetTextFieldState) - required(true) - min("1") - onInput { - categoryBudgetTextFieldState = it.value.toString() - } + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + required(true) + min("1") + onInput { + categoryBudgetTextFieldState = it.value.toString() } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( attrs = { - classes(AppStylesheet.margin) + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + //Text((viewState as UiState.Success<*>).element.toString()) } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - Div { - when (viewState) { - is UiState.Success<*> -> { - //Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 2b704955..8bd83a2a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -66,43 +66,38 @@ fun CategorySummaryView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Category Summary") } - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onCategoryCreateButton() } + H1( + attrs = { style { margin(2.percent) } - }) { - Text("Create Category") } - CategoryList(categoryList, onEditButton, onDeleteButton) - Div { - when (viewState) { - is UiState.Success<*> -> { - when (val element = (viewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - categoryList = it - } + ) { Text(" Category Summary") } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { onCategoryCreateButton() } + style { margin(2.percent) } + }) { + Text("Create Category") + } + CategoryList(categoryList, onEditButton, onDeleteButton) + Div { + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + categoryList = it } - } + } } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index c7237976..2a691030 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -26,7 +26,7 @@ fun DashboardComponent(screenState: MutableState) { entriesState = entriesViewState, onCategorySummaryButton = { screenState.value = Screen.CategorySummary}, onSettingsButton = {screenState.value = Screen._Settings}, - onEntryCreateButton = {screenState.value = Screen.EntryCreate}, + onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, onEntryEditButton = {screenState.value = Screen.EntryEdit} ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 26d81ed1..c1b1e254 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -24,7 +24,7 @@ fun DashboardView( entriesState: State, onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, - onEntryCreateButton: () -> Unit, + onEntryCreateButton: (categoryList: List) -> Unit, onEntryEditButton: (id:Int) -> Unit ) { val categoriesViewState by remember { categoriesState } @@ -73,7 +73,7 @@ fun DashboardView( MainFlexContainer { Div { DashboardData(categoryList, entryList, onEntryEditButton) } - CreateNewEntryButton(onEntryCreateButton) + CreateNewEntryButton({ onEntryCreateButton(categoryList) }) //Process new Category Data when (categoriesViewState) { is UiState.Success<*> -> { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index e7d00bed..3686ee5f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -36,12 +36,18 @@ fun EntryComponent(screenState: MutableState) { val viewState = viewModel.state.collectAsState(scope.coroutineContext) when (screenState.value) { - Screen.EntryCreate -> EntryCreateView( + is Screen.EntryCreate -> {EntryCreateView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard }, - onCategoryCreateButton = { screenState.value = Screen.CategoryCreate } + categoryList = (screenState.value as Screen.EntryCreate).categoryList, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onCreateEntryButtonPressed = { name, amount, repeat, category_id -> + userViewModel.createEntry(Entry.In(name, amount, repeat, category_id)) }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - Screen.EntryEdit -> EntryEditView( + + } + is Screen.EntryEdit -> EntryEditView( state = viewState, onBackButton = { screenState.value = Screen.Dashboard } ) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 40b47c7c..1495873d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -1,42 +1,270 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.* +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.theme.AppStylesheet.id +import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.attributes.* +import org.jetbrains.compose.web.attributes.AutoComplete.Companion.off +import org.jetbrains.compose.web.attributes.AutoComplete.Companion.on +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Path +import org.jetbrains.compose.web.svg.Svg +@OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryCreateView( state: State, - onBackButton: () -> Unit, - onCategoryCreateButton: () -> Unit + categoryList: List, + onChangeToDashboard: () -> Unit, + onChangeToSettings: () -> Unit, + onChangeToCategory: () -> Unit, + onCreateEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category_id: Int) -> Unit, ) { + var switchState by remember { mutableStateOf(false) } + var entryNameTextFieldState by remember { mutableStateOf("") } + var entryAmountTextFieldState by remember { mutableStateOf("") } + var entryRepeatState by remember { mutableStateOf("") } + var entryCategoryIDTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("EntryCreate")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + }) + + MainFlexContainer { + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Create new Entry") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$entryNameTextFieldState, $entryAmountTextFieldState, $entryRepeatState, $entryCategoryIDTextFieldState") + onCreateEntryButtonPressed( + entryNameTextFieldState, + (if (!switchState) "-$entryAmountTextFieldState" else entryAmountTextFieldState).toFloat(), + entryRepeatState.toBoolean(), + entryCategoryIDTextFieldState.toInt() + ) + it.preventDefault() } } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Dashboard") - } - Button(attrs = { - onClick { onCategoryCreateButton() } - }) { - Text("Create new Category (Needs to be put as the last option when selecting a category for an entry)") + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Entry Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(entryNameTextFieldState) + required(true) + onInput { + entryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Amount") } + Div { + Button( + attrs = { + if (!switchState) classes("mdc-switch", "mdc-switch--unselected") + else classes("mdc-switch", "mdc-switch--selected") + id("basic-switch") + attr("role", "switch") + attr("aria-checked", "false") + type(ButtonType.Button) + onClick { switchState = !switchState } + } + ) { + Div(attrs = { classes("mdc-switch__track") }) { } + Div(attrs = { classes("mdc-switch__handle-track") }) { + Div(attrs = { classes("mdc-switch__handle") }) { + Div(attrs = { classes("mdc-switch__shadow") }) { + Div(attrs = { classes("mdc-elevation-overlay") }) { } + } + Div(attrs = { classes("mdc-switch__ripple") }) { } + Div(attrs = { classes("mdc-switch__icons") }) { + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") + } + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M20 13H4v-2h16v2z") + } + } + } + } + } + } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { + Text(if (switchState) "+" else "-") + } + Input( + type = InputType.Number + ) { + attr("step", "0.01") + classes("mdc-text-field__input") + onInput { + entryAmountTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) + } + ) { + Div(attrs = {style { flex(50.percent) }}) { + Div(attrs = { classes("mdc-form-field") }) { + Div(attrs = { classes("mdc-checkbox") }) { + Input(type = InputType.Checkbox) + { + classes("mdc-checkbox__native-control") + id("checkbox-1") + onInput { + entryRepeatState = it.value.toString() + } + } + Div(attrs = { classes("mdc-checkbox__background") }) { + Svg(attrs = { classes("mdc-checkbox__checkmark") }, viewBox = "0 0 24 24") { + Path("M1.73,12.91 8.1,19.28 22.79,4.59", attrs = { classes("mdc-checkbox__checkmark") }) + } + Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } + } + Div(attrs = { classes("mdc-checkbox__ripple") }) { } + } + Label(forId = "checkbox-1") { Text("repeat") } + } + } + Div(attrs = {style { flex(50.percent) }}) { + ChooseCategoryMenu(categoryList) { id -> entryCategoryIDTextFieldState = id.toString() } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt index 82e7ed1c..55e44092 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt @@ -69,119 +69,113 @@ fun LoginView( } } - MainFlexContainer{ + MainFlexContainer { // -- Login Form -- + H1 { Text(" Login") } + Form( + attrs = { + this.addEventListener("submit") { + console.log("${emailTextFieldState}, ${passwordTextFieldState}") + onLoginButtonPressed(emailTextFieldState, passwordTextFieldState) + it.preventDefault() + } + } + ) { Div( attrs = { - classes("mdc-card", AppStylesheet.card) + classes(AppStylesheet.margin) } ) { - H1 { Text(" Login") } - Form( + Label( attrs = { - this.addEventListener("submit") { - console.log("${emailTextFieldState}, ${passwordTextFieldState}") - onLoginButtonPressed(emailTextFieldState, passwordTextFieldState) - it.preventDefault() - } + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Div( + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field__ripple") } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Email") } - EmailInput(value = emailTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - emailTextFieldState = it.value - - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( + ) { } + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-floating-label", "mdc-floating-label--float-above") } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + ) { Text("Email") } + EmailInput(value = emailTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + emailTextFieldState = it.value + } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( + }) + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-line-ripple") } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - // -- Login Request Management -- - when (viewState) { - is UiState.Success<*> -> { - onLoginSuccess() + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { Text("Password") } + PasswordInput(value = passwordTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + passwordTextFieldState = it.value + } + }) + Span( + attrs = { + classes("mdc-line-ripple") } - else -> {} - } + ) { } } } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + // -- Login Request Management -- + when (viewState) { + is UiState.Success<*> -> { + onLoginSuccess() + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + else -> {} + } } + } } \ No newline at end of file diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt index 9cb0697a..4e7924bf 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt @@ -74,198 +74,191 @@ fun RegisterView( } } - MainFlexContainer{ + MainFlexContainer { // -- Register Form -- - Div( - attrs = { - classes("mdc-card", AppStylesheet.card) + H1 { Text(" Register") } + Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit + this.addEventListener("submit") { + console.log("$firstNameTextFieldState, $lastNameTextFieldState, $emailTextFieldState, $passwordTextFieldState") + onRegisterButtonPressed( + firstNameTextFieldState, + lastNameTextFieldState, + emailTextFieldState, + passwordTextFieldState + ) + it.preventDefault() } + } ) { - - H1 { Text(" Register") } - Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit - this.addEventListener("submit") { - console.log("$firstNameTextFieldState, $lastNameTextFieldState, $emailTextFieldState, $passwordTextFieldState") - onRegisterButtonPressed( - firstNameTextFieldState, - lastNameTextFieldState, - emailTextFieldState, - passwordTextFieldState - ) - it.preventDefault() - } + Div( + attrs = { + classes(AppStylesheet.margin) } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } ) { - Div( + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field__ripple") } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Firstname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(firstNameTextFieldState) - onInput { - firstNameTextFieldState = it.value - } - } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( + ) { } + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Firstname") } + Input( + type = InputType.Text ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Lastname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(lastNameTextFieldState) - onInput { - lastNameTextFieldState = it.value - } - } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } + classes("mdc-text-field__input") + value(firstNameTextFieldState) + onInput { + firstNameTextFieldState = it.value } } - Div( + Span( attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Email") } - EmailInput(value = emailTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - emailTextFieldState = it.value - - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } + classes("mdc-line-ripple") } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - Div( + ) { + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Lastname") } + Input( + type = InputType.Text ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } + classes("mdc-text-field__input") + value(lastNameTextFieldState) + onInput { + lastNameTextFieldState = it.value } } - Div( + Span( attrs = { - classes(AppStylesheet.margin) + classes("mdc-line-ripple") } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - // -- Register Request Management -- - when (viewState) { - is UiState.Success<*> -> { - onChangeToLogin() + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { Text("Email") } + EmailInput(value = emailTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + emailTextFieldState = it.value + + } + }) + Span( + attrs = { + classes("mdc-line-ripple") } - else -> {} + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Password") } + PasswordInput(value = passwordTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + passwordTextFieldState = it.value + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + // -- Register Request Management -- + when (viewState) { + is UiState.Success<*> -> { + onChangeToLogin() + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + else -> {} + } } } } \ No newline at end of file diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt index 30b8488d..e9dcf578 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt @@ -64,155 +64,148 @@ fun SettingsChangeUserDataView( }) MainFlexContainer { - Div( - attrs = { - classes("mdc-card", AppStylesheet.card) + H1 { Text("Change User Data") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$firstNameTextFieldState, $lastNameTextFieldState, $passwordTextFieldState") + onChangeDataButtonPressed( + firstNameTextFieldState, + lastNameTextFieldState, + passwordTextFieldState + ) + it.preventDefault() } + } ) { - - H1 { Text("Change User Data") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$firstNameTextFieldState, $lastNameTextFieldState, $passwordTextFieldState") - onChangeDataButtonPressed( - firstNameTextFieldState, - lastNameTextFieldState, - passwordTextFieldState - ) - it.preventDefault() + Div( + attrs = { + classes(AppStylesheet.margin) } - } ) { - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Firstname") } + Input( + type = InputType.Text ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Firstname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(firstNameTextFieldState) - onInput { - firstNameTextFieldState = it.value - } + classes("mdc-text-field__input") + value(firstNameTextFieldState) + onInput { + firstNameTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Lastname") } + Input( + type = InputType.Text ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Lastname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(lastNameTextFieldState) - onInput { - lastNameTextFieldState = it.value - } + classes("mdc-text-field__input") + value(lastNameTextFieldState) + onInput { + lastNameTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Password") } + PasswordInput(value = passwordTextFieldState, + attrs = { + classes("mdc-text-field__input") + onInput { + passwordTextFieldState = it.value } - ) { } - } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) } - Div( + ) { + SubmitInput( attrs = { - classes(AppStylesheet.margin) - } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) } - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt index 8a9b0225..94e3eab8 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt @@ -64,61 +64,56 @@ fun SettingsView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) + H1( + attrs = { + style { marginLeft(2.percent) } + } + ) { Text("Settings") } + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } } - ) { - H1( - attrs = { - style { marginLeft(2.percent) } - } - ) { Text("Settings") } - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) } - Div( + ) { + Button( attrs = { - classes(AppStylesheet.margin, AppStylesheet.flexContainer) + classes("mdc-button", "mdc-button--raised") + onClick { onChangeButtonPressed() } + style { flex(100.percent) } } ) { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onChangeButtonPressed() } - style { flex(100.percent) } - } - ) { - Text("Change Userdata") - } + Text("Change Userdata") + } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) } - Div( + ) { + Button( attrs = { - classes(AppStylesheet.margin, AppStylesheet.flexContainer) - } - ) { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { - deleteDialog = true - } - style { flex(100.percent) } + classes("mdc-button", "mdc-button--raised") + onClick { + deleteDialog = true } - ) { - Text("Delete User") + style { flex(100.percent) } } + ) { + Text("Delete User") } } - if (deleteDialog) { - DeleteDialog(false, {onDeleteButtonPressed()}, {deleteDialog = false}) { Text("Delete User?") } - } + } + if (deleteDialog) { + DeleteDialog(false, { onDeleteButtonPressed() }, { deleteDialog = false }) { Text("Delete User?") } } } From 34e0e66750a58d4da76af56cfda9ef689b371a2e Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sat, 18 Jun 2022 18:52:51 +0200 Subject: [PATCH 202/325] Delete unused Imports --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt | 1 - .../de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt | 4 ---- 2 files changed, 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 2f0b8729..62cb248b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -4,7 +4,6 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.image import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 1495873d..691b2bb5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -4,13 +4,9 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.* import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.theme.AppStylesheet.id -import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.* -import org.jetbrains.compose.web.attributes.AutoComplete.Companion.off -import org.jetbrains.compose.web.attributes.AutoComplete.Companion.on import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Path From c64082b4666bb991e96b328bcece5a20926028f0 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 12:03:09 +0200 Subject: [PATCH 203/325] Fix wrong images used. Fix padding of images. Set image container to justify-content center --- .../hsfl/budgetBinder/compose/Composables.kt | 2 +- .../compose/category/CategoryCreateView.kt | 274 +++++++++--------- .../compose/theme/AppStylesheet.kt | 19 +- .../budgetBinder/presentation/CategoryIcon.kt | 14 +- 4 files changed, 164 insertions(+), 145 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 62cb248b..ea360d49 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -147,7 +147,7 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { ) { Ul( attrs = { - classes("mdc-image-list", "my-image-list") + classes("mdc-image-list", AppStylesheet.categoryImageList) } ) { for (image in Category.Image.values()) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index 2fefac50..edf490e5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -68,179 +68,185 @@ fun CategoryCreateView( }) MainFlexContainer { - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text("Create a new Category") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") - onCreateCategoryButtonPressed( - categoryNameTextFieldState, - categoryColorTextFieldState, - categoryImageState, - categoryBudgetTextFieldState.toFloat() - ) - it.preventDefault() - } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) } ) { - Div( - attrs = { - classes(AppStylesheet.margin) + H1 { Text("Create a new Category") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onCreateCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() } + } ) { - Label( + //Category Name Input + Div( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes(AppStylesheet.margin) } ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( + Label( attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - ) { Text("Category Name") } - Input( - type = InputType.Text ) { - classes("mdc-text-field__input") - value(categoryNameTextFieldState) - required(true) - onInput { - categoryNameTextFieldState = it.value + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Category Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + required(true) + onInput { + categoryNameTextFieldState = it.value + } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) } - ) { - Label( + //Category Color Input + Div( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes(AppStylesheet.margin) } ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( + Label( attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } - ) { Text("Color") } - Input( - type = InputType.Color ) { - classes("mdc-text-field__input") - value(categoryColorTextFieldState) - onInput { - categoryColorTextFieldState = it.value + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Color") } + Input( + type = InputType.Color + ) { + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value + } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( + //Category Image Input + Div( attrs = { - style { width(100.percent) } + classes(AppStylesheet.margin) } ) { - Span( + Label( attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent); marginLeft(2.percent) } + style { width(100.percent) } } - ) { Text("Image") } - CategoryImagesToImageList(onClick = { categoryImageState = it }) - } - } - Div( - attrs = { - classes(AppStylesheet.margin) + ) { + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent)} + } + ) { Text("Image") } + CategoryImagesToImageList(onClick = {categoryImageState = it}) + } } - ) { - Label( + //Category Budget Input + Div( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes(AppStylesheet.margin) } ) { - Span( + Label( attrs = { - classes("mdc-text-field__ripple") + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Budget") } - Input( - type = InputType.Number ) { - classes("mdc-text-field__input") - value(categoryBudgetTextFieldState) - required(true) - min("1") - onInput { - categoryBudgetTextFieldState = it.value.toString() + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number + ) { + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + required(true) + min("1") + onInput { + categoryBudgetTextFieldState = it.value.toString() + } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - SubmitInput( + //Submit button + Div( attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - Div { - when (viewState) { - is UiState.Success<*> -> { - //Text((viewState as UiState.Success<*>).element.toString()) + classes(AppStylesheet.margin) } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + //Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 84f02957..5bcbcafe 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -63,6 +63,21 @@ object AppStylesheet : StyleSheet() { height(auto) } + val categoryListElement by style{ + flexDirection(FlexDirection("row")) + alignItems(AlignItems.Center) + margin(10.px) + marginTop(0.px) + } + + val categoryListElementText by style{ + flex("2 2 90%") + } + + val categoryImageList by style{ + justifyContent(JustifyContent.Center) + } + //EntryList val entryListElement by style{ flexDirection(FlexDirection("row")) @@ -73,10 +88,6 @@ object AppStylesheet : StyleSheet() { val entryListElementText by style{ flex("2 2 90%") } - val text by style{ - textAlign("center") - padding(10.px) - } val moneyText by style{ textAlign("center") padding(10.px) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt index f84b6cb5..cffd4de2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/presentation/CategoryIcon.kt @@ -3,8 +3,7 @@ package de.hsfl.budgetBinder.presentation import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import org.jetbrains.compose.web.css.padding -import org.jetbrains.compose.web.css.px +import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Span import org.jetbrains.compose.web.dom.Text @@ -15,7 +14,10 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Span( attrs = { classes("material-icons") - style { padding(8.px) } + style { + paddingTop(8.px) + paddingBottom(8.px) + } } ) { Text( @@ -27,7 +29,7 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Category.Image.WRONG -> "dangerous" Category.Image.HOME -> "home" Category.Image.FOOD -> "bakery_dining" - Category.Image.FASTFOOD -> "bakery_dining" + Category.Image.FASTFOOD -> "fastfood" Category.Image.RESTAURANT -> "restaurant" Category.Image.FAMILY -> "people" Category.Image.MONEY -> "payments" @@ -41,10 +43,10 @@ actual fun CategoryImageToIcon(icon: Category.Image) { Category.Image.FLOWER -> "local_florist" Category.Image.PET -> "pets" Category.Image.BILLS -> "receipt" - Category.Image.KEYBOARD -> "redeem" + Category.Image.KEYBOARD -> "keyboard" Category.Image.PRINTER -> "print" Category.Image.WATER -> "water_drop" - Category.Image.FIRE -> "fire" + Category.Image.FIRE -> "local_fire_department" Category.Image.STAR -> "grade" Category.Image.SAVINGS -> "savings" Category.Image.CAR -> "minor_crash" From b98e193ca9f57bb5a4a41ecef28fdaed1674065f Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:11:52 +0200 Subject: [PATCH 204/325] Add EntryOverview Screen and open EntryOverview with corresponding ID when clicking on an entry in dashboard --- .../budgetBinder/compose/dashboard/DashboardComponent.kt | 1 + .../de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 2a691030..d0992b48 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -28,5 +28,6 @@ fun DashboardComponent(screenState: MutableState) { onSettingsButton = {screenState.value = Screen._Settings}, onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, onEntryEditButton = {screenState.value = Screen.EntryEdit} + onEntryOverviewButton = {id -> screenState.value = Screen.EntryOverview(id)} ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index c1b1e254..2cabe030 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -12,9 +12,7 @@ import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import kotlinx.serialization.json.JsonNull.content import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.css.keywords.auto import org.jetbrains.compose.web.dom.* @@ -25,7 +23,7 @@ fun DashboardView( onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, onEntryCreateButton: (categoryList: List) -> Unit, - onEntryEditButton: (id:Int) -> Unit + onEntryOverviewButton: (id:Int) -> Unit ) { val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } @@ -72,7 +70,7 @@ fun DashboardView( MainFlexContainer { - Div { DashboardData(categoryList, entryList, onEntryEditButton) } + Div { DashboardData(categoryList, entryList, onEntryOverviewButton) } CreateNewEntryButton({ onEntryCreateButton(categoryList) }) //Process new Category Data when (categoriesViewState) { From ffec0c2547b95033a4fd0c8a560b4f9c66ef40c3 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:21:09 +0200 Subject: [PATCH 205/325] Fix Router routing per type and not per instance --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index c24ec50d..067df92a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -17,8 +17,10 @@ fun Router(screenState: MutableState) { is Screen.Register -> RegisterComponent(screenState = screenState) is Screen.Login -> LoginComponent(screenState = screenState) is Screen.Dashboard -> DashboardComponent(screenState = screenState) - is Screen.Settings, Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - is Screen.CategorySummary,Screen.CategoryEdit,Screen.CategoryCreate, Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) - is Screen.EntryCreate, Screen.EntryEdit -> EntryComponent(screenState = screenState) + is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) + is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, Screen.CategoryCreateOnRegister + -> CategoryComponent(screenState = screenState) + is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) + else -> {} } } From 806950f084ccc637587977b2e27dfe740776ac89 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:43:59 +0200 Subject: [PATCH 206/325] Add EntryOverviewView and connect it in EntryComponent --- .../compose/entry/EntryOverviewView.kt | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt new file mode 100644 index 00000000..28ee388a --- /dev/null +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -0,0 +1,168 @@ +package de.hsfl.budgetBinder.compose.entry + +import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.CategoryList +import de.hsfl.budgetBinder.compose.DeleteDialog +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import de.hsfl.budgetBinder.presentation.UiState +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Circle +import org.jetbrains.compose.web.svg.Svg + + +@Composable +fun EntryOverviewView( + state: State, + onEditButton: () -> Unit, + onDeleteButton: (id: Int) -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToCategory: () -> Unit, + onChangeToSettings: () -> Unit +) { + var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } + val viewState by remember { state } + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } + } + }) + + MainFlexContainer { + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Entry") } + + EntryOverview(entry,onEditButton,onDeleteButton) + } + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is Entry -> entry = element + else -> {} + } + + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } +} + +@Composable +fun EntryOverview( + entry: Entry, + onEditButton: () -> Unit, + onDeleteButton: (Int) -> Unit +) { + var deleteDialog by remember { mutableStateOf(false) } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + Div( + attrs = { + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) + } + ) { + + Div( + attrs = { + classes(AppStylesheet.categoryListElementText) + } + ) { + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(entry.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Amount: ${entry.amount}€") } + } + } + } + Div( + attrs = { + classes(AppStylesheet.flexContainer) + } + ) { + Button(attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + onClick { onEditButton() } + style { + flex(50.percent) + margin(1.5.percent) + } + }) { + Text("Edit Entry") + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { deleteDialog = true } + style { + flex(50.percent) + margin(1.5.percent) + backgroundColor(Color("#b00020")) + } + }) { + Text("Delete Entry") + } + } + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton(entry.id) }, + { deleteDialog = false }) { Text("Delete Entry?") } + } + } +} + From b04ac0e551edec23d2a1a6725fc7c7346dd2cacc Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:45:01 +0200 Subject: [PATCH 207/325] Add EntryComponent stuff for EntryOverview --- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 3686ee5f..a746cf2c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -51,6 +51,14 @@ fun EntryComponent(screenState: MutableState) { state = viewState, onBackButton = { screenState.value = Screen.Dashboard } ) + is Screen.EntryOverview -> EntryOverviewView( + state = viewState, + onEditButton = {}, + onDeleteButton = {id -> entryViewModel.removeEntry(id)}, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) else -> {} } } From a5a8ac1afa5f463947479702cf9c81eed1937210 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 15:58:10 +0200 Subject: [PATCH 208/325] Load Entry-Data when EntryOverview is opened --- .../compose/entry/EntryComponent.kt | 22 +++-- .../compose/entry/EntryOverviewView.kt | 94 +++++++++---------- 2 files changed, 57 insertions(+), 59 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index a746cf2c..6ea574af 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -51,14 +51,17 @@ fun EntryComponent(screenState: MutableState) { state = viewState, onBackButton = { screenState.value = Screen.Dashboard } ) - is Screen.EntryOverview -> EntryOverviewView( - state = viewState, - onEditButton = {}, - onDeleteButton = {id -> entryViewModel.removeEntry(id)}, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) + is Screen.EntryOverview -> { + EntryOverviewView( + state = viewState, + onEditButton = {}, + onDeleteButton = { id -> entryViewModel.removeEntry(id) }, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) + entryViewModel.getEntryById((screenState.value as Screen.EntryOverview).id) + } else -> {} } } @@ -105,8 +108,7 @@ fun EntryList(list: List, categoryList: List, onEntry: (id: Int AppStylesheet.text ) }) { Text("No Entries in this category") } - } - else { + } else { for (entry in list) { EntryListElement(entry, categoryList, onEntry) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index 28ee388a..861308b2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -78,7 +78,7 @@ fun EntryOverviewView( } ) { Text(" Entry") } - EntryOverview(entry,onEditButton,onDeleteButton) + EntryOverview(entry, onEditButton, onDeleteButton) } when (viewState) { is UiState.Success<*> -> { @@ -105,64 +105,60 @@ fun EntryOverview( onDeleteButton: (Int) -> Unit ) { var deleteDialog by remember { mutableStateOf(false) } - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } + Div( + attrs = { + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) + } ) { - Div( - attrs = { - classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) - } - ) { - Div( - attrs = { - classes(AppStylesheet.categoryListElementText) - } - ) { - Div { - Div(attrs = { - classes("mdc-typography--headline4", AppStylesheet.text) - }) { Text(entry.name) } - Div(attrs = { - classes("mdc-typography--headline6", AppStylesheet.text) - }) { Text("Amount: ${entry.amount}€") } - } - } - } Div( attrs = { - classes(AppStylesheet.flexContainer) + classes(AppStylesheet.categoryListElementText) } ) { - Button(attrs = { - classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton() } - style { - flex(50.percent) - margin(1.5.percent) - } - }) { - Text("Edit Entry") + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(entry.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Amount: ${entry.amount}€") } } - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { deleteDialog = true } - style { - flex(50.percent) - margin(1.5.percent) - backgroundColor(Color("#b00020")) - } - }) { - Text("Delete Entry") + } + } + Div( + attrs = { + classes(AppStylesheet.flexContainer) + } + ) { + Button(attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + onClick { onEditButton() } + style { + flex(50.percent) + margin(1.5.percent) } + }) { + Text("Edit Entry") } - if (deleteDialog) { - DeleteDialog( - false, - { onDeleteButton(entry.id) }, - { deleteDialog = false }) { Text("Delete Entry?") } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { deleteDialog = true } + style { + flex(50.percent) + margin(1.5.percent) + backgroundColor(Color("#b00020")) + } + }) { + Text("Delete Entry") } } + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton(entry.id) }, + { deleteDialog = false }) { Text("Delete Entry?") } + } } + From 1440399a816370b591c8a621978e9a84a9e180a1 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 18:39:56 +0200 Subject: [PATCH 209/325] Make editEntry button go to EntryEdit:Screen --- .../kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 6ea574af..db70c0e1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -54,7 +54,7 @@ fun EntryComponent(screenState: MutableState) { is Screen.EntryOverview -> { EntryOverviewView( state = viewState, - onEditButton = {}, + onEditButton = {screenState.value = Screen.EntryEdit}, onDeleteButton = { id -> entryViewModel.removeEntry(id) }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, From ebc94b027d745afe5eeb3620b517d12ebf91038b Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 18:53:46 +0200 Subject: [PATCH 210/325] Fetch the right entry data when loading EntryEdit:Screen --- .../hsfl/budgetBinder/presentation/Screen.kt | 2 +- .../compose/entry/EntryComponent.kt | 33 +++++++++++-------- .../compose/entry/EntryOverviewView.kt | 6 ++-- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 33852673..5d20cb6f 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -23,7 +23,7 @@ sealed class Screen { } sealed class Entry: Screen() { data class Overview(val id: Int): Entry() - object Edit: Entry() + data class Edit(val id: Int): Entry() data class Create (val categoryList :List): Entry() } object Login : Screen() diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index db70c0e1..ebc8260d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -36,25 +36,30 @@ fun EntryComponent(screenState: MutableState) { val viewState = viewModel.state.collectAsState(scope.coroutineContext) when (screenState.value) { - is Screen.EntryCreate -> {EntryCreateView( - state = viewState, - categoryList = (screenState.value as Screen.EntryCreate).categoryList, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onCreateEntryButtonPressed = { name, amount, repeat, category_id -> - userViewModel.createEntry(Entry.In(name, amount, repeat, category_id)) }, - onChangeToSettings = { screenState.value = Screen.Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) + is Screen.EntryCreate -> { + EntryCreateView( + state = viewState, + categoryList = (screenState.value as Screen.EntryCreate).categoryList, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onCreateEntryButtonPressed = { name, amount, repeat, category_id -> + userViewModel.createEntry(Entry.In(name, amount, repeat, category_id)) + }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) } - is Screen.EntryEdit -> EntryEditView( - state = viewState, - onBackButton = { screenState.value = Screen.Dashboard } - ) + is Screen.EntryEdit -> { + EntryEditView( + state = viewState, + onBackButton = { screenState.value = Screen.Dashboard } + ) + entryViewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) + } is Screen.EntryOverview -> { EntryOverviewView( state = viewState, - onEditButton = {screenState.value = Screen.EntryEdit}, + onEditButton = {id -> screenState.value = Screen.EntryEdit(id)}, onDeleteButton = { id -> entryViewModel.removeEntry(id) }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index 861308b2..dbf22003 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -19,7 +19,7 @@ import org.jetbrains.compose.web.svg.Svg @Composable fun EntryOverviewView( state: State, - onEditButton: () -> Unit, + onEditButton: (id: Int) -> Unit, onDeleteButton: (id: Int) -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, @@ -101,7 +101,7 @@ fun EntryOverviewView( @Composable fun EntryOverview( entry: Entry, - onEditButton: () -> Unit, + onEditButton: (Int) -> Unit, onDeleteButton: (Int) -> Unit ) { var deleteDialog by remember { mutableStateOf(false) } @@ -133,7 +133,7 @@ fun EntryOverview( ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton() } + onClick { onEditButton(entry.id) } style { flex(50.percent) margin(1.5.percent) From 08301e1eb34f1fcbfd6abf2bdb92b71eb906d31f Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Sat, 18 Jun 2022 18:56:08 +0200 Subject: [PATCH 211/325] Go back to Dashboard when deleting an entry --- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index ebc8260d..68dfbda4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -60,7 +60,9 @@ fun EntryComponent(screenState: MutableState) { EntryOverviewView( state = viewState, onEditButton = {id -> screenState.value = Screen.EntryEdit(id)}, - onDeleteButton = { id -> entryViewModel.removeEntry(id) }, + onDeleteButton = { id -> + entryViewModel.removeEntry(id) + screenState.value = Screen.Dashboard}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, From 7fce3cc6fb337646ad60a0ab5444568199831006 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sat, 18 Jun 2022 21:55:41 +0200 Subject: [PATCH 212/325] add is to all screens --- .../src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 067df92a..94a6372f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -18,8 +18,7 @@ fun Router(screenState: MutableState) { is Screen.Login -> LoginComponent(screenState = screenState) is Screen.Dashboard -> DashboardComponent(screenState = screenState) is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, Screen.CategoryCreateOnRegister - -> CategoryComponent(screenState = screenState) + is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) else -> {} } From ab14a2b2dd4aaa7be311b10b14e30879b833bf62 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sun, 19 Jun 2022 14:33:14 +0200 Subject: [PATCH 213/325] Fix delete Category --- .../de/hsfl/budgetBinder/compose/Composables.kt | 13 +++---------- .../compose/category/CategoryComponent.kt | 10 +++++----- .../compose/category/CategoryEditView.kt | 5 +++-- .../compose/category/CategorySummaryView.kt | 11 +++++++++-- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index ea360d49..b2064038 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -180,10 +180,9 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { @Composable fun CategoryList( categoryList: List, - onEditButton: () -> Unit, + onEditButton: (Int) -> Unit, onDeleteButton: (Int) -> Unit ) { - var deleteDialog by remember { mutableStateOf(false) } Div { for (category in categoryList) Div(attrs = { @@ -234,7 +233,7 @@ fun CategoryList( ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton() } + onClick { onEditButton(category.id) } style { flex(50.percent) margin(1.5.percent) @@ -244,7 +243,7 @@ fun CategoryList( } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { deleteDialog = true } + onClick { onDeleteButton(category.id) } style { flex(50.percent) margin(1.5.percent) @@ -254,12 +253,6 @@ fun CategoryList( Text("Delete Category") } } - if (deleteDialog) { - DeleteDialog( - false, - { onDeleteButton(category.id) }, - { deleteDialog = false }) { Text("Delete Category?") } - } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 18a0b59f..5293a4ad 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -35,24 +35,24 @@ fun CategoryComponent(screenState: MutableState) { val viewState = viewModel.state.collectAsState(scope.coroutineContext) when (screenState.value) { - Screen.CategoryCreate -> CategoryCreateView( + is Screen.CategoryCreate -> CategoryCreateView( state = viewState, onBackButton = { screenState.value = Screen.CategorySummary} ) - Screen.CategorySummary -> CategorySummaryView( + is Screen.CategorySummary -> CategorySummaryView( state = viewState, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, - onEditButton = { screenState.value = Screen.CategoryEdit}, + onEditButton = { id -> screenState.value = Screen.CategoryEdit(id)}, onDeleteButton = {id -> categoryViewModel.removeCategory(id)}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - Screen.CategoryEdit -> CategoryEditView( + is Screen.CategoryEdit -> CategoryEditView( state = viewState, onBackButton = { screenState.value = Screen.CategorySummary} ) - Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( + is Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( state = viewState, onFinishedButton = { screenState.value = Screen.Dashboard} //Should go back to the previous Screen, which could be CategorySummary or EntryCreate. ) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt index 892e8511..d2a714f3 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt @@ -14,11 +14,12 @@ fun CategoryEditView( onBackButton: () -> Unit ) { val viewState by remember { state } - H1{Text("CategoryEditView")} + H1{Text("Edit Category")} + console.log() Div { when (viewState) { is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + //Text((viewState as UiState.Success<*>).element.toString()) } is UiState.Error -> { Text((viewState as UiState.Error).error) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 8bd83a2a..4cd5c9a4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -17,12 +17,13 @@ import org.jetbrains.compose.web.dom.* fun CategorySummaryView( state: State, onCategoryCreateButton: () -> Unit, - onEditButton: () -> Unit, + onEditButton: (id: Int) -> Unit, onDeleteButton: (id: Int) -> Unit, onChangeToDashboard: () -> Unit, onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -78,7 +79,13 @@ fun CategorySummaryView( }) { Text("Create Category") } - CategoryList(categoryList, onEditButton, onDeleteButton) + CategoryList(categoryList, {id -> onEditButton(id)}, {id -> onDeleteButton(id)}) + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton }, + { deleteDialog = false }) { Text("Delete Category?") } + } Div { when (viewState) { is UiState.Success<*> -> { From 7377c54ea95ec3a8b097945eea165db16164e634 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sun, 19 Jun 2022 15:02:15 +0200 Subject: [PATCH 214/325] Fix openDialog on delete Category --- .../de/hsfl/budgetBinder/compose/Composables.kt | 11 ++++++++++- .../compose/category/CategorySummaryView.kt | 8 +------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index b2064038..c3240a58 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -183,7 +183,16 @@ fun CategoryList( onEditButton: (Int) -> Unit, onDeleteButton: (Int) -> Unit ) { + var deleteDialog by remember { mutableStateOf(false) } + var id by remember { mutableStateOf(0) } + Div { + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton(id) }, + { deleteDialog = false }) { Text("Delete Category?") } + } for (category in categoryList) Div(attrs = { classes("mdc-card", AppStylesheet.card) @@ -243,7 +252,7 @@ fun CategoryList( } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { onDeleteButton(category.id) } + onClick { deleteDialog = !deleteDialog; id = category.id } style { flex(50.percent) margin(1.5.percent) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 4cd5c9a4..7554dfe6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -23,7 +23,6 @@ fun CategorySummaryView( onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { - var deleteDialog by remember { mutableStateOf(false) } var categoryList by remember { mutableStateOf>(emptyList()) } val viewState by remember { state } @@ -80,12 +79,7 @@ fun CategorySummaryView( Text("Create Category") } CategoryList(categoryList, {id -> onEditButton(id)}, {id -> onDeleteButton(id)}) - if (deleteDialog) { - DeleteDialog( - false, - { onDeleteButton }, - { deleteDialog = false }) { Text("Delete Category?") } - } + Div { when (viewState) { is UiState.Success<*> -> { From 20ca0325f9e94b43ec56b1f0b8b5f25a38fc0044 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Sun, 19 Jun 2022 19:12:43 +0200 Subject: [PATCH 215/325] Add form in edit category --- .../hsfl/budgetBinder/compose/Composables.kt | 11 +- .../compose/category/CategoryComponent.kt | 127 +++++--- .../compose/category/CategoryCreateView.kt | 281 +++++++++--------- .../compose/category/CategoryEditView.kt | 262 ++++++++++++++-- .../compose/category/CategorySummaryView.kt | 1 - 5 files changed, 476 insertions(+), 206 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index c3240a58..04b2f2bc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -138,8 +138,11 @@ fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { @Composable -fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { - var highlightImage by remember { mutableStateOf(Category.Image.DEFAULT) } +fun CategoryImagesToImageList( + inputImage: MutableState, + onClick: (Category.Image) -> Unit +) { + var highlightImage by remember { mutableStateOf(inputImage) } Div( attrs = { classes("mdc-card", AppStylesheet.card) @@ -158,14 +161,14 @@ fun CategoryImagesToImageList(onClick: (Category.Image) -> Unit) { ) { Div( attrs = { - if (highlightImage == image) + if (highlightImage.value == image) classes( "mdc-image-list__image-aspect-container", "mdc-icon-button", "mdc-button--raised" ) else classes("mdc-image-list__image-aspect-container", "mdc-icon-button") - onClick { onClick(image); highlightImage = image } + onClick { onClick(image); highlightImage.value = image } } ) { CategoryImageToIcon(image) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 5293a4ad..3b1ca325 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -4,14 +4,21 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.domain.usecase.* +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.viewmodel.category._CategoryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel import di +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg +import org.kodein.di.compose.localDI import org.kodein.di.instance @Composable @@ -37,31 +44,51 @@ fun CategoryComponent(screenState: MutableState) { when (screenState.value) { is Screen.CategoryCreate -> CategoryCreateView( state = viewState, - onBackButton = { screenState.value = Screen.CategorySummary} - ) - is Screen.CategorySummary -> CategorySummaryView( - state = viewState, - onCategoryCreateButton = { screenState.value = Screen.CategoryCreate}, - onEditButton = { id -> screenState.value = Screen.CategoryEdit(id)}, - onDeleteButton = {id -> categoryViewModel.removeCategory(id)}, + onCreateCategoryButtonPressed = { name, color, image, budget -> + categoryViewModel.createCategory(Category.In(name, color.drop(1), image, budget)) + screenState.value = Screen.CategorySummary }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onChangeToSettings = { screenState.value = Screen.Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - is Screen.CategoryEdit -> CategoryEditView( - state = viewState, - onBackButton = { screenState.value = Screen.CategorySummary} - ) + is Screen.CategorySummary -> { + CategorySummaryView( + state = viewState, + onCategoryCreateButton = { screenState.value = Screen.CategoryCreate }, + onEditButton = { id -> screenState.value = Screen.CategoryEdit(id) }, + onDeleteButton = { id -> categoryViewModel.removeCategory(id) }, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) + categoryViewModel.getAllCategories() + } + is Screen.CategoryEdit -> { + CategoryEditView( + state = viewState, + onEditCategoryButtonPressed = { name, color, image, budget -> + categoryViewModel.changeCategory( + Category.Patch(name, color.drop(1), image, budget), + (screenState.value as Screen.CategoryEdit).id + ); screenState.value = Screen.CategorySummary }, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, + ) + categoryViewModel.getCategoryById((screenState.value as Screen.CategoryEdit).id) + } is Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( state = viewState, - onFinishedButton = { screenState.value = Screen.Dashboard} //Should go back to the previous Screen, which could be CategorySummary or EntryCreate. + onFinishedButton = { + screenState.value = Screen.Dashboard + } //Should go back to the previous Screen, which could be CategorySummary or EntryCreate. ) else -> {} } } -fun categoryIdToCategory(category_id: Int?,categoryList: List): Category { - for (category in categoryList){ +fun categoryIdToCategory(category_id: Int?, categoryList: List): Category { + for (category in categoryList) { if (category.id == category_id) return category } return DEFAULT_CATEGORY //If the category wasn't found (or is set to no category) return default @@ -69,7 +96,7 @@ fun categoryIdToCategory(category_id: Int?,categoryList: List): Catego @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun BudgetBar(category: Category, entryList: List){ +fun BudgetBar(category: Category, entryList: List) { //category = Category we want to show //entryList = List of entries //width and height are for aspect ratio - tries to fill out wherever its in, so its more like @@ -78,44 +105,62 @@ fun BudgetBar(category: Category, entryList: List){ val budget = category.budget var usedBudget = 0f for (entry in entryList) { - usedBudget-= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget + usedBudget -= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget + } + H1(attrs = { classes("mdc-typography--headline4", AppStylesheet.flexContainer) }) { + CategoryImageToIcon(category.image) + Text("${category.name} - Budget") } - H1{Text("${category.name} - Budget")} - Div{ - if (usedBudget < budget) { + + Div { + if (usedBudget <= budget && budget > 0) { //Normal not Spent Budget //Money Text - Div(attrs={style { - display(DisplayStyle.Flex) - justifyContent(JustifyContent("space-between")) - }}){ - Div{Text(usedBudget.toString()+"€")} - Div{Text(budget.toString()+"€")} + MoneyTextDiv { + Div(attrs = { + classes("mdc-typography--headline5") + }) { Text(usedBudget.toString() + "€") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(budget.toString() + "€") } } - //Bar - Svg(viewBox = "0 0 $width $height"){//For aspect ratio - tries to fill out wherever its in + Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { attr("fill", Color.lightgray.toString()) }) - Rect(x = 0, y = 0, width = usedBudget/budget*width, height = height, { - attr("fill", Color.darkred.toString()) + if (0 < usedBudget) // If there is used budget, draw it + Rect(x = 0, y = 0, width = usedBudget / budget * width, height = height, { + attr("fill", "#" + category.color) + }) + } + } else if (usedBudget > budget && budget > 0) { //Over Budget + MoneyTextDiv { + Div(attrs = { classes("mdc-typography--headline5") }) { Text("Budget limit for " + category.name + " reached! " + usedBudget.toString() + "€ of " + budget.toString() + "€ Budget spent") } + } + Svg(viewBox = "0 0 $width $height") { + Rect(x = 0, y = 0, width = width, height = height, { + attr("fill", "#b00020") }) } - } - else{ - //SpentBudget Text - Div(attrs={style { - display(DisplayStyle.Flex) - justifyContent(JustifyContent("center")) - }}){ - Div{Text("Budget limit for "+category.name+" reached! "+usedBudget.toString()+"€ of "+budget.toString()+"€ Budget spent")} + } else if (budget <= 0f) { //No Category View or other unpredictable case (or no categories, overall screen) + MoneyTextDiv { + Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€ spent") } } - //Bar - Svg(viewBox = "0 0 $width $height"){//For aspect ratio - tries to fill out wherever its in + Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { - attr("fill", Color.red.toString()) + attr("fill", "#" + category.color) }) } } } } +@Composable +fun MoneyTextDiv(content: @Composable () -> Unit) { + Div(attrs = { + style { + display(DisplayStyle.Flex) + justifyContent(JustifyContent("space-between")) + } + }) { + content() + } +} + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt index edf490e5..06af894f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt @@ -24,7 +24,7 @@ fun CategoryCreateView( ) { var categoryNameTextFieldState by remember { mutableStateOf("") } var categoryColorTextFieldState by remember { mutableStateOf("") } - var categoryImageState by remember { mutableStateOf(Category.Image.DEFAULT) } + var categoryImageState = remember { mutableStateOf(Category.Image.DEFAULT) } var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } @@ -68,185 +68,184 @@ fun CategoryCreateView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Create a new Category") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onCreateCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState.value, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() + } } ) { - H1 { Text("Create a new Category") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") - onCreateCategoryButtonPressed( - categoryNameTextFieldState, - categoryColorTextFieldState, - categoryImageState, - categoryBudgetTextFieldState.toFloat() - ) - it.preventDefault() + //Category Name Input + Div( + attrs = { + classes(AppStylesheet.margin) } - } ) { - //Category Name Input - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Category Name") } + Input( + type = InputType.Text ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Category Name") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(categoryNameTextFieldState) - required(true) - onInput { - categoryNameTextFieldState = it.value - } + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + required(true) + onInput { + categoryNameTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Category Color Input + Div( + attrs = { + classes(AppStylesheet.margin) } - //Category Color Input - Div( + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } ) { - Label( + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } } + ) { Text("Color") } + Input( + type = InputType.Color ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } - } - ) { Text("Color") } - Input( - type = InputType.Color - ) { - classes("mdc-text-field__input") - value(categoryColorTextFieldState) - onInput { - categoryColorTextFieldState = it.value - } + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - //Category Image Input - Div( + } + //Category Image Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + style { width(100.percent) } } ) { - Label( + Span( attrs = { - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent) } } - ) { - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent); marginLeft(2.percent)} - } - ) { Text("Image") } - CategoryImagesToImageList(onClick = {categoryImageState = it}) - } + ) { Text("Image") } + CategoryImagesToImageList(categoryImageState, onClick = { categoryImageState.value = it }) + } + } + //Category Budget Input + Div( + attrs = { + classes(AppStylesheet.margin) } - //Category Budget Input - Div( + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field__ripple") } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Budget") } - Input( - type = InputType.Number - ) { - classes("mdc-text-field__input") - value(categoryBudgetTextFieldState) - required(true) - min("1") - onInput { - categoryBudgetTextFieldState = it.value.toString() - } + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + required(true) + min("1") + onInput { + categoryBudgetTextFieldState = it.value.toString() } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - //Submit button - Div( + } + //Submit button + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( attrs = { - classes(AppStylesheet.margin) + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + //Text((viewState as UiState.Success<*>).element.toString()) } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - Div { - when (viewState) { - is UiState.Success<*> -> { - //Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt index d2a714f3..900dda55 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt @@ -1,37 +1,261 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.CategoryImagesToImageList +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.min +import org.jetbrains.compose.web.attributes.required +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* @Composable fun CategoryEditView( state: State, - onBackButton: () -> Unit + onEditCategoryButtonPressed: (name: String, color: String, image: Category.Image, budget: Float) -> Unit, + onChangeToDashboard: () -> Unit, + onChangeToCategory: () -> Unit, + onChangeToSettings: () -> Unit ) { + var category by remember { mutableStateOf(Category(0, "", "", Category.Image.DEFAULT, 0f)) } + var categoryNameTextFieldState by remember { mutableStateOf("") } + var categoryColorTextFieldState by remember { mutableStateOf("") } + var categoryImageState = remember { mutableStateOf(Category.Image.DEFAULT) } + var categoryBudgetTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("Edit Category")} - console.log() - Div { - when (viewState) { - is UiState.Success<*> -> { - //Text((viewState as UiState.Success<*>).element.toString()) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } - is UiState.Loading -> { - //CircularProgressIndicator() + }) + + MainFlexContainer { + H1(attrs = { style { margin(2.percent) } }) { Text("Edit Category") } + + Form(attrs = { + this.addEventListener("submit") { + console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") + onEditCategoryButtonPressed( + categoryNameTextFieldState, + categoryColorTextFieldState, + categoryImageState.value, + categoryBudgetTextFieldState.toFloat() + ) + it.preventDefault() } } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Category Overview") + ) { + //Category Name Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Category Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(categoryNameTextFieldState) + required(true) + onInput { + categoryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Category Color Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Color") } + Input( + type = InputType.Color + ) { + classes("mdc-text-field__input") + value(categoryColorTextFieldState) + onInput { + categoryColorTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Category Image Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent) } + } + ) { Text("Image") } + CategoryImagesToImageList(categoryImageState, onClick = { categoryImageState.value = it }) + } + } + //Category Budget Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Budget") } + Input( + type = InputType.Number + ) { + classes("mdc-text-field__input") + value(categoryBudgetTextFieldState) + required(true) + min("1") + onInput { + categoryBudgetTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Submit button + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + + Div { + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is Category -> { + category = element + categoryNameTextFieldState = category.name + categoryColorTextFieldState = "#" + category.color + categoryImageState.value = category.image + categoryBudgetTextFieldState = category.budget.toString() + } + } + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index 7554dfe6..af48f680 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -3,7 +3,6 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.CategoryList -import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain From 0cb8fc9e9ef0b486f778bfde684b75851806e655 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Mon, 20 Jun 2022 09:54:25 +0200 Subject: [PATCH 216/325] Add form in entryEdit and add categoryList in entryEdit and entryOverview --- .../hsfl/budgetBinder/presentation/Screen.kt | 10 +- .../hsfl/budgetBinder/compose/Composables.kt | 12 +- .../compose/dashboard/DashboardComponent.kt | 3 +- .../compose/dashboard/DashboardView.kt | 4 +- .../compose/entry/EntryComponent.kt | 11 +- .../compose/entry/EntryEditView.kt | 286 ++++++++++++++++-- .../compose/entry/EntryOverviewView.kt | 20 +- 7 files changed, 299 insertions(+), 47 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 5d20cb6f..63404306 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -22,8 +22,8 @@ sealed class Screen { object CreateOnRegister: Category() } sealed class Entry: Screen() { - data class Overview(val id: Int): Entry() - data class Edit(val id: Int): Entry() + data class Overview(val id: Int, val categoryList :List): Entry() + data class Edit(val id: Int, val categoryList :List): Entry() data class Create (val categoryList :List): Entry() } object Login : Screen() @@ -44,8 +44,10 @@ sealed class Screen { object CategoryCreate : Screen() @Deprecated(message = "use sealed class Category") object CategoryCreateOnRegister : Screen() + @Deprecated(message = "use sealed class Category") + data class EntryOverview (val id: Int, val categoryList :List) : Screen() @Deprecated(message = "use sealed class Entry") - object EntryEdit : Screen() + data class EntryEdit (val id: Int, val categoryList :List): Screen() @Deprecated(message = "use sealed class Entry") - object EntryCreate : Screen() + data class EntryCreate (val categoryList :List): Screen() } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 04b2f2bc..4587300c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -2,9 +2,11 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.StateManager.screenState import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import de.hsfl.budgetBinder.presentation.Screen import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType import org.jetbrains.compose.web.attributes.type @@ -374,7 +376,7 @@ fun DeleteDialog(hidden: Boolean, buttonAction: () -> Unit, resetDialog: () -> U @Composable fun ChooseCategoryMenu( categoryList: List, - getCategoryId: (Int) -> Unit + getCategoryId: (Int?) -> Unit ) { var chosenCategory by remember { mutableStateOf(categoryList[0]) } var showList by remember { mutableStateOf(false) } @@ -401,14 +403,10 @@ fun ChooseCategoryMenu( Li(attrs = { classes("mdc-list-item") attr("role", "menuitem") - onClick { } + onClick { chosenCategory = category; getCategoryId(category.id) } }) { Span(attrs = { classes("mdc-list-item__ripple") }) { } - Span(attrs = { onClick { chosenCategory = category; getCategoryId(category.id) } }) { - Text( - category.name - ) - } + Span(attrs = { }) { Text(category.name) } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index d0992b48..da1ae3cc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -27,7 +27,6 @@ fun DashboardComponent(screenState: MutableState) { onCategorySummaryButton = { screenState.value = Screen.CategorySummary}, onSettingsButton = {screenState.value = Screen._Settings}, onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, - onEntryEditButton = {screenState.value = Screen.EntryEdit} - onEntryOverviewButton = {id -> screenState.value = Screen.EntryOverview(id)} + onEntryOverviewButton = {id, categoryList -> screenState.value = Screen.EntryOverview(id, categoryList)} ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 2cabe030..7453e2a6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -23,7 +23,7 @@ fun DashboardView( onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, onEntryCreateButton: (categoryList: List) -> Unit, - onEntryOverviewButton: (id:Int) -> Unit + onEntryOverviewButton: (id:Int, categoryList: List) -> Unit ) { val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } @@ -70,7 +70,7 @@ fun DashboardView( MainFlexContainer { - Div { DashboardData(categoryList, entryList, onEntryOverviewButton) } + Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id, categoryList) } } CreateNewEntryButton({ onEntryCreateButton(categoryList) }) //Process new Category Data when (categoriesViewState) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 68dfbda4..64bcda05 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -52,7 +52,16 @@ fun EntryComponent(screenState: MutableState) { is Screen.EntryEdit -> { EntryEditView( state = viewState, - onBackButton = { screenState.value = Screen.Dashboard } + categoryList = (screenState.value as Screen.EntryEdit).categoryList, + onChangeToDashboard = { screenState.value = Screen.Dashboard }, + onEditEntryButtonPressed = { name, amount, repeat, category -> + entryViewModel.changeEntry( + Entry.Patch(name, amount, repeat, category), + (screenState.value as Screen.EntryEdit).id + ) + }, + onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) entryViewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 0aac23a6..8622874e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -1,36 +1,286 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.ChooseCategoryMenu +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.category.categoryIdToCategory +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.attributes.ButtonType +import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.required +import org.jetbrains.compose.web.attributes.type +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Path +import org.jetbrains.compose.web.svg.Svg +@OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryEditView( state: State, - onBackButton: () -> Unit + categoryList: List, + onChangeToDashboard: () -> Unit, + onChangeToSettings: () -> Unit, + onChangeToCategory: () -> Unit, + onEditEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category: Entry.Category) -> Unit, ) { + var entry by remember { mutableStateOf(Entry(0, "", 0f, false, 0)) } + var switchState by remember { mutableStateOf(false) } + var entryNameTextFieldState by remember { mutableStateOf("") } + var entryAmountTextFieldState by remember { mutableStateOf("") } + var entryRepeatState by remember { mutableStateOf("") } + var entryCategoryIDTextFieldState by remember { mutableStateOf("") } val viewState by remember { state } - H1{Text("EntryEditView")} - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) + + topBarMain( + logoButton = { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { onChangeToDashboard() } + } + ) + }, navButtons = { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToCategory() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onChangeToSettings() } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + }) + + MainFlexContainer { + H1( + attrs = { + style { margin(2.percent) } } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { Text("Edit Entry") } + Form(attrs = { + this.addEventListener("submit") { + console.log("$entryNameTextFieldState, $entryAmountTextFieldState, $entryRepeatState, ${entryCategoryIDTextFieldState.toInt()}") + onEditEntryButtonPressed( + entryNameTextFieldState, + (if (!switchState) "-$entryAmountTextFieldState" else entryAmountTextFieldState).toFloat(), + entryRepeatState.toBoolean(), + Entry.Category(entryCategoryIDTextFieldState.toInt()) + ) + it.preventDefault() } } - Button(attrs = { - onClick { onBackButton() } - }) { - Text("Back to Dashboard") + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Entry Name") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(entryNameTextFieldState) + required(true) + onInput { + entryNameTextFieldState = it.value + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } + } + ) { Text("Amount") } + Div { + Button( + attrs = { + if (!switchState) classes("mdc-switch", "mdc-switch--unselected") + else classes("mdc-switch", "mdc-switch--selected") + id("basic-switch") + attr("role", "switch") + attr("aria-checked", "false") + type(ButtonType.Button) + onClick { switchState = !switchState } + } + ) { + Div(attrs = { classes("mdc-switch__track") }) { } + Div(attrs = { classes("mdc-switch__handle-track") }) { + Div(attrs = { classes("mdc-switch__handle") }) { + Div(attrs = { classes("mdc-switch__shadow") }) { + Div(attrs = { classes("mdc-elevation-overlay") }) { } + } + Div(attrs = { classes("mdc-switch__ripple") }) { } + Div(attrs = { classes("mdc-switch__icons") }) { + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") + } + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M20 13H4v-2h16v2z") + } + } + } + } + } + } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { + Text(if (switchState) "+" else "-") + } + Input( + type = InputType.Number + ) { + attr("step", "0.01") + classes("mdc-text-field__input") + onInput { + entryAmountTextFieldState = it.value.toString() + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) + } + ) { + Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { classes("mdc-form-field") }) { + Div(attrs = { classes("mdc-checkbox") }) { + Input(type = InputType.Checkbox) + { + classes("mdc-checkbox__native-control") + id("checkbox-1") + onInput { + entryRepeatState = it.value.toString() + } + } + Div(attrs = { classes("mdc-checkbox__background") }) { + Svg(attrs = { classes("mdc-checkbox__checkmark") }, viewBox = "0 0 24 24") { + Path( + "M1.73,12.91 8.1,19.28 22.79,4.59", + attrs = { classes("mdc-checkbox__checkmark") }) + } + Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } + } + Div(attrs = { classes("mdc-checkbox__ripple") }) { } + } + Label(forId = "checkbox-1") { Text("repeat") } + } + } + Div(attrs = { style { flex(50.percent) } }) { + ChooseCategoryMenu(categoryList) { id -> entryCategoryIDTextFieldState = id.toString() } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + when (val element = (viewState as UiState.Success<*>).element) { + is Entry -> { + entry = element + entryNameTextFieldState = entry.name + entryAmountTextFieldState = entry.amount.toString() + switchState = !entry.amount.toString().startsWith("-") + entryRepeatState = entry.repeat.toString() + entryCategoryIDTextFieldState = entry.category_id.toString() + } + } + Text((viewState as UiState.Success<*>).element.toString()) + } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index dbf22003..1d79a64a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -25,7 +25,7 @@ fun EntryOverviewView( onChangeToCategory: () -> Unit, onChangeToSettings: () -> Unit ) { - var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } + var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } val viewState by remember { state } topBarMain( @@ -68,25 +68,19 @@ fun EntryOverviewView( }) MainFlexContainer { - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Entry") } + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Entry") } - EntryOverview(entry, onEditButton, onDeleteButton) - } + EntryOverview(entry, onEditButton, onDeleteButton) when (viewState) { is UiState.Success<*> -> { when (val element = (viewState as UiState.Success<*>).element) { is Entry -> entry = element else -> {} } - } is UiState.Error -> { Text((viewState as UiState.Error).error) From bdbcf79fdb0a22b83b4ca9a8c1bb224963de979a Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Tue, 14 Jun 2022 15:15:48 +0200 Subject: [PATCH 217/325] Delete unused imports --- .../hsfl/budgetBinder/compose/category/CategorySummaryView.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt index af48f680..c6f877c0 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt @@ -2,11 +2,14 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.StateManager.screenState import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain +import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState +import org.jetbrains.compose.web.css.flex import org.jetbrains.compose.web.css.margin import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* From 6124c927359ff8ab40e0d1eab8922d47022a2c56 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:23:39 +0200 Subject: [PATCH 218/325] Make slight style adjustments --- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 5bcbcafe..07f9583e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -77,6 +77,14 @@ object AppStylesheet : StyleSheet() { val categoryImageList by style{ justifyContent(JustifyContent.Center) } + //Container for main content in BudgetBar + val budgetBarContainer by style { + flex("90%") + } + //Container for arrow in BudgetBar + val arrowFlexContainer by style { + flex("0.1 0.1 5%") + } //EntryList val entryListElement by style{ From c99e0b51b62ca7e66afa67dbbb5def53973229fc Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 13 Jun 2022 20:30:38 +0200 Subject: [PATCH 219/325] Format dashboard category switch buttons --- .../kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 07f9583e..2b6890f1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -84,6 +84,7 @@ object AppStylesheet : StyleSheet() { //Container for arrow in BudgetBar val arrowFlexContainer by style { flex("0.1 0.1 5%") + height(auto) } //EntryList From 9397a74459ff6933959d328647d2c4cd6c9b8acc Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 14:47:17 +0200 Subject: [PATCH 220/325] Add first form of newEntry button style --- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 2b6890f1..64b34199 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -127,6 +127,12 @@ object AppStylesheet : StyleSheet() { textAlign("center") padding(10.px) } + val moneyText by style{ + textAlign("center") + padding(10.px) + whiteSpace("nowrap") + + } val card by style { margin(10.px) From 694e8f95e2ea69ff5a4a31516a27ba502aa37c76 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 15 Jun 2022 15:25:08 +0200 Subject: [PATCH 221/325] Fix position for newEntry button --- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 64b34199..26a329f5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -131,7 +131,11 @@ object AppStylesheet : StyleSheet() { textAlign("center") padding(10.px) whiteSpace("nowrap") - + } + val newEntryButton by style{ + position(Position.Fixed) + bottom(16.px) + marginRight(20.px) } val card by style { From 0cdfa5e75ff0e328cf94dc1a0e8b6a2ad68342b3 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 20:04:57 +0200 Subject: [PATCH 222/325] Remove categoryList from Entry-Screens. Will get loaded via ViewModel later --- .../kotlin/de/hsfl/budgetBinder/presentation/Screen.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index 63404306..fc8557d2 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -22,9 +22,9 @@ sealed class Screen { object CreateOnRegister: Category() } sealed class Entry: Screen() { - data class Overview(val id: Int, val categoryList :List): Entry() - data class Edit(val id: Int, val categoryList :List): Entry() - data class Create (val categoryList :List): Entry() + data class Overview(val id: Int): Entry() + data class Edit(val id: Int): Entry() + object Create: Entry() } object Login : Screen() object Register : Screen() From e7edaac5f5827a9dfb9a66643db88c1f78fce1b7 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 20:10:55 +0200 Subject: [PATCH 223/325] Remove unnecessary imports in Composables and fix CategoryComponent --- .../hsfl/budgetBinder/compose/Composables.kt | 4 +--- .../compose/category/CategoryComponent.kt | 22 ++++++++----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 4587300c..5451397c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -2,11 +2,9 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.StateManager.screenState import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import de.hsfl.budgetBinder.presentation.Screen import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType import org.jetbrains.compose.web.attributes.type @@ -144,7 +142,7 @@ fun CategoryImagesToImageList( inputImage: MutableState, onClick: (Category.Image) -> Unit ) { - var highlightImage by remember { mutableStateOf(inputImage) } + val highlightImage by remember { mutableStateOf(inputImage) } Div( attrs = { classes("mdc-card", AppStylesheet.card) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 3b1ca325..34e20df4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -10,15 +10,11 @@ import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel import di -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg -import org.kodein.di.compose.localDI import org.kodein.di.instance @Composable @@ -45,37 +41,37 @@ fun CategoryComponent(screenState: MutableState) { is Screen.CategoryCreate -> CategoryCreateView( state = viewState, onCreateCategoryButtonPressed = { name, color, image, budget -> - categoryViewModel.createCategory(Category.In(name, color.drop(1), image, budget)) + viewModel.createCategory(Category.In(name, color.drop(1), image, budget)) screenState.value = Screen.CategorySummary }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) is Screen.CategorySummary -> { CategorySummaryView( state = viewState, onCategoryCreateButton = { screenState.value = Screen.CategoryCreate }, - onEditButton = { id -> screenState.value = Screen.CategoryEdit(id) }, - onDeleteButton = { id -> categoryViewModel.removeCategory(id) }, + onEditButton = { id -> screenState.value = Screen.Category.Edit(id) }, + onDeleteButton = { id -> viewModel.removeCategory(id) }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - categoryViewModel.getAllCategories() + viewModel.getAllCategories() } is Screen.CategoryEdit -> { CategoryEditView( state = viewState, onEditCategoryButtonPressed = { name, color, image, budget -> - categoryViewModel.changeCategory( + viewModel.changeCategory( Category.Patch(name, color.drop(1), image, budget), (screenState.value as Screen.CategoryEdit).id ); screenState.value = Screen.CategorySummary }, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - categoryViewModel.getCategoryById((screenState.value as Screen.CategoryEdit).id) + viewModel.getCategoryById((screenState.value as Screen.CategoryEdit).id) } is Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( state = viewState, From b285695b1022c911e67594b046f3111a8e119b87 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 20:16:18 +0200 Subject: [PATCH 224/325] Fix EntryComponent --- .../hsfl/budgetBinder/presentation/Screen.kt | 2 +- .../compose/entry/EntryComponent.kt | 24 ++++++++----------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index fc8557d2..c5b3a0c7 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -39,7 +39,7 @@ sealed class Screen { @Deprecated(message = "use sealed class Category") object CategorySummary : Screen() @Deprecated(message = "use sealed class Category") - object CategoryEdit : Screen() + data class CategoryEdit(val id: Int) : Screen() @Deprecated(message = "use sealed class Category") object CategoryCreate : Screen() @Deprecated(message = "use sealed class Category") diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 64bcda05..cae054b1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -10,12 +10,8 @@ import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.viewmodel.EntryViewModel import di -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Text -import org.kodein.di.compose.localDI import org.kodein.di.instance import kotlin.math.absoluteValue @@ -41,10 +37,10 @@ fun EntryComponent(screenState: MutableState) { state = viewState, categoryList = (screenState.value as Screen.EntryCreate).categoryList, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onCreateEntryButtonPressed = { name, amount, repeat, category_id -> - userViewModel.createEntry(Entry.In(name, amount, repeat, category_id)) + onCreateEntryButtonPressed = { name:String, amount:Float, repeat:Boolean, category_id:Int -> + viewModel.createEntry(Entry.In(name, amount, repeat, category_id)) }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) @@ -54,29 +50,29 @@ fun EntryComponent(screenState: MutableState) { state = viewState, categoryList = (screenState.value as Screen.EntryEdit).categoryList, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onEditEntryButtonPressed = { name, amount, repeat, category -> - entryViewModel.changeEntry( + onEditEntryButtonPressed = { name:String, amount:Float, repeat:Boolean, category:Entry.Category? -> + viewModel.changeEntry( Entry.Patch(name, amount, repeat, category), (screenState.value as Screen.EntryEdit).id ) }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - entryViewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) + viewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) } is Screen.EntryOverview -> { EntryOverviewView( state = viewState, onEditButton = {id -> screenState.value = Screen.EntryEdit(id)}, onDeleteButton = { id -> - entryViewModel.removeEntry(id) + viewModel.removeEntry(id) screenState.value = Screen.Dashboard}, onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen.Settings }, + onChangeToSettings = { screenState.value = Screen._Settings }, onChangeToCategory = { screenState.value = Screen.CategorySummary }, ) - entryViewModel.getEntryById((screenState.value as Screen.EntryOverview).id) + viewModel.getEntryById((screenState.value as Screen.EntryOverview).id) } else -> {} } From 6294b04fff485b719f2cdc0dd308582038835cd2 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 20:54:46 +0200 Subject: [PATCH 225/325] Remove categoryList from EntryScreen-Views --- .../kotlin/de/hsfl/budgetBinder/presentation/Screen.kt | 4 ++-- .../hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt | 2 +- .../de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt | 4 ++-- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 3 +-- .../de/hsfl/budgetBinder/compose/entry/EntryEditView.kt | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index c5b3a0c7..05c526ee 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -45,9 +45,9 @@ sealed class Screen { @Deprecated(message = "use sealed class Category") object CategoryCreateOnRegister : Screen() @Deprecated(message = "use sealed class Category") - data class EntryOverview (val id: Int, val categoryList :List) : Screen() + data class EntryOverview (val id: Int) : Screen() @Deprecated(message = "use sealed class Entry") - data class EntryEdit (val id: Int, val categoryList :List): Screen() + data class EntryEdit (val id: Int): Screen() @Deprecated(message = "use sealed class Entry") data class EntryCreate (val categoryList :List): Screen() } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index da1ae3cc..0881187e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -27,6 +27,6 @@ fun DashboardComponent(screenState: MutableState) { onCategorySummaryButton = { screenState.value = Screen.CategorySummary}, onSettingsButton = {screenState.value = Screen._Settings}, onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, - onEntryOverviewButton = {id, categoryList -> screenState.value = Screen.EntryOverview(id, categoryList)} + onEntryOverviewButton = {id -> screenState.value = Screen.EntryOverview(id)} ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt index 7453e2a6..0ec060a3 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt @@ -23,7 +23,7 @@ fun DashboardView( onCategorySummaryButton: () -> Unit, onSettingsButton: () -> Unit, onEntryCreateButton: (categoryList: List) -> Unit, - onEntryOverviewButton: (id:Int, categoryList: List) -> Unit + onEntryOverviewButton: (id:Int) -> Unit ) { val categoriesViewState by remember { categoriesState } val entriesViewState by remember { entriesState } @@ -70,7 +70,7 @@ fun DashboardView( MainFlexContainer { - Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id, categoryList) } } + Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id) } } CreateNewEntryButton({ onEntryCreateButton(categoryList) }) //Process new Category Data when (categoriesViewState) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index cae054b1..0e704a15 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -48,7 +48,6 @@ fun EntryComponent(screenState: MutableState) { is Screen.EntryEdit -> { EntryEditView( state = viewState, - categoryList = (screenState.value as Screen.EntryEdit).categoryList, onChangeToDashboard = { screenState.value = Screen.Dashboard }, onEditEntryButtonPressed = { name:String, amount:Float, repeat:Boolean, category:Entry.Category? -> viewModel.changeEntry( @@ -64,7 +63,7 @@ fun EntryComponent(screenState: MutableState) { is Screen.EntryOverview -> { EntryOverviewView( state = viewState, - onEditButton = {id -> screenState.value = Screen.EntryEdit(id)}, + onEditButton = {id, -> screenState.value = Screen.EntryEdit(id)}, onDeleteButton = { id -> viewModel.removeEntry(id) screenState.value = Screen.Dashboard}, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 8622874e..bc189082 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -24,13 +24,13 @@ import org.jetbrains.compose.web.svg.Svg @Composable fun EntryEditView( state: State, - categoryList: List, onChangeToDashboard: () -> Unit, onChangeToSettings: () -> Unit, onChangeToCategory: () -> Unit, onEditEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category: Entry.Category) -> Unit, ) { var entry by remember { mutableStateOf(Entry(0, "", 0f, false, 0)) } + var categoryList by remember { mutableStateOf>(emptyList()) } var switchState by remember { mutableStateOf(false) } var entryNameTextFieldState by remember { mutableStateOf("") } var entryAmountTextFieldState by remember { mutableStateOf("") } From 0985e3ab8ae6463b00781ed1ae11e28cb3ffbb14 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 21:22:49 +0200 Subject: [PATCH 226/325] Update RegisterComponent.kt to work with new RegisterViewModel --- .../compose/register/RegisterComponent.kt | 270 ++++++++++++++++-- 1 file changed, 253 insertions(+), 17 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt index 0dd246e8..fae09b44 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt @@ -2,31 +2,267 @@ package de.hsfl.budgetBinder.compose.register import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.User +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.viewmodel.auth.register.RegisterViewModel +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.register.RegisterEvent +import de.hsfl.budgetBinder.presentation.viewmodel.register.RegisterViewModel import di +import kotlinx.coroutines.flow.collectLatest +import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.dom.* import org.kodein.di.instance @Composable -fun RegisterComponent(screenState: MutableState) { - /*al scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - val registerUseCase: RegisterUseCase by di.instance() - val loginUseCase: LoginUseCase by di.instance() - val getMyUserUseCase : GetMyUserUseCase by di.instance() - val viewModel = RegisterViewModel(registerUseCase,loginUseCase,getMyUserUseCase, scope) - val viewState = viewModel.state.collectAsState(scope)*/ - val scope = rememberCoroutineScope() +fun RegisterComponent() { val viewModel: RegisterViewModel by di.instance() - val viewState = viewModel.state.collectAsState(scope.coroutineContext) + val firstNameTextState = viewModel.firstNameText.collectAsState() + val lastNameTextState = viewModel.lastNameText.collectAsState() + val emailTextState = viewModel.emailText.collectAsState() + val passwordTextState = viewModel.passwordText.collectAsState() + val confirmedPasswordTextState = viewModel.confirmedPasswordText.collectAsState() + val loadingState = remember { mutableStateOf(false) } + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> { + // TODO: Refactor this, it's working but ahh + loadingState.value = true + } + else -> loadingState.value = false + } + } + } + if (loadingState.value) { + Text("Loading") + //TODO: LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) + } + //Body + Header( + attrs = { + classes("mdc-top-app-bar") + } + ) { + Div( + attrs = { + classes("mdc-top-app-bar__row") + } + ) { + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") + } + ) { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + } + ) + Span( + attrs = { + classes("mdc-top-app-bar__title") + } + ) { + Text("Budget-Binder") + } + } + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") + } + ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(RegisterEvent.OnLoginScreen) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Login Instead") + } + } + } + } + } - RegisterView( - state = viewState, - onRegisterButtonPressed = { firstName, lastName, email, password -> - viewModel._register(User.In(firstName,lastName,email,password)) - }, - onChangeToLogin = { screenState.value = Screen.Login } - ) + MainFlexContainer { + // -- Register Form -- + H1 { Text(" Register") } + Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit + this.addEventListener("submit") { + console.log("$firstNameTextState, $lastNameTextState, $emailTextState, $passwordTextState") + viewModel.onEvent(RegisterEvent.OnRegister) + it.preventDefault() + } + } + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Firstname") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(firstNameTextState.value.firstName) + onInput { + viewModel.onEvent(RegisterEvent.EnteredFirstname(it.value)) + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Lastname") } + Input( + type = InputType.Text + ) { + classes("mdc-text-field__input") + value(lastNameTextState.value.firstName) + onInput { + viewModel.onEvent(RegisterEvent.EnteredLastname(it.value)) + } + } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Email") } + EmailInput(value = emailTextState.value.email, + attrs = { + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(RegisterEvent.EnteredEmail(it.value)) + + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Password") } + PasswordInput(value = passwordTextState.value.password, + attrs = { + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(RegisterEvent.EnteredPassword(it.value)) + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + } + } } From 0b3696daee2d91dcd0fce4e005287af44f6a657f Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 21:23:30 +0200 Subject: [PATCH 227/325] Delete previously used RegisterView (Now part of RegisterComponent --- .../compose/register/RegisterView.kt | 264 ------------------ 1 file changed, 264 deletions(-) delete mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt deleted file mode 100644 index 4e7924bf..00000000 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterView.kt +++ /dev/null @@ -1,264 +0,0 @@ -package de.hsfl.budgetBinder.compose.register - - -import androidx.compose.runtime.* -import de.hsfl.budgetBinder.compose.MainFlexContainer -import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.attributes.InputType -import org.jetbrains.compose.web.css.flex -import org.jetbrains.compose.web.css.percent -import org.jetbrains.compose.web.css.width -import org.jetbrains.compose.web.dom.* - -@Composable -fun RegisterView( - state: State, - onRegisterButtonPressed: (firstName: String, lastName: String, email: String, password: String) -> Unit, - onChangeToLogin: () -> Unit -) { - var firstNameTextFieldState by remember { mutableStateOf("") } - var lastNameTextFieldState by remember { mutableStateOf("") } - var emailTextFieldState by remember { mutableStateOf("") } - var passwordTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } - - Header( - attrs = { - classes("mdc-top-app-bar") - } - ) { - Div( - attrs = { - classes("mdc-top-app-bar__row") - } - ) { - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") - } - ) { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - } - ) - Span( - attrs = { - classes("mdc-top-app-bar__title") - } - ) { - Text("Budget-Binder") - } - } - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") - } - ) { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToLogin() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Login Instead") - } - } - } - } - } - - MainFlexContainer { - // -- Register Form -- - H1 { Text(" Register") } - Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit - this.addEventListener("submit") { - console.log("$firstNameTextFieldState, $lastNameTextFieldState, $emailTextFieldState, $passwordTextFieldState") - onRegisterButtonPressed( - firstNameTextFieldState, - lastNameTextFieldState, - emailTextFieldState, - passwordTextFieldState - ) - it.preventDefault() - } - } - ) { - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Firstname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(firstNameTextFieldState) - onInput { - firstNameTextFieldState = it.value - } - } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Lastname") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(lastNameTextFieldState) - onInput { - lastNameTextFieldState = it.value - } - } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Email") } - EmailInput(value = emailTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - emailTextFieldState = it.value - - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - // -- Register Request Management -- - when (viewState) { - is UiState.Success<*> -> { - onChangeToLogin() - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - else -> {} - } - } - } -} \ No newline at end of file From a17598a41acdb027e67fdd98c356d4f4a976c3d6 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 21:49:11 +0200 Subject: [PATCH 228/325] Update LoginComponent to work with new LoginViewModel, change Router accordingly --- .../de/hsfl/budgetBinder/compose/Router.kt | 23 ++- .../compose/login/LoginComponent.kt | 192 ++++++++++++++++-- .../src/jsMain/kotlin/main.kt | 3 +- 3 files changed, 193 insertions(+), 25 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 94a6372f..dd87a630 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -2,6 +2,8 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.rememberCoroutineScope import de.hsfl.budgetBinder.compose.category.CategoryComponent import de.hsfl.budgetBinder.compose.dashboard.DashboardComponent import de.hsfl.budgetBinder.compose.entry.EntryComponent @@ -9,17 +11,24 @@ import de.hsfl.budgetBinder.compose.login.LoginComponent import de.hsfl.budgetBinder.compose.register.RegisterComponent import de.hsfl.budgetBinder.compose.settings.SettingsComponent import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.flow.RouterFlow +import di +import org.jetbrains.compose.web.dom.Text +import org.kodein.di.instance @Composable -fun Router(screenState: MutableState) { +fun Router() { + val scope = rememberCoroutineScope() + val routerFlow: RouterFlow by di.instance() + val screenState = routerFlow.state.collectAsState(scope.coroutineContext) when (screenState.value) { is Screen.Welcome -> {} - is Screen.Register -> RegisterComponent(screenState = screenState) - is Screen.Login -> LoginComponent(screenState = screenState) - is Screen.Dashboard -> DashboardComponent(screenState = screenState) - is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) - is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) + is Screen.Register -> RegisterComponent() + is Screen.Login -> LoginComponent() + is Screen.Dashboard -> Text("Dashboard")//DashboardComponent() + //is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) + //is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) + //is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) else -> {} } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt index ecd10e54..59d859f5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt @@ -1,29 +1,189 @@ package de.hsfl.budgetBinder.compose.login import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.viewmodel.auth.login.LoginViewModel +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginEvent +import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginViewModel import di +import kotlinx.coroutines.flow.collectLatest +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.css.width +import org.jetbrains.compose.web.dom.* import org.kodein.di.compose.withDI import org.kodein.di.instance @Composable -fun LoginComponent(screenState: MutableState) = withDI(di) { - /*val scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - val loginUseCase: LoginUseCase by di.instance() - val getMyUserUseCase : GetMyUserUseCase by di.instance() - val viewModel = LoginViewModel(scope,loginUseCase, getMyUserUseCase) - val viewState = viewModel.state.collectAsState(scope)*/ +fun LoginComponent() { val scope = rememberCoroutineScope() val viewModel: LoginViewModel by di.instance() - val viewState = viewModel.state.collectAsState(scope) + val emailTextState = viewModel.emailText.collectAsState(scope.coroutineContext) + val passwordTextState = viewModel.passwordText.collectAsState(scope.coroutineContext) + val loadingState = remember { mutableStateOf(false) } - LoginView( - state = viewState, - onLoginButtonPressed = { email, password -> - viewModel._login(email, password) - }, - onLoginSuccess = { screenState.value = Screen.Dashboard }, - onChangeToRegister = { screenState.value = Screen.Register } - ) + + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> loadingState.value = true + else -> loadingState.value = false + } + } + } + + if (loadingState.value) { + Text("Loading") + //LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) + } + //Body + Header( + attrs = { + classes("mdc-top-app-bar") + } + ) { + Div( + attrs = { + classes("mdc-top-app-bar__row") + } + ) { + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") + } + ) { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + } + ) + Span( + attrs = { + classes("mdc-top-app-bar__title") + } + ) { + Text("Budget-Binder") + } + } + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") + } + ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(LoginEvent.OnRegisterScreen) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Register Instead") + } + } + } + } + } + + MainFlexContainer { + // -- Login Form -- + H1 { Text(" Login") } + Form( + attrs = { + this.addEventListener("submit") { + console.log("$emailTextState, $passwordTextState") + viewModel.onEvent(LoginEvent.OnLogin) + it.preventDefault() + } + } + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Email") } + EmailInput(value = emailTextState.value.email, + attrs = { + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(LoginEvent.EnteredEmail(it.value)) + + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Password") } + PasswordInput(value = passwordTextState.value.password, + attrs = { + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(LoginEvent.EnteredPassword(it.value)) + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + } + } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt index bdeb7a75..69ba53a0 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt @@ -19,6 +19,5 @@ val di = kodein(ktorEngine = Js.create()) @Composable fun App() = withDI(di) { - val screenState = remember { mutableStateOf(Screen.Login) } - Router(screenState = screenState) + Router() } From b8958d3f08727798766f8e2e22bf09f888d05aeb Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 22:05:27 +0200 Subject: [PATCH 229/325] Remove DashboardView and put content in DashboardComponent. Fix DashboardData and SwipeContainer --- .../de/hsfl/budgetBinder/compose/Router.kt | 2 +- .../compose/dashboard/DashboardComponent.kt | 189 ++++++++++-- .../compose/dashboard/DashboardView.kt | 271 ------------------ 3 files changed, 170 insertions(+), 292 deletions(-) delete mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index dd87a630..eb3c6d19 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -25,7 +25,7 @@ fun Router() { is Screen.Welcome -> {} is Screen.Register -> RegisterComponent() is Screen.Login -> LoginComponent() - is Screen.Dashboard -> Text("Dashboard")//DashboardComponent() + is Screen.Dashboard -> DashboardComponent() //is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) //is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) //is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 0881187e..2ae30c30 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -1,32 +1,181 @@ package de.hsfl.budgetBinder.compose.dashboard import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.FeedbackSnackbar +import de.hsfl.budgetBinder.compose.Icon +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.category.BudgetBar +import de.hsfl.budgetBinder.compose.entry.EntryList +import de.hsfl.budgetBinder.compose.entry.entriesFromCategory +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel import di +import kotlinx.coroutines.flow.collectLatest +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* import org.kodein.di.instance @Composable fun DashboardComponent(screenState: MutableState) { - //val scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - val scope = rememberCoroutineScope() - /*val di = localDI() - val getAllEntriesUseCase: GetAllEntriesUseCase by di.instance() - val getAllCategoriesUseCase: GetAllCategoriesUseCase by di.instance() - val dashboardViewModel = DashboardViewModel(getAllEntriesUseCase,getAllCategoriesUseCase, scope) - val categoriesViewState = dashboardViewModel.categoriesState.collectAsState(scope) - val entriesViewState = dashboardViewModel.entriesState.collectAsState(scope)*/ - val viewModel: DashboardViewModel by di.instance() - val categoriesViewState = viewModel.categoriesState.collectAsState(scope.coroutineContext) - val entriesViewState = viewModel.entriesState.collectAsState(scope.coroutineContext) - - DashboardView( - categoriesState = categoriesViewState, - entriesState = entriesViewState, - onCategorySummaryButton = { screenState.value = Screen.CategorySummary}, - onSettingsButton = {screenState.value = Screen._Settings}, - onEntryCreateButton = {categoryList -> screenState.value = Screen.EntryCreate(categoryList)}, - onEntryOverviewButton = {id -> screenState.value = Screen.EntryOverview(id)} - ) + val entryList = viewModel.entryListState.collectAsState() + val focusedCategory = viewModel.focusedCategoryState.collectAsState() + val totalSpendBudget = viewModel.spendBudgetOnCurrentCategory.collectAsState() + val olderEntries = viewModel.oldEntriesMapState.collectAsState() + val loadingState = remember { mutableStateOf(false) } + // val scaffoldState = rememberScaffoldState() + + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> loadingState.value = true + is UiEvent.HideSuccess -> loadingState.value = false + else -> loadingState.value = false + } + } + } + //TODO: TOPBAR + MainFlexContainer { + Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id) } } + CreateNewEntryButton({ onEntryCreateButton(categoryList) }) + //Process new Category Data + when (categoriesViewState) { + is UiState.Success<*> -> { + //Updates Data + // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot + when (val element = (categoriesViewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + categoryList = it + } + } + } + } + } + is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + //Process new Entry Data + when (entriesViewState) { + is UiState.Success<*> -> { + //Updates Data + when (val element = (entriesViewState as UiState.Success<*>).element) { + is List<*> -> { + element.filterIsInstance() + .let { + if (it.size == element.size) { + entryList = it + } + } + } + } + } + is UiState.Error -> { + FeedbackSnackbar((entriesViewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() + } + } + } + + + +} + +@Composable +fun DashboardData( + focusedCategory: Category, + totalSpendBudget: Float, + totalBudget: Float, + hasPrev: Boolean, + hasNext: Boolean, + onPrevClicked: () -> Unit, + onNextClicked: () -> Unit +) { + SwipeContainer ( + hasPrev, hasNext, onPrevClicked, onNextClicked + ){ + BudgetBar(categoryList[focusedCategory], filteredEntryList) + } } + + +@Composable +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { + Div (attrs = {style { + display(DisplayStyle.Flex) + justifyContent(JustifyContent.FlexEnd) + }}) { + Button(attrs = { + classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) + onClick { onEntryCreateButton() } + }) { + Div(attrs = { classes("mdc-fab__ripple") }) + Icon("add") + Div(attrs = { classes("mdc-fab__touch") }) + } + } +} + +@Composable +fun SwipeContainer( + hasPrev: Boolean, + hasNext: Boolean, + onPrevClicked: () -> Unit, + onNextClicked: () -> Unit, + content: @Composable () -> Unit +) { + Div( + attrs = { + classes(AppStylesheet.flexContainer) + }) { + Div(attrs = { + if(hasPrev) { + classes(AppStylesheet.imageFlexContainer, "mdc-button") + onClick { onPrevClicked() } + } + else{ + classes(AppStylesheet.imageFlexContainer) + style{ + paddingLeft(8.px) + paddingRight(8.px) + } + } + }){ + if(hasPrev) Icon("arrow_back_ios_new") + } + Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) + { + content() + } + Div(attrs = { + if(hasNext) { + classes(AppStylesheet.imageFlexContainer, "mdc-button") + onClick { onNextClicked() } + } + else{ + classes(AppStylesheet.imageFlexContainer) + style{ + paddingLeft(8.px) + paddingRight(8.px) + } + } + }) { + if(hasNext) Icon("arrow_forward_ios_new") + } + } +} + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt deleted file mode 100644 index 0ec060a3..00000000 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardView.kt +++ /dev/null @@ -1,271 +0,0 @@ -package de.hsfl.budgetBinder.compose.dashboard - -import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.Entry -import de.hsfl.budgetBinder.compose.FeedbackSnackbar -import de.hsfl.budgetBinder.compose.Icon -import de.hsfl.budgetBinder.compose.MainFlexContainer -import de.hsfl.budgetBinder.compose.category.BudgetBar -import de.hsfl.budgetBinder.compose.entry.EntryList -import de.hsfl.budgetBinder.compose.entry.entriesFromCategory -import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.dom.* - - -@Composable -fun DashboardView( - categoriesState: State, - entriesState: State, - onCategorySummaryButton: () -> Unit, - onSettingsButton: () -> Unit, - onEntryCreateButton: (categoryList: List) -> Unit, - onEntryOverviewButton: (id:Int) -> Unit -) { - val categoriesViewState by remember { categoriesState } - val entriesViewState by remember { entriesState } - var categoryList by remember { mutableStateOf>(emptyList()) } - var entryList by remember { mutableStateOf>(emptyList()) } - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { } - } - ) - }, navButtons = { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onCategorySummaryButton() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onSettingsButton() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Settings") - } - } - }) - - MainFlexContainer { - - Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id) } } - CreateNewEntryButton({ onEntryCreateButton(categoryList) }) - //Process new Category Data - when (categoriesViewState) { - is UiState.Success<*> -> { - //Updates Data - // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot - when (val element = (categoriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - categoryList = it - } - } - } - } - } - is UiState.Error -> { - FeedbackSnackbar((entriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } - //Process new Entry Data - when (entriesViewState) { - is UiState.Success<*> -> { - //Updates Data - when (val element = (entriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - entryList = it - } - } - } - } - } - is UiState.Error -> { - FeedbackSnackbar((entriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } - } - - - -} - -@Composable -fun DashboardData(categoryList: List, entryList: List, onEntry: (id:Int) -> Unit) { - console.log("Category $categoryList and Entry $entryList") - var focusedCategory by remember { mutableStateOf(-1) } //Variable from -1 (all) to categoryList.size - console.log("Focus:${focusedCategory}") - fun changeFocusedCategory(increase: Boolean): Int { - var newFocus = focusedCategory - if (increase) newFocus++ - else newFocus-- - newFocus = - when { - (newFocus) < -1 -> -1 - (newFocus > categoryList.size) -> categoryList.size - else -> { - newFocus - } - } - return newFocus - } - - //if (entryList.isNotEmpty()) { - when (focusedCategory) { - //Overall View - -1 -> { - var everyBudgetTogether = 0f - for (category in categoryList) { - everyBudgetTogether += category.budget - } - val fakeOverallBudget = - Category(0, "Overall", "111111", Category.Image.DEFAULT, everyBudgetTogether) - SwipeContainer ( - content = {BudgetBar(fakeOverallBudget, entryList)}, //Every CategoryBudget with every Entry's Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)}, - leftOn = false - ) - - EntryList(entryList, categoryList, onEntry) //List of Every Entry - } - //Normal Category View - in categoryList.indices -> { - val filteredEntryList = - entriesFromCategory(entryList, categoryList[focusedCategory].id) - SwipeContainer ( - content = {BudgetBar(categoryList[focusedCategory], filteredEntryList)}, //Every Category with their Entries' Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)} - ) - EntryList( - filteredEntryList, - listOf(categoryList[focusedCategory]), - onEntry - ) //Only gives CategoryData of selected category, as everything else seems unnecessary - } - - //No Category View - categoryList.size -> { - val filteredEntryList = entriesFromCategory(entryList, null) - val fakeNoCategory = - Category(0, "No Category", "111111", Category.Image.DEFAULT, 0f) - SwipeContainer ( - content = {BudgetBar(fakeNoCategory, filteredEntryList)}, //"No Category" with their Entries' Budget - onFocusCategoryChange = {focusedCategory = changeFocusedCategory(it)}, - rightOn = false - ) - EntryList( - filteredEntryList, - emptyList(), - onEntry - ) //Needs no categoryList, as they have no category - } - } - /*} else { - Div(attrs = { - classes( - "mdc-typography--headline5", - AppStylesheet.text - ) - }) { Text("No data to load") } - }*/ - -} - - -@Composable -fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { - Div (attrs = {style { - display(DisplayStyle.Flex) - justifyContent(JustifyContent.FlexEnd) - }}) { - Button(attrs = { - classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) - onClick { onEntryCreateButton() } - }) { - Div(attrs = { classes("mdc-fab__ripple") }) - Icon("add") - Div(attrs = { classes("mdc-fab__touch") }) - } - } -} - -@Composable -fun SwipeContainer(content: @Composable () -> Unit, onFocusCategoryChange: (Boolean) -> Unit, leftOn: Boolean = true, rightOn:Boolean = true) { - Div( - attrs = { - classes(AppStylesheet.flexContainer) - }) { - Div(attrs = { - if(leftOn) { - classes(AppStylesheet.imageFlexContainer, "mdc-button") - onClick { onFocusCategoryChange(false) } - } - else{ - classes(AppStylesheet.imageFlexContainer) - style{ - paddingLeft(8.px) - paddingRight(8.px) - } - } - }){ - if(leftOn) Icon("arrow_back_ios_new") - } - Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) - { - content() - } - Div(attrs = { - if(rightOn) { - classes(AppStylesheet.imageFlexContainer, "mdc-button") - onClick { onFocusCategoryChange(true) } - } - else{ - classes(AppStylesheet.imageFlexContainer) - style{ - paddingLeft(8.px) - paddingRight(8.px) - } - } - }) { - if(rightOn) Icon("arrow_forward_ios_new") - } - } -} - - - - - From 3b09d480ffc547a8d09bf63ba058f966ffa1bca6 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 22:19:28 +0200 Subject: [PATCH 230/325] Update Dashboards BudgetBar --- .../compose/category/CategoryComponent.kt | 40 +++++------ .../compose/dashboard/DashboardComponent.kt | 70 +++++-------------- 2 files changed, 36 insertions(+), 74 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 34e20df4..44885fcb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -92,56 +92,54 @@ fun categoryIdToCategory(category_id: Int?, categoryList: List): Categ @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun BudgetBar(category: Category, entryList: List) { - //category = Category we want to show - //entryList = List of entries +fun BudgetBar( + focusedCategory: Category, + totalSpendBudget: Float, + totalBudget: Float, +) { //width and height are for aspect ratio - tries to fill out wherever its in, so its more like val width = 20 val height = 2 - val budget = category.budget - var usedBudget = 0f - for (entry in entryList) { - usedBudget -= entry.amount //Money spent negative, so we want to add the negative amount (- - = +)to usedBudget - } + H1(attrs = { classes("mdc-typography--headline4", AppStylesheet.flexContainer) }) { - CategoryImageToIcon(category.image) - Text("${category.name} - Budget") + CategoryImageToIcon(focusedCategory.image) + Text("${focusedCategory.name} - Budget") } Div { - if (usedBudget <= budget && budget > 0) { //Normal not Spent Budget + if (totalSpendBudget <= totalBudget && totalBudget > 0) { //Normal not Spent Budget //Money Text MoneyTextDiv { Div(attrs = { classes("mdc-typography--headline5") - }) { Text(usedBudget.toString() + "€") } - Div(attrs = { classes("mdc-typography--headline5") }) { Text(budget.toString() + "€") } + }) { Text(totalSpendBudget.toString() + "€") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(totalBudget.toString() + "€") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { attr("fill", Color.lightgray.toString()) }) - if (0 < usedBudget) // If there is used budget, draw it - Rect(x = 0, y = 0, width = usedBudget / budget * width, height = height, { - attr("fill", "#" + category.color) + if (0 < totalSpendBudget) // If there is used budget, draw it + Rect(x = 0, y = 0, width = totalSpendBudget/ totalBudget * width, height = height, { + attr("fill", "#" + focusedCategory.color) }) } - } else if (usedBudget > budget && budget > 0) { //Over Budget + } else if (totalSpendBudget> totalBudget && totalBudget > 0) { //Over Budget MoneyTextDiv { - Div(attrs = { classes("mdc-typography--headline5") }) { Text("Budget limit for " + category.name + " reached! " + usedBudget.toString() + "€ of " + budget.toString() + "€ Budget spent") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text("Budget limit for " + focusedCategory.name + " reached! " + totalSpendBudget.toString() + "€ of " + totalBudget.toString() + "€ Budget spent") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { attr("fill", "#b00020") }) } - } else if (budget <= 0f) { //No Category View or other unpredictable case (or no categories, overall screen) + } else if (totalBudget <= 0f) { //No Category View or other unpredictable case (or no categories, overall screen) MoneyTextDiv { - Div(attrs = { classes("mdc-typography--headline5") }) { Text(usedBudget.toString() + "€ spent") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(totalSpendBudget.toString() + "€ spent") } } Svg(viewBox = "0 0 $width $height") { Rect(x = 0, y = 0, width = width, height = height, { - attr("fill", "#" + category.color) + attr("fill", "#" + focusedCategory.color) }) } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 2ae30c30..8924fc9c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -14,6 +14,7 @@ import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiEvent import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEvent import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel import di import kotlinx.coroutines.flow.collectLatest @@ -22,7 +23,7 @@ import org.jetbrains.compose.web.dom.* import org.kodein.di.instance @Composable -fun DashboardComponent(screenState: MutableState) { +fun DashboardComponent() { val viewModel: DashboardViewModel by di.instance() val entryList = viewModel.entryListState.collectAsState() val focusedCategory = viewModel.focusedCategoryState.collectAsState() @@ -42,57 +43,20 @@ fun DashboardComponent(screenState: MutableState) { } //TODO: TOPBAR MainFlexContainer { - Div { DashboardData(categoryList, entryList) { id -> onEntryOverviewButton(id) } } - CreateNewEntryButton({ onEntryCreateButton(categoryList) }) - //Process new Category Data - when (categoriesViewState) { - is UiState.Success<*> -> { - //Updates Data - // https://stackoverflow.com/questions/36569421/kotlin-how-to-work-with-list-casts-unchecked-cast-kotlin-collections-listkot - when (val element = (categoriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - categoryList = it - } - } - } - } - } - is UiState.Error -> { - FeedbackSnackbar((entriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + Div { + DashboardData( + focusedCategory = focusedCategory.value.category, + totalSpendBudget = totalSpendBudget.value.spendBudgetOnCurrentCategory, + totalBudget = focusedCategory.value.category.budget, + hasPrev = focusedCategory.value.hasPrev, + hasNext = focusedCategory.value.hasNext, + onPrevClicked = { viewModel.onEvent(DashboardEvent.OnPrevCategory) }, + onNextClicked = { viewModel.onEvent(DashboardEvent.OnNextCategory) } + ) } - //Process new Entry Data - when (entriesViewState) { - is UiState.Success<*> -> { - //Updates Data - when (val element = (entriesViewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - entryList = it - } - } - } - } - } - is UiState.Error -> { - FeedbackSnackbar((entriesViewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } - } - - + CreateNewEntryButton(viewModel.onEvent(DashboardEvent.OnEntryCreate)) + } } @Composable @@ -108,20 +72,20 @@ fun DashboardData( SwipeContainer ( hasPrev, hasNext, onPrevClicked, onNextClicked ){ - BudgetBar(categoryList[focusedCategory], filteredEntryList) + BudgetBar(focusedCategory,totalSpendBudget,totalBudget) } } @Composable -fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { +fun CreateNewEntryButton(onEntryCreateButton: Unit) { Div (attrs = {style { display(DisplayStyle.Flex) justifyContent(JustifyContent.FlexEnd) }}) { Button(attrs = { classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) - onClick { onEntryCreateButton() } + onClick { onEntryCreateButton } }) { Div(attrs = { classes("mdc-fab__ripple") }) Icon("add") From 6353e029f435556a125e20b2743e529143cc84b6 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 22:41:37 +0200 Subject: [PATCH 231/325] Fix bug where dashboard automatically switches to EntryCreateScreen --- .../kotlin/de/hsfl/budgetBinder/compose/Router.kt | 11 +++++++---- .../compose/dashboard/DashboardComponent.kt | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index eb3c6d19..273337d0 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -21,14 +21,17 @@ fun Router() { val scope = rememberCoroutineScope() val routerFlow: RouterFlow by di.instance() val screenState = routerFlow.state.collectAsState(scope.coroutineContext) + console.log(screenState.value) when (screenState.value) { is Screen.Welcome -> {} is Screen.Register -> RegisterComponent() is Screen.Login -> LoginComponent() is Screen.Dashboard -> DashboardComponent() - //is Screen.Settings, is Screen.SettingsChangeUserData -> SettingsComponent(screenState = screenState) - //is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> CategoryComponent(screenState = screenState) - //is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> EntryComponent(screenState = screenState) - else -> {} + is Screen.Settings, is Screen.SettingsChangeUserData -> Text("Settings")//SettingsComponent(screenState = screenState) + is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister ->Text("Old Category") //CategoryComponent(screenState = screenState) + is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> Text("Old Entry")//EntryComponent(screenState = screenState) + is Screen.Category -> Text("New Category") + is Screen.Entry -> Text("New Entry") + else -> {Text("No known Screen! Check if the screen you're trying to reach is in the ScreenRouter")} } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 8924fc9c..1f56cc92 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -55,7 +55,7 @@ fun DashboardComponent() { ) } - CreateNewEntryButton(viewModel.onEvent(DashboardEvent.OnEntryCreate)) + CreateNewEntryButton { viewModel.onEvent(DashboardEvent.OnEntryCreate) } } } @@ -78,14 +78,14 @@ fun DashboardData( @Composable -fun CreateNewEntryButton(onEntryCreateButton: Unit) { +fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { Div (attrs = {style { display(DisplayStyle.Flex) justifyContent(JustifyContent.FlexEnd) }}) { Button(attrs = { classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) - onClick { onEntryCreateButton } + onClick { onEntryCreateButton() } }) { Div(attrs = { classes("mdc-fab__ripple") }) Icon("add") From be0922b696f1f19407799ae53ff79c7f7a0be107 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 22:58:27 +0200 Subject: [PATCH 232/325] Show current entries on Dashboard in their corresponding categories --- .../compose/dashboard/DashboardComponent.kt | 79 +++++++++++++++++-- .../compose/entry/EntryComponent.kt | 49 ------------ 2 files changed, 71 insertions(+), 57 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 1f56cc92..a27e8100 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -2,25 +2,22 @@ package de.hsfl.budgetBinder.compose.dashboard import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.Entry -import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.Icon import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.category.BudgetBar -import de.hsfl.budgetBinder.compose.entry.EntryList -import de.hsfl.budgetBinder.compose.entry.entriesFromCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.UiEvent -import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEntryState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEvent +import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.kodein.di.instance +import kotlin.math.absoluteValue @Composable fun DashboardComponent() { @@ -53,8 +50,13 @@ fun DashboardComponent() { onPrevClicked = { viewModel.onEvent(DashboardEvent.OnPrevCategory) }, onNextClicked = { viewModel.onEvent(DashboardEvent.OnNextCategory) } ) + EntryList(entryList = entryList.value.entryList, + oldEntries = olderEntries.value, + onItemClicked = { viewModel.onEvent(DashboardEvent.OnEntry(it)) }, + onLoadMore = { viewModel.onEvent(DashboardEvent.OnLoadMore) }, + onEntryDelete = { viewModel.onEvent(DashboardEvent.OnEntryDelete(it)) } + ) } - CreateNewEntryButton { viewModel.onEvent(DashboardEvent.OnEntryCreate) } } } @@ -143,3 +145,64 @@ fun SwipeContainer( } } + +//Should be put in own File +@Composable +fun EntryListElement( + entry: DashboardEntryState, + onItemClicked: (Int) -> Unit, + onEntryDelete: (Int) -> Unit +) { + Div(attrs = { + classes("mdc-card", "mdc-card--outlined", AppStylesheet.entryListElement) + onClick { onItemClicked(entry.entry.id) } + }) { + CategoryImageToIcon(entry.categoryImage) + Div(attrs = { classes(AppStylesheet.entryListElementText) }) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text(entry.entry.name) } + } + Div(attrs = { classes(AppStylesheet.imageFlexContainer) }) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.moneyText + ) + }) { Text(amountToString(entry.entry.amount)) } + } + } +} + +fun amountToString(amount: Float): String { + //This whole thing just so it's "- 10 €" and not "-10 €" + val x = if (amount < 0) "-" else "" + return "$x ${amount.absoluteValue} €" +} +//TODO: Load Old Data and old Entries +@Composable +fun EntryList( + entryList: List, + oldEntries: Map, + onItemClicked: (Int) -> Unit, + onLoadMore: () -> Unit, + onEntryDelete: (Int) -> Unit + +) { + if (entryList.isEmpty()) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text("This category has no entries. You can create an new entry.") } + } else { + for (entry in entryList) { + EntryListElement(entry, onItemClicked, onEntryDelete) + } + } +} + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 0e704a15..1b5e86f1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -77,54 +77,5 @@ fun EntryComponent(screenState: MutableState) { } } -//Should be put in own File -@Composable -fun EntryListElement(entry: Entry, categoryList: List, onEntry: (id: Int) -> Unit) { - Div(attrs = { - classes("mdc-card", "mdc-card--outlined", AppStylesheet.entryListElement) - onClick { onEntry(entry.id) } - }) { - CategoryImageToIcon(categoryIdToCategory(entry.category_id, categoryList).image) - Div(attrs = { classes(AppStylesheet.entryListElementText) }) { - Div(attrs = { - classes( - "mdc-typography--headline5", - AppStylesheet.text - ) - }) { Text(entry.name) } - } - Div(attrs = { classes(AppStylesheet.imageFlexContainer) }) { - Div(attrs = { - classes( - "mdc-typography--headline5", - AppStylesheet.moneyText - ) - }) { Text(amountToString(entry.amount)) } - } - } -} - -fun amountToString(amount: Float): String { - //This whole thing just so it's "- 10 €" and not "-10 €" - val x = if (amount < 0) "-" else "" - return "$x ${amount.absoluteValue} €" -} - -@Composable -fun EntryList(list: List, categoryList: List, onEntry: (id: Int) -> Unit) { - if (list.isEmpty()) { - Div(attrs = { - classes( - "mdc-typography--headline5", - AppStylesheet.text - ) - }) { Text("No Entries in this category") } - } else { - for (entry in list) { - EntryListElement(entry, categoryList, onEntry) - } - } -} - fun entriesFromCategory(list: List, category_id: Int?): List = list.filter { it.category_id == category_id } From 7328d2cdcecfc7e0ea41d3c02e87b12a27231935 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 23:49:56 +0200 Subject: [PATCH 233/325] Add basic logic to load older entries --- .../compose/dashboard/DashboardComponent.kt | 103 +++++++++++------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index a27e8100..acf2710e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -12,6 +12,7 @@ import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEntryState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEvent import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginEvent import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.* @@ -27,7 +28,7 @@ fun DashboardComponent() { val totalSpendBudget = viewModel.spendBudgetOnCurrentCategory.collectAsState() val olderEntries = viewModel.oldEntriesMapState.collectAsState() val loadingState = remember { mutableStateOf(false) } - // val scaffoldState = rememberScaffoldState() + // val scaffoldState = rememberScaffoldState() LaunchedEffect(key1 = true) { viewModel.eventFlow.collectLatest { event -> @@ -71,20 +72,22 @@ fun DashboardData( onPrevClicked: () -> Unit, onNextClicked: () -> Unit ) { - SwipeContainer ( + SwipeContainer( hasPrev, hasNext, onPrevClicked, onNextClicked - ){ - BudgetBar(focusedCategory,totalSpendBudget,totalBudget) + ) { + BudgetBar(focusedCategory, totalSpendBudget, totalBudget) } } @Composable fun CreateNewEntryButton(onEntryCreateButton: () -> Unit) { - Div (attrs = {style { - display(DisplayStyle.Flex) - justifyContent(JustifyContent.FlexEnd) - }}) { + Div(attrs = { + style { + display(DisplayStyle.Flex) + justifyContent(JustifyContent.FlexEnd) + } + }) { Button(attrs = { classes("mdc-fab", "mdc-fab--touch", AppStylesheet.newEntryButton) onClick { onEntryCreateButton() } @@ -109,44 +112,81 @@ fun SwipeContainer( classes(AppStylesheet.flexContainer) }) { Div(attrs = { - if(hasPrev) { + if (hasPrev) { classes(AppStylesheet.imageFlexContainer, "mdc-button") onClick { onPrevClicked() } - } - else{ + } else { classes(AppStylesheet.imageFlexContainer) - style{ + style { paddingLeft(8.px) paddingRight(8.px) } } - }){ - if(hasPrev) Icon("arrow_back_ios_new") + }) { + if (hasPrev) Icon("arrow_back_ios_new") } Div(attrs = { classes(AppStylesheet.budgetBarContainer) }) { content() } Div(attrs = { - if(hasNext) { + if (hasNext) { classes(AppStylesheet.imageFlexContainer, "mdc-button") onClick { onNextClicked() } - } - else{ + } else { classes(AppStylesheet.imageFlexContainer) - style{ + style { paddingLeft(8.px) paddingRight(8.px) } } }) { - if(hasNext) Icon("arrow_forward_ios_new") + if (hasNext) Icon("arrow_forward_ios_new") + } + } +} + +//TODO: Load Old Data and old Entries +@Composable +fun EntryList( + entryList: List, + oldEntries: Map, + onItemClicked: (Int) -> Unit, + onLoadMore: () -> Unit, + onEntryDelete: (Int) -> Unit + +) { + if (entryList.isEmpty()) { + Div(attrs = { + classes( + "mdc-typography--headline5", + AppStylesheet.text + ) + }) { Text("This category has no entries. You can create an new entry.") } + } else { + for (entry in entryList) { + EntryListElement(entry, onItemClicked, onEntryDelete) + } + Text("Older entries...") + for ((date, dashboardState) in oldEntries) { + Text(date) //TODO-WEB: Sticky? + for (entry in dashboardState.entryList) { + EntryListElement(entry, onItemClicked, onEntryDelete) + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { onLoadMore() } + } + ) { + Span(attrs = { classes("mdc-button__label") } + ) { Text("Load more Entries") } } } } -//Should be put in own File @Composable fun EntryListElement( entry: DashboardEntryState, @@ -182,27 +222,6 @@ fun amountToString(amount: Float): String { val x = if (amount < 0) "-" else "" return "$x ${amount.absoluteValue} €" } -//TODO: Load Old Data and old Entries -@Composable -fun EntryList( - entryList: List, - oldEntries: Map, - onItemClicked: (Int) -> Unit, - onLoadMore: () -> Unit, - onEntryDelete: (Int) -> Unit -) { - if (entryList.isEmpty()) { - Div(attrs = { - classes( - "mdc-typography--headline5", - AppStylesheet.text - ) - }) { Text("This category has no entries. You can create an new entry.") } - } else { - for (entry in entryList) { - EntryListElement(entry, onItemClicked, onEntryDelete) - } - } -} + From 2d7e1a760d36c92913a43f5db629c872d9e23c7c Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Mon, 20 Jun 2022 23:59:05 +0200 Subject: [PATCH 234/325] Add NavBar --- .../hsfl/budgetBinder/compose/Composables.kt | 36 ------ .../de/hsfl/budgetBinder/compose/NavBar.kt | 110 ++++++++++++++++++ 2 files changed, 110 insertions(+), 36 deletions(-) create mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 5451397c..d87c55c2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -36,42 +36,6 @@ fun MainFlexContainer(content: @Composable () -> Unit) { } } -@Composable -fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit) { - Header( - attrs = { - classes("mdc-top-app-bar") - } - ) { - Div( - attrs = { - classes("mdc-top-app-bar__row") - } - ) { - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") - } - ) { - logoButton() - Span( - attrs = { - classes("mdc-top-app-bar__title") - } - ) { - Text("Budget-Binder") - } - } - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") - } - ) { - navButtons() - } - } - } -} ///* Gives a material icon based on the icon name*/// diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt new file mode 100644 index 00000000..58219f78 --- /dev/null +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt @@ -0,0 +1,110 @@ +package de.hsfl.budgetBinder.compose + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerEvent +import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerViewModel +import di +import org.jetbrains.compose.web.dom.* +import org.kodein.di.instance + +//Top Navigation Bar +@Composable +fun NavBar(content: @Composable () -> Unit) { + val viewModel: NavDrawerViewModel by di.instance() + Header( + attrs = { + classes("mdc-top-app-bar") + } + ) { + Div( + attrs = { + classes("mdc-top-app-bar__row") + } + ) { + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") + } + ) { + Img( + src = "images/Logo.png", alt = "Logo", attrs = { + classes("mdc-icon-button", AppStylesheet.image) + onClick { viewModel.onEvent(NavDrawerEvent.OnDashboard) } + } + ) + Span( + attrs = { + classes("mdc-top-app-bar__title") + } + ) { + Text("Budget-Binder") + } + } + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") + } + ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(NavDrawerEvent.OnCreateEntry) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("New Entry") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(NavDrawerEvent.OnCategory) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Categories") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(NavDrawerEvent.OnSettings) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Settings") + } + } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + onClick { viewModel.onEvent(NavDrawerEvent.OnLogout) } + } + ) { + Span( + attrs = { + classes("mdc-button__label") + } + ) { + Text("Logout") + } + } + } + } + } + content() +} From 8f7c09bf00c171d2b3661e9eca63859dadec2c8e Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 00:04:13 +0200 Subject: [PATCH 235/325] Add new NavBar to Dashboard --- .../hsfl/budgetBinder/compose/Composables.kt | 37 +++++++++++++++++++ .../compose/dashboard/DashboardComponent.kt | 3 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index d87c55c2..fcc5331b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -36,6 +36,43 @@ fun MainFlexContainer(content: @Composable () -> Unit) { } } +@Deprecated("Use new NavBar instead! just write NavBar{} over your MainFlexContainer!") +@Composable +fun topBarMain(logoButton: @Composable () -> Unit, navButtons: @Composable () -> Unit) { + Header( + attrs = { + classes("mdc-top-app-bar") + } + ) { + Div( + attrs = { + classes("mdc-top-app-bar__row") + } + ) { + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") + } + ) { + logoButton() + Span( + attrs = { + classes("mdc-top-app-bar__title") + } + ) { + Text("Budget-Binder") + } + } + Section( + attrs = { + classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") + } + ) { + navButtons() + } + } + } +} ///* Gives a material icon based on the icon name*/// diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index acf2710e..d1ed8bc8 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.Icon import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.category.BudgetBar import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon @@ -39,7 +40,7 @@ fun DashboardComponent() { } } } - //TODO: TOPBAR + NavBar{} MainFlexContainer { Div { DashboardData( From 9cbab3aa94d18a6d619c23d1708eb58535de5019 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 00:07:50 +0200 Subject: [PATCH 236/325] Format files and remove unnecessary imports --- .../hsfl/budgetBinder/compose/Composables.kt | 16 +++++++++--- .../de/hsfl/budgetBinder/compose/NavBar.kt | 25 +++++++++++++++---- .../de/hsfl/budgetBinder/compose/Router.kt | 17 +++++++------ .../compose/dashboard/DashboardComponent.kt | 2 +- .../compose/login/LoginComponent.kt | 10 +++++--- .../src/jsMain/kotlin/main.kt | 1 - .../kotlin/de/hsfl/budgetBinder/Root.kt | 12 ++++++--- identifier.sqlite | 0 8 files changed, 57 insertions(+), 26 deletions(-) create mode 100644 identifier.sqlite diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index fcc5331b..ba902a66 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -32,7 +32,7 @@ fun MainFlexContainer(content: @Composable () -> Unit) { content() } } - Div(attrs = { classes(AppStylesheet.pufferFlexContainer)}) + Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) } } @@ -168,7 +168,10 @@ fun CategoryImagesToImageList( "mdc-icon-button", "mdc-button--raised" ) - else classes("mdc-image-list__image-aspect-container", "mdc-icon-button") + else classes( + "mdc-image-list__image-aspect-container", + "mdc-icon-button" + ) onClick { onClick(image); highlightImage.value = image } } ) { @@ -271,7 +274,12 @@ fun CategoryList( } @Composable -fun DeleteDialog(hidden: Boolean, buttonAction: () -> Unit, resetDialog: () -> Unit, content: @Composable () -> Unit) { +fun DeleteDialog( + hidden: Boolean, + buttonAction: () -> Unit, + resetDialog: () -> Unit, + content: @Composable () -> Unit +) { var hiddenValue by remember { mutableStateOf(hidden) } Div( attrs = { @@ -405,7 +413,7 @@ fun ChooseCategoryMenu( onClick { chosenCategory = category; getCategoryId(category.id) } }) { Span(attrs = { classes("mdc-list-item__ripple") }) { } - Span(attrs = { }) { Text(category.name) } + Span(attrs = { }) { Text(category.name) } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt index 58219f78..e3d7263a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt @@ -1,7 +1,6 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.Composable -import androidx.compose.runtime.rememberCoroutineScope import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerEvent import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerViewModel @@ -49,7 +48,11 @@ fun NavBar(content: @Composable () -> Unit) { ) { Button( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + classes( + "mdc-button", + "mdc-button--raised", + "mdc-top-app-bar__navigation-icon" + ) onClick { viewModel.onEvent(NavDrawerEvent.OnCreateEntry) } } ) { @@ -63,7 +66,11 @@ fun NavBar(content: @Composable () -> Unit) { } Button( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + classes( + "mdc-button", + "mdc-button--raised", + "mdc-top-app-bar__navigation-icon" + ) onClick { viewModel.onEvent(NavDrawerEvent.OnCategory) } } ) { @@ -77,7 +84,11 @@ fun NavBar(content: @Composable () -> Unit) { } Button( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + classes( + "mdc-button", + "mdc-button--raised", + "mdc-top-app-bar__navigation-icon" + ) onClick { viewModel.onEvent(NavDrawerEvent.OnSettings) } } ) { @@ -91,7 +102,11 @@ fun NavBar(content: @Composable () -> Unit) { } Button( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + classes( + "mdc-button", + "mdc-button--raised", + "mdc-top-app-bar__navigation-icon" + ) onClick { viewModel.onEvent(NavDrawerEvent.OnLogout) } } ) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 273337d0..b79632be 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -1,15 +1,11 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState import androidx.compose.runtime.collectAsState import androidx.compose.runtime.rememberCoroutineScope -import de.hsfl.budgetBinder.compose.category.CategoryComponent import de.hsfl.budgetBinder.compose.dashboard.DashboardComponent -import de.hsfl.budgetBinder.compose.entry.EntryComponent import de.hsfl.budgetBinder.compose.login.LoginComponent import de.hsfl.budgetBinder.compose.register.RegisterComponent -import de.hsfl.budgetBinder.compose.settings.SettingsComponent import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.flow.RouterFlow import di @@ -27,11 +23,16 @@ fun Router() { is Screen.Register -> RegisterComponent() is Screen.Login -> LoginComponent() is Screen.Dashboard -> DashboardComponent() - is Screen.Settings, is Screen.SettingsChangeUserData -> Text("Settings")//SettingsComponent(screenState = screenState) - is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister ->Text("Old Category") //CategoryComponent(screenState = screenState) - is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> Text("Old Entry")//EntryComponent(screenState = screenState) + is Screen.Settings, is Screen.SettingsChangeUserData + -> Text("Settings")//SettingsComponent(screenState = screenState) + is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister + -> Text("Old Category") //CategoryComponent(screenState = screenState) + is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview + -> Text("Old Entry")//EntryComponent(screenState = screenState) is Screen.Category -> Text("New Category") is Screen.Entry -> Text("New Entry") - else -> {Text("No known Screen! Check if the screen you're trying to reach is in the ScreenRouter")} + else -> { + Text("No known Screen! Check if the screen you're trying to reach is in the ScreenRouter") + } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index d1ed8bc8..8b34b215 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -40,7 +40,7 @@ fun DashboardComponent() { } } } - NavBar{} + NavBar {} MainFlexContainer { Div { DashboardData( diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt index 59d859f5..17a053fc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt @@ -1,10 +1,9 @@ package de.hsfl.budgetBinder.compose.login + import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiEvent -import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginEvent import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginViewModel import di @@ -12,7 +11,6 @@ import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* -import org.kodein.di.compose.withDI import org.kodein.di.instance @@ -74,7 +72,11 @@ fun LoginComponent() { ) { Button( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + classes( + "mdc-button", + "mdc-button--raised", + "mdc-top-app-bar__navigation-icon" + ) onClick { viewModel.onEvent(LoginEvent.OnRegisterScreen) } } ) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt index 69ba53a0..797d4749 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt @@ -2,7 +2,6 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.Router import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.di.kodein -import de.hsfl.budgetBinder.presentation.Screen import io.ktor.client.engine.js.* import org.jetbrains.compose.web.css.Style import org.jetbrains.compose.web.renderComposable diff --git a/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/Root.kt b/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/Root.kt index 0db8eb37..a0f27381 100644 --- a/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/Root.kt +++ b/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/Root.kt @@ -7,7 +7,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import de.hsfl.budgetBinder.common.User import de.hsfl.budgetBinder.di.kodein import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.flow.DataFlow @@ -36,12 +35,19 @@ fun App() = withDI(di) { is UiEvent.ShowLoading -> loadingState.value = true is UiEvent.ShowError -> { loadingState.value = false - scaffoldState.snackbarHostState.showSnackbar(message = event.msg, actionLabel = "Dismiss") + scaffoldState.snackbarHostState.showSnackbar( + message = event.msg, + actionLabel = "Dismiss" + ) } is UiEvent.ShowSuccess -> { loadingState.value = false - scaffoldState.snackbarHostState.showSnackbar(message = event.msg, actionLabel = "Dismiss") + scaffoldState.snackbarHostState.showSnackbar( + message = event.msg, + actionLabel = "Dismiss" + ) } + else -> {} } } } diff --git a/identifier.sqlite b/identifier.sqlite new file mode 100644 index 00000000..e69de29b From 1b1e1942865807d9006e52bd265c75b838ceae33 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 00:18:15 +0200 Subject: [PATCH 237/325] Fix Login (LoginViewModel isn't complete, add todo for it) --- .../presentation/viewmodel/auth/login/LoginViewModel.kt | 3 +++ .../de/hsfl/budgetBinder/compose/login/LoginComponent.kt | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/auth/login/LoginViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/auth/login/LoginViewModel.kt index 2d4799ee..a333b37f 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/auth/login/LoginViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/auth/login/LoginViewModel.kt @@ -55,6 +55,9 @@ class LoginViewModel( private fun validateInput() { if (validateEmail(email = emailText.value.email)) { + //TODO: Check what frontend this is opened from. + // Web -> super.login(...), + // everyone else -> toggleDialog() toggleDialog() } else { _emailText.value = emailText.value.copy(emailValid = false) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt index 17a053fc..316720bb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt @@ -99,7 +99,7 @@ fun LoginComponent() { attrs = { this.addEventListener("submit") { console.log("$emailTextState, $passwordTextState") - viewModel.onEvent(LoginEvent.OnLogin) + viewModel.onEvent(LoginEvent.OnServerUrlDialogConfirm) //TODO: Change to OnLogin as soon as LoginViewModel has corresponding logic it.preventDefault() } } From 8e68cddad6cf293aac7f42ba147c90a8aa46a532 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 00:25:15 +0200 Subject: [PATCH 238/325] Delete unused LoginView --- .../budgetBinder/compose/login/LoginView.kt | 181 ------------------ 1 file changed, 181 deletions(-) delete mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt deleted file mode 100644 index 55e44092..00000000 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginView.kt +++ /dev/null @@ -1,181 +0,0 @@ -package de.hsfl.budgetBinder.compose.login - -import androidx.compose.runtime.* -import de.hsfl.budgetBinder.compose.MainFlexContainer -import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.dom.* - -@Composable -fun LoginView( - state: State, - onLoginButtonPressed: (email: String, password: String) -> Unit, - onLoginSuccess: () -> Unit, - onChangeToRegister: () -> Unit -) { - var emailTextFieldState by remember { mutableStateOf("") } - var passwordTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } - - Header( - attrs = { - classes("mdc-top-app-bar") - } - ) { - Div( - attrs = { - classes("mdc-top-app-bar__row") - } - ) { - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-start") - } - ) { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - } - ) - Span( - attrs = { - classes("mdc-top-app-bar__title") - } - ) { - Text("Budget-Binder") - } - } - Section( - attrs = { - classes("mdc-top-app-bar__section", "mdc-top-app-bar__section--align-end") - } - ) { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToRegister() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Register Instead") - } - } - } - } - } - - MainFlexContainer { - // -- Login Form -- - H1 { Text(" Login") } - Form( - attrs = { - this.addEventListener("submit") { - console.log("${emailTextFieldState}, ${passwordTextFieldState}") - onLoginButtonPressed(emailTextFieldState, passwordTextFieldState) - it.preventDefault() - } - } - ) { - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Email") } - EmailInput(value = emailTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - emailTextFieldState = it.value - - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( - attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, - attrs = { - classes("mdc-text-field__input") - onInput { - passwordTextFieldState = it.value - } - }) - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - // -- Login Request Management -- - when (viewState) { - is UiState.Success<*> -> { - onLoginSuccess() - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - else -> {} - } - } - } -} \ No newline at end of file From 134032649b308e96fc6330d7cfcbc25e869dcbe3 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 22:57:54 +0200 Subject: [PATCH 239/325] Create basis for new EntryViewModel --- .../entryViewModel/EntryViewModel.kt | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt new file mode 100644 index 00000000..ad6ee5fb --- /dev/null +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -0,0 +1,41 @@ +package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel + +import de.hsfl.budgetBinder.common.DataResponse +import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.domain.usecase.* +import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.flow.DataFlow +import de.hsfl.budgetBinder.presentation.flow.RouterFlow +import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.flow.* + +class EntryViewModel( + private val loginUseCases: LoginUseCases, + private val routerFlow: RouterFlow, + private val dataFlow: DataFlow, + private val scope: CoroutineScope + ) { + /* *** Variables *** */ + + //Dialog used to confirm deletion + private val _dialogState = MutableStateFlow(false) + val dialogState: StateFlow = _dialogState + private val _eventFlow = UiEventSharedFlow.mutableEventFlow + val eventFlow = UiEventSharedFlow.eventFlow + + + init{ + //Do we need something to init? + } + + fun onEvent(event: EntryEvent){ + //TODO Event action + } + + private fun toggleDialog() { + _dialogState.value = !dialogState.value + } +} From 79d44a93a1c7c30601c3b0ec49510acfdcb55d8f Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:02:00 +0200 Subject: [PATCH 240/325] Add boiler use case functions --- .../viewmodel/entryViewModel/EntryViewModel.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index ad6ee5fb..0582e0e6 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -31,10 +31,19 @@ class EntryViewModel( //Do we need something to init? } + /* *** Event Handling *** */ fun onEvent(event: EntryEvent){ //TODO Event action } + + /* *** Use Case usages *** */ + fun getEntryById(id: Int) {} + fun createEntry(entry: Entry.In) {} + fun changeEntry(entry: Entry.Patch, id: Int) {} + fun removeEntry(id: Int) {} + + /* *** Helper *** */ private fun toggleDialog() { _dialogState.value = !dialogState.value } From 509bb1159b21a7512f428a31e600ba4b851de3d7 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:14:57 +0200 Subject: [PATCH 241/325] Add EntryEvents --- .../viewmodel/entryViewModel/EntryEvent.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt new file mode 100644 index 00000000..3ae90ace --- /dev/null +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -0,0 +1,19 @@ +package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel + +// View is not allowed to declare what should be done, only notify what has happened, names are assigned as such + +sealed class EntryEvent { + data class EnteredName(val value: String) : EntryEvent() + + //If the amount will be added or subtracted from the current spent sum + data class EnteredAmountInputType(val value: Boolean) : EntryEvent() + data class EnteredAmount(val value: Float) : EntryEvent() + data class EnteredRepeatState(val value: Boolean) : EntryEvent() + data class EnteredCategoryID(val value: Int) : EntryEvent() + object OnCreateEntry : EntryEvent() + object OnEditEntry : EntryEvent() + object OnDeleteEntry : EntryEvent() + object OnDeleteDialogConfirm : EntryEvent() + object OnDeleteDialogDismiss : EntryEvent() + +} From 4f6278b65556704f6d402d4ebfa972446f3b8bc8 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:23:59 +0200 Subject: [PATCH 242/325] Add boiler for each event in onEvent --- .../entryViewModel/EntryViewModel.kt | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 0582e0e6..ef9c6390 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -17,7 +17,7 @@ class EntryViewModel( private val routerFlow: RouterFlow, private val dataFlow: DataFlow, private val scope: CoroutineScope - ) { +) { /* *** Variables *** */ //Dialog used to confirm deletion @@ -27,13 +27,28 @@ class EntryViewModel( val eventFlow = UiEventSharedFlow.eventFlow - init{ + init { //Do we need something to init? } /* *** Event Handling *** */ - fun onEvent(event: EntryEvent){ - //TODO Event action + fun onEvent(event: EntryEvent) { + when (event) { + is EntryEvent.EnteredName -> {} + is EntryEvent.EnteredAmount -> {} + is EntryEvent.EnteredRepeatState -> {} + is EntryEvent.EnteredCategoryID -> {} + is EntryEvent.EnteredAmountInputType -> {} + is EntryEvent.OnCreateEntry -> {} + is EntryEvent.OnEditEntry -> {} + is EntryEvent.OnDeleteEntry -> {} + is EntryEvent.OnDeleteDialogConfirm -> {} + is EntryEvent.OnDeleteDialogDismiss -> {} + else -> { + throw Exception("Unhandled EntryEvent in EntryViewModel") + } + } + } From 1d4de203389d0e60b1e4a728e6a5609eb45ff487 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:35:12 +0200 Subject: [PATCH 243/325] Rename EnteredAmountInputType to EnteredAmountSign and EnteredRepeatState to EnteredRepeat --- .../presentation/viewmodel/entryViewModel/EntryEvent.kt | 8 ++++---- .../viewmodel/entryViewModel/EntryViewModel.kt | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt index 3ae90ace..3fa91208 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -4,12 +4,12 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel sealed class EntryEvent { data class EnteredName(val value: String) : EntryEvent() - - //If the amount will be added or subtracted from the current spent sum - data class EnteredAmountInputType(val value: Boolean) : EntryEvent() data class EnteredAmount(val value: Float) : EntryEvent() - data class EnteredRepeatState(val value: Boolean) : EntryEvent() + data class EnteredRepeat(val value: Boolean) : EntryEvent() data class EnteredCategoryID(val value: Int) : EntryEvent() + data class EnteredAmountSign(val value: Boolean) : + EntryEvent() //If the amount will be added or subtracted from the current spent sum + object OnCreateEntry : EntryEvent() object OnEditEntry : EntryEvent() object OnDeleteEntry : EntryEvent() diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index ef9c6390..342cf682 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -7,6 +7,7 @@ import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow +import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginTextFieldState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -20,7 +21,8 @@ class EntryViewModel( ) { /* *** Variables *** */ - //Dialog used to confirm deletion + + //Default ViewModel Variables private val _dialogState = MutableStateFlow(false) val dialogState: StateFlow = _dialogState private val _eventFlow = UiEventSharedFlow.mutableEventFlow @@ -36,9 +38,9 @@ class EntryViewModel( when (event) { is EntryEvent.EnteredName -> {} is EntryEvent.EnteredAmount -> {} - is EntryEvent.EnteredRepeatState -> {} + is EntryEvent.EnteredRepeat -> {} is EntryEvent.EnteredCategoryID -> {} - is EntryEvent.EnteredAmountInputType -> {} + is EntryEvent.EnteredAmountSign -> {} is EntryEvent.OnCreateEntry -> {} is EntryEvent.OnEditEntry -> {} is EntryEvent.OnDeleteEntry -> {} From cb5ff381e6cb810e03416bafd2147d22f7ca9162 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:36:28 +0200 Subject: [PATCH 244/325] Add EntryInputState --- .../viewmodel/entryViewModel/EntryInputState.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt new file mode 100644 index 00000000..5cc9feb0 --- /dev/null +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt @@ -0,0 +1,9 @@ +package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel + +data class EntryInputState( + val name: String = "", + val amount: String = "", + val repeat: Boolean = false, + val categoryID: Int? = null, + val amountSign: Boolean = false +) From 3a1e5d197f0327eb4d364dbd9d6311b7075e9922 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Tue, 21 Jun 2022 23:53:26 +0200 Subject: [PATCH 245/325] Add StateFlows for data inputs --- .../viewmodel/entryViewModel/EntryViewModel.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 342cf682..499211f2 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -20,6 +20,20 @@ class EntryViewModel( private val scope: CoroutineScope ) { /* *** Variables *** */ + private val _nameText = MutableStateFlow(EntryInputState()) + val nameText: StateFlow = _nameText + + private val _amountText = MutableStateFlow(EntryInputState()) + val amountText: StateFlow = _amountText + + private val _repeatText = MutableStateFlow(EntryInputState()) + val repeatText: StateFlow = _repeatText + + private val _categoryIDText = MutableStateFlow(EntryInputState()) + val categoryIDText: StateFlow = _categoryIDText + + private val _amountSignText = MutableStateFlow(EntryInputState()) + val amountSignText: StateFlow = _amountSignText //Default ViewModel Variables From 32bb8f0b74c73bd591c6e2a76aadaaf014ac18f7 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 00:10:51 +0200 Subject: [PATCH 246/325] Add button events, rename some data input variable names --- .../viewmodel/entryViewModel/EntryEvent.kt | 3 +- .../entryViewModel/EntryViewModel.kt | 41 +++++++++++++------ 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt index 3fa91208..f6b492f9 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -7,8 +7,7 @@ sealed class EntryEvent { data class EnteredAmount(val value: Float) : EntryEvent() data class EnteredRepeat(val value: Boolean) : EntryEvent() data class EnteredCategoryID(val value: Int) : EntryEvent() - data class EnteredAmountSign(val value: Boolean) : - EntryEvent() //If the amount will be added or subtracted from the current spent sum + data class EnteredAmountSign(val value: Boolean) : EntryEvent() object OnCreateEntry : EntryEvent() object OnEditEntry : EntryEvent() diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 499211f2..890c467c 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -3,6 +3,7 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel import de.hsfl.budgetBinder.common.DataResponse import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.domain.usecase.* +import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow @@ -20,28 +21,30 @@ class EntryViewModel( private val scope: CoroutineScope ) { /* *** Variables *** */ + + // ---- Data Input Variables ---- private val _nameText = MutableStateFlow(EntryInputState()) val nameText: StateFlow = _nameText private val _amountText = MutableStateFlow(EntryInputState()) val amountText: StateFlow = _amountText - private val _repeatText = MutableStateFlow(EntryInputState()) - val repeatText: StateFlow = _repeatText + private val _repeatState = MutableStateFlow(EntryInputState()) + val repeatState: StateFlow = _repeatState - private val _categoryIDText = MutableStateFlow(EntryInputState()) - val categoryIDText: StateFlow = _categoryIDText + private val _categoryIDState = MutableStateFlow(EntryInputState()) + val categoryIDState: StateFlow = _categoryIDState - private val _amountSignText = MutableStateFlow(EntryInputState()) - val amountSignText: StateFlow = _amountSignText + private val _amountSignState = MutableStateFlow(EntryInputState()) + val amountSignState: StateFlow = _amountSignState - //Default ViewModel Variables + // --- Default ViewModel Variables ---- private val _dialogState = MutableStateFlow(false) val dialogState: StateFlow = _dialogState private val _eventFlow = UiEventSharedFlow.mutableEventFlow val eventFlow = UiEventSharedFlow.eventFlow - + // ---- init { //Do we need something to init? @@ -55,11 +58,23 @@ class EntryViewModel( is EntryEvent.EnteredRepeat -> {} is EntryEvent.EnteredCategoryID -> {} is EntryEvent.EnteredAmountSign -> {} - is EntryEvent.OnCreateEntry -> {} - is EntryEvent.OnEditEntry -> {} - is EntryEvent.OnDeleteEntry -> {} - is EntryEvent.OnDeleteDialogConfirm -> {} - is EntryEvent.OnDeleteDialogDismiss -> {} + is EntryEvent.OnCreateEntry -> { + when (routerFlow.state.value) { + is Screen.Entry.Create -> createEntry( + Entry.In( + nameText, + amountState, + repeatState, + categoryIDState + ) + ) + else -> routerFlow.navigateTo(Screen.Entry.Create) + } + } + is EntryEvent.OnEditEntry -> routerFlow.navigateTo(Screen.Settings.Server) + is EntryEvent.OnDeleteEntry -> _dialogState.value = true + is EntryEvent.OnDeleteDialogConfirm -> removeEntry()//TODO Entry ID + is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") } From efeb604aa434a5b7ea6154e27aacc700ec4e6432 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 00:15:01 +0200 Subject: [PATCH 247/325] Change data input variable structure to have a more precise type --- .../entryViewModel/EntryInputState.kt | 2 +- .../entryViewModel/EntryViewModel.kt | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt index 5cc9feb0..7debc864 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt @@ -2,7 +2,7 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel data class EntryInputState( val name: String = "", - val amount: String = "", + val amount: Float = 0f, val repeat: Boolean = false, val categoryID: Int? = null, val amountSign: Boolean = false diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 890c467c..622ac5dc 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -23,20 +23,20 @@ class EntryViewModel( /* *** Variables *** */ // ---- Data Input Variables ---- - private val _nameText = MutableStateFlow(EntryInputState()) - val nameText: StateFlow = _nameText + private val _nameText = MutableStateFlow(EntryInputState().name) + val nameText: StateFlow = _nameText - private val _amountText = MutableStateFlow(EntryInputState()) - val amountText: StateFlow = _amountText + private val _amountText = MutableStateFlow(EntryInputState().amount) + val amountText: StateFlow = _amountText - private val _repeatState = MutableStateFlow(EntryInputState()) - val repeatState: StateFlow = _repeatState + private val _repeatState = MutableStateFlow(EntryInputState().repeat) + val repeatState: StateFlow = _repeatState - private val _categoryIDState = MutableStateFlow(EntryInputState()) - val categoryIDState: StateFlow = _categoryIDState + private val _categoryIDState = MutableStateFlow(EntryInputState().categoryID) + val categoryIDState: StateFlow = _categoryIDState - private val _amountSignState = MutableStateFlow(EntryInputState()) - val amountSignState: StateFlow = _amountSignState + private val _amountSignState = MutableStateFlow(EntryInputState().amountSign) + val amountSignState: StateFlow = _amountSignState // --- Default ViewModel Variables ---- @@ -62,10 +62,10 @@ class EntryViewModel( when (routerFlow.state.value) { is Screen.Entry.Create -> createEntry( Entry.In( - nameText, - amountState, - repeatState, - categoryIDState + nameText.value, + amountText.value, + repeatState.value, + categoryIDState.value ) ) else -> routerFlow.navigateTo(Screen.Entry.Create) From 237b33f4d2731302f6f5ef4f8f034f94824581b1 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 00:22:56 +0200 Subject: [PATCH 248/325] Add SelectedEntry --- .../presentation/viewmodel/entryViewModel/EntryEvent.kt | 2 ++ .../presentation/viewmodel/entryViewModel/EntryViewModel.kt | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt index f6b492f9..9e306f6c 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -3,12 +3,14 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel // View is not allowed to declare what should be done, only notify what has happened, names are assigned as such sealed class EntryEvent { + //User-made Data Input data class EnteredName(val value: String) : EntryEvent() data class EnteredAmount(val value: Float) : EntryEvent() data class EnteredRepeat(val value: Boolean) : EntryEvent() data class EnteredCategoryID(val value: Int) : EntryEvent() data class EnteredAmountSign(val value: Boolean) : EntryEvent() + //Action object OnCreateEntry : EntryEvent() object OnEditEntry : EntryEvent() object OnDeleteEntry : EntryEvent() diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 622ac5dc..550d713d 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -38,6 +38,8 @@ class EntryViewModel( private val _amountSignState = MutableStateFlow(EntryInputState().amountSign) val amountSignState: StateFlow = _amountSignState + private val _selectedEntry = MutableStateFlow(EntryState().selectedEntry) + val selectedEntry: StateFlow = _selectedEntry // --- Default ViewModel Variables ---- private val _dialogState = MutableStateFlow(false) @@ -73,7 +75,7 @@ class EntryViewModel( } is EntryEvent.OnEditEntry -> routerFlow.navigateTo(Screen.Settings.Server) is EntryEvent.OnDeleteEntry -> _dialogState.value = true - is EntryEvent.OnDeleteDialogConfirm -> removeEntry()//TODO Entry ID + is EntryEvent.OnDeleteDialogConfirm -> removeEntry(selectedEntry.value.id)//TODO Entry ID is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") From 70021a57ae0335c6b0a26e8e4d2495eec11aedae Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 00:26:27 +0200 Subject: [PATCH 249/325] Add data input eventhandling in viewmodel --- .../viewmodel/entryViewModel/EntryViewModel.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 550d713d..9024e664 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -55,11 +55,11 @@ class EntryViewModel( /* *** Event Handling *** */ fun onEvent(event: EntryEvent) { when (event) { - is EntryEvent.EnteredName -> {} - is EntryEvent.EnteredAmount -> {} - is EntryEvent.EnteredRepeat -> {} - is EntryEvent.EnteredCategoryID -> {} - is EntryEvent.EnteredAmountSign -> {} + is EntryEvent.EnteredName -> _nameText.value = nameText.value + is EntryEvent.EnteredAmount -> _amountText.value = amountText.value + is EntryEvent.EnteredRepeat -> _repeatState.value = repeatState.value + is EntryEvent.EnteredCategoryID -> _categoryIDState.value = categoryIDState.value + is EntryEvent.EnteredAmountSign -> _amountSignState.value = amountSignState.value is EntryEvent.OnCreateEntry -> { when (routerFlow.state.value) { is Screen.Entry.Create -> createEntry( From 7829c796c056640ba368f354f5f407cafc2afe0e Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 00:40:04 +0200 Subject: [PATCH 250/325] Add OnEditEntry Event --- .../viewmodel/entryViewModel/EntryViewModel.kt | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 9024e664..09224408 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -60,7 +60,7 @@ class EntryViewModel( is EntryEvent.EnteredRepeat -> _repeatState.value = repeatState.value is EntryEvent.EnteredCategoryID -> _categoryIDState.value = categoryIDState.value is EntryEvent.EnteredAmountSign -> _amountSignState.value = amountSignState.value - is EntryEvent.OnCreateEntry -> { + is EntryEvent.OnCreateEntry -> when (routerFlow.state.value) { is Screen.Entry.Create -> createEntry( Entry.In( @@ -72,8 +72,19 @@ class EntryViewModel( ) else -> routerFlow.navigateTo(Screen.Entry.Create) } - } - is EntryEvent.OnEditEntry -> routerFlow.navigateTo(Screen.Settings.Server) + + is EntryEvent.OnEditEntry -> + when (routerFlow.state.value) { + is Screen.Entry.Edit -> changeEntry( + Entry.Patch( + nameText.value, + amountText.value, + repeatState.value, + Entry.Category(categoryIDState.value) + ), selectedEntry.value.id + ) + else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntry.value.id)) //using ID seems... unnecessary? + } is EntryEvent.OnDeleteEntry -> _dialogState.value = true is EntryEvent.OnDeleteDialogConfirm -> removeEntry(selectedEntry.value.id)//TODO Entry ID is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false From c505110e8f72810a5fc0bc2ea248ac2e925f730b Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 01:00:58 +0200 Subject: [PATCH 251/325] Get SelectedEntry when Screen is Edit or Overview --- .../viewmodel/entryViewModel/EntryViewModel.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 09224408..6b4093a0 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -49,7 +49,11 @@ class EntryViewModel( // ---- init { - //Do we need something to init? + when (routerFlow.state.value) { + is Screen.Entry.Overview -> getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) + is Screen.Entry.Edit -> getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) + else -> {} + } } /* *** Event Handling *** */ @@ -86,7 +90,7 @@ class EntryViewModel( else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntry.value.id)) //using ID seems... unnecessary? } is EntryEvent.OnDeleteEntry -> _dialogState.value = true - is EntryEvent.OnDeleteDialogConfirm -> removeEntry(selectedEntry.value.id)//TODO Entry ID + is EntryEvent.OnDeleteDialogConfirm -> removeEntry(selectedEntry.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") @@ -96,7 +100,7 @@ class EntryViewModel( } - /* *** Use Case usages *** */ + /* *** Use Case usages *** */ //TODO Implement use cases fun getEntryById(id: Int) {} fun createEntry(entry: Entry.In) {} fun changeEntry(entry: Entry.Patch, id: Int) {} From 2acb65eedcb9c9242cf594583209cf6427f6a6b2 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 01:01:25 +0200 Subject: [PATCH 252/325] Add EntryState with selectedEntry --- .../presentation/viewmodel/entryViewModel/EntryState.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt new file mode 100644 index 00000000..d87cca04 --- /dev/null +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt @@ -0,0 +1,7 @@ +package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel + +import de.hsfl.budgetBinder.common.Entry + +data class EntryState( + val selectedEntry: Entry = Entry(0,"",0f,false,null) +) From be768c562fd23c6201705e6d2ceb4373178fb0a9 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 14:44:34 +0200 Subject: [PATCH 253/325] Rename EntriesUseCases to EntryUseCases --- .../domain/usecase/{EntriesUseCases.kt => EntryUseCases.kt} | 2 +- .../presentation/viewmodel/entryViewModel/EntryViewModel.kt | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) rename budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/{EntriesUseCases.kt => EntryUseCases.kt} (91%) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntriesUseCases.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt similarity index 91% rename from budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntriesUseCases.kt rename to budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt index 0f914830..7233f2a2 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntriesUseCases.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt @@ -1,6 +1,6 @@ package de.hsfl.budgetBinder.domain.usecase -data class EntriesUseCases( +data class EntryUseCases( val getAllEntriesUseCase: GetAllEntriesUseCase, val getEntryByIdUseCase: GetEntryByIdUseCase, val createNewEntryUseCase: CreateNewEntryUseCase, diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 6b4093a0..998dab5a 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -15,7 +15,7 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.* class EntryViewModel( - private val loginUseCases: LoginUseCases, + private val entryUseCases: EntryUseCases, private val routerFlow: RouterFlow, private val dataFlow: DataFlow, private val scope: CoroutineScope @@ -101,7 +101,9 @@ class EntryViewModel( /* *** Use Case usages *** */ //TODO Implement use cases - fun getEntryById(id: Int) {} + fun getEntryById(id: Int) { + + } fun createEntry(entry: Entry.In) {} fun changeEntry(entry: Entry.Patch, id: Int) {} fun removeEntry(id: Int) {} From 3501a308ab2846644c5cd420f1eac2482d2f97ed Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 14:50:47 +0200 Subject: [PATCH 254/325] Add getEntryById UseCase to EntryViewModel --- .../viewmodel/entryViewModel/EntryViewModel.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 998dab5a..264575c1 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -4,6 +4,7 @@ import de.hsfl.budgetBinder.common.DataResponse import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.UiEvent import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow @@ -102,7 +103,16 @@ class EntryViewModel( /* *** Use Case usages *** */ //TODO Implement use cases fun getEntryById(id: Int) { - + entryUseCases.getEntryByIdUseCase(id).onEach { + when (it){ + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + is DataResponse.Success<*> -> { + _selectedEntry.value = it.data!! + } + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + } + } } fun createEntry(entry: Entry.In) {} fun changeEntry(entry: Entry.Patch, id: Int) {} From 9a06a78ad251d29d1423ef04d90e239b4f87e8e1 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 14:55:32 +0200 Subject: [PATCH 255/325] Add createEntry UseCase to EntryViewModel --- .../viewmodel/entryViewModel/EntryViewModel.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 264575c1..dab96316 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -114,7 +114,16 @@ class EntryViewModel( } } } - fun createEntry(entry: Entry.In) {} + fun createEntry(entry: Entry.In) { + entryUseCases.createNewEntryUseCase(entry).onEach { + when (it){ + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + } + } + } fun changeEntry(entry: Entry.Patch, id: Int) {} fun removeEntry(id: Int) {} From f70da90357845a01ce6c7026991e3b7514290c01 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 14:56:31 +0200 Subject: [PATCH 256/325] Add changeEntry UseCase to EntryViewModel --- .../viewmodel/entryViewModel/EntryViewModel.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index dab96316..f3d98c9a 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -124,7 +124,16 @@ class EntryViewModel( } } } - fun changeEntry(entry: Entry.Patch, id: Int) {} + fun changeEntry(entry: Entry.Patch, id: Int) { + entryUseCases.changeEntryByIdUseCase(entry,id).onEach { + when (it){ + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully changed")) //TODO?: Change the msg + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + } + } + } fun removeEntry(id: Int) {} /* *** Helper *** */ From 46e6e09be996681265348ea1d10fdf1967e43142 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 14:59:56 +0200 Subject: [PATCH 257/325] Add removeEntry UseCase to EntryViewModel --- .../entryViewModel/EntryViewModel.kt | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index f3d98c9a..aa8b1f5a 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -104,7 +104,7 @@ class EntryViewModel( /* *** Use Case usages *** */ //TODO Implement use cases fun getEntryById(id: Int) { entryUseCases.getEntryByIdUseCase(id).onEach { - when (it){ + when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) is DataResponse.Success<*> -> { @@ -114,9 +114,10 @@ class EntryViewModel( } } } + fun createEntry(entry: Entry.In) { entryUseCases.createNewEntryUseCase(entry).onEach { - when (it){ + when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg @@ -124,9 +125,10 @@ class EntryViewModel( } } } + fun changeEntry(entry: Entry.Patch, id: Int) { - entryUseCases.changeEntryByIdUseCase(entry,id).onEach { - when (it){ + entryUseCases.changeEntryByIdUseCase(entry, id).onEach { + when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully changed")) //TODO?: Change the msg @@ -134,10 +136,15 @@ class EntryViewModel( } } } - fun removeEntry(id: Int) {} - /* *** Helper *** */ - private fun toggleDialog() { - _dialogState.value = !dialogState.value + fun removeEntry(id: Int) { + entryUseCases.deleteEntryByIdUseCase(id).onEach { + when (it) { + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully deleted")) //TODO?: Change the msg + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + } + } } } From 11507ffe28767abbc385ef3c14451c837bb218f6 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 15:01:22 +0200 Subject: [PATCH 258/325] Do small renaming --- .../viewmodel/entryViewModel/EntryViewModel.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index aa8b1f5a..c8c58810 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -80,7 +80,7 @@ class EntryViewModel( is EntryEvent.OnEditEntry -> when (routerFlow.state.value) { - is Screen.Entry.Edit -> changeEntry( + is Screen.Entry.Edit -> updateEntry( Entry.Patch( nameText.value, amountText.value, @@ -91,7 +91,7 @@ class EntryViewModel( else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntry.value.id)) //using ID seems... unnecessary? } is EntryEvent.OnDeleteEntry -> _dialogState.value = true - is EntryEvent.OnDeleteDialogConfirm -> removeEntry(selectedEntry.value.id) + is EntryEvent.OnDeleteDialogConfirm -> deleteEntry(selectedEntry.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") @@ -126,7 +126,7 @@ class EntryViewModel( } } - fun changeEntry(entry: Entry.Patch, id: Int) { + fun updateEntry(entry: Entry.Patch, id: Int) { entryUseCases.changeEntryByIdUseCase(entry, id).onEach { when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) @@ -137,7 +137,7 @@ class EntryViewModel( } } - fun removeEntry(id: Int) { + fun deleteEntry(id: Int) { entryUseCases.deleteEntryByIdUseCase(id).onEach { when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) From 247989829bd81691162a561c1c1750e53d26c31d Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 15:16:20 +0200 Subject: [PATCH 259/325] Add basic variables to web EntryComponent --- .../entryViewModel/EntryViewModel.kt | 14 ++++++------ .../compose/entry/EntryComponent.kt | 22 +++++++------------ 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index c8c58810..0a9791c5 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -39,8 +39,8 @@ class EntryViewModel( private val _amountSignState = MutableStateFlow(EntryInputState().amountSign) val amountSignState: StateFlow = _amountSignState - private val _selectedEntry = MutableStateFlow(EntryState().selectedEntry) - val selectedEntry: StateFlow = _selectedEntry + private val _selectedEntryState = MutableStateFlow(EntryState().selectedEntry) + val selectedEntryState: StateFlow = _selectedEntryState // --- Default ViewModel Variables ---- private val _dialogState = MutableStateFlow(false) @@ -86,12 +86,12 @@ class EntryViewModel( amountText.value, repeatState.value, Entry.Category(categoryIDState.value) - ), selectedEntry.value.id + ), selectedEntryState.value.id ) - else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntry.value.id)) //using ID seems... unnecessary? + else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntryState.value.id)) //using ID seems... unnecessary? } is EntryEvent.OnDeleteEntry -> _dialogState.value = true - is EntryEvent.OnDeleteDialogConfirm -> deleteEntry(selectedEntry.value.id) + is EntryEvent.OnDeleteDialogConfirm -> deleteEntry(selectedEntryState.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") @@ -101,14 +101,14 @@ class EntryViewModel( } - /* *** Use Case usages *** */ //TODO Implement use cases + /* *** Use Case usages *** */ fun getEntryById(id: Int) { entryUseCases.getEntryByIdUseCase(id).onEach { when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) is DataResponse.Success<*> -> { - _selectedEntry.value = it.data!! + _selectedEntryState.value = it.data!! } is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 1b5e86f1..409ef23e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -8,7 +8,9 @@ import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.viewmodel.EntryViewModel + +import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel import di import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Text @@ -16,20 +18,12 @@ import org.kodein.di.instance import kotlin.math.absoluteValue @Composable -fun EntryComponent(screenState: MutableState) { - //val scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - val scope = rememberCoroutineScope() - /*val di = localDI() - val getAllEntriesUseCase: GetAllEntriesUseCase by di.instance() - val getEntryByIdUseCase: GetEntryByIdUseCase by di.instance() - val changeEntryByIdUseCase: ChangeEntryByIdUseCase by di.instance() - val deleteEntryByIdUseCase: DeleteEntryByIdUseCase by di.instance() - val createNewEntryUseCase: CreateNewEntryUseCase by di.instance() - val userViewModel = EntryViewModel(getAllEntriesUseCase, getEntryByIdUseCase, createNewEntryUseCase,changeEntryByIdUseCase,deleteEntryByIdUseCase, scope) - val viewState = userViewModel.state.collectAsState(scope)*/ - +fun EntryComponent() { val viewModel: EntryViewModel by di.instance() - val viewState = viewModel.state.collectAsState(scope.coroutineContext) + //Data to load + val entry = viewModel.selectedEntryState.collectAsState() + val loadingState = remember { mutableStateOf(false) } + when (screenState.value) { is Screen.EntryCreate -> { From 10f11bf1271b53bb6ce9401b4d132f14deb6f8bd Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 15:22:22 +0200 Subject: [PATCH 260/325] Remove old data parts from web entrycomponent --- .../compose/entry/EntryComponent.kt | 95 ++++++++++--------- 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 409ef23e..321b2bf0 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -3,15 +3,20 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.category.categoryIdToCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel import di +import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Text import org.kodein.di.instance @@ -19,55 +24,59 @@ import kotlin.math.absoluteValue @Composable fun EntryComponent() { + val viewModel: EntryViewModel by di.instance() + val routerFlow: RouterFlow by di.instance() + val screenState = routerFlow.state.collectAsState() + val loadingState = remember { mutableStateOf(false) } //Data to load val entry = viewModel.selectedEntryState.collectAsState() - val loadingState = remember { mutableStateOf(false) } - + val categoryList = viewModel.categoryListState.collectAsState() - when (screenState.value) { - is Screen.EntryCreate -> { - EntryCreateView( - state = viewState, - categoryList = (screenState.value as Screen.EntryCreate).categoryList, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onCreateEntryButtonPressed = { name:String, amount:Float, repeat:Boolean, category_id:Int -> - viewModel.createEntry(Entry.In(name, amount, repeat, category_id)) - }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) - - } - is Screen.EntryEdit -> { - EntryEditView( - state = viewState, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onEditEntryButtonPressed = { name:String, amount:Float, repeat:Boolean, category:Entry.Category? -> - viewModel.changeEntry( - Entry.Patch(name, amount, repeat, category), - (screenState.value as Screen.EntryEdit).id - ) - }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) - viewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> loadingState.value = true + is UiEvent.HideSuccess -> loadingState.value = false + else -> loadingState.value = false + } } - is Screen.EntryOverview -> { - EntryOverviewView( - state = viewState, - onEditButton = {id, -> screenState.value = Screen.EntryEdit(id)}, - onDeleteButton = { id -> - viewModel.removeEntry(id) - screenState.value = Screen.Dashboard}, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) - viewModel.getEntryById((screenState.value as Screen.EntryOverview).id) + } + NavBar {} + MainFlexContainer { + when (screenState.value) { + is Screen.EntryCreate -> { + EntryCreateView( + categoryList = (screenState.value as Screen.EntryCreate).categoryList, + onCreateEntryButtonPressed = { name: String, amount: Float, repeat: Boolean, category_id: Int -> + viewModel.createEntry(Entry.In(name, amount, repeat, category_id)) + } + ) + + } + is Screen.EntryEdit -> { + EntryEditView( + onEditEntryButtonPressed = { name: String, amount: Float, repeat: Boolean, category: Entry.Category? -> + viewModel.changeEntry( + Entry.Patch(name, amount, repeat, category), + (screenState.value as Screen.EntryEdit).id + ) + } + ) + viewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) + } + is Screen.EntryOverview -> { + EntryOverviewView( + onEditButton = { id, -> screenState.value = Screen.EntryEdit(id) }, + onDeleteButton = { id -> + viewModel.removeEntry(id) + screenState.value = Screen.Dashboard + } + ) + viewModel.getEntryById((screenState.value as Screen.EntryOverview).id) + } + else -> {} } - else -> {} } } From 625cca1cfd7d4953a12ec0d24c48152e70d21b4d Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 15:34:08 +0200 Subject: [PATCH 261/325] Add getCategoryList to EntryViewModel --- .../domain/usecase/EntryUseCases.kt | 1 + .../viewmodel/entryViewModel/EntryState.kt | 4 ++- .../entryViewModel/EntryViewModel.kt | 33 +++++++++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt index 7233f2a2..2ccc8b09 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/domain/usecase/EntryUseCases.kt @@ -2,6 +2,7 @@ package de.hsfl.budgetBinder.domain.usecase data class EntryUseCases( val getAllEntriesUseCase: GetAllEntriesUseCase, + val getCategoryListUseCase : GetAllCategoriesUseCase, val getEntryByIdUseCase: GetEntryByIdUseCase, val createNewEntryUseCase: CreateNewEntryUseCase, val changeEntryByIdUseCase: ChangeEntryByIdUseCase, diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt index d87cca04..883fb485 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt @@ -1,7 +1,9 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry data class EntryState( - val selectedEntry: Entry = Entry(0,"",0f,false,null) + val selectedEntry: Entry = Entry(0,"",0f,false,null), + val categoryList: List = listOf() ) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 0a9791c5..1238772e 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -1,5 +1,6 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.DataResponse import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.domain.usecase.* @@ -14,6 +15,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch class EntryViewModel( private val entryUseCases: EntryUseCases, @@ -42,6 +44,9 @@ class EntryViewModel( private val _selectedEntryState = MutableStateFlow(EntryState().selectedEntry) val selectedEntryState: StateFlow = _selectedEntryState + private val _categoryListState = MutableStateFlow(EntryState().categoryList) + val categoryListState: StateFlow> = _categoryListState + // --- Default ViewModel Variables ---- private val _dialogState = MutableStateFlow(false) val dialogState: StateFlow = _dialogState @@ -51,8 +56,14 @@ class EntryViewModel( init { when (routerFlow.state.value) { - is Screen.Entry.Overview -> getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) - is Screen.Entry.Edit -> getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) + is Screen.Entry.Overview -> { + getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) + getCategoryList() + } + is Screen.Entry.Edit -> { + getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) + getCategoryList() + } else -> {} } } @@ -114,6 +125,10 @@ class EntryViewModel( } } } + private fun getCategoryList() = scope.launch { + entryUseCases.getCategoryListUseCase.categories() + .collect { handleDataResponse(response = it, onSuccess = {cl -> _categoryListState.value = cl}) } + } fun createEntry(entry: Entry.In) { entryUseCases.createNewEntryUseCase(entry).onEach { @@ -147,4 +162,18 @@ class EntryViewModel( } } } + private suspend fun handleDataResponse(response: DataResponse, onSuccess: (T) -> Unit) { + when (response) { + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + is DataResponse.Success -> { + _eventFlow.emit(UiEvent.HideSuccess) + onSuccess(response.data!!) + } + is DataResponse.Unauthorized -> { + _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + routerFlow.navigateTo(Screen.Login) + } + } + } } From 95041a31fc5fc7ec1d1f3cf19f10c9496cd9340f Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 15:44:02 +0200 Subject: [PATCH 262/325] Update entryCreate usage in entryComponent --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt | 3 ++- .../de/hsfl/budgetBinder/compose/entry/EntryComponent.kt | 9 ++++----- .../hsfl/budgetBinder/compose/entry/EntryCreateView.kt | 6 +----- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index b79632be..bee63303 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.rememberCoroutineScope import de.hsfl.budgetBinder.compose.dashboard.DashboardComponent +import de.hsfl.budgetBinder.compose.entry.EntryComponent import de.hsfl.budgetBinder.compose.login.LoginComponent import de.hsfl.budgetBinder.compose.register.RegisterComponent import de.hsfl.budgetBinder.presentation.Screen @@ -23,6 +24,7 @@ fun Router() { is Screen.Register -> RegisterComponent() is Screen.Login -> LoginComponent() is Screen.Dashboard -> DashboardComponent() + is Screen.Entry -> EntryComponent() is Screen.Settings, is Screen.SettingsChangeUserData -> Text("Settings")//SettingsComponent(screenState = screenState) is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister @@ -30,7 +32,6 @@ fun Router() { is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> Text("Old Entry")//EntryComponent(screenState = screenState) is Screen.Category -> Text("New Category") - is Screen.Entry -> Text("New Entry") else -> { Text("No known Screen! Check if the screen you're trying to reach is in the ScreenRouter") } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 321b2bf0..c4069a34 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -14,6 +14,7 @@ import de.hsfl.budgetBinder.presentation.UiEvent import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel import di import kotlinx.coroutines.flow.collectLatest @@ -45,12 +46,10 @@ fun EntryComponent() { NavBar {} MainFlexContainer { when (screenState.value) { - is Screen.EntryCreate -> { + is Screen.Entry.Create -> { EntryCreateView( - categoryList = (screenState.value as Screen.EntryCreate).categoryList, - onCreateEntryButtonPressed = { name: String, amount: Float, repeat: Boolean, category_id: Int -> - viewModel.createEntry(Entry.In(name, amount, repeat, category_id)) - } + categoryList = categoryList.value, + onCreateEntryButtonPressed = { viewModel.onEvent(EntryEvent.OnCreateEntry) } ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 691b2bb5..1ca4a5dc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -16,12 +16,8 @@ import org.jetbrains.compose.web.svg.Svg @OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryCreateView( - state: State, categoryList: List, - onChangeToDashboard: () -> Unit, - onChangeToSettings: () -> Unit, - onChangeToCategory: () -> Unit, - onCreateEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category_id: Int) -> Unit, + onCreateEntryButtonPressed: () -> Unit, ) { var switchState by remember { mutableStateOf(false) } var entryNameTextFieldState by remember { mutableStateOf("") } From 99b138d5ef52f5c7f2348aacaa1c5f33095072d9 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 16:09:25 +0200 Subject: [PATCH 263/325] Update parts of entryCreate --- .../compose/entry/EntryComponent.kt | 4 +- .../compose/entry/EntryCreateView.kt | 354 ++++++++---------- 2 files changed, 163 insertions(+), 195 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index c4069a34..9a91041c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -33,6 +33,7 @@ fun EntryComponent() { //Data to load val entry = viewModel.selectedEntryState.collectAsState() val categoryList = viewModel.categoryListState.collectAsState() + //Inputs LaunchedEffect(key1 = true) { viewModel.eventFlow.collectLatest { event -> @@ -48,7 +49,8 @@ fun EntryComponent() { when (screenState.value) { is Screen.Entry.Create -> { EntryCreateView( - categoryList = categoryList.value, + onRepeatClicked = { input -> viewModel.onEvent(EntryEvent.EnteredRepeat(input))}, + onAmountTypeSwitched = { input -> viewModel.onEvent(EntryEvent.EnteredAmountSign(input))}, onCreateEntryButtonPressed = { viewModel.onEvent(EntryEvent.OnCreateEntry) } ) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 1ca4a5dc..1aaf9a1f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -5,258 +5,224 @@ import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.* import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditUserViewModel +import di import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.* import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Path import org.jetbrains.compose.web.svg.Svg +import org.kodein.di.instance @OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryCreateView( - categoryList: List, + onRepeatClicked: (Boolean) -> Unit, + onAmountTypeSwitched: (Boolean) -> Unit, onCreateEntryButtonPressed: () -> Unit, ) { - var switchState by remember { mutableStateOf(false) } - var entryNameTextFieldState by remember { mutableStateOf("") } - var entryAmountTextFieldState by remember { mutableStateOf("") } - var entryRepeatState by remember { mutableStateOf("") } - var entryCategoryIDTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } + val viewModel: EntryViewModel by di.instance() + val entryNameTextField by viewModel.nameText.collectAsState() + val entryAmountTextField by viewModel.amountText.collectAsState() + val entryRepeat by viewModel.repeatState.collectAsState() + val entryCategoryIDTextField by viewModel.repeatState.collectAsState() + val amountSign by viewModel.amountSignState.collectAsState() - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Create new Entry") } + Form(attrs = { + this.addEventListener("submit") { + onCreateEntryButtonPressed() + it.preventDefault() + } + } + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { Span( attrs = { - classes("mdc-button__label") + classes("mdc-text-field__ripple") } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { + ) { } Span( attrs = { - classes("mdc-button__label") + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Entry Name") } + Input( + type = InputType.Text ) { - Text("Settings") + classes("mdc-text-field__input") + value(entryNameTextFieldState) + required(true) + onInput { + entryNameTextFieldState = it.value + } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - }) - - MainFlexContainer { - H1( + } + Div( attrs = { - style { margin(2.percent) } - } - ) { Text("Create new Entry") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$entryNameTextFieldState, $entryAmountTextFieldState, $entryRepeatState, $entryCategoryIDTextFieldState") - onCreateEntryButtonPressed( - entryNameTextFieldState, - (if (!switchState) "-$entryAmountTextFieldState" else entryAmountTextFieldState).toFloat(), - entryRepeatState.toBoolean(), - entryCategoryIDTextFieldState.toInt() - ) - it.preventDefault() + classes(AppStylesheet.margin) } - } ) { - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Entry Name") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(entryNameTextFieldState) - required(true) - onInput { - entryNameTextFieldState = it.value - } + classes("mdc-text-field__ripple") } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } } - ) { - Span( + ) { Text("Amount") } + Div { + Button( attrs = { - classes("mdc-text-field__ripple") + if (!switchState) classes("mdc-switch", "mdc-switch--unselected") + else classes("mdc-switch", "mdc-switch--selected") + id("basic-switch") + attr("role", "switch") + attr("aria-checked", "false") + type(ButtonType.Button) + onClick { switchState = !switchState } } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } - } - ) { Text("Amount") } - Div { - Button( - attrs = { - if (!switchState) classes("mdc-switch", "mdc-switch--unselected") - else classes("mdc-switch", "mdc-switch--selected") - id("basic-switch") - attr("role", "switch") - attr("aria-checked", "false") - type(ButtonType.Button) - onClick { switchState = !switchState } - } - ) { - Div(attrs = { classes("mdc-switch__track") }) { } - Div(attrs = { classes("mdc-switch__handle-track") }) { - Div(attrs = { classes("mdc-switch__handle") }) { - Div(attrs = { classes("mdc-switch__shadow") }) { - Div(attrs = { classes("mdc-elevation-overlay") }) { } + ) { + Div(attrs = { classes("mdc-switch__track") }) { } + Div(attrs = { classes("mdc-switch__handle-track") }) { + Div(attrs = { classes("mdc-switch__handle") }) { + Div(attrs = { classes("mdc-switch__shadow") }) { + Div(attrs = { classes("mdc-elevation-overlay") }) { } + } + Div(attrs = { classes("mdc-switch__ripple") }) { } + Div(attrs = { classes("mdc-switch__icons") }) { + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") } - Div(attrs = { classes("mdc-switch__ripple") }) { } - Div(attrs = { classes("mdc-switch__icons") }) { - Svg( - attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, - viewBox = "0 0 24 24" - ) { - Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") - } - Svg( - attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, - viewBox = "0 0 24 24" - ) { - Path("M20 13H4v-2h16v2z") - } + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M20 13H4v-2h16v2z") } } } } } - Div(attrs = { - classes("mdc-typography--headline6", AppStylesheet.text) - }) { - Text(if (switchState) "+" else "-") - } - Input( - type = InputType.Number - ) { - attr("step", "0.01") - classes("mdc-text-field__input") - onInput { - entryAmountTextFieldState = it.value.toString() - } + } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { + Text(if (switchState) "+" else "-") + } + Input( + type = InputType.Number + ) { + attr("step", "0.01") + classes("mdc-text-field__input") + onInput { + entryAmountTextFieldState = it.value.toString() } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( - attrs = { - classes(AppStylesheet.margin, AppStylesheet.flexContainer) - } - ) { - Div(attrs = {style { flex(50.percent) }}) { - Div(attrs = { classes("mdc-form-field") }) { - Div(attrs = { classes("mdc-checkbox") }) { - Input(type = InputType.Checkbox) - { - classes("mdc-checkbox__native-control") - id("checkbox-1") - onInput { - entryRepeatState = it.value.toString() - } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) + } + ) { + Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { classes("mdc-form-field") }) { + Div(attrs = { classes("mdc-checkbox") }) { + Input(type = InputType.Checkbox) + { + classes("mdc-checkbox__native-control") + id("checkbox-1") + onInput { + entryRepeatState = it.value.toString() } - Div(attrs = { classes("mdc-checkbox__background") }) { - Svg(attrs = { classes("mdc-checkbox__checkmark") }, viewBox = "0 0 24 24") { - Path("M1.73,12.91 8.1,19.28 22.79,4.59", attrs = { classes("mdc-checkbox__checkmark") }) - } - Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } + } + Div(attrs = { classes("mdc-checkbox__background") }) { + Svg( + attrs = { classes("mdc-checkbox__checkmark") }, + viewBox = "0 0 24 24" + ) { + Path( + "M1.73,12.91 8.1,19.28 22.79,4.59", + attrs = { classes("mdc-checkbox__checkmark") }) } - Div(attrs = { classes("mdc-checkbox__ripple") }) { } + Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } } - Label(forId = "checkbox-1") { Text("repeat") } + Div(attrs = { classes("mdc-checkbox__ripple") }) { } } + Label(forId = "checkbox-1") { Text("repeat") } } - Div(attrs = {style { flex(50.percent) }}) { - ChooseCategoryMenu(categoryList) { id -> entryCategoryIDTextFieldState = id.toString() } + } + Div(attrs = { style { flex(50.percent) } }) { + ChooseCategoryMenu(categoryList) { id -> + entryCategoryIDTextFieldState = id.toString() } } - Div( + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( attrs = { - classes(AppStylesheet.margin) + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } + Div { + when (viewState) { + is UiState.Success<*> -> { + Text((viewState as UiState.Success<*>).element.toString()) } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + is UiState.Error -> { + Text((viewState as UiState.Error).error) + } + is UiState.Loading -> { + //CircularProgressIndicator() } } } } } + From 535bf357cd154c149c45e24d3046066cf84807e7 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 16:24:26 +0200 Subject: [PATCH 264/325] Update EntryCreateView --- .../viewmodel/entryViewModel/EntryEvent.kt | 6 +-- .../entryViewModel/EntryViewModel.kt | 4 +- .../compose/entry/EntryComponent.kt | 2 - .../compose/entry/EntryCreateView.kt | 39 +++++++------------ 4 files changed, 18 insertions(+), 33 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt index 9e306f6c..b71a37d1 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -6,9 +6,9 @@ sealed class EntryEvent { //User-made Data Input data class EnteredName(val value: String) : EntryEvent() data class EnteredAmount(val value: Float) : EntryEvent() - data class EnteredRepeat(val value: Boolean) : EntryEvent() - data class EnteredCategoryID(val value: Int) : EntryEvent() - data class EnteredAmountSign(val value: Boolean) : EntryEvent() + object EnteredRepeat : EntryEvent() + data class EnteredCategoryID(val value: Int?) : EntryEvent() + object EnteredAmountSign : EntryEvent() //Action object OnCreateEntry : EntryEvent() diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 1238772e..a6696638 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -73,9 +73,9 @@ class EntryViewModel( when (event) { is EntryEvent.EnteredName -> _nameText.value = nameText.value is EntryEvent.EnteredAmount -> _amountText.value = amountText.value - is EntryEvent.EnteredRepeat -> _repeatState.value = repeatState.value + is EntryEvent.EnteredRepeat -> _repeatState.value = !repeatState.value is EntryEvent.EnteredCategoryID -> _categoryIDState.value = categoryIDState.value - is EntryEvent.EnteredAmountSign -> _amountSignState.value = amountSignState.value + is EntryEvent.EnteredAmountSign -> _amountSignState.value = !amountSignState.value is EntryEvent.OnCreateEntry -> when (routerFlow.state.value) { is Screen.Entry.Create -> createEntry( diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 9a91041c..3c5dd3d6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -49,8 +49,6 @@ fun EntryComponent() { when (screenState.value) { is Screen.Entry.Create -> { EntryCreateView( - onRepeatClicked = { input -> viewModel.onEvent(EntryEvent.EnteredRepeat(input))}, - onAmountTypeSwitched = { input -> viewModel.onEvent(EntryEvent.EnteredAmountSign(input))}, onCreateEntryButtonPressed = { viewModel.onEvent(EntryEvent.OnCreateEntry) } ) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 1aaf9a1f..92dff5ed 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -1,12 +1,10 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.* import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel -import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditUserViewModel import di import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.* @@ -20,16 +18,17 @@ import org.kodein.di.instance @OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryCreateView( - onRepeatClicked: (Boolean) -> Unit, - onAmountTypeSwitched: (Boolean) -> Unit, onCreateEntryButtonPressed: () -> Unit, ) { val viewModel: EntryViewModel by di.instance() + //Input val entryNameTextField by viewModel.nameText.collectAsState() val entryAmountTextField by viewModel.amountText.collectAsState() val entryRepeat by viewModel.repeatState.collectAsState() val entryCategoryIDTextField by viewModel.repeatState.collectAsState() val amountSign by viewModel.amountSignState.collectAsState() + //Data + val categoryList by viewModel.categoryListState.collectAsState() H1( attrs = { @@ -68,10 +67,10 @@ fun EntryCreateView( type = InputType.Text ) { classes("mdc-text-field__input") - value(entryNameTextFieldState) + value(entryNameTextField) required(true) onInput { - entryNameTextFieldState = it.value + viewModel.onEvent(EntryEvent.EnteredName(it.value)) } } Span( @@ -106,13 +105,13 @@ fun EntryCreateView( Div { Button( attrs = { - if (!switchState) classes("mdc-switch", "mdc-switch--unselected") + if (!amountSign) classes("mdc-switch", "mdc-switch--unselected") else classes("mdc-switch", "mdc-switch--selected") id("basic-switch") attr("role", "switch") attr("aria-checked", "false") type(ButtonType.Button) - onClick { switchState = !switchState } + onClick { viewModel.onEvent(EntryEvent.EnteredAmountSign) } } ) { Div(attrs = { classes("mdc-switch__track") }) { } @@ -143,15 +142,16 @@ fun EntryCreateView( Div(attrs = { classes("mdc-typography--headline6", AppStylesheet.text) }) { - Text(if (switchState) "+" else "-") + Text(if (amountSign) "+" else "-") } Input( type = InputType.Number ) { attr("step", "0.01") + value(entryAmountTextField) classes("mdc-text-field__input") onInput { - entryAmountTextFieldState = it.value.toString() + viewModel.onEvent(EntryEvent.EnteredAmount(it.value!!.toFloat())) } } Span( @@ -174,7 +174,7 @@ fun EntryCreateView( classes("mdc-checkbox__native-control") id("checkbox-1") onInput { - entryRepeatState = it.value.toString() + viewModel.onEvent(EntryEvent.EnteredRepeat) } } Div(attrs = { classes("mdc-checkbox__background") }) { @@ -195,7 +195,7 @@ fun EntryCreateView( } Div(attrs = { style { flex(50.percent) } }) { ChooseCategoryMenu(categoryList) { id -> - entryCategoryIDTextFieldState = id.toString() + viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) } } } @@ -210,19 +210,6 @@ fun EntryCreateView( value("Submit") }) } - Div { - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } - } } } From 6017092bb5299932ef7ed5614dd99fe976f54b3c Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 17:08:45 +0200 Subject: [PATCH 265/325] Try to fix entryCreate --- .../kotlin/de/hsfl/budgetBinder/di/DI.kt | 5 ++- .../presentation/viewmodel/EntryViewModel.kt | 12 +++--- .../viewmodel/entryViewModel/EntryState.kt | 2 +- .../entryViewModel/EntryViewModel.kt | 16 ++++---- .../hsfl/budgetBinder/compose/Composables.kt | 14 ++++++- .../compose/entry/EntryComponent.kt | 37 ------------------- .../compose/entry/EntryCreateView.kt | 4 +- .../compose/entry/EntryEditView.kt | 2 +- 8 files changed, 35 insertions(+), 57 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt index 8c79f219..4072213f 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt @@ -25,6 +25,7 @@ import de.hsfl.budgetBinder.presentation.viewmodel.category.create.CategoryCreat import de.hsfl.budgetBinder.presentation.viewmodel.category.detail.CategoryDetailViewModel import de.hsfl.budgetBinder.presentation.viewmodel.category.edit.CategoryEditViewModel import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerViewModel import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditServerUrlViewModel import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditUserViewModel @@ -79,7 +80,7 @@ fun kodein(ktorEngine: HttpClientEngine) = DI { bindSingleton { StoreUserStateUseCase() } bindSingleton { StoreServerUrlUseCase() } bindSingleton { StoreDarkModeUseCase() } - bindSingleton { EntriesUseCases(instance(), instance(), instance(), instance(), instance()) } + bindSingleton { EntryUseCases(instance(), instance(), instance(), instance(), instance(), instance()) } bindSingleton { CategoriesUseCases(instance(), instance(), instance(), instance(), instance(), instance()) } bindSingleton { SettingsUseCases(instance(), instance(), instance()) } bindSingleton { AuthUseCases(instance(), instance(), instance()) } @@ -102,7 +103,7 @@ fun kodein(ktorEngine: HttpClientEngine) = DI { bindSingleton { CategoryDetailViewModel(instance(), instance(), instance()) } bindSingleton { CategoryEditViewModel(instance(), instance(), instance()) } bindSingleton { CategoryCreateViewModel(instance(), instance(), instance()) } - bindSingleton { EntryViewModel(instance(), instance()) } + bindSingleton { EntryViewModel(instance(), instance(), instance(), instance()) } bindSingleton { DashboardViewModel(instance(), instance(), instance(), instance()) } bindSingleton { NavDrawerViewModel(instance(), instance(), instance()) } } diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt index 23ab5a8c..b67d908f 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/EntryViewModel.kt @@ -10,14 +10,14 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.* class EntryViewModel( - private val entriesUseCases: EntriesUseCases, + private val entryUseCases: EntryUseCases, private val scope: CoroutineScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) ) { private val _state = MutableStateFlow(UiState.Empty) val state: StateFlow = _state fun getAllEntries() { - entriesUseCases.getAllEntriesUseCase().onEach { + entryUseCases.getAllEntriesUseCase().onEach { when (it) { is DataResponse.Success -> _state.value = UiState.Success(it.data) is DataResponse.Error -> _state.value = UiState.Error(it.error!!.message) @@ -28,7 +28,7 @@ class EntryViewModel( } fun getEntryById(id: Int) { - entriesUseCases.getEntryByIdUseCase(id).onEach { + entryUseCases.getEntryByIdUseCase(id).onEach { when (it) { is DataResponse.Success -> _state.value = UiState.Success(it.data) is DataResponse.Error -> _state.value = UiState.Error(it.error!!.message) @@ -39,7 +39,7 @@ class EntryViewModel( } fun createEntry(entry: Entry.In) { - entriesUseCases.createNewEntryUseCase(entry).onEach { + entryUseCases.createNewEntryUseCase(entry).onEach { when (it) { is DataResponse.Success -> _state.value = UiState.Success(it.data) is DataResponse.Error -> _state.value = UiState.Error(it.error!!.message) @@ -50,7 +50,7 @@ class EntryViewModel( } fun changeEntry(entry: Entry.Patch, id: Int) { - entriesUseCases.changeEntryByIdUseCase(entry, id).onEach { + entryUseCases.changeEntryByIdUseCase(entry, id).onEach { when (it) { is DataResponse.Success -> _state.value = UiState.Success(it.data) is DataResponse.Error -> _state.value = UiState.Error(it.error!!.message) @@ -61,7 +61,7 @@ class EntryViewModel( } fun removeEntry(id: Int) { - entriesUseCases.deleteEntryByIdUseCase(id).onEach { + entryUseCases.deleteEntryByIdUseCase(id).onEach { when (it) { is DataResponse.Success -> _state.value = UiState.Success(it.data) is DataResponse.Error -> _state.value = UiState.Error(it.error!!.message) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt index 883fb485..28cb3b67 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt @@ -5,5 +5,5 @@ import de.hsfl.budgetBinder.common.Entry data class EntryState( val selectedEntry: Entry = Entry(0,"",0f,false,null), - val categoryList: List = listOf() + val categoryList: List = listOf(Category(0,"","ffffff",Category.Image.DEFAULT,0f)) ) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index a6696638..c47cc0c4 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -55,14 +55,13 @@ class EntryViewModel( // ---- init { + getCategoryList() when (routerFlow.state.value) { is Screen.Entry.Overview -> { getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) - getCategoryList() } is Screen.Entry.Edit -> { getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) - getCategoryList() } else -> {} } @@ -71,10 +70,10 @@ class EntryViewModel( /* *** Event Handling *** */ fun onEvent(event: EntryEvent) { when (event) { - is EntryEvent.EnteredName -> _nameText.value = nameText.value - is EntryEvent.EnteredAmount -> _amountText.value = amountText.value + is EntryEvent.EnteredName -> _nameText.value = event.value + is EntryEvent.EnteredAmount -> _amountText.value = event.value is EntryEvent.EnteredRepeat -> _repeatState.value = !repeatState.value - is EntryEvent.EnteredCategoryID -> _categoryIDState.value = categoryIDState.value + is EntryEvent.EnteredCategoryID -> _categoryIDState.value = event.value is EntryEvent.EnteredAmountSign -> _amountSignState.value = !amountSignState.value is EntryEvent.OnCreateEntry -> when (routerFlow.state.value) { @@ -125,7 +124,7 @@ class EntryViewModel( } } } - private fun getCategoryList() = scope.launch { + fun getCategoryList() = scope.launch { entryUseCases.getCategoryListUseCase.categories() .collect { handleDataResponse(response = it, onSuccess = {cl -> _categoryListState.value = cl}) } } @@ -135,7 +134,10 @@ class EntryViewModel( when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) - is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg + is DataResponse.Success<*> -> { + _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg + routerFlow.navigateTo(Screen.Dashboard) + } is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index ba902a66..b264465e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -8,6 +8,7 @@ import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType import org.jetbrains.compose.web.attributes.type +import org.jetbrains.compose.web.attributes.value import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle @@ -383,9 +384,20 @@ fun DeleteDialog( @Composable fun ChooseCategoryMenu( categoryList: List, + selectedCategory: Int?, getCategoryId: (Int?) -> Unit ) { - var chosenCategory by remember { mutableStateOf(categoryList[0]) } + var chosenCategory by remember { + mutableStateOf( + if (selectedCategory == null) { + categoryList[0] + } else { + categoryList[selectedCategory] + } + ) + } + + var showList by remember { mutableStateOf(false) } Button(attrs = { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 3c5dd3d6..7a22fd76 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -5,23 +5,14 @@ import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.NavBar -import de.hsfl.budgetBinder.compose.category.categoryIdToCategory -import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.domain.usecase.* -import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiEvent import de.hsfl.budgetBinder.presentation.flow.RouterFlow - -import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel import di import kotlinx.coroutines.flow.collectLatest -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.Text import org.kodein.di.instance -import kotlin.math.absoluteValue @Composable fun EntryComponent() { @@ -30,10 +21,6 @@ fun EntryComponent() { val routerFlow: RouterFlow by di.instance() val screenState = routerFlow.state.collectAsState() val loadingState = remember { mutableStateOf(false) } - //Data to load - val entry = viewModel.selectedEntryState.collectAsState() - val categoryList = viewModel.categoryListState.collectAsState() - //Inputs LaunchedEffect(key1 = true) { viewModel.eventFlow.collectLatest { event -> @@ -53,31 +40,7 @@ fun EntryComponent() { ) } - is Screen.EntryEdit -> { - EntryEditView( - onEditEntryButtonPressed = { name: String, amount: Float, repeat: Boolean, category: Entry.Category? -> - viewModel.changeEntry( - Entry.Patch(name, amount, repeat, category), - (screenState.value as Screen.EntryEdit).id - ) - } - ) - viewModel.getEntryById((screenState.value as Screen.EntryEdit).id)//(screenState.value as Screen.EntryEdit).id) - } - is Screen.EntryOverview -> { - EntryOverviewView( - onEditButton = { id, -> screenState.value = Screen.EntryEdit(id) }, - onDeleteButton = { id -> - viewModel.removeEntry(id) - screenState.value = Screen.Dashboard - } - ) - viewModel.getEntryById((screenState.value as Screen.EntryOverview).id) - } else -> {} } } } - -fun entriesFromCategory(list: List, category_id: Int?): List = - list.filter { it.category_id == category_id } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 92dff5ed..fa8e84c3 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -25,7 +25,7 @@ fun EntryCreateView( val entryNameTextField by viewModel.nameText.collectAsState() val entryAmountTextField by viewModel.amountText.collectAsState() val entryRepeat by viewModel.repeatState.collectAsState() - val entryCategoryIDTextField by viewModel.repeatState.collectAsState() + val entryCategoryIDTextField by viewModel.categoryIDState.collectAsState() val amountSign by viewModel.amountSignState.collectAsState() //Data val categoryList by viewModel.categoryListState.collectAsState() @@ -194,7 +194,7 @@ fun EntryCreateView( } } Div(attrs = { style { flex(50.percent) } }) { - ChooseCategoryMenu(categoryList) { id -> + ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index bc189082..5067a17e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -244,7 +244,7 @@ fun EntryEditView( } } Div(attrs = { style { flex(50.percent) } }) { - ChooseCategoryMenu(categoryList) { id -> entryCategoryIDTextFieldState = id.toString() } + //ChooseCategoryMenu(categoryList, ) { id -> entryCategoryIDTextFieldState = id.toString() } } } Div( From 8438754326bdeedea239598eac7d205a3558e328 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 18:56:23 +0200 Subject: [PATCH 266/325] Add first version of snackbar UiEvent feedback --- .../viewmodel/entryViewModel/EntryState.kt | 2 +- .../entryViewModel/EntryViewModel.kt | 43 +++++++++++++------ .../hsfl/budgetBinder/compose/Composables.kt | 30 +++++++------ .../src/jsMain/kotlin/main.kt | 36 ++++++++++++++++ 4 files changed, 84 insertions(+), 27 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt index 28cb3b67..183cde42 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt @@ -5,5 +5,5 @@ import de.hsfl.budgetBinder.common.Entry data class EntryState( val selectedEntry: Entry = Entry(0,"",0f,false,null), - val categoryList: List = listOf(Category(0,"","ffffff",Category.Image.DEFAULT,0f)) + val categoryList: List = listOf(Category(0,"No category","ffffff",Category.Image.DEFAULT,0f)) ) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index c47cc0c4..5aeca5d4 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -75,18 +75,22 @@ class EntryViewModel( is EntryEvent.EnteredRepeat -> _repeatState.value = !repeatState.value is EntryEvent.EnteredCategoryID -> _categoryIDState.value = event.value is EntryEvent.EnteredAmountSign -> _amountSignState.value = !amountSignState.value - is EntryEvent.OnCreateEntry -> + is EntryEvent.OnCreateEntry -> { when (routerFlow.state.value) { is Screen.Entry.Create -> createEntry( Entry.In( nameText.value, - amountText.value, + buildAmount(), repeatState.value, categoryIDState.value ) ) - else -> routerFlow.navigateTo(Screen.Entry.Create) + + else -> { + routerFlow.navigateTo(Screen.Entry.Create) + } } + } is EntryEvent.OnEditEntry -> when (routerFlow.state.value) { @@ -124,21 +128,28 @@ class EntryViewModel( } } } + fun getCategoryList() = scope.launch { entryUseCases.getCategoryListUseCase.categories() - .collect { handleDataResponse(response = it, onSuccess = {cl -> _categoryListState.value = cl}) } + .collect { + handleDataResponse( + response = it, + onSuccess = { cl -> _categoryListState.value = cl }) + } } fun createEntry(entry: Entry.In) { - entryUseCases.createNewEntryUseCase(entry).onEach { - when (it) { - is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) - is DataResponse.Success<*> -> { - _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg - routerFlow.navigateTo(Screen.Dashboard) + scope.launch { + entryUseCases.createNewEntryUseCase(entry).collect { response -> + when (response) { + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + is DataResponse.Success<*> -> { + _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg + routerFlow.navigateTo(Screen.Dashboard) + } + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) } - is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) } } } @@ -164,6 +175,7 @@ class EntryViewModel( } } } + private suspend fun handleDataResponse(response: DataResponse, onSuccess: (T) -> Unit) { when (response) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) @@ -178,4 +190,11 @@ class EntryViewModel( } } } + private fun buildAmount(): Float{ + return if(_amountSignState.value){ + _amountText.value + }else{ + _amountText.value*-1 + } + } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index b264465e..713c342a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -93,19 +93,15 @@ fun Icon(icon_name: String) { // Snackbar that shows msg @Composable -fun FeedbackSnackbar(msg: String, hidden: Boolean = false) { - var hiddenValue by remember { mutableStateOf(hidden) } +fun FeedbackSnackbar(msg: String, hidden: Boolean = false, onDismiss: () -> Unit) { Aside( attrs = { - when (hiddenValue) { + when (hidden) { false -> classes("mdc-snackbar", "mdc-snackbar--open") true -> classes("mdc-snackbar", "maria") } onClick { - hiddenValue = true - console.log(this@Aside) - console.log("ldsadsad") - + onDismiss() } }) { Div(attrs = { @@ -387,15 +383,20 @@ fun ChooseCategoryMenu( selectedCategory: Int?, getCategoryId: (Int?) -> Unit ) { + console.log(categoryList) + var choseCat = categoryList[0] + + for (category in categoryList) { + if (category.id == selectedCategory) { + choseCat = category + break + } + } + var chosenCategory by remember { - mutableStateOf( - if (selectedCategory == null) { - categoryList[0] - } else { - categoryList[selectedCategory] - } - ) + mutableStateOf(choseCat) } + console.log(chosenCategory) var showList by remember { mutableStateOf(false) } @@ -434,3 +435,4 @@ fun ChooseCategoryMenu( } } + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt index 797d4749..210b3a1b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt @@ -1,11 +1,16 @@ import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.Router import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.di.kodein +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow import io.ktor.client.engine.js.* +import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.Style import org.jetbrains.compose.web.renderComposable import org.kodein.di.compose.withDI +import org.kodein.di.instance fun main() { renderComposable("root") { @@ -18,5 +23,36 @@ val di = kodein(ktorEngine = Js.create()) @Composable fun App() = withDI(di) { + val uiEventFlow: UiEventSharedFlow by di.instance() + val loadingState = remember { mutableStateOf(false) } + val snackBarText = remember { mutableStateOf("") } + val snackBarHidden = remember { mutableStateOf(true) } + LaunchedEffect(key1 = true) { + uiEventFlow.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> loadingState.value = true + is UiEvent.ShowError -> { + loadingState.value = false + snackBarText.value = event.msg + snackBarHidden.value = false + } + is UiEvent.ShowSuccess -> { + loadingState.value = false + snackBarText.value = event.msg + snackBarHidden.value = false + } + else -> {} + } + } + } + if (loadingState.value && snackBarHidden.value) { + snackBarText.value = "Loading" + snackBarHidden.value = false + console.log("loading now! ${snackBarHidden.value}") + } + FeedbackSnackbar(snackBarText.value,snackBarHidden.value) { + snackBarHidden.value = true + loadingState.value = false + } Router() } From b52ba5df73b1d6ee344b3d0ccc5e15b0f5ca9015 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 18:59:45 +0200 Subject: [PATCH 267/325] Fix EntryViewModels usage of UseCases --- .../entryViewModel/EntryViewModel.kt | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 5aeca5d4..f33b123a 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -155,23 +155,33 @@ class EntryViewModel( } fun updateEntry(entry: Entry.Patch, id: Int) { - entryUseCases.changeEntryByIdUseCase(entry, id).onEach { - when (it) { - is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) - is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully changed")) //TODO?: Change the msg - is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + scope.launch { + entryUseCases.changeEntryByIdUseCase(entry, id).collect { response -> + when (response) { + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + is DataResponse.Success<*> -> { + _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully updated")) //TODO?: Change the msg + routerFlow.navigateTo(Screen.Dashboard) + } + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + } } } } fun deleteEntry(id: Int) { - entryUseCases.deleteEntryByIdUseCase(id).onEach { - when (it) { - is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) - is DataResponse.Success<*> -> _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully deleted")) //TODO?: Change the msg - is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + scope.launch { + entryUseCases.deleteEntryByIdUseCase(id).collect { response -> + when (response) { + is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + is DataResponse.Success<*> -> { + _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully deleted")) //TODO?: Change the msg + routerFlow.navigateTo(Screen.Dashboard) + } + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) + } } } } @@ -190,11 +200,12 @@ class EntryViewModel( } } } - private fun buildAmount(): Float{ - return if(_amountSignState.value){ + + private fun buildAmount(): Float { + return if (_amountSignState.value) { _amountText.value - }else{ - _amountText.value*-1 + } else { + _amountText.value * -1 } } } From d4595c3620f266fdbaa7d60c53a196afec6c5f3b Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 19:54:32 +0200 Subject: [PATCH 268/325] Restructure init to loadEvents, reset data inputs in load --- .../viewmodel/entryViewModel/EntryEvent.kt | 5 ++ .../entryViewModel/EntryViewModel.kt | 48 +++++++++++++------ .../compose/entry/EntryComponent.kt | 2 +- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt index b71a37d1..463668d9 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt @@ -17,4 +17,9 @@ sealed class EntryEvent { object OnDeleteDialogConfirm : EntryEvent() object OnDeleteDialogDismiss : EntryEvent() + //Load Data for Screen (has some problems when done in init) + object LoadCreate : EntryEvent() + object LoadOverview : EntryEvent() + object LoadEdit : EntryEvent() + } diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index f33b123a..96101604 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -54,18 +54,6 @@ class EntryViewModel( val eventFlow = UiEventSharedFlow.eventFlow // ---- - init { - getCategoryList() - when (routerFlow.state.value) { - is Screen.Entry.Overview -> { - getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) - } - is Screen.Entry.Edit -> { - getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) - } - else -> {} - } - } /* *** Event Handling *** */ fun onEvent(event: EntryEvent) { @@ -88,6 +76,7 @@ class EntryViewModel( else -> { routerFlow.navigateTo(Screen.Entry.Create) + } } } @@ -102,16 +91,32 @@ class EntryViewModel( Entry.Category(categoryIDState.value) ), selectedEntryState.value.id ) - else -> routerFlow.navigateTo(Screen.Entry.Edit(selectedEntryState.value.id)) //using ID seems... unnecessary? + else -> { + resetFlows() + routerFlow.navigateTo(Screen.Entry.Edit(selectedEntryState.value.id)) + } //using ID seems... unnecessary?} } is EntryEvent.OnDeleteEntry -> _dialogState.value = true is EntryEvent.OnDeleteDialogConfirm -> deleteEntry(selectedEntryState.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false + is EntryEvent.LoadCreate -> { + resetFlows() + getCategoryList() + } + is EntryEvent.LoadOverview -> { + resetFlows() + getCategoryList() + getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) + } + is EntryEvent.LoadEdit -> { + resetFlows() + getCategoryList() + getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) + } else -> { throw Exception("Unhandled EntryEvent in EntryViewModel") } } - } @@ -201,6 +206,9 @@ class EntryViewModel( } } + /** + * Negates amount if amountSign is false + * */ private fun buildAmount(): Float { return if (_amountSignState.value) { _amountText.value @@ -208,4 +216,16 @@ class EntryViewModel( _amountText.value * -1 } } + + /** + * Resets Data Input Variables + */ + private fun resetFlows(){ + _nameText.value = EntryInputState().name + _amountText.value = EntryInputState().amount + _amountSignState.value = EntryInputState().amountSign + _repeatState.value = EntryInputState().repeat + _categoryIDState.value = EntryInputState().categoryID + } + } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 7a22fd76..8fa1b36b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -38,7 +38,7 @@ fun EntryComponent() { EntryCreateView( onCreateEntryButtonPressed = { viewModel.onEvent(EntryEvent.OnCreateEntry) } ) - + viewModel.onEvent(EntryEvent.LoadCreate) } else -> {} } From 4750ff9ff6f323e6faf3caa1f29d15db9fa6192c Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 22:48:57 +0200 Subject: [PATCH 269/325] Overhaul EntryOverviewView with new ViewModel features --- .../entryViewModel/EntryViewModel.kt | 8 +- .../compose/entry/EntryComponent.kt | 9 ++ .../compose/entry/EntryOverviewView.kt | 112 ++++++------------ 3 files changed, 46 insertions(+), 83 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index 96101604..bf13e935 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -105,7 +105,6 @@ class EntryViewModel( } is EntryEvent.LoadOverview -> { resetFlows() - getCategoryList() getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) } is EntryEvent.LoadEdit -> { @@ -113,16 +112,13 @@ class EntryViewModel( getCategoryList() getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) } - else -> { - throw Exception("Unhandled EntryEvent in EntryViewModel") - } } } /* *** Use Case usages *** */ - fun getEntryById(id: Int) { - entryUseCases.getEntryByIdUseCase(id).onEach { + fun getEntryById(id: Int) = scope.launch { + entryUseCases.getEntryByIdUseCase(id).collect { when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 8fa1b36b..eb13f870 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -40,6 +40,15 @@ fun EntryComponent() { ) viewModel.onEvent(EntryEvent.LoadCreate) } + is Screen.Entry.Overview -> { + EntryOverviewView( + onEditButton = { viewModel.onEvent(EntryEvent.OnEditEntry) }, + onDeleteButton = { viewModel.onEvent(EntryEvent.OnDeleteEntry) }, + onDeleteDialogConfirmButton = { viewModel.onEvent(EntryEvent.OnDeleteDialogConfirm) }, + onDeleteDialogDismissButton = { viewModel.onEvent(EntryEvent.OnDeleteDialogDismiss) } + ) + viewModel.onEvent(EntryEvent.LoadOverview) + } else -> {} } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index 1d79a64a..66c0c8c5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -10,95 +10,52 @@ import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import di import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle import org.jetbrains.compose.web.svg.Svg +import org.kodein.di.instance @Composable fun EntryOverviewView( - state: State, - onEditButton: (id: Int) -> Unit, - onDeleteButton: (id: Int) -> Unit, - onChangeToDashboard: () -> Unit, - onChangeToCategory: () -> Unit, - onChangeToSettings: () -> Unit + onEditButton: () -> Unit, + onDeleteButton: () -> Unit, + onDeleteDialogConfirmButton: () -> Unit, + onDeleteDialogDismissButton: () -> Unit ) { - var entry by remember { mutableStateOf(Entry(0, "", 0f, false, null)) } - val viewState by remember { state } - - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Settings") - } - } - }) - - MainFlexContainer { - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Entry") } - - EntryOverview(entry, onEditButton, onDeleteButton) - when (viewState) { - is UiState.Success<*> -> { - when (val element = (viewState as UiState.Success<*>).element) { - is Entry -> entry = element - else -> {} - } - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } + val viewModel: EntryViewModel by di.instance() + //Data + val entry by viewModel.selectedEntryState.collectAsState() + console.log("Our Entry is $entry") + val deleteDialog by viewModel.dialogState.collectAsState() + H1( + attrs = { + style { margin(2.percent) } } - } + ) { Text(" Entry") } + + EntryOverview( + entry, + deleteDialog, + onEditButton, + onDeleteButton, + onDeleteDialogConfirmButton, + onDeleteDialogDismissButton + ) } @Composable fun EntryOverview( entry: Entry, - onEditButton: (Int) -> Unit, - onDeleteButton: (Int) -> Unit + deleteDialog: Boolean, + onEditButton: () -> Unit, + onDeleteButton: () -> Unit, + onDeleteDialogConfirmButton: () -> Unit, + onDeleteDialogDismissButton: () -> Unit ) { - var deleteDialog by remember { mutableStateOf(false) } Div( attrs = { classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) @@ -127,7 +84,7 @@ fun EntryOverview( ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton(entry.id) } + onClick { onEditButton() } style { flex(50.percent) margin(1.5.percent) @@ -137,7 +94,7 @@ fun EntryOverview( } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { deleteDialog = true } + onClick { onDeleteButton() } style { flex(50.percent) margin(1.5.percent) @@ -150,8 +107,9 @@ fun EntryOverview( if (deleteDialog) { DeleteDialog( false, - { onDeleteButton(entry.id) }, - { deleteDialog = false }) { Text("Delete Entry?") } + { onDeleteDialogConfirmButton() }, + { onDeleteDialogDismissButton() }) + { Text("Delete Entry?") } } } From 9dc9393fe816f78d33e868322441f1fc2ea82d73 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Wed, 22 Jun 2022 23:42:30 +0200 Subject: [PATCH 270/325] Overhaul EntryEditView with new ViewModel structure and fix some small stuff --- .../compose/entry/EntryComponent.kt | 9 +- .../compose/entry/EntryCreateView.kt | 5 +- .../compose/entry/EntryEditView.kt | 365 ++++++++---------- 3 files changed, 161 insertions(+), 218 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index eb13f870..38016c5e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -36,7 +36,7 @@ fun EntryComponent() { when (screenState.value) { is Screen.Entry.Create -> { EntryCreateView( - onCreateEntryButtonPressed = { viewModel.onEvent(EntryEvent.OnCreateEntry) } + onCreateButton = { viewModel.onEvent(EntryEvent.OnCreateEntry) } ) viewModel.onEvent(EntryEvent.LoadCreate) } @@ -49,6 +49,13 @@ fun EntryComponent() { ) viewModel.onEvent(EntryEvent.LoadOverview) } + is Screen.Entry.Edit -> { + EntryEditView( + onEditButton = { viewModel.onEvent(EntryEvent.OnEditEntry)} + ) + viewModel.onEvent(EntryEvent.LoadEdit) + + } else -> {} } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index fa8e84c3..fc383ee4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -18,13 +18,12 @@ import org.kodein.di.instance @OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryCreateView( - onCreateEntryButtonPressed: () -> Unit, + onCreateButton: () -> Unit, ) { val viewModel: EntryViewModel by di.instance() //Input val entryNameTextField by viewModel.nameText.collectAsState() val entryAmountTextField by viewModel.amountText.collectAsState() - val entryRepeat by viewModel.repeatState.collectAsState() val entryCategoryIDTextField by viewModel.categoryIDState.collectAsState() val amountSign by viewModel.amountSignState.collectAsState() //Data @@ -37,7 +36,7 @@ fun EntryCreateView( ) { Text("Create new Entry") } Form(attrs = { this.addEventListener("submit") { - onCreateEntryButtonPressed() + onCreateButton() it.preventDefault() } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 5067a17e..f1d58c14 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -9,6 +9,9 @@ import de.hsfl.budgetBinder.compose.category.categoryIdToCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent +import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import di import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType import org.jetbrains.compose.web.attributes.InputType @@ -18,269 +21,203 @@ import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Path import org.jetbrains.compose.web.svg.Svg +import org.kodein.di.instance @OptIn(ExperimentalComposeWebSvgApi::class) @Composable fun EntryEditView( - state: State, - onChangeToDashboard: () -> Unit, - onChangeToSettings: () -> Unit, - onChangeToCategory: () -> Unit, - onEditEntryButtonPressed: (name: String, amount: Float, repeat: Boolean, category: Entry.Category) -> Unit, + onEditButton: () -> Unit, ) { - var entry by remember { mutableStateOf(Entry(0, "", 0f, false, 0)) } - var categoryList by remember { mutableStateOf>(emptyList()) } - var switchState by remember { mutableStateOf(false) } - var entryNameTextFieldState by remember { mutableStateOf("") } - var entryAmountTextFieldState by remember { mutableStateOf("") } - var entryRepeatState by remember { mutableStateOf("") } - var entryCategoryIDTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } + val viewModel: EntryViewModel by di.instance() + //Input + val entryNameTextField by viewModel.nameText.collectAsState() + val entryAmountTextField by viewModel.amountText.collectAsState() + val entryRepeat by viewModel.repeatState.collectAsState() + val entryCategoryIDTextField by viewModel.categoryIDState.collectAsState() + val amountSign by viewModel.amountSignState.collectAsState() + //Data + val categoryList by viewModel.categoryListState.collectAsState() + val entry by viewModel.selectedEntryState.collectAsState() - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Edit Entry") } + Form(attrs = { + this.addEventListener("submit") { + onEditButton() + it.preventDefault() + } + } + ) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { Span( attrs = { - classes("mdc-button__label") + classes("mdc-text-field__ripple") } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { + ) { } Span( attrs = { - classes("mdc-button__label") + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Entry Name") } + Input( + type = InputType.Text ) { - Text("Settings") + classes("mdc-text-field__input") + value(entryNameTextField) + required(true) + onInput { + viewModel.onEvent(EntryEvent.EnteredName(it.value)) + } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - }) - - MainFlexContainer { - H1( + } + Div( attrs = { - style { margin(2.percent) } - } - ) { Text("Edit Entry") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$entryNameTextFieldState, $entryAmountTextFieldState, $entryRepeatState, ${entryCategoryIDTextFieldState.toInt()}") - onEditEntryButtonPressed( - entryNameTextFieldState, - (if (!switchState) "-$entryAmountTextFieldState" else entryAmountTextFieldState).toFloat(), - entryRepeatState.toBoolean(), - Entry.Category(entryCategoryIDTextFieldState.toInt()) - ) - it.preventDefault() + classes(AppStylesheet.margin) } - } ) { - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Entry Name") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(entryNameTextFieldState) - required(true) - onInput { - entryNameTextFieldState = it.value - } + classes("mdc-text-field__ripple") } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } } - ) { - Span( + ) { Text("Amount") } + Div { + Button( attrs = { - classes("mdc-text-field__ripple") + if (!amountSign) classes("mdc-switch", "mdc-switch--unselected") + else classes("mdc-switch", "mdc-switch--selected") + id("basic-switch") + attr("role", "switch") + attr("aria-checked", "false") + type(ButtonType.Button) + onClick { viewModel.onEvent(EntryEvent.EnteredAmountSign) } } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } - } - ) { Text("Amount") } - Div { - Button( - attrs = { - if (!switchState) classes("mdc-switch", "mdc-switch--unselected") - else classes("mdc-switch", "mdc-switch--selected") - id("basic-switch") - attr("role", "switch") - attr("aria-checked", "false") - type(ButtonType.Button) - onClick { switchState = !switchState } - } - ) { - Div(attrs = { classes("mdc-switch__track") }) { } - Div(attrs = { classes("mdc-switch__handle-track") }) { - Div(attrs = { classes("mdc-switch__handle") }) { - Div(attrs = { classes("mdc-switch__shadow") }) { - Div(attrs = { classes("mdc-elevation-overlay") }) { } + ) { + Div(attrs = { classes("mdc-switch__track") }) { } + Div(attrs = { classes("mdc-switch__handle-track") }) { + Div(attrs = { classes("mdc-switch__handle") }) { + Div(attrs = { classes("mdc-switch__shadow") }) { + Div(attrs = { classes("mdc-elevation-overlay") }) { } + } + Div(attrs = { classes("mdc-switch__ripple") }) { } + Div(attrs = { classes("mdc-switch__icons") }) { + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") } - Div(attrs = { classes("mdc-switch__ripple") }) { } - Div(attrs = { classes("mdc-switch__icons") }) { - Svg( - attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, - viewBox = "0 0 24 24" - ) { - Path("M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z") - } - Svg( - attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, - viewBox = "0 0 24 24" - ) { - Path("M20 13H4v-2h16v2z") - } + Svg( + attrs = { classes("mdc-switch__icon", "mdc-switch__icon") }, + viewBox = "0 0 24 24" + ) { + Path("M20 13H4v-2h16v2z") } } } } } - Div(attrs = { - classes("mdc-typography--headline6", AppStylesheet.text) - }) { - Text(if (switchState) "+" else "-") - } - Input( - type = InputType.Number - ) { - attr("step", "0.01") - classes("mdc-text-field__input") - onInput { - entryAmountTextFieldState = it.value.toString() - } + } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { + Text(if (amountSign) "+" else "-") + } + Input( + type = InputType.Number + ) { + attr("step", "0.01") + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(EntryEvent.EnteredAmount(it.value as Float)) } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - Div( - attrs = { - classes(AppStylesheet.margin, AppStylesheet.flexContainer) - } - ) { - Div(attrs = { style { flex(50.percent) } }) { - Div(attrs = { classes("mdc-form-field") }) { - Div(attrs = { classes("mdc-checkbox") }) { - Input(type = InputType.Checkbox) - { - classes("mdc-checkbox__native-control") - id("checkbox-1") - onInput { - entryRepeatState = it.value.toString() - } + } + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) + } + ) { + Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { classes("mdc-form-field") }) { + Div(attrs = { classes("mdc-checkbox") }) { + Input(type = InputType.Checkbox) + { + classes("mdc-checkbox__native-control") + id("checkbox-1") + onInput { + viewModel.onEvent(EntryEvent.EnteredRepeat) } - Div(attrs = { classes("mdc-checkbox__background") }) { - Svg(attrs = { classes("mdc-checkbox__checkmark") }, viewBox = "0 0 24 24") { - Path( - "M1.73,12.91 8.1,19.28 22.79,4.59", - attrs = { classes("mdc-checkbox__checkmark") }) - } - Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } + } + Div(attrs = { classes("mdc-checkbox__background") }) { + Svg( + attrs = { classes("mdc-checkbox__checkmark") }, + viewBox = "0 0 24 24" + ) { + Path( + "M1.73,12.91 8.1,19.28 22.79,4.59", + attrs = { classes("mdc-checkbox__checkmark") }) } - Div(attrs = { classes("mdc-checkbox__ripple") }) { } + Div(attrs = { classes("mdc-checkbox__mixedmark") }) { } } - Label(forId = "checkbox-1") { Text("repeat") } + Div(attrs = { classes("mdc-checkbox__ripple") }) { } } - } - Div(attrs = { style { flex(50.percent) } }) { - //ChooseCategoryMenu(categoryList, ) { id -> entryCategoryIDTextFieldState = id.toString() } + Label(forId = "checkbox-1") { Text("repeat") } } } - Div( - attrs = { - classes(AppStylesheet.margin) + Div(attrs = { style { flex(50.percent) } }) { + ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> + viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) } - ) { - SubmitInput( - attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) } - Div { - when (viewState) { - is UiState.Success<*> -> { - when (val element = (viewState as UiState.Success<*>).element) { - is Entry -> { - entry = element - entryNameTextFieldState = entry.name - entryAmountTextFieldState = entry.amount.toString() - switchState = !entry.amount.toString().startsWith("-") - entryRepeatState = entry.repeat.toString() - entryCategoryIDTextFieldState = entry.category_id.toString() - } - } - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } + } + Div( + attrs = { + classes(AppStylesheet.margin) } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) } } } From 6820b2d6c277fc1584fdcf447d0a2174d49948ad Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 00:26:31 +0200 Subject: [PATCH 271/325] Load EntryEditView with data from selected entry (except amount) --- .../viewmodel/entryViewModel/EntryViewModel.kt | 13 +++++++++++-- .../budgetBinder/compose/entry/EntryEditView.kt | 5 +++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt index bf13e935..6cc2e3ed 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt @@ -16,6 +16,9 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch +import kotlin.math.absoluteValue +import kotlin.math.sign +import kotlin.math.withSign class EntryViewModel( private val entryUseCases: EntryUseCases, @@ -124,6 +127,12 @@ class EntryViewModel( is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) is DataResponse.Success<*> -> { _selectedEntryState.value = it.data!! + //Load data into variables for edit + _nameText.value = _selectedEntryState.value.name + _amountText.value = _selectedEntryState.value.amount.absoluteValue + _amountSignState.value = _selectedEntryState.value.amount >= 0 + _repeatState.value = _selectedEntryState.value.repeat + _categoryIDState.value = _selectedEntryState.value.category_id } is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) } @@ -173,7 +182,7 @@ class EntryViewModel( fun deleteEntry(id: Int) { scope.launch { - entryUseCases.deleteEntryByIdUseCase(id).collect { response -> + entryUseCases.deleteEntryByIdUseCase(id).collect { response -> when (response) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) @@ -216,7 +225,7 @@ class EntryViewModel( /** * Resets Data Input Variables */ - private fun resetFlows(){ + private fun resetFlows() { _nameText.value = EntryInputState().name _amountText.value = EntryInputState().amount _amountSignState.value = EntryInputState().amountSign diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index f1d58c14..7763e54a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -178,14 +178,15 @@ fun EntryEditView( Div(attrs = { style { flex(50.percent) } }) { Div(attrs = { classes("mdc-form-field") }) { Div(attrs = { classes("mdc-checkbox") }) { - Input(type = InputType.Checkbox) + CheckboxInput (attrs = { + checked(entryRepeat) classes("mdc-checkbox__native-control") id("checkbox-1") onInput { viewModel.onEvent(EntryEvent.EnteredRepeat) } - } + }) Div(attrs = { classes("mdc-checkbox__background") }) { Svg( attrs = { classes("mdc-checkbox__checkmark") }, From 68fe15b4003c39b3566cb8f0c10188e778a8e3ee Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 00:36:45 +0200 Subject: [PATCH 272/325] Load EntryEditView with amount data from selected entry --- .../kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 7763e54a..c57e1213 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -159,6 +159,7 @@ fun EntryEditView( ) { attr("step", "0.01") classes("mdc-text-field__input") + value(entryAmountTextField) onInput { viewModel.onEvent(EntryEvent.EnteredAmount(it.value as Float)) } From fe9055e3c4cb52bc961e2a22cbc41d73dbd27772 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 00:59:11 +0200 Subject: [PATCH 273/325] Add some padding and nowrap to Categories in ChooseCategoryMenu --- .../de/hsfl/budgetBinder/compose/Composables.kt | 2 +- .../hsfl/budgetBinder/compose/entry/EntryEditView.kt | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 713c342a..e6c4b967 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -426,7 +426,7 @@ fun ChooseCategoryMenu( onClick { chosenCategory = category; getCategoryId(category.id) } }) { Span(attrs = { classes("mdc-list-item__ripple") }) { } - Span(attrs = { }) { Text(category.name) } + Span(attrs = { classes(AppStylesheet.moneyText)}) { Text(category.name) } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index c57e1213..4929d7bb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -1,14 +1,8 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.ChooseCategoryMenu -import de.hsfl.budgetBinder.compose.MainFlexContainer -import de.hsfl.budgetBinder.compose.category.categoryIdToCategory import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel import di @@ -204,7 +198,10 @@ fun EntryEditView( Label(forId = "checkbox-1") { Text("repeat") } } } - Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { style { + flex(50.percent) + alignItems(AlignItems.Stretch) + } }) { ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) } From 88e8e40c4802a96407b59ef28a731daec66a5ad2 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 16:37:57 +0200 Subject: [PATCH 274/325] Add space between Buttons --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt index e3d7263a..61cdebde 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt @@ -51,7 +51,8 @@ fun NavBar(content: @Composable () -> Unit) { classes( "mdc-button", "mdc-button--raised", - "mdc-top-app-bar__navigation-icon" + "mdc-top-app-bar__navigation-icon", + AppStylesheet.marginRight ) onClick { viewModel.onEvent(NavDrawerEvent.OnCreateEntry) } } @@ -69,7 +70,8 @@ fun NavBar(content: @Composable () -> Unit) { classes( "mdc-button", "mdc-button--raised", - "mdc-top-app-bar__navigation-icon" + "mdc-top-app-bar__navigation-icon", + AppStylesheet.marginRight ) onClick { viewModel.onEvent(NavDrawerEvent.OnCategory) } } @@ -87,7 +89,8 @@ fun NavBar(content: @Composable () -> Unit) { classes( "mdc-button", "mdc-button--raised", - "mdc-top-app-bar__navigation-icon" + "mdc-top-app-bar__navigation-icon", + AppStylesheet.marginRight ) onClick { viewModel.onEvent(NavDrawerEvent.OnSettings) } } From cd0939312d855f1cd5ba57e70362d8aaba43c037 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 17:07:02 +0200 Subject: [PATCH 275/325] Add new viewModel logic --- .../de/hsfl/budgetBinder/compose/Router.kt | 4 +- .../settings/SettingsChangeUserDataView.kt | 151 +++++++++--------- .../compose/settings/SettingsComponent.kt | 50 +++--- .../compose/settings/SettingsView.kt | 98 ++++-------- 4 files changed, 130 insertions(+), 173 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index bee63303..cc096d5e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -7,6 +7,7 @@ import de.hsfl.budgetBinder.compose.dashboard.DashboardComponent import de.hsfl.budgetBinder.compose.entry.EntryComponent import de.hsfl.budgetBinder.compose.login.LoginComponent import de.hsfl.budgetBinder.compose.register.RegisterComponent +import de.hsfl.budgetBinder.compose.settings.SettingsComponent import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.flow.RouterFlow import di @@ -24,9 +25,8 @@ fun Router() { is Screen.Register -> RegisterComponent() is Screen.Login -> LoginComponent() is Screen.Dashboard -> DashboardComponent() + is Screen.Settings -> SettingsComponent() is Screen.Entry -> EntryComponent() - is Screen.Settings, is Screen.SettingsChangeUserData - -> Text("Settings")//SettingsComponent(screenState = screenState) is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> Text("Old Category") //CategoryComponent(screenState = screenState) is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt index e9dcf578..73eb02a4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt @@ -1,78 +1,50 @@ package de.hsfl.budgetBinder.compose.settings import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.viewmodel.settings.EditUserEvent +import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditUserViewModel +import di +import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.required import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* +import org.kodein.di.instance @Composable -fun SettingsChangeUserDataView( - state: State, - onChangeToDashboard: () -> Unit, - onChangeToSettings: () -> Unit, - onChangeToCategory: () -> Unit, - onChangeDataButtonPressed: (firstName: String, lastName: String, password: String) -> Unit -) { - var firstNameTextFieldState by remember { mutableStateOf("") } - var lastNameTextFieldState by remember { mutableStateOf("") } - var passwordTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } +fun SettingsChangeUserDataView() { + val viewModel: SettingsEditUserViewModel by di.instance() + val loadingState = remember { mutableStateOf(false) } + val firstNameText = viewModel.firstNameText.collectAsState() + val lastNameText = viewModel.lastNameText.collectAsState() + val passwordText = viewModel.passwordText.collectAsState() + val confirmedPasswordText = viewModel.confirmedPassword.collectAsState() + var checkPassword by remember { mutableStateOf(true) } - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Settings") - } + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is UiEvent.ShowLoading -> loadingState.value = true + is UiEvent.HideSuccess -> loadingState.value = false + else -> loadingState.value = false } - }) - + } + } + NavBar {} MainFlexContainer { H1 { Text("Change User Data") } Form(attrs = { this.addEventListener("submit") { - console.log("$firstNameTextFieldState, $lastNameTextFieldState, $passwordTextFieldState") - onChangeDataButtonPressed( - firstNameTextFieldState, - lastNameTextFieldState, - passwordTextFieldState - ) + checkPassword = passwordText == confirmedPasswordText + console.log(checkPassword) + if (checkPassword) viewModel.onEvent(EditUserEvent.OnUpdate) it.preventDefault() } } @@ -101,10 +73,11 @@ fun SettingsChangeUserDataView( Input( type = InputType.Text ) { + required() classes("mdc-text-field__input") - value(firstNameTextFieldState) + value(firstNameText.value.firstName) onInput { - firstNameTextFieldState = it.value + viewModel.onEvent(EditUserEvent.EnteredFirstName(it.value)) } } Span( @@ -138,10 +111,11 @@ fun SettingsChangeUserDataView( Input( type = InputType.Text ) { + required() classes("mdc-text-field__input") - value(lastNameTextFieldState) + value(lastNameText.value.lastName) onInput { - lastNameTextFieldState = it.value + viewModel.onEvent(EditUserEvent.EnteredLastName(it.value)) } } Span( @@ -172,11 +146,48 @@ fun SettingsChangeUserDataView( classes("mdc-floating-label", "mdc-floating-label--float-above") } ) { Text("Password") } - PasswordInput(value = passwordTextFieldState, + PasswordInput(value = passwordText.value.password, + attrs = { + required() + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(EditUserEvent.EnteredPassword(it.value)) + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Repeat Password") } + PasswordInput(value = confirmedPasswordText.value.confirmedPassword, attrs = { + required() classes("mdc-text-field__input") onInput { - passwordTextFieldState = it.value + viewModel.onEvent(EditUserEvent.EnteredConfirmedPassword(it.value)) } }) Span( @@ -197,17 +208,9 @@ fun SettingsChangeUserDataView( value("Submit") }) } - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } } } + if (!checkPassword) { + FeedbackSnackbar("Passwords do not match") + } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt index a52e7127..46f900c9 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt @@ -3,42 +3,34 @@ package de.hsfl.budgetBinder.compose.settings import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.User import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.flow.DataFlow +import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsViewModel import di +import kotlinx.coroutines.flow.collectLatest import org.kodein.di.instance @Composable -fun SettingsComponent(screenState: MutableState) { - /*val scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - val di = localDI() - val changeMyUserUseCase: ChangeMyUserUseCase by di.instance() - val deleteMyUserUseCase: DeleteMyUserUseCase by di.instance() - val settingsViewModel = SettingsViewModel(changeMyUserUseCase, deleteMyUserUseCase, scope) - val viewState = settingsViewModel.state.collectAsState(scope)*/ - val scope = rememberCoroutineScope() - val settingsViewModel: SettingsViewModel by di.instance() - val viewState = settingsViewModel.state.collectAsState(scope) - +fun SettingsComponent() { + val viewModel: SettingsViewModel by di.instance() + val dataFlow: DataFlow by di.instance() + val routerFlow: RouterFlow by di.instance() + val userState = dataFlow.userState.collectAsState() + val screenState = routerFlow.state.collectAsState() + val loadingState = remember { mutableStateOf(false) } + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { + when (it) { + is UiEvent.ShowLoading -> loadingState.value = true + else -> loadingState.value = false + } + } + } when (screenState.value) { - Screen._Settings -> SettingsView( - state = viewState, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - onDeleteButtonPressed = { settingsViewModel.deleteMyUser(); screenState.value = Screen.Login }, - onChangeButtonPressed = { screenState.value = Screen.SettingsChangeUserData } - ) - Screen.SettingsChangeUserData -> SettingsChangeUserDataView( - state = viewState, - onChangeDataButtonPressed = { firstName, lastName, password -> - settingsViewModel.changeMyUser(User.Patch(firstName, lastName, password)); screenState.value = - Screen._Settings - }, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) + is Screen.Settings.Menu -> SettingsView() + is Screen.Settings.User -> SettingsChangeUserDataView() else -> {} } } \ No newline at end of file diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt index 94e3eab8..325f3af4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt @@ -2,82 +2,42 @@ package de.hsfl.budgetBinder.compose.settings import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.DeleteDialog -import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import org.jetbrains.compose.web.css.flex -import org.jetbrains.compose.web.css.marginLeft -import org.jetbrains.compose.web.css.percent +import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEvent +import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsViewModel +import di +import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* +import org.kodein.di.instance @Composable -fun SettingsView( - state: State, - onChangeToDashboard: () -> Unit, - onChangeToSettings: () -> Unit, - onChangeToCategory: () -> Unit, - onDeleteButtonPressed: () -> Unit, - onChangeButtonPressed: () -> Unit -) { +fun SettingsView() { + val viewModel: SettingsViewModel by di.instance() var deleteDialog by remember { mutableStateOf(false) } - val viewState by remember { state } - - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Settings") - } - } - }) + NavBar { } MainFlexContainer { H1( attrs = { style { marginLeft(2.percent) } } ) { Text("Settings") } - when (viewState) { - is UiState.Success<*> -> { - Text((viewState as UiState.Success<*>).element.toString()) - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + Div( + attrs = { + classes(AppStylesheet.margin, AppStylesheet.flexContainer) } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { viewModel.onEvent(SettingsEvent.OnChangeToSettingsUserEdit) } + style { flex(100.percent) } + } + ) { + Text("Change Userdata") } } Div( @@ -88,11 +48,11 @@ fun SettingsView( Button( attrs = { classes("mdc-button", "mdc-button--raised") - onClick { onChangeButtonPressed() } + onClick { viewModel.onEvent(SettingsEvent.OnLogoutAllDevices) } style { flex(100.percent) } } ) { - Text("Change Userdata") + Text("Logout on all device") } } Div( @@ -103,10 +63,9 @@ fun SettingsView( Button( attrs = { classes("mdc-button", "mdc-button--raised") - onClick { - deleteDialog = true - } - style { flex(100.percent) } + onClick { deleteDialog = true } + style { flex(100.percent) + backgroundColor(Color("#b00020"))} } ) { Text("Delete User") @@ -114,6 +73,9 @@ fun SettingsView( } } if (deleteDialog) { - DeleteDialog(false, { onDeleteButtonPressed() }, { deleteDialog = false }) { Text("Delete User?") } + DeleteDialog( + false, + { viewModel.onEvent(SettingsEvent.OnDeleteDialogConfirm) }, + { deleteDialog = false }) { Text("Delete User?") } } } From c1b3c0755b96a18118b4b6c27c1f3c0994316f9e Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 17:07:36 +0200 Subject: [PATCH 276/325] Fix lastnameText field --- .../de/hsfl/budgetBinder/compose/register/RegisterComponent.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt index fae09b44..ac16bdb1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt @@ -169,7 +169,7 @@ fun RegisterComponent() { type = InputType.Text ) { classes("mdc-text-field__input") - value(lastNameTextState.value.firstName) + value(lastNameTextState.value.lastName) onInput { viewModel.onEvent(RegisterEvent.EnteredLastname(it.value)) } From bdb0cfba50245fba841e09e88031b5aa268684d6 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 17:39:22 +0200 Subject: [PATCH 277/325] Add reset to FeedbackSnackbar --- .../jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index e6c4b967..d5149adb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -122,6 +122,7 @@ fun FeedbackSnackbar(msg: String, hidden: Boolean = false, onDismiss: () -> Unit }) { Button(attrs = { classes("mdc-button", "mdc-snackbar__action") + onClick { onDismiss() } }) { Div(attrs = { classes("mdc-button__ripple") @@ -434,5 +435,3 @@ fun ChooseCategoryMenu( Text(chosenCategory.name) } } - - From 72c1d15d822f9ae7e0d47714967cd8ed57b6f8e1 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 17:39:43 +0200 Subject: [PATCH 278/325] Add FeedbackSnackbar when passwords do not match in SettingsChangeUserDataView --- .../compose/settings/SettingsChangeUserDataView.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt index 73eb02a4..e9b8427b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt @@ -26,7 +26,7 @@ fun SettingsChangeUserDataView() { val lastNameText = viewModel.lastNameText.collectAsState() val passwordText = viewModel.passwordText.collectAsState() val confirmedPasswordText = viewModel.confirmedPassword.collectAsState() - var checkPassword by remember { mutableStateOf(true) } + var openSnackbar by remember { mutableStateOf(false) } LaunchedEffect(key1 = true) { viewModel.eventFlow.collectLatest { event -> @@ -42,9 +42,10 @@ fun SettingsChangeUserDataView() { H1 { Text("Change User Data") } Form(attrs = { this.addEventListener("submit") { - checkPassword = passwordText == confirmedPasswordText - console.log(checkPassword) - if (checkPassword) viewModel.onEvent(EditUserEvent.OnUpdate) + if (passwordText != confirmedPasswordText) { + openSnackbar = true + } + viewModel.onEvent(EditUserEvent.OnUpdate) it.preventDefault() } } @@ -210,7 +211,7 @@ fun SettingsChangeUserDataView() { } } } - if (!checkPassword) { - FeedbackSnackbar("Passwords do not match") + if (openSnackbar) { + FeedbackSnackbar("Passwords do not match") { openSnackbar = false } } } From 234ebfb16e20b67d5224410aa02b05356f998500 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 17:42:29 +0200 Subject: [PATCH 279/325] Add FeedbackSnackbar when passwords do not match in RegisterComponent and add required to all inputs --- .../compose/register/RegisterComponent.kt | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt index ac16bdb1..1c984eb1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt @@ -2,6 +2,7 @@ package de.hsfl.budgetBinder.compose.register import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.User +import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet @@ -13,6 +14,7 @@ import de.hsfl.budgetBinder.presentation.viewmodel.register.RegisterViewModel import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.attributes.InputType +import org.jetbrains.compose.web.attributes.required import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* @@ -28,6 +30,7 @@ fun RegisterComponent() { val passwordTextState = viewModel.passwordText.collectAsState() val confirmedPasswordTextState = viewModel.confirmedPasswordText.collectAsState() val loadingState = remember { mutableStateOf(false) } + var openSnackbar by remember { mutableStateOf(false) } LaunchedEffect(key1 = true) { viewModel.eventFlow.collectLatest { event -> @@ -101,7 +104,9 @@ fun RegisterComponent() { H1 { Text(" Register") } Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit this.addEventListener("submit") { - console.log("$firstNameTextState, $lastNameTextState, $emailTextState, $passwordTextState") + if (passwordTextState != confirmedPasswordTextState) { + openSnackbar = true + } viewModel.onEvent(RegisterEvent.OnRegister) it.preventDefault() } @@ -132,6 +137,7 @@ fun RegisterComponent() { type = InputType.Text ) { classes("mdc-text-field__input") + required() value(firstNameTextState.value.firstName) onInput { viewModel.onEvent(RegisterEvent.EnteredFirstname(it.value)) @@ -169,6 +175,7 @@ fun RegisterComponent() { type = InputType.Text ) { classes("mdc-text-field__input") + required() value(lastNameTextState.value.lastName) onInput { viewModel.onEvent(RegisterEvent.EnteredLastname(it.value)) @@ -204,6 +211,7 @@ fun RegisterComponent() { ) { Text("Email") } EmailInput(value = emailTextState.value.email, attrs = { + required() classes("mdc-text-field__input") onInput { viewModel.onEvent(RegisterEvent.EnteredEmail(it.value)) @@ -240,6 +248,7 @@ fun RegisterComponent() { ) { Text("Password") } PasswordInput(value = passwordTextState.value.password, attrs = { + required() classes("mdc-text-field__input") onInput { viewModel.onEvent(RegisterEvent.EnteredPassword(it.value)) @@ -252,6 +261,42 @@ fun RegisterComponent() { ) { } } } + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( + attrs = { + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } + } + ) { + Span( + attrs = { + classes("mdc-text-field__ripple") + } + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") + } + ) { Text("Repeat Password") } + PasswordInput(value = confirmedPasswordTextState.value.confirmedPassword, + attrs = { + required() + classes("mdc-text-field__input") + onInput { + viewModel.onEvent(RegisterEvent.EnteredConfirmedPassword(it.value)) + } + }) + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } Div( attrs = { classes(AppStylesheet.margin) @@ -265,4 +310,7 @@ fun RegisterComponent() { } } } + if (openSnackbar) { + FeedbackSnackbar("Passwords do not match") { openSnackbar = false } + } } From bff05c3bdcfc3afd945bd0a3c12f525ebd3f05e1 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Wed, 22 Jun 2022 18:12:50 +0200 Subject: [PATCH 280/325] Add confirmedPasswordValid for if Snackbar should open or not --- .../budgetBinder/compose/register/RegisterComponent.kt | 10 ++++++++-- .../compose/settings/SettingsChangeUserDataView.kt | 9 +++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt index 1c984eb1..91bda546 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt @@ -15,6 +15,7 @@ import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.required +import org.jetbrains.compose.web.css.marginLeft import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* @@ -101,10 +102,15 @@ fun RegisterComponent() { MainFlexContainer { // -- Register Form -- - H1 { Text(" Register") } + H1( + attrs = { + style { marginLeft(2.percent) } + } + ) { Text("Register") } Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit this.addEventListener("submit") { - if (passwordTextState != confirmedPasswordTextState) { + console.log("$firstNameTextState, $lastNameTextState, $emailTextState, $passwordTextState") + if (!confirmedPasswordTextState.value.confirmedPasswordValid) { openSnackbar = true } viewModel.onEvent(RegisterEvent.OnRegister) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt index e9b8427b..085ae1c4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt @@ -12,6 +12,7 @@ import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.required +import org.jetbrains.compose.web.css.marginLeft import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* @@ -39,10 +40,14 @@ fun SettingsChangeUserDataView() { } NavBar {} MainFlexContainer { - H1 { Text("Change User Data") } + H1( + attrs = { + style { marginLeft(2.percent) } + } + ) { Text("Change User Data") } Form(attrs = { this.addEventListener("submit") { - if (passwordText != confirmedPasswordText) { + if (!confirmedPasswordText.value.confirmedPasswordIsValid) { openSnackbar = true } viewModel.onEvent(EditUserEvent.OnUpdate) From bed95cc5bd1f41889a73e18d4dac4b7781c86f06 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 12:26:06 +0200 Subject: [PATCH 281/325] Change folder name entryViewModel to entry --- .../viewmodel/{entryViewModel => entry}/EntryEvent.kt | 2 +- .../{entryViewModel => entry}/EntryInputState.kt | 2 +- .../viewmodel/{entryViewModel => entry}/EntryState.kt | 2 +- .../{entryViewModel => entry}/EntryViewModel.kt | 8 +------- .../hsfl/budgetBinder/compose/entry/EntryComponent.kt | 6 ++---- .../hsfl/budgetBinder/compose/entry/EntryCreateView.kt | 4 ++-- .../hsfl/budgetBinder/compose/entry/EntryEditView.kt | 4 ++-- .../budgetBinder/compose/entry/EntryOverviewView.kt | 10 +--------- 8 files changed, 11 insertions(+), 27 deletions(-) rename budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/{entryViewModel => entry}/EntryEvent.kt (92%) rename budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/{entryViewModel => entry}/EntryInputState.kt (73%) rename budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/{entryViewModel => entry}/EntryState.kt (80%) rename budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/{entryViewModel => entry}/EntryViewModel.kt (96%) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt similarity index 92% rename from budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt rename to budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt index 463668d9..00a691f1 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +package de.hsfl.budgetBinder.presentation.viewmodel.entry // View is not allowed to declare what should be done, only notify what has happened, names are assigned as such diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryInputState.kt similarity index 73% rename from budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt rename to budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryInputState.kt index 7debc864..db25b34e 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryInputState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryInputState.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +package de.hsfl.budgetBinder.presentation.viewmodel.entry data class EntryInputState( val name: String = "", diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryState.kt similarity index 80% rename from budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt rename to budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryState.kt index 183cde42..b3486a6a 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryState.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryState.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +package de.hsfl.budgetBinder.presentation.viewmodel.entry import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt similarity index 96% rename from budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt rename to budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index 6cc2e3ed..e9b4188f 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entryViewModel/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel +package de.hsfl.budgetBinder.presentation.viewmodel.entry import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.DataResponse @@ -6,19 +6,13 @@ import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiEvent -import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow -import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginTextFieldState import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import kotlin.math.absoluteValue -import kotlin.math.sign -import kotlin.math.withSign class EntryViewModel( private val entryUseCases: EntryUseCases, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 38016c5e..6684fc74 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -1,15 +1,13 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.UiEvent import de.hsfl.budgetBinder.presentation.flow.RouterFlow -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di import kotlinx.coroutines.flow.collectLatest import org.kodein.di.instance diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index fc383ee4..1391c7db 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -3,8 +3,8 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.* import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.* diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 4929d7bb..4bab291c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -3,8 +3,8 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.ChooseCategoryMenu import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryEvent -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index 66c0c8c5..9cac0722 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -1,21 +1,13 @@ package de.hsfl.budgetBinder.compose.entry import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry -import de.hsfl.budgetBinder.compose.CategoryList import de.hsfl.budgetBinder.compose.DeleteDialog -import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import de.hsfl.budgetBinder.presentation.UiState -import de.hsfl.budgetBinder.presentation.viewmodel.entryViewModel.EntryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* -import org.jetbrains.compose.web.svg.Circle -import org.jetbrains.compose.web.svg.Svg import org.kodein.di.instance From 8820c87c08605598080cc9ea023a4d29d2f62b6e Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 13:54:39 +0200 Subject: [PATCH 282/325] Fix major errors from merging --- .../hsfl/budgetBinder/presentation/Screen.kt | 6 ------ .../viewmodel/entry/EntryViewModel.kt | 18 +++++++----------- .../compose/category/CategoryComponent.kt | 4 +--- .../compose/dashboard/DashboardComponent.kt | 3 +-- .../compose/entry/EntryComponent.kt | 2 +- .../compose/login/LoginComponent.kt | 6 +++--- .../compose/register/RegisterComponent.kt | 10 +++------- .../settings/SettingsChangeUserDataView.kt | 2 +- .../compose/settings/SettingsComponent.kt | 5 ++--- .../src/jsMain/kotlin/main.kt | 2 +- 10 files changed, 20 insertions(+), 38 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index af1481ed..db1b855d 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -1,10 +1,4 @@ package de.hsfl.budgetBinder.presentation - - -import de.hsfl.budgetBinder.common.Category - -import de.hsfl.budgetBinder.common.Category - sealed class Screen { sealed class Welcome: Screen() { object Screen1: Welcome() diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index e9b4188f..fe0661ce 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -5,7 +5,7 @@ import de.hsfl.budgetBinder.common.DataResponse import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow @@ -118,9 +118,9 @@ class EntryViewModel( entryUseCases.getEntryByIdUseCase(id).collect { when (it) { is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error.message)) is DataResponse.Success<*> -> { - _selectedEntryState.value = it.data!! + _selectedEntryState.value = (it.data as Entry?)!! //Load data into variables for edit _nameText.value = _selectedEntryState.value.name _amountText.value = _selectedEntryState.value.amount.absoluteValue @@ -128,18 +128,14 @@ class EntryViewModel( _repeatState.value = _selectedEntryState.value.repeat _categoryIDState.value = _selectedEntryState.value.category_id } - is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error!!.message)) + is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error.message)) } } } - fun getCategoryList() = scope.launch { - entryUseCases.getCategoryListUseCase.categories() - .collect { - handleDataResponse( - response = it, - onSuccess = { cl -> _categoryListState.value = cl }) - } + protected fun getCategoryList() = scope.launch { + entryUseCases.getCategoryListUseCase() + .collect { it.handleDataResponse>(routerFlow = routerFlow, onSuccess = { cl -> _categoryListState.value = cl }) } } fun createEntry(entry: Entry.In) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt index 44885fcb..d58ee0f4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt @@ -3,12 +3,10 @@ package de.hsfl.budgetBinder.compose.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY -import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.viewmodel.CategoryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.category._CategoryViewModel import di import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index 8b34b215..e26343f9 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -8,12 +8,11 @@ import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.category.BudgetBar import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEntryState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEvent import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardViewModel -import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginEvent import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.* diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 6684fc74..fe2d1c3f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -4,7 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt index 316720bb..2e473417 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt @@ -3,9 +3,9 @@ package de.hsfl.budgetBinder.compose.login import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.UiEvent -import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginEvent -import de.hsfl.budgetBinder.presentation.viewmodel.login.LoginViewModel +import de.hsfl.budgetBinder.presentation.event.UiEvent +import de.hsfl.budgetBinder.presentation.viewmodel.auth.login.LoginEvent +import de.hsfl.budgetBinder.presentation.viewmodel.auth.login.LoginViewModel import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.percent diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt index 91bda546..8d7e7ba1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt @@ -1,16 +1,12 @@ package de.hsfl.budgetBinder.compose.register import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.User import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet - -import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.UiEvent -import de.hsfl.budgetBinder.presentation.UiState -import de.hsfl.budgetBinder.presentation.viewmodel.register.RegisterEvent -import de.hsfl.budgetBinder.presentation.viewmodel.register.RegisterViewModel +import de.hsfl.budgetBinder.presentation.event.UiEvent +import de.hsfl.budgetBinder.presentation.viewmodel.auth.register.RegisterEvent +import de.hsfl.budgetBinder.presentation.viewmodel.auth.register.RegisterViewModel import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.attributes.InputType diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt index 085ae1c4..479d67f9 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt @@ -5,7 +5,7 @@ import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.viewmodel.settings.EditUserEvent import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsEditUserViewModel import di diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt index 46f900c9..8e926a9c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt @@ -1,9 +1,8 @@ package de.hsfl.budgetBinder.compose.settings import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.User import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.viewmodel.settings.SettingsViewModel @@ -33,4 +32,4 @@ fun SettingsComponent() { is Screen.Settings.User -> SettingsChangeUserDataView() else -> {} } -} \ No newline at end of file +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt index 210b3a1b..755d2ca4 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt @@ -3,7 +3,7 @@ import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.Router import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.di.kodein -import de.hsfl.budgetBinder.presentation.UiEvent +import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow import io.ktor.client.engine.js.* import kotlinx.coroutines.flow.collectLatest From 99077e305a4468b4ce2a29af41854266748a8c6b Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 16:26:36 +0200 Subject: [PATCH 283/325] Add LifeCycle to EntryViewModel. Add LifeCycle to web frontends (launched&disposable effect) --- .../presentation/viewmodel/entry/EntryEvent.kt | 5 +++++ .../compose/dashboard/DashboardComponent.kt | 12 +++++++++++- .../budgetBinder/compose/entry/EntryComponent.kt | 10 +++++++++- .../budgetBinder/compose/login/LoginComponent.kt | 9 +++++++++ .../compose/register/RegisterComponent.kt | 9 ++++++++- 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt index 00a691f1..21ce06f7 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt @@ -1,5 +1,7 @@ package de.hsfl.budgetBinder.presentation.viewmodel.entry +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent + // View is not allowed to declare what should be done, only notify what has happened, names are assigned as such sealed class EntryEvent { @@ -22,4 +24,7 @@ sealed class EntryEvent { object LoadOverview : EntryEvent() object LoadEdit : EntryEvent() + //LifeCycle + data class LifeCycle(val value: LifecycleEvent): EntryEvent() + } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index e26343f9..e812b66f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -8,7 +8,9 @@ import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.category.BudgetBar import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.event.UiEvent +import de.hsfl.budgetBinder.presentation.viewmodel.auth.register.RegisterEvent import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEntryState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEvent import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardState @@ -28,9 +30,10 @@ fun DashboardComponent() { val totalSpendBudget = viewModel.spendBudgetOnCurrentCategory.collectAsState() val olderEntries = viewModel.oldEntriesMapState.collectAsState() val loadingState = remember { mutableStateOf(false) } - // val scaffoldState = rememberScaffoldState() + //LifeCycle LaunchedEffect(key1 = true) { + viewModel.onEvent(DashboardEvent.LifeCycle(LifecycleEvent.OnLaunch)) viewModel.eventFlow.collectLatest { event -> when (event) { is UiEvent.ShowLoading -> loadingState.value = true @@ -39,6 +42,13 @@ fun DashboardComponent() { } } } + DisposableEffect(Unit) { + onDispose { + viewModel.onEvent(DashboardEvent.LifeCycle(LifecycleEvent.OnDispose)) + } + } + + //Webpage content NavBar {} MainFlexContainer { Div { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index fe2d1c3f..103dc61c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -4,8 +4,10 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.flow.RouterFlow +import de.hsfl.budgetBinder.presentation.viewmodel.category.edit.CategoryEditEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di @@ -20,7 +22,8 @@ fun EntryComponent() { val screenState = routerFlow.state.collectAsState() val loadingState = remember { mutableStateOf(false) } - LaunchedEffect(key1 = true) { + LaunchedEffect(Unit) { + viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnLaunch)) viewModel.eventFlow.collectLatest { event -> when (event) { is UiEvent.ShowLoading -> loadingState.value = true @@ -29,6 +32,11 @@ fun EntryComponent() { } } } + DisposableEffect(Unit) { + onDispose { + viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnDispose)) + } + } NavBar {} MainFlexContainer { when (screenState.value) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt index 2e473417..d17402ba 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt @@ -3,6 +3,7 @@ package de.hsfl.budgetBinder.compose.login import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.viewmodel.auth.login.LoginEvent import de.hsfl.budgetBinder.presentation.viewmodel.auth.login.LoginViewModel @@ -24,6 +25,7 @@ fun LoginComponent() { LaunchedEffect(key1 = true) { + viewModel.onEvent(LoginEvent.LifeCycle(LifecycleEvent.OnLaunch)) viewModel.eventFlow.collectLatest { event -> when (event) { is UiEvent.ShowLoading -> loadingState.value = true @@ -31,6 +33,13 @@ fun LoginComponent() { } } } + DisposableEffect(Unit) { + onDispose { + viewModel.onEvent( + LoginEvent.LifeCycle(LifecycleEvent.OnDispose) + ) + } + } if (loadingState.value) { Text("Loading") diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt index 8d7e7ba1..944377dd 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.FeedbackSnackbar import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.viewmodel.auth.register.RegisterEvent import de.hsfl.budgetBinder.presentation.viewmodel.auth.register.RegisterViewModel @@ -28,8 +29,9 @@ fun RegisterComponent() { val confirmedPasswordTextState = viewModel.confirmedPasswordText.collectAsState() val loadingState = remember { mutableStateOf(false) } var openSnackbar by remember { mutableStateOf(false) } - + LaunchedEffect(key1 = true) { + viewModel.onEvent(RegisterEvent.LifeCycle(LifecycleEvent.OnLaunch)) viewModel.eventFlow.collectLatest { event -> when (event) { is UiEvent.ShowLoading -> { @@ -40,6 +42,11 @@ fun RegisterComponent() { } } } + DisposableEffect(Unit) { + onDispose { + viewModel.onEvent(RegisterEvent.LifeCycle(LifecycleEvent.OnDispose)) + } + } if (loadingState.value) { Text("Loading") //TODO: LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) From 28223535b6294006f5f5f65fdf05ec7a1f4c08f0 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 16:37:06 +0200 Subject: [PATCH 284/325] Remove unnecessary loading checks in components --- .../compose/dashboard/DashboardComponent.kt | 1 + .../compose/entry/EntryComponent.kt | 4 ++++ .../compose/login/LoginComponent.kt | 7 ++----- .../compose/register/RegisterComponent.kt | 19 +++++++++++-------- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt index e812b66f..f7e84beb 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt @@ -31,6 +31,7 @@ fun DashboardComponent() { val olderEntries = viewModel.oldEntriesMapState.collectAsState() val loadingState = remember { mutableStateOf(false) } + //LifeCycle LaunchedEffect(key1 = true) { viewModel.onEvent(DashboardEvent.LifeCycle(LifecycleEvent.OnLaunch)) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 103dc61c..31292864 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -22,6 +22,8 @@ fun EntryComponent() { val screenState = routerFlow.state.collectAsState() val loadingState = remember { mutableStateOf(false) } + + //LifeCycle LaunchedEffect(Unit) { viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnLaunch)) viewModel.eventFlow.collectLatest { event -> @@ -37,6 +39,8 @@ fun EntryComponent() { viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnDispose)) } } + + //Webpage content NavBar {} MainFlexContainer { when (screenState.value) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt index d17402ba..6be6620e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt @@ -24,6 +24,7 @@ fun LoginComponent() { val loadingState = remember { mutableStateOf(false) } + //LifeCycle LaunchedEffect(key1 = true) { viewModel.onEvent(LoginEvent.LifeCycle(LifecycleEvent.OnLaunch)) viewModel.eventFlow.collectLatest { event -> @@ -41,11 +42,7 @@ fun LoginComponent() { } } - if (loadingState.value) { - Text("Loading") - //LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) - } - //Body + //Webpage content Header( attrs = { classes("mdc-top-app-bar") diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt index 944377dd..5b2283ff 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt @@ -29,7 +29,9 @@ fun RegisterComponent() { val confirmedPasswordTextState = viewModel.confirmedPasswordText.collectAsState() val loadingState = remember { mutableStateOf(false) } var openSnackbar by remember { mutableStateOf(false) } - + + + //LifeCycle LaunchedEffect(key1 = true) { viewModel.onEvent(RegisterEvent.LifeCycle(LifecycleEvent.OnLaunch)) viewModel.eventFlow.collectLatest { event -> @@ -47,11 +49,8 @@ fun RegisterComponent() { viewModel.onEvent(RegisterEvent.LifeCycle(LifecycleEvent.OnDispose)) } } - if (loadingState.value) { - Text("Loading") - //TODO: LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) - } - //Body + + //Webpage content Header( attrs = { classes("mdc-top-app-bar") @@ -87,7 +86,11 @@ fun RegisterComponent() { ) { Button( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") + classes( + "mdc-button", + "mdc-button--raised", + "mdc-top-app-bar__navigation-icon" + ) onClick { viewModel.onEvent(RegisterEvent.OnLoginScreen) } } ) { @@ -109,7 +112,7 @@ fun RegisterComponent() { attrs = { style { marginLeft(2.percent) } } - ) { Text("Register") } + ) { Text("Register") } Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit this.addEventListener("submit") { console.log("$firstNameTextState, $lastNameTextState, $emailTextState, $passwordTextState") From 0604183b9f8a31ea06481cc2af338ba1eb2dd8ad Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 18:32:16 +0200 Subject: [PATCH 285/325] Change getEntryById to getById and use handleDataResponse --- .../viewmodel/entry/EntryViewModel.kt | 43 ++++++++----------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index fe0661ce..49af96eb 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -70,14 +70,9 @@ class EntryViewModel( categoryIDState.value ) ) - - else -> { - routerFlow.navigateTo(Screen.Entry.Create) - - } + else -> routerFlow.navigateTo(Screen.Entry.Create) } } - is EntryEvent.OnEditEntry -> when (routerFlow.state.value) { is Screen.Entry.Edit -> updateEntry( @@ -102,40 +97,38 @@ class EntryViewModel( } is EntryEvent.LoadOverview -> { resetFlows() - getEntryById((routerFlow.state.value as Screen.Entry.Overview).id) + getById((routerFlow.state.value as Screen.Entry.Overview).id) } is EntryEvent.LoadEdit -> { resetFlows() getCategoryList() - getEntryById((routerFlow.state.value as Screen.Entry.Edit).id) + getById((routerFlow.state.value as Screen.Entry.Edit).id) } } } /* *** Use Case usages *** */ - fun getEntryById(id: Int) = scope.launch { - entryUseCases.getEntryByIdUseCase(id).collect { - when (it) { - is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(it.error.message)) - is DataResponse.Success<*> -> { - _selectedEntryState.value = (it.data as Entry?)!! - //Load data into variables for edit - _nameText.value = _selectedEntryState.value.name - _amountText.value = _selectedEntryState.value.amount.absoluteValue - _amountSignState.value = _selectedEntryState.value.amount >= 0 - _repeatState.value = _selectedEntryState.value.repeat - _categoryIDState.value = _selectedEntryState.value.category_id - } - is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(it.error.message)) - } + protected fun getById(id: Int) = scope.launch { + entryUseCases.getEntryByIdUseCase(id).collect { it -> + it.handleDataResponse(routerFlow = routerFlow, onSuccess = { + _selectedEntryState.value = it + _nameText.value = _selectedEntryState.value.name + _amountText.value = _selectedEntryState.value.amount.absoluteValue + _amountSignState.value = _selectedEntryState.value.amount >= 0 + _repeatState.value = _selectedEntryState.value.repeat + _categoryIDState.value = _selectedEntryState.value.category_id + }) } } protected fun getCategoryList() = scope.launch { entryUseCases.getCategoryListUseCase() - .collect { it.handleDataResponse>(routerFlow = routerFlow, onSuccess = { cl -> _categoryListState.value = cl }) } + .collect { + it.handleDataResponse>( + routerFlow = routerFlow, + onSuccess = { cl -> _categoryListState.value = cl }) + } } fun createEntry(entry: Entry.In) { From fb20a99e9c00c2a935f365888378fa8883e4a2f0 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 18:46:40 +0200 Subject: [PATCH 286/325] Change createEntry to create and use handleDataResponse --- .../viewmodel/entry/EntryViewModel.kt | 39 +++++++------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index 49af96eb..37392170 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -62,7 +62,7 @@ class EntryViewModel( is EntryEvent.EnteredAmountSign -> _amountSignState.value = !amountSignState.value is EntryEvent.OnCreateEntry -> { when (routerFlow.state.value) { - is Screen.Entry.Create -> createEntry( + is Screen.Entry.Create -> create( Entry.In( nameText.value, buildAmount(), @@ -75,7 +75,7 @@ class EntryViewModel( } is EntryEvent.OnEditEntry -> when (routerFlow.state.value) { - is Screen.Entry.Edit -> updateEntry( + is Screen.Entry.Edit -> update( Entry.Patch( nameText.value, amountText.value, @@ -110,9 +110,9 @@ class EntryViewModel( /* *** Use Case usages *** */ protected fun getById(id: Int) = scope.launch { - entryUseCases.getEntryByIdUseCase(id).collect { it -> - it.handleDataResponse(routerFlow = routerFlow, onSuccess = { - _selectedEntryState.value = it + entryUseCases.getEntryByIdUseCase(id).collect { + it.handleDataResponse(routerFlow = routerFlow, onSuccess = { entry -> + _selectedEntryState.value = entry _nameText.value = _selectedEntryState.value.name _amountText.value = _selectedEntryState.value.amount.absoluteValue _amountSignState.value = _selectedEntryState.value.amount >= 0 @@ -123,31 +123,20 @@ class EntryViewModel( } protected fun getCategoryList() = scope.launch { - entryUseCases.getCategoryListUseCase() - .collect { - it.handleDataResponse>( - routerFlow = routerFlow, - onSuccess = { cl -> _categoryListState.value = cl }) - } + entryUseCases.getCategoryListUseCase().collect { + it.handleDataResponse>( + routerFlow = routerFlow, onSuccess = { cl -> _categoryListState.value = cl }) + } } - fun createEntry(entry: Entry.In) { - scope.launch { - entryUseCases.createNewEntryUseCase(entry).collect { response -> - when (response) { - is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) - is DataResponse.Success<*> -> { - _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) //TODO?: Change the msg - routerFlow.navigateTo(Screen.Dashboard) - } - is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) - } - } + fun create(entry: Entry.In) = scope.launch { + entryUseCases.createNewEntryUseCase(entry).collect { + it.handleDataResponse( + routerFlow = routerFlow, onSuccess = { routerFlow.navigateTo(Screen.Dashboard) }) } } - fun updateEntry(entry: Entry.Patch, id: Int) { + fun update(entry: Entry.Patch, id: Int) { scope.launch { entryUseCases.changeEntryByIdUseCase(entry, id).collect { response -> when (response) { From a97eb0109a9f796fcddaf157d93aa3ef6da1b5b6 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 18:53:26 +0200 Subject: [PATCH 287/325] Change update- and deleteEntry to update and delete + use handleDataResponse --- .../viewmodel/entry/EntryViewModel.kt | 51 ++++--------------- 1 file changed, 10 insertions(+), 41 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index 37392170..365d144a 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -89,8 +89,9 @@ class EntryViewModel( } //using ID seems... unnecessary?} } is EntryEvent.OnDeleteEntry -> _dialogState.value = true - is EntryEvent.OnDeleteDialogConfirm -> deleteEntry(selectedEntryState.value.id) + is EntryEvent.OnDeleteDialogConfirm -> delete(selectedEntryState.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false + //TODO: Replace Loads with LifeCycle is EntryEvent.LoadCreate -> { resetFlows() getCategoryList() @@ -136,52 +137,20 @@ class EntryViewModel( } } - fun update(entry: Entry.Patch, id: Int) { - scope.launch { - entryUseCases.changeEntryByIdUseCase(entry, id).collect { response -> - when (response) { - is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) - is DataResponse.Success<*> -> { - _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully updated")) //TODO?: Change the msg - routerFlow.navigateTo(Screen.Dashboard) - } - is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) - } - } + fun update(entry: Entry.Patch, id: Int) = scope.launch { + entryUseCases.changeEntryByIdUseCase(entry, id).collect { + it.handleDataResponse( + routerFlow = routerFlow, onSuccess = { routerFlow.navigateTo(Screen.Dashboard) }) } } - fun deleteEntry(id: Int) { - scope.launch { - entryUseCases.deleteEntryByIdUseCase(id).collect { response -> - when (response) { - is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) - is DataResponse.Success<*> -> { - _eventFlow.emit(UiEvent.ShowSuccess("Entry successfully deleted")) //TODO?: Change the msg - routerFlow.navigateTo(Screen.Dashboard) - } - is DataResponse.Unauthorized -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) - } - } + fun delete(id: Int) = scope.launch { + entryUseCases.deleteEntryByIdUseCase(id).collect { + it.handleDataResponse( + routerFlow = routerFlow, onSuccess = { routerFlow.navigateTo(Screen.Dashboard) }) } } - private suspend fun handleDataResponse(response: DataResponse, onSuccess: (T) -> Unit) { - when (response) { - is DataResponse.Loading -> _eventFlow.emit(UiEvent.ShowLoading) - is DataResponse.Error -> _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) - is DataResponse.Success -> { - _eventFlow.emit(UiEvent.HideSuccess) - onSuccess(response.data!!) - } - is DataResponse.Unauthorized -> { - _eventFlow.emit(UiEvent.ShowError(response.error!!.message)) - routerFlow.navigateTo(Screen.Login) - } - } - } /** * Negates amount if amountSign is false From 406494702255529f9ef438889610a592305b9b87 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 18:55:18 +0200 Subject: [PATCH 288/325] Make functions private --- .../presentation/viewmodel/entry/EntryViewModel.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index 365d144a..b8889b9c 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -110,7 +110,7 @@ class EntryViewModel( /* *** Use Case usages *** */ - protected fun getById(id: Int) = scope.launch { + private fun getById(id: Int) = scope.launch { entryUseCases.getEntryByIdUseCase(id).collect { it.handleDataResponse(routerFlow = routerFlow, onSuccess = { entry -> _selectedEntryState.value = entry @@ -123,28 +123,28 @@ class EntryViewModel( } } - protected fun getCategoryList() = scope.launch { + private fun getCategoryList() = scope.launch { entryUseCases.getCategoryListUseCase().collect { it.handleDataResponse>( routerFlow = routerFlow, onSuccess = { cl -> _categoryListState.value = cl }) } } - fun create(entry: Entry.In) = scope.launch { + private fun create(entry: Entry.In) = scope.launch { entryUseCases.createNewEntryUseCase(entry).collect { it.handleDataResponse( routerFlow = routerFlow, onSuccess = { routerFlow.navigateTo(Screen.Dashboard) }) } } - fun update(entry: Entry.Patch, id: Int) = scope.launch { + private fun update(entry: Entry.Patch, id: Int) = scope.launch { entryUseCases.changeEntryByIdUseCase(entry, id).collect { it.handleDataResponse( routerFlow = routerFlow, onSuccess = { routerFlow.navigateTo(Screen.Dashboard) }) } } - fun delete(id: Int) = scope.launch { + private fun delete(id: Int) = scope.launch { entryUseCases.deleteEntryByIdUseCase(id).collect { it.handleDataResponse( routerFlow = routerFlow, onSuccess = { routerFlow.navigateTo(Screen.Dashboard) }) From 87a50ab5c125817820e0e540152c6760e7d2c5a8 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 19:28:22 +0200 Subject: [PATCH 289/325] Replace Load-Events with LifeCycle --- .../viewmodel/entry/EntryEvent.kt | 5 --- .../viewmodel/entry/EntryViewModel.kt | 33 +++++++++++-------- .../compose/entry/EntryComponent.kt | 4 --- .../compose/entry/EntryEditView.kt | 3 +- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt index 21ce06f7..e5b4c895 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt @@ -19,11 +19,6 @@ sealed class EntryEvent { object OnDeleteDialogConfirm : EntryEvent() object OnDeleteDialogDismiss : EntryEvent() - //Load Data for Screen (has some problems when done in init) - object LoadCreate : EntryEvent() - object LoadOverview : EntryEvent() - object LoadEdit : EntryEvent() - //LifeCycle data class LifeCycle(val value: LifecycleEvent): EntryEvent() diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index b8889b9c..62b84731 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -6,6 +6,7 @@ import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.domain.usecase.* import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.event.UiEvent +import de.hsfl.budgetBinder.presentation.event.handleLifeCycle import de.hsfl.budgetBinder.presentation.flow.DataFlow import de.hsfl.budgetBinder.presentation.flow.RouterFlow import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow @@ -84,26 +85,30 @@ class EntryViewModel( ), selectedEntryState.value.id ) else -> { - resetFlows() routerFlow.navigateTo(Screen.Entry.Edit(selectedEntryState.value.id)) } //using ID seems... unnecessary?} } is EntryEvent.OnDeleteEntry -> _dialogState.value = true is EntryEvent.OnDeleteDialogConfirm -> delete(selectedEntryState.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false - //TODO: Replace Loads with LifeCycle - is EntryEvent.LoadCreate -> { - resetFlows() - getCategoryList() - } - is EntryEvent.LoadOverview -> { - resetFlows() - getById((routerFlow.state.value as Screen.Entry.Overview).id) - } - is EntryEvent.LoadEdit -> { - resetFlows() - getCategoryList() - getById((routerFlow.state.value as Screen.Entry.Edit).id) + is EntryEvent.LifeCycle -> { + event.value.handleLifeCycle( + onLaunch = { + getCategoryList() + when (routerFlow.state.value) { + is Screen.Entry.Overview -> getById((routerFlow.state.value as Screen.Entry.Overview).id) + is Screen.Entry.Edit -> getById((routerFlow.state.value as Screen.Entry.Edit).id) + else -> { + } + } + }, + onDispose = { + when (routerFlow.state.value) { + is Screen.Entry.Overview, is Screen.Entry.Edit -> resetFlows() + else -> { + } + } + }) } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index 31292864..ad6b7f09 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -48,7 +48,6 @@ fun EntryComponent() { EntryCreateView( onCreateButton = { viewModel.onEvent(EntryEvent.OnCreateEntry) } ) - viewModel.onEvent(EntryEvent.LoadCreate) } is Screen.Entry.Overview -> { EntryOverviewView( @@ -57,14 +56,11 @@ fun EntryComponent() { onDeleteDialogConfirmButton = { viewModel.onEvent(EntryEvent.OnDeleteDialogConfirm) }, onDeleteDialogDismissButton = { viewModel.onEvent(EntryEvent.OnDeleteDialogDismiss) } ) - viewModel.onEvent(EntryEvent.LoadOverview) } is Screen.Entry.Edit -> { EntryEditView( onEditButton = { viewModel.onEvent(EntryEvent.OnEditEntry)} ) - viewModel.onEvent(EntryEvent.LoadEdit) - } else -> {} } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt index 4bab291c..f6650dce 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt @@ -33,7 +33,8 @@ fun EntryEditView( //Data val categoryList by viewModel.categoryListState.collectAsState() val entry by viewModel.selectedEntryState.collectAsState() - + console.log("unser Entry ist $entry") + console.log("$entryNameTextField und $entryAmountTextField und $entryCategoryIDTextField") H1( attrs = { style { margin(2.percent) } From 4ff630f09e4065acba21827ab6145eb6d015f2c6 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 19:33:36 +0200 Subject: [PATCH 290/325] Remove dataFlow and _eventFlow --- .../presentation/viewmodel/entry/EntryViewModel.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index 62b84731..4e7725f3 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -18,7 +18,6 @@ import kotlin.math.absoluteValue class EntryViewModel( private val entryUseCases: EntryUseCases, private val routerFlow: RouterFlow, - private val dataFlow: DataFlow, private val scope: CoroutineScope ) { /* *** Variables *** */ @@ -48,8 +47,7 @@ class EntryViewModel( // --- Default ViewModel Variables ---- private val _dialogState = MutableStateFlow(false) val dialogState: StateFlow = _dialogState - private val _eventFlow = UiEventSharedFlow.mutableEventFlow - val eventFlow = UiEventSharedFlow.eventFlow + val eventFlow = UiEventSharedFlow.mutableEventFlow // ---- From 4b71372b4ea15b0a17b5cdc76d6ec6c04d06d6bf Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 19:39:01 +0200 Subject: [PATCH 291/325] Add OnBack Event that brings one back to the dashboard --- .../budgetBinder/presentation/viewmodel/entry/EntryEvent.kt | 2 ++ .../presentation/viewmodel/entry/EntryViewModel.kt | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt index e5b4c895..0ba19f80 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt @@ -18,6 +18,8 @@ sealed class EntryEvent { object OnDeleteEntry : EntryEvent() object OnDeleteDialogConfirm : EntryEvent() object OnDeleteDialogDismiss : EntryEvent() + object OnBack: EntryEvent() + //LifeCycle data class LifeCycle(val value: LifecycleEvent): EntryEvent() diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index 4e7725f3..4f188816 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -77,7 +77,7 @@ class EntryViewModel( is Screen.Entry.Edit -> update( Entry.Patch( nameText.value, - amountText.value, + buildAmount(), repeatState.value, Entry.Category(categoryIDState.value) ), selectedEntryState.value.id @@ -89,6 +89,7 @@ class EntryViewModel( is EntryEvent.OnDeleteEntry -> _dialogState.value = true is EntryEvent.OnDeleteDialogConfirm -> delete(selectedEntryState.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false + is EntryEvent.OnBack -> routerFlow.navigateTo(Screen.Dashboard) is EntryEvent.LifeCycle -> { event.value.handleLifeCycle( onLaunch = { From d31949a6a8d2f76bce0ac9878d2d7bf2c60bd777 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen <49916041+MrHemanik@users.noreply.github.com> Date: Thu, 23 Jun 2022 19:41:02 +0200 Subject: [PATCH 292/325] Delete identifier.sqlite Nothing that should be on Branch, IDE specific file to open server database. --- identifier.sqlite | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 identifier.sqlite diff --git a/identifier.sqlite b/identifier.sqlite deleted file mode 100644 index e69de29b..00000000 From ded7f31fe26804ca047c3461b784fab417048d0d Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 19:43:57 +0200 Subject: [PATCH 293/325] Format ViewModel --- .../viewmodel/entry/EntryViewModel.kt | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index 4f188816..63024032 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -90,25 +90,21 @@ class EntryViewModel( is EntryEvent.OnDeleteDialogConfirm -> delete(selectedEntryState.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false is EntryEvent.OnBack -> routerFlow.navigateTo(Screen.Dashboard) - is EntryEvent.LifeCycle -> { - event.value.handleLifeCycle( - onLaunch = { - getCategoryList() - when (routerFlow.state.value) { - is Screen.Entry.Overview -> getById((routerFlow.state.value as Screen.Entry.Overview).id) - is Screen.Entry.Edit -> getById((routerFlow.state.value as Screen.Entry.Edit).id) - else -> { - } - } - }, - onDispose = { - when (routerFlow.state.value) { - is Screen.Entry.Overview, is Screen.Entry.Edit -> resetFlows() - else -> { - } - } - }) - } + is EntryEvent.LifeCycle -> event.value.handleLifeCycle( + onLaunch = { + getCategoryList() + when (routerFlow.state.value) { + is Screen.Entry.Overview -> getById((routerFlow.state.value as Screen.Entry.Overview).id) + is Screen.Entry.Edit -> getById((routerFlow.state.value as Screen.Entry.Edit).id) + else -> {} + } + }, + onDispose = { + when (routerFlow.state.value) { + is Screen.Entry.Overview, is Screen.Entry.Edit -> resetFlows() + else -> {} + } + }) } } From 01dbb47ee30fdd38e6725bc4b20cca248e219b40 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 20:01:17 +0200 Subject: [PATCH 294/325] Rename OnBack to OnCancel and add Cancel button to EntryOverviewView and EntryCreateView --- .../kotlin/de/hsfl/budgetBinder/di/DI.kt | 2 +- .../viewmodel/entry/EntryEvent.kt | 2 +- .../viewmodel/entry/EntryViewModel.kt | 2 +- .../compose/entry/EntryComponent.kt | 3 +- .../compose/entry/EntryCreateView.kt | 9 ++++++ .../compose/entry/EntryOverviewView.kt | 28 +++++++++++++++---- 6 files changed, 36 insertions(+), 10 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt index 84f0836b..6ec87f71 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/di/DI.kt @@ -102,7 +102,7 @@ fun kodein(ktorEngine: HttpClientEngine) = DI { bindSingleton { CategoryDetailViewModel(instance(), instance(), instance()) } bindSingleton { CategoryEditViewModel(instance(), instance(), instance()) } bindSingleton { CategoryCreateViewModel(instance(), instance(), instance()) } - bindSingleton { EntryViewModel(instance(), instance(), instance(), instance()) } + bindSingleton { EntryViewModel(instance(), instance(), instance()) } bindSingleton { DashboardViewModel(instance(), instance(), instance(), instance()) } bindSingleton { NavDrawerViewModel(instance(), instance(), instance()) } } diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt index 0ba19f80..fbdda0dd 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryEvent.kt @@ -18,7 +18,7 @@ sealed class EntryEvent { object OnDeleteEntry : EntryEvent() object OnDeleteDialogConfirm : EntryEvent() object OnDeleteDialogDismiss : EntryEvent() - object OnBack: EntryEvent() + object OnCancel: EntryEvent() //LifeCycle diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index 63024032..4b322539 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -89,7 +89,7 @@ class EntryViewModel( is EntryEvent.OnDeleteEntry -> _dialogState.value = true is EntryEvent.OnDeleteDialogConfirm -> delete(selectedEntryState.value.id) is EntryEvent.OnDeleteDialogDismiss -> _dialogState.value = false - is EntryEvent.OnBack -> routerFlow.navigateTo(Screen.Dashboard) + is EntryEvent.OnCancel -> routerFlow.navigateTo(Screen.Dashboard) is EntryEvent.LifeCycle -> event.value.handleLifeCycle( onLaunch = { getCategoryList() diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt index ad6b7f09..cfcdde7a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt @@ -54,7 +54,8 @@ fun EntryComponent() { onEditButton = { viewModel.onEvent(EntryEvent.OnEditEntry) }, onDeleteButton = { viewModel.onEvent(EntryEvent.OnDeleteEntry) }, onDeleteDialogConfirmButton = { viewModel.onEvent(EntryEvent.OnDeleteDialogConfirm) }, - onDeleteDialogDismissButton = { viewModel.onEvent(EntryEvent.OnDeleteDialogDismiss) } + onDeleteDialogDismissButton = { viewModel.onEvent(EntryEvent.OnDeleteDialogDismiss) }, + onCancel = { viewModel.onEvent(EntryEvent.OnCancel) } ) } is Screen.Entry.Edit -> { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index 1391c7db..f58412d8 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -203,6 +203,15 @@ fun EntryCreateView( classes(AppStylesheet.margin) } ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { viewModel.onEvent(EntryEvent.OnCancel) } + } + ) { + Span(attrs = { classes("mdc-button__label") } + ) { Text("Cancel") } + } SubmitInput( attrs = { classes("mdc-button", "mdc-button--raised") diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt index 9cac0722..30b7db48 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di import org.jetbrains.compose.web.css.* @@ -16,7 +17,8 @@ fun EntryOverviewView( onEditButton: () -> Unit, onDeleteButton: () -> Unit, onDeleteDialogConfirmButton: () -> Unit, - onDeleteDialogDismissButton: () -> Unit + onDeleteDialogDismissButton: () -> Unit, + onCancel: () -> Unit ) { val viewModel: EntryViewModel by di.instance() //Data @@ -35,7 +37,8 @@ fun EntryOverviewView( onEditButton, onDeleteButton, onDeleteDialogConfirmButton, - onDeleteDialogDismissButton + onDeleteDialogDismissButton, + onCancel ) } @@ -46,7 +49,8 @@ fun EntryOverview( onEditButton: () -> Unit, onDeleteButton: () -> Unit, onDeleteDialogConfirmButton: () -> Unit, - onDeleteDialogDismissButton: () -> Unit + onDeleteDialogDismissButton: () -> Unit, + onCancel: () -> Unit ) { Div( attrs = { @@ -75,10 +79,22 @@ fun EntryOverview( } ) { Button(attrs = { - classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + classes("mdc-button", "mdc-button--raised") + onClick { onCancel() } + style { + flex(33.percent) + margin(1.5.percent) + } + } + ) { + Span(attrs = { classes("mdc-button__label") } + ) { Text("Cancel") } + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") onClick { onEditButton() } style { - flex(50.percent) + flex(33.percent) margin(1.5.percent) } }) { @@ -88,7 +104,7 @@ fun EntryOverview( classes("mdc-button", "mdc-button--raised") onClick { onDeleteButton() } style { - flex(50.percent) + flex(33.percent) margin(1.5.percent) backgroundColor(Color("#b00020")) } From 8ea4468ca31fed2d74b8d391e44ba4834a5df253 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Thu, 23 Jun 2022 22:07:08 +0200 Subject: [PATCH 295/325] Add type Button to cancel button --- .../kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt index f58412d8..35b5b127 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt @@ -206,6 +206,7 @@ fun EntryCreateView( Button( attrs = { classes("mdc-button", "mdc-button--raised") + type(ButtonType.Button) onClick { viewModel.onEvent(EntryEvent.OnCancel) } } ) { From 449174bd0e635861d041bd358b0c4df784e679b7 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Thu, 23 Jun 2022 23:11:59 +0200 Subject: [PATCH 296/325] Add Loading.gif --- .../src/jsMain/resources/images/Loading.gif | Bin 0 -> 40957 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 budget-binder-multiplatform-app/src/jsMain/resources/images/Loading.gif diff --git a/budget-binder-multiplatform-app/src/jsMain/resources/images/Loading.gif b/budget-binder-multiplatform-app/src/jsMain/resources/images/Loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..faadfe5b282334a46b97c11c92cdbc92818c85e1 GIT binary patch literal 40957 zcmaf*dpOho*w++Gb3jIy_wTy@bGclX?X}DGemtMg$BU!0gQb;s2hah`9|lH7o{f%< ze*f`9B%1j6@zd<=?8wN|;o+w(Ev-XC!`)rIBg3PgK7DFx5_WfYH{BCgyY(re4?9*3Zq&O}~9NKK^`s?D^NPUneFetEy_| z=jZR;yFWcWJvut}{P~N@%Idt_Dao(aoEJ z%Bt$OZ>L|qdj0CvtAT+h&z_Foxl{M}@xYHCKYDt4A3SIm3R^}-MxHzwx_$f3)2C0n zy1F|$I*N<0efaRPudnaRmzl-I#q8`$4Gs66Jsacm3xZRWp__+Rn?u`+)Ixh z_2uSVSy))OdZpmWlP5DXvq?#5*;%>CiD~cNy&oJLtgO8AY;czCoq$FNe zX5N=CpYJy{H{BPOm)%%eTI%ZT{rPjDxcGWwV^e2m*YNOgS7%Rd&ZWYF;%g;kHPv@` zDHreGZ!Rq@Yier#_U-G>pFaxmI_y1V+4lX>&=3rUG-Bg0R# zvT}t&;qvlwLPGM@tNfm>N0;*W4fXdve*Dni-KJUB3P>t=ORV@pH*{p3Vma#DIp z(Y4{BX9B^UXU|4QMu+R`?+*<;tmdq;am$D_i+!sVsqA3whT{`GrdVSaJ(=koH> z(D2aj-@isihP!*Z=NA^1mY0^6mz(Z47Znv&R^1sIe%9IbXntY-(xpqke*ezO%5H3E zV=*}^D=Qi+;#;@u*ltIrZZTO$gn|G7X#9l1p}=9lX!YyWKavgrK&=4nC>19Gzd0Hu zW3azNkWZEnXHTy=Z5Q2|fZuRzyrZ(PJp}-L>|!tNNKq>F)8JI?m{^Cjl*&M_61Kh^Hn*k2>dr$Nu!Gnjb9 z;r%RC#Q|D0b%CI9?(~j24+V8v0F5X;+OFXU<)B;!@{FQV#fs7u&j-=;;7$q5f4B?-gQMq~WCq4;1ER*SNTGW7mso zNF9y$rJy~{ux#<&F^34{GkawP@HNK5it(pm6?SG``9`NVn2H~Fki{4tl`J{<0V^H* zezE0(qLr&`4Rn?O-X60$a??&{KmSq{ttT$EA>gkf!WM%q#`NP2}|09nyY47^8s90X2&@J4sDf#qV2Wr}JmEq)pqZ z-GyhdD)*2Vl00OT?8p>5O`{|%YQMtAm@&n;6@HMs9kB=+m;Lb`6{UHxr?xY@u&=6LSD8uKGG&&lCO%6%*(~pu{21^lZ-5PmaWocv(=g*&_pC@a z>IapiC~cIuM2FbhsLRIdAH-Y?hf4a*F<_Dw9lp$_F|kT2B-ZT>oiZVx2yZb_oj@RD zh`{e{7KF48trWa>n-*tz!qtt;uPB$n8O+%^M=;4hVVZ|YZec=(6xRT0(SO-3g2&xo z_k}6714K8zk(MT6Jl0TED3&D1y?|x_0}}3;j;3h=pB(X{(Qc6h461&H83(ZMkxalP zKLa@PuoI3CWY|$P&WNYV-Cl8{8D&vvvZOlIm?;M6Ae@p|pICr%0u#g|CAB*rXXr8N zuo6N(E`)2ZEeUeA!9<#7{1MD%6V^w4oXhcLE@F{lKo%&kF0Bv@sh9 zaPMAp0w#V~TmYFUsB;cCm0%gDR`i>9LDn)HAu+m&v z2{(K%!V-OVmrB1OWl$hnVQV?YZh(|>l zL8)YTA%`z_g3Ow}n#Eyudxb=as{WK;rcm|YmV?gki6+u%0 zYx3hwfD zQemGO2|H?sa=9clkNV2xBeeGxU^xmQ8 zZjZB1i!q3@j|sR@GN#`BbHv!#3*+f#jqSb6p@I2EGoB%tGy{)#xgn_yT{v4Jp+uHzB_RL)ATm+)M;BEhVuTVxvWE?W5ox- z!TdIkH1*zl&HE%t=ib>Hr`rKlOUUTCWS01a+_obxAAxu()SyE34aMopwI}#csOl4B z=mjgnR(Ix^Yx^O=CtF6K7rva%Qwlo&_L2YX-Z1uh>!H!aM!usBLZXiU6&cEO+-CE# zDX)%Tw9q<9UeCfT>=_zKT0#c6@RVek-;MQHojVTzJ70`nG4F36pCEA5sbplwwx+LH zeamn3u8M8ekIvh7@15KwKzy{X=|^qfug`~9U>c?56}Ak7rA?n$p5AtUailM5P9}GF zCguL}+ife0V=KQG`tJXp?_2r3w3!?y2cQ{HaRQi7un{5zl={KIeh^0tQm95rQ(+QR zrUVJ1-48J6R68v|rXN;52L=ic+>wUZFqrb$EIAY`@FGla#=)gcQ}3*SqX5d~vn;)s zmRK`q>~_2l1j-Z3XaVgQfMRyEr4!_E7O{PcN013jhCruGg0>9yu2FzH6FA=zTF8PI zDyZr7Lw8%o_@@))83*ve5S1f%7#4MSA?8&EQHK_0PyjBS#pC*6sF|2k3(!LWhQDJr znF&x_4bWZ~8)*q|@Hh0^O_W{{!q@pI1X2-Puee*GYm@X%H0ZHDAcQ;v&ERr3&+Hk2 zg#I#xSr9nh%@7BCJhy{B?*sked+>@*KB00f4vC6HnVHNg#avN{Z?+yYR~ z<$m*B$MZi}yTRWz6&9PB$aR7=TKbtIgRH2~J9rr=0CjXqI^_gOBUxnx@3fc)FDyuJ zV<6@5$&*~RHWgOnWui)h2%U_x7Np5Q%4`6K%Yg2+G=&ksEc)q>b2#;xlt>i#CTx8o z5TH7ur80^O6vSe3qVdzvC$*LY?76K@hrX|VGdtCp3y_GstLAR1wTUVqL^dF8jT6LD zbO_}QnyrXHbpYm01ZvvlPx?ZkL_kRhWC(EZpQm)`CzXR>7Wx+zO3x{!dYK53V)P8L ze#kv6usKIgo&nkh0DceCF+qqxUQ&ZuqOvhSeF~`D#T}!wsiGRJBtU&dB`g z4X6>LBtQtB5tCMxtk|5X8;9D-&y-*u+Wi!ACN2X@KzVcIBo%b6`azZE-2fJI>I@JQ zhm)B}pXH)F=_e#pfz-RXd-kM~KnU{)!M#68q8SCl<`o752d?7?RL-Om#9ol17zC~8 z%#{!f>@_NPRYQCoxSa2=cr$*RM`?Khe--SXybwW4#AlijT_hLVUfByXbYbd=32L zUF-o8AVY(iQ=zJ)O!Q;W&cfhJEl!4bB`6q><{echgSG_zZZ2wM%_Y@Y7^*(khm;TZ z-l-;Vv0{Mh_F}tooXVzg2Sn~cU%}&}={^A*DFz@;EmX`0Pv0##g9aIUum|`q)t2h& z!fb>FWzgrMq6fg#SJxBd5mpak2HFw89A1E0ii%Y$p)N`}egIQ>j%6@kc$f}-akxl{ z4Ep&4R)PbY$)FwqZp#2{32>0gSHnSAf|4_Pe8pCbA$t|{tY}61oz`ajlwM+k8UlzR z4Jt#sw!Rs(5|dG(BI5UEg;dfMG*(I3Fs#@m%adA|%gFntfi$ee?kc+q zrKbx@{Hh}|u=FxWKH?_|NbthKMP*D@?)4);YZ-tQK%Y2ci}lu&yI_xPC%R+HuA75T zA~MD{Vz=q7LGQuJiz>W*fbNK630T+@0~EO*t8ZbDd<_fZRg4+KM)n@_269@TL1SF7 zZ&kayttYuh>EAdeG2<*BKT3X%MpL>Yvyz0nkFm7W7md=ox7;Ps@eHppYeUX|@o$gjb-)bJo1D9UDr1VOa{RH?jru;6yAmdW?oqq0=+n?a=_ z^ESfgju;4e7k*Gt$xNMi)00#z2G)Mls1SS2Jpa$+X-XononTr=Z?H81H9s~QHJV_u~H|8^_AHAc2D@LcyU$Z`f-nXF%JMP zgL(PNT$WeWY5*0K)m3XYh|QK(ON#@*jW@wi+P<=fE>$_*xMRYb^eJ;aYE7{LJT$MS zw;OkHqrvNlwQ9t2$rS-p9c&l_8^xNTDoXm+!}r=vz|MvONs+;;yn8B-O?SUH$Mr*t z-ve<8ckhc!Co;;vksEX0nVUD1xGvPsHRPN**AQ3;);AQG%!sWeHwnF)FhRG1d>YXk zV3G`e{hh|&n+))cSb1KP?IfseX*!E&nMX^@j|Z-AE~KVG-7>8(gsk+03?3TP1!Ro( zw_wPCeoyg%O&k1YuANzf!cs39Zn=M)KBJc+jxc;eDMhV4kfHWTd;(ZG!1e2Tu7yly$p8 zJODfmszFM3q_^hCVE?WZ0KfQZtL>;rfVX40~=n>)J1N+HTGqpF{H*ft>qt)ELQyWjLYiPW;T0%9qv{ED` z+d4YCR%@+Cef^IIo(u-8i#4rQqKx<|4~ZrwUroJ!^S0lpI&S*Y=Pxs}U%$G4-}k_R;YS)COAcXiT?cK?lU zVS2OvRh=}eZRj`J^VP>W-hRt?*#6F{V%LFPaMqEi; zU!l`Q&5u}USN}EkR{hH^8G5*D+hUvgJ#LqeBw=cNd+W7@Bh>*i<~deBuBX({UrC2Q z{_!reF047(m8 zxV$}guVWRGI&uzbUl95MSBPaq=!tW-PGg5vaJXyy0l8dxg$P1d{xM?3yV9#D4jEbe zJ=cl%QI!Av2X`SANQtB8|xg5pg08Q|;?f7ZsVLWYkdybYjGZz%oo~mefP{ zqenu;PiTLj)<_R>vf4kFAZhzgkT2b8J4yI-t@R+gwW#PI(|~rWZMW`~F`I(7Tb`Kj z3bd06NWGzR+>JSkQ^X+G1?}tSdfYSLX~>g$`eOuzhzsYpG*m>OoE%W6&wioUjRu|2 zPOW$hJ-V5?KS)zU#ciEKjIa3DJ4GDc(FZ%D3aSJOI*gnAk`^&V*slHxnnu^gbYr%% zp09oD>G3VOB-s-hHMrS0Ec3CUg{gPzZteLR(oR#?YV~ghA#;TiLqdl;Z~bPzlW@~B zCm(QncqVrK(TjGi$4M(bGh-f3{O6-l_`B2>&I%zdauOpT2a zovc&cJ28m~^kLVKGAeeHxXZ(rkAAWwMF0}V1teo;n6NNuhJ8SvR0K^(i4^qwIwJ-KFU!ag7@X=*fLT&XLg_fHGANkVz>CZX)}(g$hvl~-OYmoP+8tg ztR|MCzfvcXwwQ5=sxWASy!7RaKlY6|7{FMaGS|-j3654 z>a=Jc{lHXfTzz_mwTPigHSB(zePA}oj9Po0DOo@Iz?d&WV)vopYyoA%NpiS?2Sp~5 z!BC|Wv_fQMJE~}RGc8+UBVm*Hhcp!FM6%W?Z0^qzY2a`t+BfC2vw{+@b5}eGxrs+} zj1sCE$Z6sP-^A{~GEio>VbBY~r`zWQ?J( zFapt;(1K|s#oGCjr4(tPCr#jS<{^Lx=;@HSLWQF%43Bs(tnt*QZf8E^BkgO{I^zwf zx;wUAXWV6q4|ERhDgZzV$Kaqf30}6#>|%_*ok5LQw$g&A9J*F{&xABeI!x}yW_$9w zk@zgFbPYEBwU(Tc{YYavfH3Yb#Ci~Vo5ZG(r+N+1lE+5t7zDr#`w_+A4L*GH8fAkj z@!c}Bqx+#B(DxNWHd?iV)5C0(?aj9sQK=fzZd841Cjy;GE&~cG+zw0Rlri{ z5g`m0(C#8brfLCbY|00@9fBB(o(aj&g%-jv5msa6&0z=uu22xWyJu1&+OlnpLz}V@ zbu!wEhRhGIOb+dNrM6TDYS#rMp{p3`%0D|C9NKL3KE|jQ;XA3x!B8x{1+53PdOoU3 zRToUHzSZu%k{eRaGvYNIMV&rdtCPnJX^1JWm0r3oC>eu^w`jHM)t(7RQl!7N4c#T& zPa?%E8NE@Tp>=rZxAM_9UR!BJ0JI|^>CPk{`+3s99(j`jR}s|B?kTd$zJ{dR|4!Vn z;6dqcLGojjgB}V~s7=(MGJl%@>Cug*(GSTP2UI!I)=U%%bw?2E{?SKy3EA-*gb-%f zAHQxCQ_%;YCGMY&?OS>_TJq!2mEKQ*=l-rv+&>5BEsY;~#Z=x!VCp)NpwbQ&jz)Y? zMPKw{A(O0RV0bEVP=sEP3=@7I{}Q9^jWWU3wS0O0nkB_XLiM8|5du0>?^3U13QMAh zI-6`rLL_upl2KH6O5P=rg00%a&V`)7}z@JsLpAq+iY z)%}21cj~kdDy^{i=)BcuB?1}iG7|3npqG>8cwk!Mtr;|z{=HP;z#xHZ39GmLCa+JB zoVdcc*ST(v(DCD`9%|#5zZ$IM^b+*&)lJ=g{cPTaJa~Ekrf!-3(}5cZ?^p_!FcpBQ z%AFs3aUfX`R5Mb+wHw9IYC)yy&7%zGV6njMFV6n0X`HAgH;{cyzp3kT-x`- zTQyp!G80@>i2AYn(3|fURQ&-+9Zr@8fuo|_g{TEMB-cN96C)Bodmg8Mo;2gMkOA99 zxFEM1^d=o%7X-`dXR6g{Vk#l!@bi8o*3Tc{-FazsA!}d+=HHJ6`1=SnXpjIZCxGe_ z0f{>4Kz{TO%npKi zaY$Go)r$@z#v9>L`nwYj08BR&Y<5?I2QhA={`NOc*zD41D_Z;qJX`~S;Q{~>g98r@ z`5wlY)yKjK;5J^upyT=XqbZ1Hlu|#eFdzk_Lxcf5m~Qk%W_vx!)s1rId3p?1%jJ?&Wx<1l-mP`QKQ~H(UA&5ORZ-`~xjOzIp#8^2*>%bJ zqAUW1g%17!+I?3^(PFADHKmVNLEGR!SIzY&*Qhx!7##$1D+*|{f8MooH+qd_L%gc% zkN((o*p&1G-FH3>%S*%dM2f@yP5_X<5CXfJ|L+7qw$Q^ahkLRT{*?gQ6OWc^ zS5XGy#c+Pfk$=4~HMFU~r>LYicNZ1U`16G+twG&&9z3Fn{$o59yXYEIKuzjFHP@64 zm19Et6I}*fpcS;%z3wKjO4M&!Zss27&b-FH5fCSR)U`IS-6SaAv$DH(eXC}8LLfL% zEAVEbATmRCBEjLNIJvRG!mpLD*|G@sERo+?a3xhoIe+{~5(u+}960N0kBlGD5AYQ> z14jZniw;Q!kvkH<$a2&^?!Oo8h{1JS)N-8A?CBnhKV5Ca6kh!DVZ=tmiPETrc`eFt zTnR$k2JuLWjFX6*=aTY!jtx9_MLn2D&_}}+sux{KP9lwqkfY?*QEzT z>W<_hEbZJC44H3dODLU?#KiA<60KCpf4~MF37a|MXZX=EsQ1)X7l{J6kAnn;qR9dI zrBoRsO)f=>7-6~BPt|$iLDHvtGttRttAWB8r*K)V-5U;Svy+^v93dA`J7=|7n`H^b zyq)GX(d<1{wO|%phD3$avv6o;(nl@74z#y?_zM3ZB-GC)9c94e(F_$=U~EzEoyTQ zKZvXR-bckjpC~~Q_^0P&?m(6+1FIz!ia^83XU}*KE>7h2W5)vDKR~N0v!P-G4~12B z+7|*$DDT&m+jS$ZH?!+5w6#-v?KaLibj49jHuS+bhDKuO{>T|hplQ`QO*iEoLaDEw z)^mem&4Qb1GQKCNsCH*@ZM)5kq<(-`vBY_b^uur1DUQ1l%NP5#Qft&6qQGuOOx|h0 z;wS?^7sY>FLJViMgG2NTC#yqTR1JesL?n}2o+wvcX75i|dGS7h7Bt8!AmM`{h zCT?9ok(f4vkMUoC5@tSW@x4+7Gk35mJ;ErgV{r#IVJVtBXl(l)k@%hy9jJY;8&lF5=#Wx7)m*1`>-|$G zRB3_QV@HT){|7C209@gII%w=Y1@j}Yw2XK-e1)Dz6kh0}&tMqJQjGqRRA`Rze%n4Bjmk#UZ1#n}$MB;py4g`Y*Qz9p}nQ}qt@`7ml z1NFjO_g-$)227r1CZVt90$aY;Md`qdn*I7RChfzMx za+C|Qv1s064NZIvNzJwEk!F~o7S0KPgwVKnd0g zIrq+Stud0n4u-b3(bp`Rd64KPg1Xbl3u1+!e9b8>PX^oT{4um?%}xyqr{m5z9L)34 zR$!;s``m*Jo3?Pogu_KvU3+Dg+h9=-G z3LZh6VQp%B?&n2sSsx4u+PpmZ(qW;^m<0_xy!>kH=G;S72t<*wJoR)%p8dn&GY?gv z{F?BEv)3ysReMVLjrw}dwWCegtXIpg)&`jL;V4Y8WtCSprEUGH5O(1q>u%TGD8#|f zAuOcTd-r2uL(iW>w)$Mwfa$jme_snfcH#W#P5i~ty9dBumwz2-qAop?>xYRq{nCV4 zlCfRF`KF~`Ul>x2FAb?2nG-)gD^vnVG2z0)O}}S(DUq)ZB`tLA`~5Y$uknpV-_J+q zet+ZpKU37FMx#e*kp0AS(}z6K>%ss)kYWQ^&paPm{luZXdmkl)OBrKLS_C`;4A~Yr zy7}9@vXvb&m$*DB^Ab=cH93sWfN%Gy1G?FQIfa548N3iS68d`u5_$i8bO;D-eS7{} z>#cK7Gwu_t`L;_>PqBVC9U?fQS{L7*Iu9NE{fmHw=n5_@?~X)Z0qNQZYd$F2&G;C~ zxE37=6GpD$s^mf>)&HC`0aWl}An1{Ib^{i`Ir&j0BAb!t51R3y!88`UH0VkwOi#p; z41?4lBJeZ_k`(>TAJD@xulPf)J1*$bpmXvOfkgH<1%w4E0^ZMXDLsco!B+Ffo!BT3 zE>nhozT5(`A)8a*4pHRb{Hfstfa4MXWQn3z-eR@r;f_FzTsAZ?7Mnl_IfN9`31I2+ zLA?Up0jf`^0vHg$YE^*5)Zjch;ab%5rv71obbpLuD!aokTx*)K2?Zc$z{jB%vOT!V z*Fe&AoZ2e}f(XPp#iN_STNW2q(?^*THbDRxSskT_;3<4UAQ$YZy?`LXlt|(A*0#{r13V`<~l!O0*@_1Cj|J9aX<^K)k88)T= z)t1-&uTZ|)mJbb&2sB6kf$}=TS8v`MJ34b61Dj12Ca#_TF^@6|yRZj- zH*8k>Y?bv@%X^OYpYF~dJd5fX@s!v+evK~${}`I*{yRvPAqL$QV6U;LIPIY*b{5Zw zmU37XDmQoqlUd@7cmC^hM@#}Ta^ zteOmsdQj-#zKohWZxLy#bwHyx||H#TbO0M`|h&`*+Ko8*<@9^L{SxsBo@GK{N z_i?*xZ_4(gDq^O~?5v64xWK`e{&9<}SD6v6_r(uGvb(iXxth%Wa~}9EgHV>kJ%b-c zc8)0W+N|;14^)^<(HKL@(Rc8s@0WG#wwhKY>B4)GM`?#{YWv1NzHfQnkc8LqJkDuF zZPMm6ZBCz|m*X{vr*11Ao{G71_s2|SwL&;CShFWH(gRr3WTo3-6Xc1MjXg_FP?N(j zmegX4XpfzhU0pTVjw@cKW{muVtzUd`ojRa7Eifg+cBp(fv(@EOzviLo57F%yZ}$ho z(C@@5R3JC$F^pSe=xfKdsWZ2;h+NrNq3+jl*`rDPP`uM!@$Xb^Iqo`kht?o#f+bSS zV3?FK*VovkULclW^LSEu9rfvlP3J*y+4*iUwX< zQOwe4j`@W52pj6=hnXa_x zdN}~pbwp7#t-WJ(NE+|}8suG=37`nfu=RHcAxa}@rbXhoAv-4>^H7O92Pc@E&yM%2cV|-GN z%(Y?nN<*Bt2B(=2$)VPo;Gp|EiJj=@Kuk*COacvAu+TW=k+S*tnD+ zo!c+pA%aPVIO)VtYb9-jNUItb#UFd}Da*7=3Qx%xPaY&CLiVa!4&dx825J(>&^1c3 zkjQYAHFRU6ZP_3m;S0Bc`DnS*C}IZz_*Ka{_)frCp^G@kZt?&vv#<7BlVGqx37oBv zDKQFR87xmg;+)#xzkz7TLALm66T17J7)QW@q5Rw{K$HMyfgxb<{pyES>7easkyym^ zd)oP2?zM;_M4WpC##-R|8Vv&|)TtxqpE>bJ8*2QXGgVw;LFpB~_wDFU6|Tty_-JMZ zib*XWO%p^rl*-pa&#<}sxvidwfC*-vOHT65h~J{qV;*sKj5|5Iy?ah*NuF;F>+iZ(FX(UYD7YIUnvhb^q@GyA zK+c`>MvsWW*G7R#U#k@m*+BmD4F4NEtCtG&oye9C2?!R0rihyNT4%W~@Q?_JvxtFu zmtKVqDnAojnBRMW7@dCKpiRLPg4kw`LFM*C*Xf;I0TsWIVl5h81(rELlYy_B;FViX zpP7J^b0A`}A1`khry>1R`8`+Y`>s;RQhs=yY!VT8+fK*CyJ>CBNUrFDb0>sV9E9fo8FY!OXO0SGA_-~qnS!z z#7rE;asn4eVt`HiO(dxzlx)A?C|t-K2>h?jV0vq9{m5!!XvniXR?0+}(xM~AmR>A8 zs%`pkgQ-OKe6EE8Af+@eOL zuUn)ViLq&U%TxL*+wOMljN;nwpCMRhGeAlHZ0?x#D@4an2!aUP_Z^hYv$lD!p)O9%dW61N z8>uU=vGi2@H*jG03rz5>FpqQ)<~8$6Bq92CYK5^7x!FEr7eBJOeMk5yOW54gtz5h+ z^W6|~Y2|IL>f9&)1D+7H-Ivx2r_qV$kRimCA#{+oNA=6kD~MXDscj(}fr|uZ5%?kW zg8VhtH$R}W?HBa?(WiM3IXadggjiWHCPD!tM(E@Zkj7`|hN6@SzOa0R5&^WLL3G1d z`q?alI+h+6F3krC^CxX+s5k~N^?y1r7s)sNabW&0s*l~#*;Clv z+kd6+@nFuAq0y&*SMB`{6QW&HgCISMC40 z4)mW?zrS-pHYW4Ws=d0TH_!5P@})nie)DbMp66?S`89v=>0ed*D%HE(UgcA->SOMT zESbz3wALypK>CO3@7x%xr7OI8VW12Mci&a$W-T~_w+@}sO_S%zqW*4oXTK{{N_$vYZ>#Y9v zh5jo6t@=X$pR+RF&OO2W=dzUxV1!v6QW}B0Kj}Z?Klg$e0tbDxi%sJd3Y`d1gk%6yi&{Ve=xh`k}QyigYqqqIe(HuPvxalmrxu?2~rzXio zX+pf)^|8iVQr7)4fe{QeS?vo?4(lDylqQga-qYZ={2i{i6@3K8s?yzenF5@xbYK_!DqHyhGTS zB{Tgk3Twf-EQWG8O~i@8XA$fWrlSP)@=ERe{jx`3 zx5weX^E6|iHKja+al`^S$=sY#xWyfB@-P{ZIdPcc4SVM;p`OGYPL*gTw4}K`9BI9X z;t=D~mv(x4IqnMPyr!tP^%pY_F~a*Le9foTbGIn{#5>|lXG)l!9Y_0NXFl(C2vaUz zGn9)qo4v-|gxX70@RN-=C@wA9qg{x+tI<~YJfF}Ok|sUHEPk6oE^~-CzjMvOiLs)j z4k?zm2NO$8cEcTSZ2fNFpm9R)I6bCfXZiKJnQuuE6>mD%khK3F&_Sm>` z+{UHyErxYgYvp$CamDhU-4Rl%^P;-3aITxOisT#l8Yjpz18TF2!uP#74dQT5QH=zV zdWsxqIkW$!p6}F`BtS0&N`ErY-`0$P3y5VV_|=61PbS<#)%fhkf*Hq_U=C6j) zzfD%S@k!EO6Bhq2(X4_BiSKsdR0>wtkCUBc4Op1D=A_cDY5qHY%fbyc#s6+}Bvh5&?WlVOsd`*~gxhKSwA zon?L#S`E4cDBGG2-0CDi04AU(k9YP44?&~WPD!dQv`Cfo1NI9dwElkXGv6)IPPf?* zq7z$gzC+mLRRqXQX)5UO5t(!Vc{h#n$;gDM52FG89ZuMo2W-p0BEYXdTCPHb+&ohm z&zWItaiKAwC{La)jVy2F1HH7zC4E;V^9AWaZHhJxdbOt*=atRda7mOdgfY;%0;ePl zIaqR==$tLuOUgY6nkW_L0W;Rf>?rxq2ap)ay8G5z(JgsaM z@b+IV1Je+v2*uIf-mlOI*q%0M!ujjSCdEdj1;&kwNqQ341fI5~S@nV`2_Ny^+-wI~ ziY;-{`a5ZT;tH04EU`an3-UpSId|xe^c!}HrLiO4Fj&ygS_`J2r}TkaorIY^*K!ge zHNO2WD-wbg#2HI8V(YKYLGkv2!ITg(l-YJu(p@wfO%`4hJ%6ROdQI+86%3}~bSq*l z>UKmB89tMA3bT`nf_V+-$Xb#E=MC@649Xt%q?N9Yc+Q(q%)rf7Pz76n@!|6btlU%q zt=mJ|oLzvCIw*!D3PlTwj9YJl!8n--DEeSAU^IFQ!~kBW-w~Q<0tlLjkzaR7*jj1^ z9KZ2BdLeMaCvbu+kqfX@{pH0!-OiK(jK(Hg>ekBFHDh_!9?%N@5vWMpGsWew=oe>2 z+|cVI*mPp8WF0|h(91}|wW8M9Ph7v;>LoKbO7$ExPRp(Y;Il^|QJH1PwA)9ddXA{C z>Q6miHwYo}{cK9T1Z3ijNUESNU(1P~kkS~?J3xSWww)DH^uJuhlL6%u8=}5U_-cG#-3z`%EiJuVj-kj?f!E>RU{GVAu0`PyeM49?GTpq+br+vS zHeIFvky`9W!=U7Jl2o)H?4e^5{ovV1Es2#5i_YDW^lgG~Q;Ld!w%68g7d`-QRNj$$ zLm!=Tl2v)D@DuEdZDPX#8?6oa#Ycw(u+3`EH6y4Iy;(D?V>ZtvX`zrS&YPop9w> zsy@vA?R_k4eC2m4ANuv-1(*h8W&Q$n2Kr45ZV#7 zkIs~GLdFQ9`V^pQVa(k#@X7f|H7ZMO0hMfVAwtMf$Y!q3I_F73ngp=6)Ajo1;j5i6 z(hIpq6w*2mwM4O{^dYZyBWP6Q83udhE%H?s?2rgfUASOj5v4W*-5kbwp@0r*iBjXC z(r4HQz0NC;7*2%q{!Zs(snLCo0E!MjX?gzk7KXYAa$uTc@5I=~N6Jrge1wcgF|aqG z943VeV}hr-?Bm;MA@N>V1QD9bi;e?A*{Gu?0efsJnL+KaHMAIHHY!RX4q*&v)7kS` zkYrlCgmJ*UBT7sZuaJr`pvDb3A{BYzHQ9$Nr z{!7?lA(H<#>ErFQ|1jzQJ4O75N&i1nL>{{1Z<9VjeO1^Q`G1k|J@Uspc3+;NzWzbR z?b=&@-ctPq{5wV1mhiv+9BPvd1d)XhlPV+j1Y{w;MnRZx~<>}Rz1tR|sW#{78;{X5u z>)NiJYSp!MPKT}YNmimz+19FcVucQbl}3&)pZE9k{rtY)-|x0Rpxv&u+a9mS>;AkyuOFNl!@KX>SQAu0AvXd&S_J+f z&LN$cQ@d<9IC@pWqhrOMn7upedQ$0KYD!?=CWT;Aa#W-Q_SK0&O>b}7rhKY&k1Rc^ zWt@ffUw2D4UVoQBQ_~`%>_y}y-gFL^j&u~w+&XQZcln}ixqzoL-GPljI*0%zU`cUfmI77V~ z=YR0fK0K$Xq&L|XVk7gK+MC@AfJ+H1-m+Dy1Y|;wGCAtNB(la{tx_czRSmySr zz0*u*wUydt(CzmG9m?g;?bDB`vRZ?#9*tpWwvfN-96Fd#)n0#wDnGiy$9!J-UfmDh zch;i4=uo3MY+Hu03;V&)JvV!6AFiY4yBE122!3)LJ5YA~tj=!A(K>UH<5Ik;d<`Aa zTYXO7+m-JBCLYD&jU30-acCE`BBf&*1GcmIO~8m>QTxo~ADGr)nmw#x682D3qRoGE z=p>ebpN`V^yqv=qV}k`=4jJJ=;E$fARaa5lc+3X6a}fQSmen1oQA0)t`_L9eZ&0cO zwVa!qQb^-9ft*0j8P|t%KC_JL^WU+88|S@3Un-c+0q2;nky&f0$)2lk4VZG4UE12S z-1B~%vEl>6g)VR=huZtY_o zb(*R(Yb4pUL$JWNd@PS@x@&%}It)F&rS|Y}0{sh$rc7(<)(dV23*e&M!zvh>Jt2Ah z)!Q7-1(Xg4&*tv&x0jfH)n7=REfJuRTPR2Cu#k2_-LUE>$>xDZF25o^g zo;_+j3K~PFV}o76DQhQDBt~XIvKGS3?#_<{yp>r^MD>)1R8|l#P(@2*klrb~@NZme zyH_34Qt2||k8+sWoj(nK#PqnA*UCfRWdfLc$*BN9%_V@k=T`v~h?^U1<0&E{4mr5q`LPQogkn<+w*u6*4m&%_2iDcXJ1vB)*K(?SxBSj$dYTSNVg( z^)%?s0y7u5bGlc)U*AU_M*>0m;d3Vg*hCLh` z8ELyjgtN_c8tUpMEG7A^FG(hDp@hAqXilL_@m6n5P!zP2ioL2iv z!eSUy8Qmi{9;HX9?N&9mJ9fo(RFS7Yi%f8}^tsYyAGc8-qJSxduv-h)mHK%q?nq0W_{47T|>8Mi>0@OWTG9z-J z!g@7b0MI_1JmlLsCkH|2n$C7~mBxctXt{dXeBlm@2e6Vp)9O;-uJzOnsK9{fBm?I_ z0hPlc%)Wkg$SwZ(nmGT552hY`X>PrKJTc?i!^hvhw8+#P{BBADO(=@i?!Xf%rPl_Z zZKmSqkxzJ8BOzvCU(XI)Kat*YZn<_VrSX;*n@|Q|-|hX{HWCOyg9eZJg8-(Aelq*z zzU5>?hqee9W%Jbk$wl+{*!}#> z2+|RPKTXPhgTA|a!xV+D{C=>cd2=6ryODY0^nurgXu$8ybws^UiVGZJPWvtwFKDdP zy*@%NP{ATdJ5Kaqq;SMvH5L(6S4eVL+3nYNpTIkgk10dd(4AOX+OatL3(l50QjOAe zu&5rqcs9!+U($49)ix|N__ZH3)_x*yTLNiFKC&)XYZ5H3 zNC%sa9>l@Pf+PD(PQ7cdFTg+)Xo4-6^25sn`=x0~kUA26t znk2cM_2&yM`vv;kJMvtlLv|@}4WxQjC0_Ei}F6q{dMkqJVPU& z)}?N}u82}KZKURlsB?KOXc@uKTHl@3{|dp!MTx+b@uIF(KLu8U{b-5&?1Sl%`LkRr zcIp$*rf!a3@=yPGcG{h<+b{icA;}1IC;)$D`L?Ygs0Cx^p1xG%WW+%bqr0i60?~c2 zIqE~fNum1UU=*ERc_+=JMPK3Y0JaA|70ibkKSztTM4KP!^4_exD9gC>!=3aCHq`QX zudC;A8ef0@saes}-4r@z{*y1N4)o{uofs1Z3qgrX3fe?m{$O)_)2E7)nXF+J%9J~M z>de;nlXH0&-}{f9_1B@H@2O7SiJt&#;vNE@4z7G_t+=`_iY8R0fuJI085$vcJ(6Bj zzrNy2Hl`*m3-GDvheGR-rMS#)OQ79~zg~h#$E?+pVDwyZ7NPtY&PG)>j?du}C3q7( zw6-;{gooG5#K$k@t61~Bu3mVYj!4=kqYqn#@p&Xsb0g8p)E-v&vlIWEysHO?o94caXN})BwpH zLD?#B4hl4At@}5bqfFm)Wz0+l4k*+2kH3299Et#|DgKMh5lsJ&9sd82zR!DhH)CC{ zHR5o@o4?4M|CGM}By+|RojzU4{QCVZZJ@HV|DU(p3gr!{Et!ewa71} z*Z*(&&bbnObWz6K1Alh-huN(1nMW2F{mz*9r|;X}5MSH(O8c*#UKzV>l+WYfpNg@6 z#co?I8I`aVgtjM#{f_Vdirtw-*9e+8z!3i`vV*l$@b2bB2!;rPf)@*^|%)r9*sB?P;0PNVd>O|_xBckhkPQGxKnlkvAh z0-Vy{KuyXy*{%mV$DlKrccW-QUti_T+U#6r@Ab;dD_W{5KT4B2wh=O*%TRK9V`MNN^{vVJ$>UU&~GMl$swliu8Kp6 zPUd}P41k{bl&8C&SC!amzh{voml00VUG&1TGccrC^qk{q+|{kQ{KOYl*-iJOMbmKU z;oi{Nf>)N_%b}v`1iL${<9IPTTFlL>v7q3f{kB(SB?OXuMJdch;wv+j-sw7^Qa5Kc zf-qxAr5k&A{nZQ7vqI~Z>humX>)XGYx812UnH;=wz8oE6=jBD(l`|!Am8e*fK z_eEtmUuMeU7j4YtuJxN;KC+Jq8kW95-K=)zBPQl+gNU7)MiD!9~!Pm?adc% z^L&O~GEj+*I?|PMZ%^rVSxvd>V$|^W&)k_l6bQ+D)fh?)jbD8q0AF{{Dh$>uwr0+I zYtFOK9gSC$D=$s1(xCGOHcx;@owwC9Mxj8NeM-#0yGR44`JCUzcCK0|$Ls0U3yDr| z#@2%d+LZP;&u;&ep`Y(d;y}Lj`$?)RWf8xn@Q9~>MYq1?D`nyVMibU1VmimV4NYZ=Oi+ z+yw!7d(1%86cKJPPBcdy2Pz-IBxqPa$Se>(NZy@3pFTN~Z!>2|YnlT6oEu~jH4uf~ z42$@iNERiXR6>^(=JNg^i+P+%jS~}>cejCgwxX3r;lU_a<%8Py2haSx;me?hEKP7H zAG?`z9@C+Kw)j^q$mN_jAu@Ip4-zb9=HYE1r=9Z%Xv%1A-i$GLm;b8{0uMk#6Lj)I znQVaLtF5j)gf{jbcF4GTZN>MGr7~hQEzdWgg!UA>#2UT5YRsxiNTmR~a$lt0kK1Qti@i4?c9Oe&-`ucU zg=fLn;30ic4?dsByk5KFYtOw4-#?#3cAM+&RS1nK6}U+0YOY2{&Wv6eK1BJ$xC9Y6 z@z$L}e?#Cx+5H>o{VH=abz?E)+$&jM8q1e}rm=cq#4ezzeiq7x90YYt{icno5+6^D zNh!`Sm0so|KDjv!so?%(T>S3EVs4lNxdW~j zvf$3wS$lGshOQTMX?tgEl!$RxzTz%I0`)p>znOnCU0v4g&d9?hrTETVj z6V^fUt{`$N-XNvD?m;vYrL~cSUYmaTNMILoDijU5MiOG#A5~W%SQFRJre01o$(%Jg zKSyT}vk+!+OK*&O+sGD=nz3CLYcGIWf@|@Qoea#|i!>)QrY>_S>qnUqvGc?GMBAEb zud`f4uX~__8x}bV134B?_FUso7=*)==V&1VW3;XuTgMx5_N1y_e$=hUlhRXpzI<=OQ(D$6!(L!#Nm2{8im%IO1(0a8y49O_Ia;bM!W< z7qxa+Mfj1Rfd@CZt!w>gbjZ;zL$&waLcB`yo5W=uNQneEAatbjBEzY*SWWL?8g_}QS>tMP`Rh9p`!~o zsoU1D4T9yVR`|WS%cs7d>ReDXPbz&C+YQ`1?~&HLC>nnt{;XBi7|W<;(_7s=bFRn9 zzh0d7@SWEE^xL>TwAuGZW8x!Xy}jx=%;>p-9a9^Jbx{KS=tsm?v5_zCUig;7=D%Tl zWi>k{W!A4@;doPBcMV*=pDbMwze4__HC*G{HvG@wC03DdUtcIPh#$fP#+}CI?HGT! zNOULg9`mev_vHS0Tc|#n8|9_ksK;xJEv)FjOp~sT{?&zYdP=7Q>ClZ^o^xw>Zmt2# z*h$N+1E$Hda^Nt$JWGTNqsz0FeGS!-V77$f-ebc&#xk;y@I)zYWd>%YPMD?w!_L67 zX-iR5P^3snRYZxbfmw2(%z&1ZCRLdUuit772PseiJa8r*gV6K8YyP9WwgF%z+P)G1 zP>!Mou=VugwjUa~PuV3e@~cOCn%}8j`518T%eI%_Z+!i!K~%}>dKyr# z44Qvl&aD28$BSo!K8894f5~L>7vjpXR+H>I9i6E`wKDZf8aEbw=G{)Z{}UoqY?+7UrI{)Gl%HGqGc!u>tQ|JPD~ z<=LxBbe*p0@%I!i=40!kN^DLQ$32+K#~@1plf=RNo+Xtz1WN!?O}~rWCB&UQ=I$!E zbhm{UZXNC)%Eh;4s+FA&%9sweA;l}jTP(I z+v-b;ToLd}(XuK<1g~_&eCMJ@O8c4ncL%%@rVfU6)P2%?)+r3oI0ZyKUAVo*S=z_*$hq0n=1!dR*U24c$7Mxgr0Z~a|I3`#*CA2Twut5mLl(Q&UEE0&t@au zK(O8m(vgE=TM|sqZ}!cN@-riHrExQ=?=XZK{qeW-F(EBGw_AOC8KL=^Uj?dKu{o$j z!v%;5+B_{ts1;RLDcc?63|fd5e2fKPvP8syLrYdy6SrDSl$C<8PB3m^Blksl%mGQr z^038s4zI%^FG)D7ZYe@Z)yb+{D%D#QMCjTii}rC7adOLZLTo#Cj2?9?kH;Fql|FiH z6~N)$ArC~zzI-f8uP~L>jyimKYH6(goLnEqx=Kv_b1$7bPHvsdmhxnCL{$jNJ1)K+ zUD4i?P=Qzw!99f8jR_>|c31h@`kN|jy5_zMIXRv>Mjyb_4|{CI2Y)!Gu<#~j+zuR- z%Nh1Gj2~NbRyLQ;T5FvScBJXvrCVNXpNpVz^rc-G7^V!?p(C9GiVT93H>&mXXlor= zZrrh2=`{4RT&#)bc*50(A-wn=oMS!uT0=8E9`5WYgfTO38`e@>4Qo#`BUx|OR|vY{ z%ZEHoAOYIjWK*o>DH#kJcd>kId!bmE4qf8%I- z%;SEABf6&tX{MD2^C zUfn=?evTI!dMF^GGu^&>9lkcV>qPCUDh6D&SHJ7Xsg2R?YJqP!xmvDl#bx}Non2_N zF5Q!pAA4QiPkxg7%=m5m&Y>!nTA(@H^<^;Q{cm3tNmC+dgTK0f;NdL&`Tb4H`=3AF zo0($Ih0K%-O*LdEm4?bG8g$!p9`pNzj||nY0}2MXJ;eZ?tT(3QSCPBNfOZwKvLzMj z>%!c2^^S$47`+FCk1yNF4H_Weua61rW`6Foj)CJNRToN6&*+xq91(zm-fo#RfX+bHd5;c|w$r6jvWdeMxum93Y z1x{XJt{M=2ZN;qy{BvP6!9Z~>>PE3PyXNkAI=45rK!%x9Zj2@l^~PRS;CO`x%;GuM z6TT>tdeJPGbFWY*-QVM$8OEVeGU1DgnfssFqg+Enq0H(rxX5Huf^hZZBWm_Ao(}HHM#G^SRy|ZrAv{7@P223uA=w#Zyk*>&Z$}^C-Kj)+`Cp zri2`?l6&H3bf9t`Xf>Gk31dPZE|GSy(54f0Yq!sV6FOoSn5a!8XUVL4a?V`=qYPuq&^eV9eyMpJs4 zNznAo(>LO2mc#g9HcMp%H&^`#KyKaDt*dVTP?e=^mN>wNFYf{0WwD46`*|^D{D!=E z1&T9LzdfT|46q>ByyUo^w*b67d%cRvJ3KXd?R~rQGKzt`bNi9HRnF#TD3{foqTyFxvgjxB8qgWNDNm0(M7 z6|J1^o@e4V3<*b4_o;1?z^++$a*d`hj+Kp`m`lBldzDl7@C`~l&b^cHNbsWYmT-lV zqPV-HTO&6xMvE>|)ulHpJ>9~p0J>^jbC;nCsc1fDW6w;nk_Fki)_uI++I*zRVnl+7 zC5pj$3tU*H3e>u3{C;MB2f6$>I)8B56Qh0?mKz7Zu2!MuO%j}b1;mRC4Tn_n#OB5o zZv~pq2}QhSlx0eCcHAUYZ>oECLwh~C(!AsTHlUg5xB1=9`O!FU?$<*zXo>@r_WSE) zpjZ5Yb^Gk9R2R$7l=RJwKFFi0);2fx#cdxGg;uHfom_94wS6Zpz!0xZ{a$~>WBnF0 z`c}s|pd~($bn4pPH-s|`)5hiEQ%_mA8@V0ld{?B+l(|zYy_@kV!MUE}S!!nMHa?l! z4m)r|AD*oyfa7o)bK}rejpU6-^mj;HCN^Sk?#?HU_arQ7oHX6L(D|hXlfQ6c-UsI* zTCHY#(VcS}J~#C@YsYezm57Ee)Om;=X|GHhG^qj~cwBlF^D(FA;QhNzE3H@<^nzBD0Xj6>Z6 zyF#4s^lVj~}A;EXPATWJ=(aKZ#i`aNhQpqsZ zgN~omyy}1yZ6fhSQNa0>Jf<9AbGBNO{}KBW07D=G*sKify~@@cFckhJnc2QWm?QaR ze=IC6RoWl(_w4^`p7r1DkADUBU-rjeH1}3)VE3WK-pWlkm4RJgf46W>!5p8n*#rAD z6(#fjZJza3%=q+iA>o@~SP*H2LBn*Oh?d33zupze|^1cUnXM54^k zL|~foJaYU$jD8L=RMr25)~kqW{x}hA9=85vv9X?49PmpQS!%aZX|eeqpqO2j;%d%+ zJrS%~?2t$c;KH|S?~B~<*)&i(9niE_DWCNq-K*QoirD(-M|#JBGoH$+b~d$F^FsFL zC@!Q|14`UzWi+X-<5PoeTO44D%dMwUYfOD(4*)v5f(@qM!wydUhHFcpI* z*P~?}jOIHe&6L*u=?@x{sta2)DGMgMKOFYypvB#IKIfLXLGHpWfwHV138ii|70ax4-J>p;1<@*Fux>@2P|SYoofuH;TB&yas(9x# z+zIOnkrhXJXaRMi^&W241<2FqbR2gY(J`Q5qqxu+5tR|l$*Lwfj zTYtvEX)NT23eWTU^O7O&8;}~}bn{v><jI zgg?~_#u6p;&3&OM&&c8^{2iH(wgL6F-$Yx@#Etf3Tl9~a?;`aXssF0Rmu8B zzx+{osgHjXhoSv8ar_76Jtt7P2;l1*tH-i%(j@)oq!{KuS%{{QuD)DT*XQvy4e1K^ zpj|{AbHK0ayb5K@un&Jbxhd6kWoSB=j{Yts5UL1Jp~Ma6QNOXMMi4IMw4+YEQw5IY z<6>dL)TS|h+CV$rKa9a*Q4e_aJ>2UrLV`*a(8=K{LlI;nbRy1dI3 z&VhQ-7Kg-m!^JH8#^LC%>QtyI#u75G8njl$^YbU@yG`6!rck<}DjUF_c2-O?y#*OR zZP>J8gt2)$O=QA$EW70i!P7cKs~R*k)qsOYD+k-p_>|!kjn~CT2EHRu0WB&Wh8ZX$ z34lHL#uwtr(GZ1BBo9Qe!st^SN#Eb$(gN6eh2b~4EILS9bC~)RFh{pdMvO&JS|SCw zAEv9!rStK#ZBbhINZg53JkEnQCkeX~a^WhYSLh8b>z$?stuhM5Z_!NR)9UgG0cuJb zwEg>H$Xs5{YLx(Sn|DIw0JcV0kB_d?4UBz_ay<#>_OX5~c=l0Hb92uU(gUsnC!#cG!}tN#LD>vsQ{}RgVoDS%&X0aFh4eax?K3ZmiFA#r&KJ>+ z4MGcI*a@2v9@9@D@X@Mlx3v}(uCx~vI8`-hzpzE-Ih{tKP&>7f(V8b{IG-;!$t6-D zj7*Y_9T+$!p)Fu0NYV4d?&HI5q?Bkn2IlOdUWqs?;5!OHN7qFKcbCa>EGqdk#K4qV z8M|F)v;6rExT1Ao_0e})Og^!DqGzf4I5Bn&Y}lyVYbsyOwsk}>yBI`w83Wk-f}~b(P_w#2j?ioiGQMX;~p` zSetdoLvL{XUPaEHjt9gUW9>|)6t(OJcrV;RWCERn)kYNerg?$PCx_5(NlP_sJ;Yi% z#J54q?%yF0P|YrTL7VwF+?DFpDqS*I=}jD5+MI&b>p+g5ICrAork(gyt#7(>7tU6e zAwAy4&&}jMTCr_(efHSsszZz<;s<_*?z_C)nb9OX;<{#sCU!bJi7}tzi7&exh{>I2 z4mpNp5C=#1&4&kx@nva@kQ*QE7g0^wuFhp!6#Fcz5Cw;KsAuDe=LhFiK|g=aQju>k z&>D=;5G}yp-19Cq4*;JANa{mxao?=+93qhKXWcya7*?MI9vVD46^@q*8afTmtd2W- z)9RL}Y}GP+)RO{@w*7I=ayQe2xH%7vQ0Ss(b$00ZuB-lW{^wV1_@K52f&15q-=^e1 zE-k2&rHLDQUApdFtj-SQ@y0Wc0E*o+HhJldEp5eB*b(9O>zYG}UCSQhtCQH8ly?H& z${3tzONxrjuc#}@ZGxCj@4jcW;J8%!wBEbjtNbKyWF`y!+M7S6nj5zp&g3grjAcKL z*-~`*&}E?z)xSJbKsS)k7Rti0g8hf$Od#s|M?>edBR7d~WOF+k4(1d-uSNw(3RU`&nz8FPOHo;Hrra9#p`a>fCpebi7ng1$M6PSe zjR}d}mS?q{kPN{z^k&+s86|i%Ix?CG+jAhVF?4|foy66B{7oKv{dYV2|2A#8HsO~9@?VpwruDOQjyIjUk}JYy zc{=?mfmGJdZbw;ScQdjWY9!^XLzq)!bb-s$g=nM48QfC1Dt=p3AcEz(nR@x8IS#=16Rp5{q-j3 z%2xmXW}^Hv!ym<+NSGC#TzgMqY@PiJZ2!B}UnW@oq-VcfD4;C$KaD=R)^hTRWR^kt zw|SqTp-!=;-HP7UQ_rqQ{wnpe^=EynIP^!U|Fd`a3evgPw6$GY(e(OW{iu=Bb?cOg ziQ8m_TGXeMFvmy8kFR6Tu9dEQ)FmQe2vXSV!o{hftYM4**RLI~;NQxTp&45yUn+$7 z!5BV-4~ZX2)g%tLQ#H~DOpF5MIqf;-OXKMf>WpHj;F*`TECQk_aL_X1D$5$D9bQ zL_!SC06BWd+M!!puxFtGT}D`2bJf(yw|fa%!Ydgu#(DK}UkXbma}P&o5&Mo5V#_(c zBo=X$Td|(axVLX>aXg@lwlF;^oH=+2A-s!OIz)&g-svJA{NmEBmigOMyscnPm5W?+ z#YF#T($MuHuLT>@=(Yz>d%S#%gA7wqD(3_(`(Wz3C5Sx;uQ>*SgFrmfa}vxoN)_3? zYaK3GbE35@zKD^sg~aPrvEowSw~hC&d4E1^n8(D=(o(=+Vm;g;gLK!9wc|A+P_aap zH)EZ!kNt-(tJc zeaERxk+j%%LN4xG*7CM9EW_3P%b?0GDj&1(Gk|@#u4U@&)s7X%0q~K?pARmw5+i9( z3ipAR9xmfkIu#;K<1P~W6oTjrtK^x_z(j2UYFFrj7NW`UoL$op=Z3DA^@m6uA)aN4 z=TN~!>Gy@~URwA2`Yi{T5g|*Gf4p^#m$4T{jwm*awQCg1LKucy+<HdJT)_~?aI~3-ZC{uZ^f*jpKoDT&SkZ@mOEXT=*IV(pRIeKf_V{o;pnMh zC_t<~_7iuG0S(z9U6DzqUUFz)gx0kdhjSJqVcOqC&>hMR9_21p--Cve;;j}x0vrZj`;>)6*l}H6fZ8<3P2&hZAhn~iRKrgLBy(M%!1jRaNWul1p zT$^3j4&$>Vs~(n(f%zN?;4#KPXUoyX{Sf4dXX@K!i zgsdm_M2ddCH9BAr5H4H#sf5Og$cA2e?UhVn9IKVm!d5nR@zDiw4Lg_H&SB1aewAY~*lrqE!yhbn?JcB9 z;YHuTiAWIoNXiC6pKJ_=VF-m%(6GG;A*Z*LJ&N9%2%=2o@kbvLQgV_ilu*;?kg7(zdnc7t@~hmT)rfSi(H0cX-q#}l+jM< zfeqh;l5iW8-ZXQNZCoFy+YxH?@D}dDrE8kiZGPGmXKGCM$BfbvN#ln5Qze``*GM9I ztQn_*>drZxu|+O{+s=ULgQ}#7heIsATKRiC zS%SXv9!-)wNn_stxd>IIcCKU^FSCaWw;X+P{JpSM`Oj2+Vre$#r9OU;s<@GIQKJEw z--%48i<=}S)!9oSu)QHWT{TBf7p1sXqPKWCIH z?>|;=u4XX#+G{_YFqXXS8a{acWgPLviLYBMief9R5OaoeXY6Wa7 z{yqY^zx;PO$eyaB%4I@zwI`L!gm#~5Qr5|WmU9;_9z8GX>^gMmf8sy>V_ba`F)>6$ z13w;n<56Q8lonSk@#j*hd|K!7IR;ApBiV?rZD|{2_h;LyjH|_lSBkGMsEkM#wD*+K z+^^=J=~eqBQu#Y69(Zj^xA20Q3w_!DO{9|J8}qLb$or?OOQcF?`7e=5)ZhHapHcCm za(AI|z%TyepHWeD%zFmmYT3-rCDJpW9Bi^yz0n>z)A;Ik&7#^B*U$bD6%PcSYkvE% zb^Ytd*Uz=Q|061r)!XR*!fp;KWu2h%1)xx@e@tEi%1@&WX#Nk~cSWbb(D-kyj9=lu zb>IJ@Vg41~|F_)yODpr=XqepJI1q?3S!rH#JPU={KR4~gh{2dkWXfN&9wK-KSrovTl$F6n6D^J0{SNeAv$mE{-x^5^=P6np&Zc zLfby;Xfbv!ZO%%gnPvCMq@3O({u+tR${EaZ$-UV94v}MMUdwd8!ND0hTy|mIVVZRX zZFdE#a+{G;Cm|}RV7EccNIlDZjbX7sb-7d4&S{Ylj0G$I*?rr-u4}wd)kUC5q_0iP zC)?MYZ2Nw8O?`)o>e`d$lYmgIiL50fa_Etl8}EdydD}Fw^oKxyra9*|2_H>;+k9Wy zeK*aZ7hwpbZa==Nf4SZJwtfeauny1me}CZ<6MSB4m)ZVa_OVjwVV_^daA+s4S=LpX z?`;2}i5q|G*t7!yb&gG&PZjVlO!Hrxr+WM`oYZYv+BXVWFKmNQ$JOcG9n(K4v-JrT zFy;D>*s)_;R-f9EYEGsmkk7}oV7nX z2BJ%Ub>F3d)3pv72E4}Md+B(C)O+i`KFWN#+=V)mG6l0wV}f`htVlO;Vn}SY!c`Y> zc{lM);^XjbcvooRx94-c#`x%UVDV)jHe7~aEn55d24?i#kb3R}n5*qQ@qta9n@K6b z=s8Eq-T?p?!6k;t7X$iXAH<~YEAOs+w4HptglskLaDM!pKP57F^D)Wfm%(M=`cTra zvirV$Ql1lpX|2S)8EiS|wtv}lvirC3X|yirsA^Luk=y!y{zqGGc}M~m^vDp6s_cS}2TXk5UI0xcu$kzHr%(ik84yNC;l9@kxq8fyTy~d110~Nc z644+t3aql^8n#@WkT8yyDOQ2~=705c+eDXphf-bs0wU)9UB!dpYPW^ zMsj2mLtE+X3&+m%lwNFcvFv z&mdgPYiC7~4s(jHCp*0fFMZ*u!V?&e1K21w+GR}#pO&p45aO8x<|{b**!ulg8mL23 zriaP(8@N3FTgze*bp*gz!+gIbqr#jH2(q#kQncuc_V#cw`sLmFeiGr<*iTt1zKF@s zqXPY1>rEr*GQZMe!3KCLV`e0xMFIGGmujP2xpXfTDIfJh6S(Zwt(mKGgDI0@wUdRW zWj!GzIdF_tAyZ$dsEd zn6n&D)A%OVuOXUQbOQ<6=Tu9z=qgGbIkB;TG>fQcrsF&H4V*-t$7Hw*jd*hK+=yoK z5eox$Vsvs}kr`Wd#2o5aNqUN&?KFfnA_&#bJ`B;tpRBZ}(cyHt$g)nCimo}9`Px=U z&WuKx(35^!AZ6vXQnBshD;*qYOAD=cUs$`XJyr?)(k7(f*#tyPk|600EELMPen|#B zXlrUDYK29lCNc^WTPYn6cUn>6%Zn^|x}E;p+PC0308B5FWU5qTMk4%NY1pOob=5v9 zV}q&}Dou$9-DKh6U`T}z75bAI7WCfR6cC2y9rTTr1bl|Rkn)2e1LJ0AEAX6zq>eh@R^szJc zxgAY@K|JG})*?d^WAsDqQav;M(5P9_}I;J*N=UgJQ(d3b1jtF?@yc>1&{4FSH zD+PN#oQ=ACJ$Awdg1RrwhU{nQU<2A8Wk<8&k@GL`PSL25%eDFKra7#g`WWWGZ00dK z&tjgG>XwN*s||P6a}{@by!q#KnI8(aPCQkc8WIrY(}gZuyom2~Q0w)BQ+6I|qgwHR zvqHFJT9@pR_5${GyUpu!&8b?`ZoUg~sC$EbvzOv&mD#7CBGkH;g`4@L05`Y|)zUXO zY*os(I40roW4+W4^1f!6kkhgj?xz}reXFO+g=%pzICZPj@RwJT<{dxY5(&uN=S03G zjcKO|%sCM>wkLnW{Q=^$USs?bn!5_~;&D3TxW&iJl|DbaSn@MTw3as=P`{}udTX(#h03I?I!~n7r&bhZ)yBS>Oh=` z#yxgY6>{5k(e+UCpKE7t0n)eF>ZAq+VOy0!8BQ9zvQfVsoQJH#c57Wa67M|bt_LD( zED?MVdZ1*>q9N>)Bk_(f#-M_)bA)6DL!Fm1`i{ik*vVI~A=!qm)~*lYI6?*K{ziO( z?`1xL6qjO|925lU&BpTR&iX^b$a|y-Y|K13VM#m29El8hN(varGI0d%S+0noWiPG( z@pN?OXPQY-4!s7}lq8+-TC_N42{%kzhlACZWQdV$cUPf_vdX3`TE~WBc&OJQ+Da26 z?)fjWgeqAUSCdECq}&=xg9sA97)GV_Yd1>B@!~lIM_$jBe7s}QL3{z0n#ldStcnfK zqNBJ+vW{8m4csN3s4GB+XrP9w-p7TwtFYdujjStfej;T#B@X#R&k; z|B0{sdp(|{_P37xKb|+Pp?_aqy8ppX!rwaf#W*6nGg6~Hl4i{?M62j_c!hPJdbXcv zthxk0C&64vmn@p`yWHfDB}w-$gHZD9OVc@0iXk6xzl1rgl$-puB*~_LpkbWz7h|tH zV*vp1KlxPZNRZDS2)6#GPX+KPv`b^<*X@kyf&LimBvTJ~u8-;|49EHH{e7_0hI_g9 zpp)5W#jigpazJeNug72RJHknuU2%Hx(Iey_WvU-Jee4!?S!Y3Drr=npG}XLt`MLh~ z`-hnWJ&y{cH=MIY&^Q6Jbo>|08R{{(;yC^K zH|H~-yp76c-mDOIo?g8*vN!j@p_h%X^B0F)DO~)bX`Rpjd-VkRMYA&WL|+M*eE3Dg z>ZlOeY(7^oHfKxO6L0DyNAuOmeG#Ms_#bOn9cHhlJ}2(oYBdzECvj05IR0YZGy zy46?HCUzcVEj_+R<>!s8fu;vk{-o8O^m9$IiYUC;bTCs@{RL>yF^54HiJGhiH|m9$ zGc;Dp0JaADO*EL&a9uvcLUZ_7tr=yJSgmlqr{V=MHM#e-6YInh^A%mz&m=R|E77WR zUU9AzmwBZKc3@}KLq&`CI(AdyDN=^NfxNwHRgo6{Ih|cbjo$6F!e$i}J~l2ywi}T< z%1~+mVQ*#+{t|KFu`VyOio+DW{RqA2<^L({%)_B<`#yeMvzxKZj2Q-D>^nn3NHcaS z4J{;PR2Wn!A?r1ZEzu;UMH zkLx)9Igj)EJFoBe^DW=f3UPcP{wvs7SWS6fd2xpX0ShWmV3h8lr*Kt^v#}n!Zt*03 zVdOTT7NE%!-_-LcOP@e5m+|mCqdypLx{EJ&yg|bDM>Jtzw1daH6zj1fH*9;y&n_bW z3)SBA5w-f}{HJnuss3^=omoNeV6rPme9r_)>n1Yg8?A>TX3MpP zm-!Fz2y3VVO{xgDK^d-maiB@fuG5V|V2ev?#n((qkP*U?ss(jL{=#kqbXnIl|P zX^5xvPe*v5)hhW_)0#KY8!2H~+LC(e@A>JH^&N!S>dPJ9J$J{2z9s<`FiJ*4?9#9K znIj!o7s&h|xLU;hjq;{1Zqacpg1dvN{d7HO{qB^V3|)0^2JDSaQ2b{OVAkKcaI|7$ zyfOpr#lB@R`ySIwEyoUf9YXY6L}`RfVKnA=tzpz`n`xHbvlVvs(*l05zyD#Xr@`vr|&xil=H;8+BR4SqgRGr>JfC0Xj1H;W=`Iz@*0qKyHxN``IAM z8qo2BgB#EPY=8iLWGu;pm8C^2&vE%VcLb8ZK>c2W)+9}(cjp7}Xd1`U@zXyY;Y=RG z`eV__feVKAckcM5d^#qSofwn|ZbGMH-9!vyasUL_Qc=2;ZVD5Exyi=L`eprcc!(Qx zcb~j2Cc=D-be9OYBHBq+HphMVn=D~yNAFiQ)oKGHX+(^gu*xn=jaR*gD7&~`+O_0y zyTeBmyeZX=JRk1b04iu1G~<{x#95;_h5j^9{kF({38YMaKDSqYQZt2$i2A+1G&^@- z&RGKEX(g1ZIcVYV(ji_(c`}9S>Y;Q9HuAa#39DHgMz0~yh z42e|dWZh$XE;~0@S{C=S%Qa4BuN|bZu%SgGt>qyKn^dxCJLS6hYidbH$ z27)-E6s0d=VZz68N`@>RC@)6IQyBifRDRvv0EBo1gVBcoqCf~H_r@T*993{E76!mH zu=X=~9?}bPn-n5YMY5y@oqAa?_*RKhPsZDJ0w{b#gn|TIdN~c>RKQR(&m*9UbsKAX z&BDuJTqX9mYn&By#rf++8cX7Y3+?>Q3I|Z-sx3EdAX=AY5k z4O})ShLh&DKKvGIMsfHMfAul(OyNVM<=Q*rbqiaS*jey(Lm%Q-{Xvu)w>xJ&3$F7o z0zUm#kqe%3jd+9`BTHt>U52!LZ6RQx>M=U{nm5sq$}zMJ18#MDqszphqo;vna~)vQ z6Cb!CJ!uchZ;#mrCP9(SLSxw+DhUA5#Zw5%W(-P&88(_h?X-x8Tis~`P22$^IA$(( zXPN*rUV+4VHx_A10L(j~7pYU65!3MWN29v}nNnxd2cR``!MhGe`2zoZ;H9a%0)yFj z`iVK*lIgw#-ScT}dWLjUED+t|1@Rv4&WYt7 zF%F}JwAzZSGOSwv_(i4CoUWcXEwLAjp`Fn;{zZ2+HWiRlF7rkO`&cta6 zV!k%1xTvyU6%)~zXt|Skl9VkrO4~_D-}w#xOf|#3&)^6uBTNT5@qOzx8g49+pgbQ% zK8aTmZ1+ZQ)e>@I7=Q0OiQ;1AeId2||rLXXOyLfPSEay@%J1Ts%%J#SH77Kbnw!H5vJmmXQg zz=U-}kug0N*e<4_8Xz>3Hqy9e;Ea$ZTPc(Ri$>e`WgY!)1 z=01M;|Iy%oHJ1L{C!$d?Wa}#62nw;&8}gKTa)OO8n%-LrqE6OLIS|0QG z!d0kRHXSJV4Q;5d9jab)TK}x?qsk*k50phu1jzPt*sGuQ=x3APX&Hk>E6ug}eJLvX zMP2)w&Gp!}_NB@xvRx$(98sBHmP=AG_^9&(A@K_p;&pDTcW$<>HJ*S zon!T=pL`V7&?ymBE1mL;jJz*k%}c^-G7F&!zLDVKm%>i9e@y&fnKh0&l9s3Rsqoq#p7-|w>fa>8 z{Gcrz9}fOB^$A;+(cdmbXU?6n*M_t}8!D$yAt1~5SKC)@-m>&7TKv8}ve+NF`G8Kg zx`{|9=lZrM{<*sfymdXJ=<<BIp5Khva^?Nb=Q=4`B-W7<2GKQSa^ZUit&xdg`3G zo{G(uT2Jw~?_lj#dB0cesltHm51}GsMQ*p}dKYqd3GNXq>-hCSdesTteR&aX-l9`u zIMW>)tC*4ZPBG=GpgTGgyIoC@>(YPb4dHq6J7#bg3N|u-pXqf0uJGCGJVc5gHoWqL zVFFh<@wuUEwTGd49m55K4Z|usE+x!H)ww&JL3EmPdflpo>xUSwE1v%^&aEH1zsPd0tK=w?JOs>jQ(>8RJ{6KyGY&;3j&lY-Jx?xJnzU4}e-`GY`JX3!KYXBS5fzv2mimSd* zJ@D$%gw7i{gSh^k2i&7cDwY#au2xo0NUnC?qBY--ksM&E?`8g_d#C9`+%~0@`7l1# zTW?R#utLyu0Gw$X9gbBq+a+^Jco6e8Z>G@CDP{EB{4%;rqa00jO|=Ep1K_7%JyLxDBIbc#P|^ zbx!Xy-ZI?pYx>VEP`8*HIpgw{#r_&i)37o0LT!|r!f9Zv1oBryGt)-1YNY5U4F=UR zHA_V809H}<{Ql8w^eOAPYCOQZH$MlT>WPHJ6Gsx8Uz8Fe1lfbT5a`X)vwMXS*pDgX zULUoyFs0z#T0c0$H%^gSNzy*#I>hfF)$nD5=;75k`aY+PH7dsDl}fDfi!2sICVw_ z?ZC5#^<-t`?>pGHOo|Hjv#4EaaNBIJwBdsA&!t!a&Fe_95R)R(rOeIt-g_OEls=t{ z!dqWeCE9Ql*Ie*&7V^#?S31(X+*Ll=z^Blis-P;>(7AI0gi)gc9<(R z4PzLZN72{%DxEO(;o;q1-*znpO3Vr6T7`*yiudT-#34SW%KmFV*FuOp13u&sRv%;g zdR#|d)f#gMPUvYU=yOxIy;iGiS*#J4Wz}6dW(3lo58OSm zl#3phlzG4A%A7pBfm#;MWgei{cLDP9bhu(jjk}TW@S)%@6_mjmPy4&WSsxg1hO9KQ zhdxqt`pX65b+wcfX146R74UfuhDqg~e)grxVX)RO-uHoaTy!~Mlp&w!`>;ZN6T&)f zVig0xoYwkU%RKu!b+ip$?fJFN!-LUKu@cl_eXaL+1TMvGLDh4=HrS_!+bltknn!DvK_OS(^d&*$cEcD9ttTW(e3~$d{2DWL;gT!}R{PFr6+~4TKKPEmzlpNDkxSZU# zX7bbD=)=n?Pj289Wp`8w$VIHZvz?c~fK^I7ETXOR(Y6wF*Tu_>pdlX0__-Lp7vhjP zn9FiOfY)fJk~)MzZk_MKPEMv+&=3e_YZv77z%bBZ~I z(G<=qX9#z#wo=1y+s?+zx9?J0qGFK1KAmk-CR2p*U{j!f>#HoZ82+p&|el4Z9ih3_SWIf5aMAJ=_ zjvRIlBfj>tM=YZ~u4}qsmJcy1^M+y%kJG{Vdr8;67x15?XR+8mytCTCVSe4TVgR%C z_LFuBKrc10VarZfeX+Qq9sS-ECAcVmFJYo&b%h zu7p5mzb_RU6E6&@NnS-#q)E5%u9-D3NS=fX&2}NYq~f9cLZp09x(+HXF1V1%($WJk zp@ABRs!>21d!LiTVP+Coa zuvDY#av=j$tTziyqeDs;@Hs^-d}RLpB!ALARGU}X>`HH^6bBmjd_p;_e0@u^!an{3 z)d?Vr`x3n)c8^I-8P!O%YB)#hwVxI^aWfF23isewOiz4sQ%cm%5iIWfD0z>K=Sd6h z#as9ZfA-yLUvj01epOti7v*DM^JLMcEVgjbeJM)2TlBlce)^Xb4J^Fs2lN|4%fFXo z{w(pnfzAk*rYh+`3)LRGS~5mvGO(jwt)dJDln$QE#IfC1KxuaZV{x2JX$i-C7w9C) z*fE2r24(0vtcHsc9|fYyS{w-T?j#^p@;%nrf#*35zHNaQ=MYR<)6Ljc8m$>fBOZnA zt^y$58X*g-2@K;jw|R>{1Jid1fy*a&KK*WTqKv0a1b=qwh8lApG3Uw?crH5I(bxrz z&KN-RV~m}R0@IyXNveeGYWwU?o17~%z+x3KnQ|~C$ZUlmO>sycqU3z5Kt(tlP?QLw zyeVAIFNm8tfy|oRZx!GbG|!xnn`)oiX@gJ{Cmy4v9^&WuSO>=wz(e*23?;;}nk3;# z<&}7fJQHboGS&ufk$k~^{jDNEzg8$hjfPyS^H!4(p1j5*dULHrlMw4D%Lu&(>C@JqvW%^hWFcTQ+ zEP{narUpUKt6q3;Qi`D<8`g{wR41VX@Wj^b&P@19JkAhGa*KrN#6>IF;gJxiE{5p{ N!4T+Zv}}5C`Uk5gn^*t< literal 0 HcmV?d00001 From c778da4c001c41d709796d4c86cb0114f6f0f8bc Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Thu, 23 Jun 2022 23:54:28 +0200 Subject: [PATCH 297/325] Add functional loading animation via gif that is visible when UiEvent.ShowLoading --- .../hsfl/budgetBinder/compose/Composables.kt | 2 +- .../compose/theme/AppStylesheet.kt | 8 ++++++++ .../src/jsMain/kotlin/main.kt | 18 +++++++++++------- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 3933b6d4..986082b7 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -97,7 +97,7 @@ fun FeedbackSnackbar(msg: String, hidden: Boolean = false, onDismiss: () -> Unit attrs = { when (hidden) { false -> classes("mdc-snackbar", "mdc-snackbar--open") - true -> classes("mdc-snackbar", "maria") + true -> classes("mdc-snackbar") } onClick { onDismiss() diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 972d6c24..9bf57d2b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -125,4 +125,12 @@ object AppStylesheet : StyleSheet() { val marginRight by style { marginRight(1.percent) } + + val loadingImage by style{ + property("z-index",1) + width(20.percent) + position(Position.Fixed) + top(40.percent) + left(40.percent) + } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt index 755d2ca4..6f034c21 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt @@ -5,9 +5,11 @@ import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.di.kodein import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.flow.UiEventSharedFlow +import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerEvent import io.ktor.client.engine.js.* import kotlinx.coroutines.flow.collectLatest -import org.jetbrains.compose.web.css.Style +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.Img import org.jetbrains.compose.web.renderComposable import org.kodein.di.compose.withDI import org.kodein.di.instance @@ -45,14 +47,16 @@ fun App() = withDI(di) { } } } - if (loadingState.value && snackBarHidden.value) { - snackBarText.value = "Loading" - snackBarHidden.value = false - console.log("loading now! ${snackBarHidden.value}") + if (!loadingState.value) { // I don't understand why it needs to be inverted to work? + Img( + src = "images/Loading.gif", alt = "Logo", attrs = { + classes(AppStylesheet.loadingImage) + } + ) } - FeedbackSnackbar(snackBarText.value,snackBarHidden.value) { + + FeedbackSnackbar(snackBarText.value, snackBarHidden.value) { snackBarHidden.value = true - loadingState.value = false } Router() } From 99864dadc515ae1e453dabf08f4f768f2957fb33 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 00:18:09 +0200 Subject: [PATCH 298/325] Move Views and Components from Folder Compose to Screens --- .../compose/CategoryComposables.kt | 81 +++++++++ .../de/hsfl/budgetBinder/compose/Router.kt | 10 +- .../compose/category/CategoryComponent.kt | 158 ------------------ .../screens/category/CategoryComponent.kt | 43 +++++ .../category/CategoryCreateOnRegisterView.kt | 2 +- .../category/CategoryCreateView.kt | 2 +- .../category/CategoryEditView.kt | 2 +- .../category/CategorySummaryView.kt | 2 +- .../dashboard/DashboardComponent.kt | 5 +- .../entry/EntryComponent.kt | 2 +- .../entry/EntryCreateView.kt | 2 +- .../entry/EntryEditView.kt | 2 +- .../entry/EntryOverviewView.kt | 2 +- .../login/LoginComponent.kt | 2 +- .../register/RegisterComponent.kt | 2 +- .../settings/SettingsChangeUserDataView.kt | 2 +- .../settings/SettingsComponent.kt | 2 +- .../settings/SettingsView.kt | 2 +- .../screens/category/CategorySummary.kt | 1 - 19 files changed, 144 insertions(+), 180 deletions(-) create mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt delete mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt create mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/category/CategoryCreateOnRegisterView.kt (95%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/category/CategoryCreateView.kt (99%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/category/CategoryEditView.kt (99%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/category/CategorySummaryView.kt (98%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/dashboard/DashboardComponent.kt (97%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/entry/EntryComponent.kt (98%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/entry/EntryCreateView.kt (99%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/entry/EntryEditView.kt (99%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/entry/EntryOverviewView.kt (98%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/login/LoginComponent.kt (99%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/register/RegisterComponent.kt (99%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/settings/SettingsChangeUserDataView.kt (99%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/settings/SettingsComponent.kt (96%) rename budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/{compose => screens}/settings/SettingsView.kt (98%) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt new file mode 100644 index 00000000..412624b1 --- /dev/null +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt @@ -0,0 +1,81 @@ +package de.hsfl.budgetBinder.compose + +import androidx.compose.runtime.Composable +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.Div +import org.jetbrains.compose.web.dom.H1 +import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.svg.Rect +import org.jetbrains.compose.web.svg.Svg + +@OptIn(ExperimentalComposeWebSvgApi::class) +@Composable +fun BudgetBar( + focusedCategory: Category, + totalSpendBudget: Float, + totalBudget: Float, +) { + //width and height are for aspect ratio - tries to fill out wherever its in, so its more like + val width = 20 + val height = 2 + + H1(attrs = { classes("mdc-typography--headline4", AppStylesheet.flexContainer) }) { + CategoryImageToIcon(focusedCategory.image) + Text("${focusedCategory.name} - Budget") + } + + Div { + if (totalSpendBudget <= totalBudget && totalBudget > 0) { //Normal not Spent Budget + //Money Text + MoneyTextDiv { + Div(attrs = { + classes("mdc-typography--headline5") + }) { Text(totalSpendBudget.toString() + "€") } + Div(attrs = { classes("mdc-typography--headline5") }) { Text(totalBudget.toString() + "€") } + } + Svg(viewBox = "0 0 $width $height") { + Rect(x = 0, y = 0, width = width, height = height, { + attr("fill", Color.lightgray.toString()) + }) + if (0 < totalSpendBudget) // If there is used budget, draw it + Rect(x = 0, y = 0, width = totalSpendBudget/ totalBudget * width, height = height, { + attr("fill", "#" + focusedCategory.color) + }) + } + } else if (totalSpendBudget> totalBudget && totalBudget > 0) { //Over Budget + MoneyTextDiv { + Div(attrs = { classes("mdc-typography--headline5") }) { Text("Budget limit for " + focusedCategory.name + " reached! " + totalSpendBudget.toString() + "€ of " + totalBudget.toString() + "€ Budget spent") } + } + Svg(viewBox = "0 0 $width $height") { + Rect(x = 0, y = 0, width = width, height = height, { + attr("fill", "#b00020") + }) + } + } else if (totalBudget <= 0f) { //No Category View or other unpredictable case (or no categories, overall screen) + MoneyTextDiv { + Div(attrs = { classes("mdc-typography--headline5") }) { Text(totalSpendBudget.toString() + "€ spent") } + } + Svg(viewBox = "0 0 $width $height") { + Rect(x = 0, y = 0, width = width, height = height, { + attr("fill", "#" + focusedCategory.color) + }) + } + } + } +} + +@Composable +fun MoneyTextDiv(content: @Composable () -> Unit) { + Div(attrs = { + style { + display(DisplayStyle.Flex) + justifyContent(JustifyContent("space-between")) + } + }) { + content() + } +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index cc096d5e..0a00fe06 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -3,13 +3,13 @@ package de.hsfl.budgetBinder.compose import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.rememberCoroutineScope -import de.hsfl.budgetBinder.compose.dashboard.DashboardComponent -import de.hsfl.budgetBinder.compose.entry.EntryComponent -import de.hsfl.budgetBinder.compose.login.LoginComponent -import de.hsfl.budgetBinder.compose.register.RegisterComponent -import de.hsfl.budgetBinder.compose.settings.SettingsComponent import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.flow.RouterFlow +import de.hsfl.budgetBinder.screens.dashboard.DashboardComponent +import de.hsfl.budgetBinder.screens.entry.EntryComponent +import de.hsfl.budgetBinder.screens.login.LoginComponent +import de.hsfl.budgetBinder.screens.register.RegisterComponent +import de.hsfl.budgetBinder.screens.settings.SettingsComponent import di import org.jetbrains.compose.web.dom.Text import org.kodein.di.instance diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt deleted file mode 100644 index d58ee0f4..00000000 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryComponent.kt +++ /dev/null @@ -1,158 +0,0 @@ -package de.hsfl.budgetBinder.compose.category - -import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY -import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.viewmodel.category._CategoryViewModel -import di -import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi -import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.dom.* -import org.jetbrains.compose.web.svg.Rect -import org.jetbrains.compose.web.svg.Svg -import org.kodein.di.instance - -@Composable -fun CategoryComponent(screenState: MutableState) { - // Old => CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - // Use rememberCoroutineScope() - val scope = rememberCoroutineScope() - - // Don't do this like here, use Kodein - /* val di = localDI() - val getAllCategoriesUseCase: GetAllCategoriesUseCase by di.instance() - val createCategoryUseCase: CreateCategoryUseCase by di.instance() - val getCategoryByIdUseCase: GetCategoryByIdUseCase by di.instance() - val changeCategoryByIdUseCase: ChangeCategoryByIdUseCase by di.instance() - val deleteCategoryByIdUseCase: DeleteCategoryByIdUseCase by di.instance() - val getAllEntriesByCategoryUseCase: GetAllEntriesByCategoryUseCase by di.instance() - val categoryViewModel = CategoryViewModel(getAllCategoriesUseCase, getCategoryByIdUseCase,createCategoryUseCase, changeCategoryByIdUseCase, deleteCategoryByIdUseCase, getAllEntriesByCategoryUseCase, scope) - val viewState = categoryViewModel.state.collectAsState(scope)*/ - - val viewModel: _CategoryViewModel by di.instance() - val viewState = viewModel.state.collectAsState(scope.coroutineContext) - - when (screenState.value) { - is Screen.CategoryCreate -> CategoryCreateView( - state = viewState, - onCreateCategoryButtonPressed = { name, color, image, budget -> - viewModel.createCategory(Category.In(name, color.drop(1), image, budget)) - screenState.value = Screen.CategorySummary }, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) - is Screen.CategorySummary -> { - CategorySummaryView( - state = viewState, - onCategoryCreateButton = { screenState.value = Screen.CategoryCreate }, - onEditButton = { id -> screenState.value = Screen.Category.Edit(id) }, - onDeleteButton = { id -> viewModel.removeCategory(id) }, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) - viewModel.getAllCategories() - } - is Screen.CategoryEdit -> { - CategoryEditView( - state = viewState, - onEditCategoryButtonPressed = { name, color, image, budget -> - viewModel.changeCategory( - Category.Patch(name, color.drop(1), image, budget), - (screenState.value as Screen.CategoryEdit).id - ); screenState.value = Screen.CategorySummary }, - onChangeToDashboard = { screenState.value = Screen.Dashboard }, - onChangeToSettings = { screenState.value = Screen._Settings }, - onChangeToCategory = { screenState.value = Screen.CategorySummary }, - ) - viewModel.getCategoryById((screenState.value as Screen.CategoryEdit).id) - } - is Screen.CategoryCreateOnRegister -> CategoryCreateOnRegisterView( - state = viewState, - onFinishedButton = { - screenState.value = Screen.Dashboard - } //Should go back to the previous Screen, which could be CategorySummary or EntryCreate. - ) - else -> {} - } -} - -fun categoryIdToCategory(category_id: Int?, categoryList: List): Category { - for (category in categoryList) { - if (category.id == category_id) return category - } - return DEFAULT_CATEGORY //If the category wasn't found (or is set to no category) return default -} - -@OptIn(ExperimentalComposeWebSvgApi::class) -@Composable -fun BudgetBar( - focusedCategory: Category, - totalSpendBudget: Float, - totalBudget: Float, -) { - //width and height are for aspect ratio - tries to fill out wherever its in, so its more like - val width = 20 - val height = 2 - - H1(attrs = { classes("mdc-typography--headline4", AppStylesheet.flexContainer) }) { - CategoryImageToIcon(focusedCategory.image) - Text("${focusedCategory.name} - Budget") - } - - Div { - if (totalSpendBudget <= totalBudget && totalBudget > 0) { //Normal not Spent Budget - //Money Text - MoneyTextDiv { - Div(attrs = { - classes("mdc-typography--headline5") - }) { Text(totalSpendBudget.toString() + "€") } - Div(attrs = { classes("mdc-typography--headline5") }) { Text(totalBudget.toString() + "€") } - } - Svg(viewBox = "0 0 $width $height") { - Rect(x = 0, y = 0, width = width, height = height, { - attr("fill", Color.lightgray.toString()) - }) - if (0 < totalSpendBudget) // If there is used budget, draw it - Rect(x = 0, y = 0, width = totalSpendBudget/ totalBudget * width, height = height, { - attr("fill", "#" + focusedCategory.color) - }) - } - } else if (totalSpendBudget> totalBudget && totalBudget > 0) { //Over Budget - MoneyTextDiv { - Div(attrs = { classes("mdc-typography--headline5") }) { Text("Budget limit for " + focusedCategory.name + " reached! " + totalSpendBudget.toString() + "€ of " + totalBudget.toString() + "€ Budget spent") } - } - Svg(viewBox = "0 0 $width $height") { - Rect(x = 0, y = 0, width = width, height = height, { - attr("fill", "#b00020") - }) - } - } else if (totalBudget <= 0f) { //No Category View or other unpredictable case (or no categories, overall screen) - MoneyTextDiv { - Div(attrs = { classes("mdc-typography--headline5") }) { Text(totalSpendBudget.toString() + "€ spent") } - } - Svg(viewBox = "0 0 $width $height") { - Rect(x = 0, y = 0, width = width, height = height, { - attr("fill", "#" + focusedCategory.color) - }) - } - } - } -} - -@Composable -fun MoneyTextDiv(content: @Composable () -> Unit) { - Div(attrs = { - style { - display(DisplayStyle.Flex) - justifyContent(JustifyContent("space-between")) - } - }) { - content() - } -} - diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt new file mode 100644 index 00000000..6ebdf3e2 --- /dev/null +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt @@ -0,0 +1,43 @@ +package de.hsfl.budgetBinder.screens.category + +import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY +import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon +import de.hsfl.budgetBinder.presentation.Screen +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent +import de.hsfl.budgetBinder.presentation.event.UiEvent +import de.hsfl.budgetBinder.presentation.flow.RouterFlow +import de.hsfl.budgetBinder.presentation.viewmodel.category.CategoryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent +import di +import kotlinx.coroutines.flow.collectLatest +import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* +import org.jetbrains.compose.web.svg.Rect +import org.jetbrains.compose.web.svg.Svg +import org.kodein.di.instance + +@Composable +fun CategoryComponent() { + val viewModel: CategoryViewModel by di.instance() + val routerFlow: RouterFlow by di.instance() + /*when (routerFlow.state.value) { + is Screen.Category.Summary -> CategorySummaryView() + is Screen.Category.Detail -> CategoryDetailView() + is Screen.Category.Edit -> CategoryEditView() + is Screen.Category.Create -> CategoryCreateView() + }*/ +} + +fun categoryIdToCategory(category_id: Int?, categoryList: List): Category { + for (category in categoryList) { + if (category.id == category_id) return category + } + return DEFAULT_CATEGORY //If the category wasn't found (or is set to no category) return default +} + + + diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateOnRegisterView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateOnRegisterView.kt similarity index 95% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateOnRegisterView.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateOnRegisterView.kt index 0101d41b..83ad2004 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateOnRegisterView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateOnRegisterView.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.category +package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.presentation.UiState diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt similarity index 99% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt index 06af894f..2b89ec58 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.category +package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt similarity index 99% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt index 900dda55..1be11093 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.category +package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt similarity index 98% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt index af48f680..8c563a31 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.category +package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/dashboard/DashboardComponent.kt similarity index 97% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/dashboard/DashboardComponent.kt index f7e84beb..dad3891f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/dashboard/DashboardComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/dashboard/DashboardComponent.kt @@ -1,16 +1,15 @@ -package de.hsfl.budgetBinder.compose.dashboard +package de.hsfl.budgetBinder.screens.dashboard import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category +import de.hsfl.budgetBinder.compose.BudgetBar import de.hsfl.budgetBinder.compose.Icon import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.NavBar -import de.hsfl.budgetBinder.compose.category.BudgetBar import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.event.UiEvent -import de.hsfl.budgetBinder.presentation.viewmodel.auth.register.RegisterEvent import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEntryState import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEvent import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardState diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryComponent.kt similarity index 98% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryComponent.kt index cfcdde7a..8d6f4cc0 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryComponent.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.entry +package de.hsfl.budgetBinder.screens.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.MainFlexContainer diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt similarity index 99% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt index 35b5b127..e58793b5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.entry +package de.hsfl.budgetBinder.screens.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.* diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt similarity index 99% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt index f6650dce..adb6a897 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.entry +package de.hsfl.budgetBinder.screens.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.ChooseCategoryMenu diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt similarity index 98% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt index 30b7db48..2a44902b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.entry +package de.hsfl.budgetBinder.screens.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Entry diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/login/LoginComponent.kt similarity index 99% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/login/LoginComponent.kt index 6be6620e..15b52831 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/login/LoginComponent.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.login +package de.hsfl.budgetBinder.screens.login import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.MainFlexContainer diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/register/RegisterComponent.kt similarity index 99% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/register/RegisterComponent.kt index 5b2283ff..25654c44 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/register/RegisterComponent.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.register +package de.hsfl.budgetBinder.screens.register import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.FeedbackSnackbar diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsChangeUserDataView.kt similarity index 99% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsChangeUserDataView.kt index 479d67f9..2f309d01 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsChangeUserDataView.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.settings +package de.hsfl.budgetBinder.screens.settings import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.FeedbackSnackbar diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsComponent.kt similarity index 96% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsComponent.kt index 8e926a9c..bfde94f5 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsComponent.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.settings +package de.hsfl.budgetBinder.screens.settings import androidx.compose.runtime.* import de.hsfl.budgetBinder.presentation.Screen diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt similarity index 98% rename from budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt rename to budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt index 325f3af4..3edccf32 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt @@ -1,4 +1,4 @@ -package de.hsfl.budgetBinder.compose.settings +package de.hsfl.budgetBinder.screens.settings import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.DeleteDialog diff --git a/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummary.kt b/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummary.kt index fd642ee8..17810cf3 100644 --- a/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummary.kt +++ b/budget-binder-multiplatform-app/src/jvmMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummary.kt @@ -17,7 +17,6 @@ import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.di import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.event.UiEvent From 0866b1d211559f828a343049f64ab13c147f2189 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 00:43:47 +0200 Subject: [PATCH 299/325] Update CategorySummary in preparation for CategoryDetailView --- .../compose/CategoryComposables.kt | 145 +++++++++++++++++- .../hsfl/budgetBinder/compose/Composables.kt | 88 ----------- .../screens/category/CategoryComponent.kt | 8 +- .../screens/category/CategorySummaryView.kt | 107 +++---------- 4 files changed, 167 insertions(+), 181 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt index 412624b1..acba7c56 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt @@ -1,14 +1,16 @@ package de.hsfl.budgetBinder.compose -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.Button import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.H1 import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.svg.Circle import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg @@ -79,3 +81,144 @@ fun MoneyTextDiv(content: @Composable () -> Unit) { content() } } + +@OptIn(ExperimentalComposeWebSvgApi::class) +@Composable +fun CategoryList( + categoryList: List, + onClicked: (Int) -> Unit, +) { + Div { + for (category in categoryList) + categoryElement(category, onClicked = onClicked(category.id)) + } +} + +@OptIn(ExperimentalComposeWebSvgApi::class) +@Composable +fun categoryElement(category: Category, onClicked: Unit){ + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + onClick { onClicked } + } + ) { + Div( + attrs = { + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) + } + ) { + Div( + attrs = { + classes(AppStylesheet.imageFlexContainer) + } + ) { + CategoryImageToIcon(category.image) + } + Div( + attrs = { + classes(AppStylesheet.categoryListElementText) + } + ) { + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(category.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Budget: ${category.budget}€") } + } + } + Div(attrs = { + classes(AppStylesheet.imageFlexContainer) + } + ) { + Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in + Circle(cx = 0.5, cy = 0.5, r = 0.5, { + attr("fill", "#${category.color}") + }) + } + } + } + } +} +@OptIn(ExperimentalComposeWebSvgApi::class) +@Composable +fun categoryDetailed(category: Category, onEditButton: (id:Int) -> Unit, onDeleteButton:(id:Int) -> Unit){ + var deleteDialog by remember { mutableStateOf(false) } + var id by remember { mutableStateOf(0) } + Div(attrs = { + classes("mdc-card", AppStylesheet.card) + } + ) { + if (deleteDialog) { + DeleteDialog( + false, + { onDeleteButton(id) }, + { deleteDialog = false }) { Text("Delete Category?") } + } + Div( + attrs = { + classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) + } + ) { + Div( + attrs = { + classes(AppStylesheet.imageFlexContainer) + } + ) { + CategoryImageToIcon(category.image) + } + Div( + attrs = { + classes(AppStylesheet.categoryListElementText) + } + ) { + Div { + Div(attrs = { + classes("mdc-typography--headline4", AppStylesheet.text) + }) { Text(category.name) } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text) + }) { Text("Budget: ${category.budget}€") } + } + } + Div(attrs = { + classes(AppStylesheet.imageFlexContainer) + } + ) { + Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in + Circle(cx = 0.5, cy = 0.5, r = 0.5, { + attr("fill", "#${category.color}") + }) + } + } + } + Div( + attrs = { + classes(AppStylesheet.flexContainer) + } + ) { + Button(attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + onClick { onEditButton?.let { it1 -> it1(category.id) } } + style { + flex(50.percent) + margin(1.5.percent) + } + }) { + Text("Edit Category") + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { deleteDialog = !deleteDialog; id = category.id } + style { + flex(50.percent) + margin(1.5.percent) + backgroundColor(Color("#b00020")) + } + }) { + Text("Delete Category") + } + } + } +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 986082b7..3213b255 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -180,95 +180,7 @@ fun CategoryImagesToImageList( } } -@OptIn(ExperimentalComposeWebSvgApi::class) -@Composable -fun CategoryList( - categoryList: List, - onEditButton: (Int) -> Unit, - onDeleteButton: (Int) -> Unit -) { - var deleteDialog by remember { mutableStateOf(false) } - var id by remember { mutableStateOf(0) } - Div { - if (deleteDialog) { - DeleteDialog( - false, - { onDeleteButton(id) }, - { deleteDialog = false }) { Text("Delete Category?") } - } - for (category in categoryList) - Div(attrs = { - classes("mdc-card", AppStylesheet.card) - } - ) { - Div( - attrs = { - classes(AppStylesheet.categoryListElement, AppStylesheet.flexContainer) - } - ) { - Div( - attrs = { - classes(AppStylesheet.imageFlexContainer) - } - ) { - CategoryImageToIcon(category.image) - } - Div( - attrs = { - classes(AppStylesheet.categoryListElementText) - } - ) { - Div { - Div(attrs = { - classes("mdc-typography--headline4", AppStylesheet.text) - }) { Text(category.name) } - Div(attrs = { - classes("mdc-typography--headline6", AppStylesheet.text) - }) { Text("Budget: ${category.budget}€") } - } - } - Div(attrs = { - classes(AppStylesheet.imageFlexContainer) - } - ) { - Svg(viewBox = "0 0 1 1") {//For aspect ratio - tries to fill out wherever it is in - Circle(cx = 0.5, cy = 0.5, r = 0.5, { - attr("fill", "#${category.color}") - }) - } - } - } - Div( - attrs = { - classes(AppStylesheet.flexContainer) - } - ) { - Button(attrs = { - classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton(category.id) } - style { - flex(50.percent) - margin(1.5.percent) - } - }) { - Text("Edit Category") - } - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { deleteDialog = !deleteDialog; id = category.id } - style { - flex(50.percent) - margin(1.5.percent) - backgroundColor(Color("#b00020")) - } - }) { - Text("Delete Category") - } - } - } - } -} @Composable fun DeleteDialog( diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt index 6ebdf3e2..f5a5fb60 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt @@ -22,14 +22,14 @@ import org.kodein.di.instance @Composable fun CategoryComponent() { - val viewModel: CategoryViewModel by di.instance() val routerFlow: RouterFlow by di.instance() - /*when (routerFlow.state.value) { + when (routerFlow.state.value) { is Screen.Category.Summary -> CategorySummaryView() - is Screen.Category.Detail -> CategoryDetailView() + //is Screen.Category.Detail -> CategoryDetailView() is Screen.Category.Edit -> CategoryEditView() is Screen.Category.Create -> CategoryCreateView() - }*/ + else -> {} + } } fun categoryIdToCategory(category_id: Int?, categoryList: List): Category { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt index 8c563a31..7e587f23 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt @@ -1,105 +1,36 @@ package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.CategoryList -import de.hsfl.budgetBinder.compose.MainFlexContainer -import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.viewmodel.category.summary.CategorySummaryEvent +import de.hsfl.budgetBinder.presentation.viewmodel.category.summary.CategorySummaryViewModel +import di import org.jetbrains.compose.web.css.margin import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* +import org.kodein.di.instance @Composable fun CategorySummaryView( - state: State, - onCategoryCreateButton: () -> Unit, - onEditButton: (id: Int) -> Unit, - onDeleteButton: (id: Int) -> Unit, - onChangeToDashboard: () -> Unit, - onChangeToCategory: () -> Unit, - onChangeToSettings: () -> Unit ) { - var categoryList by remember { mutableStateOf>(emptyList()) } - val viewState by remember { state } + val viewModel: CategorySummaryViewModel by di.instance() + val categoryList by viewModel.categoryList.collectAsState() - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { - Span( - attrs = { - classes("mdc-button__label") - } - ) { - Text("Settings") - } - } - }) - - MainFlexContainer { - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Category Summary") } - Button(attrs = { - classes("mdc-button", "mdc-button--raised") - onClick { onCategoryCreateButton() } + H1( + attrs = { style { margin(2.percent) } - }) { - Text("Create Category") - } - CategoryList(categoryList, {id -> onEditButton(id)}, {id -> onDeleteButton(id)}) - - Div { - when (viewState) { - is UiState.Success<*> -> { - when (val element = (viewState as UiState.Success<*>).element) { - is List<*> -> { - element.filterIsInstance() - .let { - if (it.size == element.size) { - categoryList = it - } - } - } - } - } - is UiState.Error -> { - Text((viewState as UiState.Error).error) - } - is UiState.Loading -> { - //CircularProgressIndicator() - } - } } + ) { Text(" Category Summary") } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") + onClick { viewModel.onEvent(CategorySummaryEvent.OnCategoryCreate) } + style { margin(2.percent) } + }) { + Text("Create Category") } + CategoryList( + categoryList + ) { id -> viewModel.onEvent(CategorySummaryEvent.OnCategory(id)) } } + From b5d456dea12ba70f7dc964cecb0e7c5bbcebea54 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 01:10:19 +0200 Subject: [PATCH 300/325] Fix CategorySummary to work properly and add CategoryDetailView (not working 100%) --- .../compose/CategoryComposables.kt | 15 ++++---- .../de/hsfl/budgetBinder/compose/Router.kt | 3 +- .../screens/category/CategoryComponent.kt | 26 ++++++------- .../screens/category/CategoryDetailView.kt | 38 +++++++++++++++++++ .../screens/category/CategorySummaryView.kt | 10 +++++ 5 files changed, 69 insertions(+), 23 deletions(-) create mode 100644 budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt index acba7c56..e49143ef 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt @@ -90,16 +90,16 @@ fun CategoryList( ) { Div { for (category in categoryList) - categoryElement(category, onClicked = onClicked(category.id)) + CategoryElement(category, onClicked = onClicked) } } @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun categoryElement(category: Category, onClicked: Unit){ +fun CategoryElement(category: Category, onClicked: (Int) -> Unit){ Div(attrs = { classes("mdc-card", AppStylesheet.card) - onClick { onClicked } + onClick { onClicked(category.id) } } ) { Div( @@ -143,9 +143,8 @@ fun categoryElement(category: Category, onClicked: Unit){ } @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun categoryDetailed(category: Category, onEditButton: (id:Int) -> Unit, onDeleteButton:(id:Int) -> Unit){ +fun CategoryDetailed(category: Category, onEditButton: () -> Unit, onDeleteButton:() -> Unit){ var deleteDialog by remember { mutableStateOf(false) } - var id by remember { mutableStateOf(0) } Div(attrs = { classes("mdc-card", AppStylesheet.card) } @@ -153,7 +152,7 @@ fun categoryDetailed(category: Category, onEditButton: (id:Int) -> Unit, onDelet if (deleteDialog) { DeleteDialog( false, - { onDeleteButton(id) }, + { onDeleteButton() }, { deleteDialog = false }) { Text("Delete Category?") } } Div( @@ -200,7 +199,7 @@ fun categoryDetailed(category: Category, onEditButton: (id:Int) -> Unit, onDelet ) { Button(attrs = { classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) - onClick { onEditButton?.let { it1 -> it1(category.id) } } + onClick { onEditButton() } style { flex(50.percent) margin(1.5.percent) @@ -210,7 +209,7 @@ fun categoryDetailed(category: Category, onEditButton: (id:Int) -> Unit, onDelet } Button(attrs = { classes("mdc-button", "mdc-button--raised") - onClick { deleteDialog = !deleteDialog; id = category.id } + onClick { deleteDialog = !deleteDialog } style { flex(50.percent) margin(1.5.percent) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 0a00fe06..efc79a44 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.rememberCoroutineScope import de.hsfl.budgetBinder.presentation.Screen import de.hsfl.budgetBinder.presentation.flow.RouterFlow +import de.hsfl.budgetBinder.screens.category.CategoryComponent import de.hsfl.budgetBinder.screens.dashboard.DashboardComponent import de.hsfl.budgetBinder.screens.entry.EntryComponent import de.hsfl.budgetBinder.screens.login.LoginComponent @@ -27,11 +28,11 @@ fun Router() { is Screen.Dashboard -> DashboardComponent() is Screen.Settings -> SettingsComponent() is Screen.Entry -> EntryComponent() + is Screen.Category -> CategoryComponent() is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> Text("Old Category") //CategoryComponent(screenState = screenState) is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview -> Text("Old Entry")//EntryComponent(screenState = screenState) - is Screen.Category -> Text("New Category") else -> { Text("No known Screen! Check if the screen you're trying to reach is in the ScreenRouter") } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt index f5a5fb60..ff0c0c6f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt @@ -3,6 +3,8 @@ package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY +import de.hsfl.budgetBinder.compose.MainFlexContainer +import de.hsfl.budgetBinder.compose.NavBar import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen @@ -23,21 +25,17 @@ import org.kodein.di.instance @Composable fun CategoryComponent() { val routerFlow: RouterFlow by di.instance() - when (routerFlow.state.value) { - is Screen.Category.Summary -> CategorySummaryView() - //is Screen.Category.Detail -> CategoryDetailView() - is Screen.Category.Edit -> CategoryEditView() - is Screen.Category.Create -> CategoryCreateView() - else -> {} + //Webpage content + NavBar {} + MainFlexContainer { + when (routerFlow.state.value) { + is Screen.Category.Summary -> CategorySummaryView() + is Screen.Category.Detail -> CategoryDetailView() + //is Screen.Category.Edit -> CategoryEditView() + //is Screen.Category.Create -> CategoryCreateView() + else -> {} + } } } -fun categoryIdToCategory(category_id: Int?, categoryList: List): Category { - for (category in categoryList) { - if (category.id == category_id) return category - } - return DEFAULT_CATEGORY //If the category wasn't found (or is set to no category) return default -} - - diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt new file mode 100644 index 00000000..af619af6 --- /dev/null +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt @@ -0,0 +1,38 @@ +package de.hsfl.budgetBinder.screens.category + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import de.hsfl.budgetBinder.compose.CategoryDetailed +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent +import de.hsfl.budgetBinder.presentation.viewmodel.category.detail.CategoryDetailEvent +import de.hsfl.budgetBinder.presentation.viewmodel.category.detail.CategoryDetailViewModel +import di +import org.jetbrains.compose.web.css.margin +import org.jetbrains.compose.web.css.percent +import org.jetbrains.compose.web.dom.H1 +import org.jetbrains.compose.web.dom.Text +import org.kodein.di.instance + +@Composable +fun CategoryDetailView() { + val viewModel: CategoryDetailViewModel by di.instance() + val category by viewModel.categoryState.collectAsState() + + //LifeCycle + LaunchedEffect(key1 = true) { + viewModel.onEvent(CategoryDetailEvent.LifeCycle(LifecycleEvent.OnLaunch)) + } + + //Webpage Content + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text(" Category Detailed") } //TODO: Put these in a "Title" Composable + CategoryDetailed( + category, {viewModel.onEvent(CategoryDetailEvent.OnEdit) }, { viewModel.onEvent(CategoryDetailEvent.OnDelete) } + ) + +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt index 7e587f23..38381531 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt @@ -2,9 +2,13 @@ package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.CategoryList +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent +import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.summary.CategorySummaryEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.summary.CategorySummaryViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEvent import di +import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.margin import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.* @@ -17,6 +21,12 @@ fun CategorySummaryView( val viewModel: CategorySummaryViewModel by di.instance() val categoryList by viewModel.categoryList.collectAsState() + //LifeCycle + LaunchedEffect(key1 = true) { + viewModel.onEvent(CategorySummaryEvent.LifeCycle(LifecycleEvent.OnLaunch)) + } + + //Webpage Content H1( attrs = { style { margin(2.percent) } From cfea1cf278543db72129bbcafb2bfc488cbd82f5 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 01:36:35 +0200 Subject: [PATCH 301/325] Add CategoryDetailView, which holds the features CategorySummary previously had --- .../de/hsfl/budgetBinder/common/Constants.kt | 3 +- .../compose/CategoryComposables.kt | 48 +++++++++++++------ .../de/hsfl/budgetBinder/compose/Router.kt | 2 + .../screens/category/CategoryComponent.kt | 16 +------ .../screens/category/CategoryDetailView.kt | 6 ++- .../screens/category/CategorySummaryView.kt | 2 + 6 files changed, 46 insertions(+), 31 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/common/Constants.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/common/Constants.kt index 832ff56f..f49b4ef7 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/common/Constants.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/common/Constants.kt @@ -5,5 +5,4 @@ actual object Constants { //Set to nothing because it hosts itself (so we don't have to deal with CORS) //for local server: http://localhost:8080 //for online server: https://bb-server.fpcloud.de - val DEFAULT_CATEGORY = (Category(0, "", "FFFFFF", Category.Image.DEFAULT, 0f)) -} \ No newline at end of file +} diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt index e49143ef..e846d912 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt @@ -6,10 +6,7 @@ import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.dom.Button -import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H1 -import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.svg.Circle import org.jetbrains.compose.web.svg.Rect import org.jetbrains.compose.web.svg.Svg @@ -44,11 +41,16 @@ fun BudgetBar( attr("fill", Color.lightgray.toString()) }) if (0 < totalSpendBudget) // If there is used budget, draw it - Rect(x = 0, y = 0, width = totalSpendBudget/ totalBudget * width, height = height, { - attr("fill", "#" + focusedCategory.color) - }) - } - } else if (totalSpendBudget> totalBudget && totalBudget > 0) { //Over Budget + Rect( + x = 0, + y = 0, + width = totalSpendBudget / totalBudget * width, + height = height, + { + attr("fill", "#" + focusedCategory.color) + }) + } + } else if (totalSpendBudget > totalBudget && totalBudget > 0) { //Over Budget MoneyTextDiv { Div(attrs = { classes("mdc-typography--headline5") }) { Text("Budget limit for " + focusedCategory.name + " reached! " + totalSpendBudget.toString() + "€ of " + totalBudget.toString() + "€ Budget spent") } } @@ -96,7 +98,7 @@ fun CategoryList( @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun CategoryElement(category: Category, onClicked: (Int) -> Unit){ +fun CategoryElement(category: Category, onClicked: (Int) -> Unit) { Div(attrs = { classes("mdc-card", AppStylesheet.card) onClick { onClicked(category.id) } @@ -141,9 +143,15 @@ fun CategoryElement(category: Category, onClicked: (Int) -> Unit){ } } } + @OptIn(ExperimentalComposeWebSvgApi::class) @Composable -fun CategoryDetailed(category: Category, onEditButton: () -> Unit, onDeleteButton:() -> Unit){ +fun CategoryDetailed( + category: Category, + onEditButton: () -> Unit, + onDeleteButton: () -> Unit, + onBackButton: () -> Unit +) { var deleteDialog by remember { mutableStateOf(false) } Div(attrs = { classes("mdc-card", AppStylesheet.card) @@ -198,10 +206,22 @@ fun CategoryDetailed(category: Category, onEditButton: () -> Unit, onDeleteButto } ) { Button(attrs = { - classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + classes("mdc-button", "mdc-button--raised") + onClick { onBackButton() } + style { + flex(33.percent) + margin(1.5.percent) + } + } + ) { + Span(attrs = { classes("mdc-button__label") } + ) { Text("Cancel") } + } + Button(attrs = { + classes("mdc-button", "mdc-button--raised") onClick { onEditButton() } style { - flex(50.percent) + flex(33.percent) margin(1.5.percent) } }) { @@ -211,7 +231,7 @@ fun CategoryDetailed(category: Category, onEditButton: () -> Unit, onDeleteButto classes("mdc-button", "mdc-button--raised") onClick { deleteDialog = !deleteDialog } style { - flex(50.percent) + flex(33.percent) margin(1.5.percent) backgroundColor(Color("#b00020")) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index efc79a44..0e559c84 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -20,6 +20,7 @@ fun Router() { val scope = rememberCoroutineScope() val routerFlow: RouterFlow by di.instance() val screenState = routerFlow.state.collectAsState(scope.coroutineContext) + console.log("Router Screen is:") console.log(screenState.value) when (screenState.value) { is Screen.Welcome -> {} @@ -28,6 +29,7 @@ fun Router() { is Screen.Dashboard -> DashboardComponent() is Screen.Settings -> SettingsComponent() is Screen.Entry -> EntryComponent() + is Screen.Category.Detail -> CategoryComponent() //To avoid weird bug where it doesn't refresh itself? I don't understand either ... is Screen.Category -> CategoryComponent() is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> Text("Old Category") //CategoryComponent(screenState = screenState) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt index ff0c0c6f..0de6d3ee 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt @@ -1,30 +1,18 @@ package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category -import de.hsfl.budgetBinder.common.Constants.DEFAULT_CATEGORY import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.NavBar -import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.Screen -import de.hsfl.budgetBinder.presentation.event.LifecycleEvent -import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.flow.RouterFlow -import de.hsfl.budgetBinder.presentation.viewmodel.category.CategoryViewModel -import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import di -import kotlinx.coroutines.flow.collectLatest -import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi -import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.dom.* -import org.jetbrains.compose.web.svg.Rect -import org.jetbrains.compose.web.svg.Svg import org.kodein.di.instance @Composable fun CategoryComponent() { + val routerFlow: RouterFlow by di.instance() + //Webpage content NavBar {} MainFlexContainer { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt index af619af6..32329656 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt @@ -23,6 +23,7 @@ fun CategoryDetailView() { //LifeCycle LaunchedEffect(key1 = true) { viewModel.onEvent(CategoryDetailEvent.LifeCycle(LifecycleEvent.OnLaunch)) + console.log("AAAAAAAAAAAAAAAAAAAAAA Category Detail") } //Webpage Content @@ -32,7 +33,10 @@ fun CategoryDetailView() { } ) { Text(" Category Detailed") } //TODO: Put these in a "Title" Composable CategoryDetailed( - category, {viewModel.onEvent(CategoryDetailEvent.OnEdit) }, { viewModel.onEvent(CategoryDetailEvent.OnDelete) } + category, + { viewModel.onEvent(CategoryDetailEvent.OnEdit) }, + { viewModel.onEvent(CategoryDetailEvent.OnDelete) }, + { viewModel.onEvent(CategoryDetailEvent.OnBack) } ) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt index 38381531..1527f553 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt @@ -24,6 +24,8 @@ fun CategorySummaryView( //LifeCycle LaunchedEffect(key1 = true) { viewModel.onEvent(CategorySummaryEvent.LifeCycle(LifecycleEvent.OnLaunch)) + viewModel.eventFlow.collectLatest {} + console.log("CategorySummary Came to Life!") } //Webpage Content From 3d7736556423b1cf42dc57d44b57d876c460fe75 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 02:05:21 +0200 Subject: [PATCH 302/325] Update CategoryEditView with new ViewModel --- .../hsfl/budgetBinder/compose/Composables.kt | 8 +- .../screens/category/CategoryComponent.kt | 2 +- .../screens/category/CategoryCreateView.kt | 2 +- .../screens/category/CategoryEditView.kt | 339 ++++++++---------- 4 files changed, 147 insertions(+), 204 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 3213b255..7a7658d3 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -137,10 +137,10 @@ fun FeedbackSnackbar(msg: String, hidden: Boolean = false, onDismiss: () -> Unit @Composable fun CategoryImagesToImageList( - inputImage: MutableState, + inputImage: Category.Image, onClick: (Category.Image) -> Unit ) { - val highlightImage by remember { mutableStateOf(inputImage) } + var highlightImage by remember { mutableStateOf(inputImage) } Div( attrs = { classes("mdc-card", AppStylesheet.card) @@ -159,7 +159,7 @@ fun CategoryImagesToImageList( ) { Div( attrs = { - if (highlightImage.value == image) + if (highlightImage == image) classes( "mdc-image-list__image-aspect-container", "mdc-icon-button", @@ -169,7 +169,7 @@ fun CategoryImagesToImageList( "mdc-image-list__image-aspect-container", "mdc-icon-button" ) - onClick { onClick(image); highlightImage.value = image } + onClick { onClick(image); highlightImage = image } } ) { CategoryImageToIcon(image) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt index 0de6d3ee..46b8b133 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt @@ -19,7 +19,7 @@ fun CategoryComponent() { when (routerFlow.state.value) { is Screen.Category.Summary -> CategorySummaryView() is Screen.Category.Detail -> CategoryDetailView() - //is Screen.Category.Edit -> CategoryEditView() + is Screen.Category.Edit -> CategoryEditView() //is Screen.Category.Create -> CategoryCreateView() else -> {} } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt index 2b89ec58..cc1aab89 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt @@ -181,7 +181,7 @@ fun CategoryCreateView( style { marginBottom(1.percent); marginLeft(2.percent) } } ) { Text("Image") } - CategoryImagesToImageList(categoryImageState, onClick = { categoryImageState.value = it }) + CategoryImagesToImageList(categoryImageState.value, onClick = { categoryImageState.value = it }) } } //Category Budget Input diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt index 1be11093..0191d4c8 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt @@ -7,255 +7,198 @@ import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent +import de.hsfl.budgetBinder.presentation.viewmodel.category.edit.CategoryEditEvent +import de.hsfl.budgetBinder.presentation.viewmodel.category.edit.CategoryEditViewModel +import di import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.min import org.jetbrains.compose.web.attributes.required import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* +import org.kodein.di.instance @Composable -fun CategoryEditView( - state: State, - onEditCategoryButtonPressed: (name: String, color: String, image: Category.Image, budget: Float) -> Unit, - onChangeToDashboard: () -> Unit, - onChangeToCategory: () -> Unit, - onChangeToSettings: () -> Unit -) { - var category by remember { mutableStateOf(Category(0, "", "", Category.Image.DEFAULT, 0f)) } - var categoryNameTextFieldState by remember { mutableStateOf("") } - var categoryColorTextFieldState by remember { mutableStateOf("") } - var categoryImageState = remember { mutableStateOf(Category.Image.DEFAULT) } - var categoryBudgetTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } +fun CategoryEditView() { + val viewModel: CategoryEditViewModel by di.instance() + val categoryNameState by viewModel.categoryNameState.collectAsState() + val categoryColorState by viewModel.categoryColorState.collectAsState() + val categoryImageState by viewModel.categoryImageState.collectAsState() + val categoryBudgetState by viewModel.categoryBudgetState.collectAsState() - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( + //Life Cycle + LaunchedEffect(Unit) { + viewModel.onEvent(CategoryEditEvent.LifeCycle(LifecycleEvent.OnLaunch)) + } + DisposableEffect(Unit) { + onDispose { + viewModel.onEvent(CategoryEditEvent.LifeCycle(LifecycleEvent.OnDispose)) + } + } + + //Webpage Content + H1(attrs = { style { margin(2.percent) } }) { Text("Edit Category") } + + Form(attrs = { + this.addEventListener("submit") { + viewModel.onEvent(CategoryEditEvent.OnSave) + it.preventDefault() + } + } + ) { + //Category Name Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { Span( attrs = { - classes("mdc-button__label") + classes("mdc-text-field__ripple") } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { + ) { } Span( attrs = { - classes("mdc-button__label") + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Category Name") } + Input( + type = InputType.Text ) { - Text("Settings") + classes("mdc-text-field__input") + value(categoryNameState) + required(true) + onInput { + viewModel.onEvent(CategoryEditEvent.EnteredCategoryName(it.value)) + } } - } - }) - - MainFlexContainer { - H1(attrs = { style { margin(2.percent) } }) { Text("Edit Category") } - - Form(attrs = { - this.addEventListener("submit") { - console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") - onEditCategoryButtonPressed( - categoryNameTextFieldState, - categoryColorTextFieldState, - categoryImageState.value, - categoryBudgetTextFieldState.toFloat() - ) - it.preventDefault() + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } } + //Category Color Input + Div( + attrs = { + classes(AppStylesheet.margin) + } ) { - //Category Name Input - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Category Name") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(categoryNameTextFieldState) - required(true) - onInput { - categoryNameTextFieldState = it.value - } + classes("mdc-text-field__ripple") } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - //Category Color Input - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } } + ) { Text("Color") } + Input( + type = InputType.Color ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } - } - ) { Text("Color") } - Input( - type = InputType.Color - ) { - classes("mdc-text-field__input") - value(categoryColorTextFieldState) - onInput { - categoryColorTextFieldState = it.value - } + classes("mdc-text-field__input") + value("#$categoryColorState") + onInput { + viewModel.onEvent(CategoryEditEvent.EnteredCategoryColor(it.value.drop(1))) } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - //Category Image Input - Div( - attrs = { - classes(AppStylesheet.margin) } - ) { - Label( + Span( attrs = { - style { width(100.percent) } + classes("mdc-line-ripple") } - ) { - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent); marginLeft(2.percent) } - } - ) { Text("Image") } - CategoryImagesToImageList(categoryImageState, onClick = { categoryImageState.value = it }) - } + ) { } } - //Category Budget Input - Div( + } + //Category Image Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent) } } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Budget") } - Input( - type = InputType.Number - ) { - classes("mdc-text-field__input") - value(categoryBudgetTextFieldState) - required(true) - min("1") - onInput { - categoryBudgetTextFieldState = it.value.toString() - } - } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } + ) { Text("Image") } + CategoryImagesToImageList( + categoryImageState, + onClick = { viewModel.onEvent(CategoryEditEvent.EnteredCategoryImage(it)) }) + } + } + //Category Budget Input + Div( + attrs = { + classes(AppStylesheet.margin) } - //Submit button - Div( + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - SubmitInput( + Span( attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - - Div { - when (viewState) { - is UiState.Success<*> -> { - when (val element = (viewState as UiState.Success<*>).element) { - is Category -> { - category = element - categoryNameTextFieldState = category.name - categoryColorTextFieldState = "#" + category.color - categoryImageState.value = category.image - categoryBudgetTextFieldState = category.budget.toString() - } - } + classes("mdc-text-field__ripple") } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { Text("Budget") } + Input( + type = InputType.Number + ) { + classes("mdc-text-field__input") + value(categoryBudgetState) + required(true) + min("1") + onInput { + viewModel.onEvent(CategoryEditEvent.EnteredCategoryBudget(it.value as Float)) } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } + } + } + //Submit button + Div( + attrs = { + classes(AppStylesheet.margin) } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + } } } From 7ea764d8eb405aa8b231f643e468e24faf258358 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 02:07:48 +0200 Subject: [PATCH 303/325] Fix small typo in CategoryEditViewModel (sate -> state) --- .../viewmodel/category/edit/CategoryEditViewModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/category/edit/CategoryEditViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/category/edit/CategoryEditViewModel.kt index 5327dc0a..27053150 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/category/edit/CategoryEditViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/category/edit/CategoryEditViewModel.kt @@ -50,13 +50,13 @@ class CategoryEditViewModel( onSuccess = { routerFlow.navigateTo(Screen.Category.Summary) } ) is CategoryEditEvent.LifeCycle -> event.value.handleLifeCycle( - onLaunch = { initSateFlows() }, + onLaunch = { initStateFlows() }, onDispose = { resetStateFlows() } ) } } - private fun initSateFlows() { + private fun initStateFlows() { super.updateCurrentCategoryId() super.getById(id = currentCategoryId, onSuccess = { category -> _categoryState.value = category From 844e5de3f56456b38a9e62533bc6283a35f49cba Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 02:11:07 +0200 Subject: [PATCH 304/325] Fix category image not showing properly when editing --- .../kotlin/de/hsfl/budgetBinder/compose/Composables.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 7a7658d3..0fc8ec2f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -140,7 +140,6 @@ fun CategoryImagesToImageList( inputImage: Category.Image, onClick: (Category.Image) -> Unit ) { - var highlightImage by remember { mutableStateOf(inputImage) } Div( attrs = { classes("mdc-card", AppStylesheet.card) @@ -159,7 +158,7 @@ fun CategoryImagesToImageList( ) { Div( attrs = { - if (highlightImage == image) + if (inputImage == image) classes( "mdc-image-list__image-aspect-container", "mdc-icon-button", @@ -169,7 +168,7 @@ fun CategoryImagesToImageList( "mdc-image-list__image-aspect-container", "mdc-icon-button" ) - onClick { onClick(image); highlightImage = image } + onClick { onClick(image) } } ) { CategoryImageToIcon(image) From edaeff518ee84ddfabffbbc7734ebe4724f86e31 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 02:23:51 +0200 Subject: [PATCH 305/325] Add cancel-buttons to categoryEdit,categoryCreate and entryEdit --- .../screens/category/CategoryComponent.kt | 2 +- .../screens/category/CategoryCreateView.kt | 349 ++++++++---------- .../screens/category/CategoryEditView.kt | 15 +- .../screens/entry/EntryEditView.kt | 10 + 4 files changed, 179 insertions(+), 197 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt index 46b8b133..5e9caf1a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryComponent.kt @@ -20,7 +20,7 @@ fun CategoryComponent() { is Screen.Category.Summary -> CategorySummaryView() is Screen.Category.Detail -> CategoryDetailView() is Screen.Category.Edit -> CategoryEditView() - //is Screen.Category.Create -> CategoryCreateView() + is Screen.Category.Create -> CategoryCreateView() else -> {} } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt index cc1aab89..d130231f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt @@ -7,248 +7,211 @@ import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.compose.topBarMain import de.hsfl.budgetBinder.presentation.UiState -import org.jetbrains.compose.web.attributes.InputType -import org.jetbrains.compose.web.attributes.min -import org.jetbrains.compose.web.attributes.required +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent +import de.hsfl.budgetBinder.presentation.viewmodel.category.create.CategoryCreateEvent +import de.hsfl.budgetBinder.presentation.viewmodel.category.create.CategoryCreateViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.category.edit.CategoryEditEvent +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent +import di +import org.jetbrains.compose.web.attributes.* import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* +import org.kodein.di.instance @Composable -fun CategoryCreateView( - state: State, - onCreateCategoryButtonPressed: (name: String, color: String, image: Category.Image, budget: Float) -> Unit, - onChangeToDashboard: () -> Unit, - onChangeToSettings: () -> Unit, - onChangeToCategory: () -> Unit, -) { - var categoryNameTextFieldState by remember { mutableStateOf("") } - var categoryColorTextFieldState by remember { mutableStateOf("") } - var categoryImageState = remember { mutableStateOf(Category.Image.DEFAULT) } - var categoryBudgetTextFieldState by remember { mutableStateOf("") } - val viewState by remember { state } +fun CategoryCreateView() { + val viewModel: CategoryCreateViewModel by di.instance() + val categoryNameState by viewModel.categoryNameState.collectAsState() + val categoryColorState by viewModel.categoryColorState.collectAsState() + val categoryImageState by viewModel.categoryImageState.collectAsState() + val categoryBudgetState by viewModel.categoryBudgetState.collectAsState() - topBarMain( - logoButton = { - Img( - src = "images/Logo.png", alt = "Logo", attrs = { - classes("mdc-icon-button", AppStylesheet.image) - onClick { onChangeToDashboard() } - } - ) - }, navButtons = { - Button( + //Life Cycle + LaunchedEffect(Unit) { + viewModel.onEvent(CategoryCreateEvent.LifeCycle(LifecycleEvent.OnLaunch)) + } + DisposableEffect(Unit) { + onDispose { + viewModel.onEvent(CategoryCreateEvent.LifeCycle(LifecycleEvent.OnDispose)) + } + } + + //Webpage Content + H1( + attrs = { + style { margin(2.percent) } + } + ) { Text("Create a new Category") } + Form(attrs = { + this.addEventListener("submit") { + viewModel.onEvent(CategoryCreateEvent.OnSave) + it.preventDefault() + } + } + ) { + //Category Name Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToCategory() } + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { Span( attrs = { - classes("mdc-button__label") + classes("mdc-text-field__ripple") } - ) { - Text("Categories") - } - } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised", "mdc-top-app-bar__navigation-icon") - onClick { onChangeToSettings() } - } - ) { + ) { } Span( attrs = { - classes("mdc-button__label") + classes("mdc-floating-label", "mdc-floating-label--float-above") } + ) { Text("Category Name") } + Input( + type = InputType.Text ) { - Text("Settings") + classes("mdc-text-field__input") + value(categoryNameState) + required(true) + onInput { + viewModel.onEvent(CategoryCreateEvent.EnteredCategoryName(it.value)) + } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } - }) - - MainFlexContainer { - H1( + } + //Category Color Input + Div( attrs = { - style { margin(2.percent) } + classes(AppStylesheet.margin) } - ) { Text("Create a new Category") } - Form(attrs = { - this.addEventListener("submit") { - console.log("$categoryNameTextFieldState, $categoryColorTextFieldState, $categoryImageState, $categoryBudgetTextFieldState") - onCreateCategoryButtonPressed( - categoryNameTextFieldState, - categoryColorTextFieldState, - categoryImageState.value, - categoryBudgetTextFieldState.toFloat() - ) - it.preventDefault() - } - } ) { - //Category Name Input - Div( + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--outlined") + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Category Name") } - Input( - type = InputType.Text - ) { - classes("mdc-text-field__input") - value(categoryNameTextFieldState) - required(true) - onInput { - categoryNameTextFieldState = it.value - } + classes("mdc-text-field__ripple") } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } - } - //Category Color Input - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( + ) { } + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent) } } + ) { Text("Color") } + Input( + type = InputType.Color ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent) } - } - ) { Text("Color") } - Input( - type = InputType.Color - ) { - classes("mdc-text-field__input") - value(categoryColorTextFieldState) - onInput { - categoryColorTextFieldState = it.value - } + classes("mdc-text-field__input") + value("#$categoryColorState") + onInput { + viewModel.onEvent(CategoryCreateEvent.EnteredCategoryColor(it.value.drop(1))) } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } } - } - //Category Image Input - Div( - attrs = { - classes(AppStylesheet.margin) - } - ) { - Label( + Span( attrs = { - style { width(100.percent) } + classes("mdc-line-ripple") } - ) { - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - style { marginBottom(1.percent); marginLeft(2.percent) } - } - ) { Text("Image") } - CategoryImagesToImageList(categoryImageState.value, onClick = { categoryImageState.value = it }) - } + ) { } } - //Category Budget Input - Div( + } + //Category Image Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + style { width(100.percent) } } ) { - Label( + Span( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } - } - ) { - Span( - attrs = { - classes("mdc-text-field__ripple") - } - ) { } - Span( - attrs = { - classes("mdc-floating-label", "mdc-floating-label--float-above") - } - ) { Text("Budget") } - Input( - type = InputType.Number - ) { - classes("mdc-text-field__input") - value(categoryBudgetTextFieldState) - required(true) - min("1") - onInput { - categoryBudgetTextFieldState = it.value.toString() - } + classes("mdc-floating-label", "mdc-floating-label--float-above") + style { marginBottom(1.percent); marginLeft(2.percent) } } - Span( - attrs = { - classes("mdc-line-ripple") - } - ) { } - } + ) { Text("Image") } + CategoryImagesToImageList( + categoryImageState, + onClick = { viewModel.onEvent(CategoryCreateEvent.EnteredCategoryImage(it)) }) } - //Submit button - Div( + } + //Category Budget Input + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Label( attrs = { - classes(AppStylesheet.margin) + classes("mdc-text-field", "mdc-text-field--filled") + style { width(100.percent) } } ) { - SubmitInput( + Span( attrs = { - classes("mdc-button", "mdc-button--raised") - value("Submit") - }) - } - Div { - when (viewState) { - is UiState.Success<*> -> { - //Text((viewState as UiState.Success<*>).element.toString()) + classes("mdc-text-field__ripple") } - is UiState.Error -> { - Text((viewState as UiState.Error).error) + ) { } + Span( + attrs = { + classes("mdc-floating-label", "mdc-floating-label--float-above") } - is UiState.Loading -> { - //CircularProgressIndicator() + ) { Text("Budget") } + Input( + type = InputType.Number + ) { + classes("mdc-text-field__input") + value(categoryBudgetState) + required(true) + min("1") + onInput { + viewModel.onEvent(CategoryCreateEvent.EnteredCategoryBudget(it.value as Float)) } } + Span( + attrs = { + classes("mdc-line-ripple") + } + ) { } } } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised") + type(ButtonType.Button) + onClick { viewModel.onEvent(CategoryCreateEvent.OnCancel) } + } + ) { + Span(attrs = { classes("mdc-button__label") } + ) { Text("Cancel") } + } + //Submit button + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + SubmitInput( + attrs = { + classes("mdc-button", "mdc-button--raised") + value("Submit") + }) + + } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt index 0191d4c8..54b09b5f 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt @@ -10,10 +10,9 @@ import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.edit.CategoryEditEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.edit.CategoryEditViewModel +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import di -import org.jetbrains.compose.web.attributes.InputType -import org.jetbrains.compose.web.attributes.min -import org.jetbrains.compose.web.attributes.required +import org.jetbrains.compose.web.attributes.* import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.kodein.di.instance @@ -187,6 +186,16 @@ fun CategoryEditView() { ) { } } } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised") + type(ButtonType.Button) + onClick { viewModel.onEvent(CategoryEditEvent.OnCancel) } + } + ) { + Span(attrs = { classes("mdc-button__label") } + ) { Text("Cancel") } + } //Submit button Div( attrs = { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt index adb6a897..f8605698 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt @@ -208,6 +208,16 @@ fun EntryEditView( } } } + Button( + attrs = { + classes("mdc-button", "mdc-button--raised") + type(ButtonType.Button) + onClick { viewModel.onEvent(EntryEvent.OnCancel) } + } + ) { + Span(attrs = { classes("mdc-button__label") } + ) { Text("Cancel") } + } Div( attrs = { classes(AppStylesheet.margin) From 873bd73085c17a87912856ec70d851c5b01d3230 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 02:32:23 +0200 Subject: [PATCH 306/325] Update CategoryCreateView with new ViewModel structure --- .../budgetBinder/compose/CategoryComposables.kt | 2 +- .../de/hsfl/budgetBinder/compose/Router.kt | 4 +++- .../src/jsMain/resources/cart.png | Bin 11357 -> 0 bytes 3 files changed, 4 insertions(+), 2 deletions(-) delete mode 100644 budget-binder-multiplatform-app/src/jsMain/resources/cart.png diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt index e846d912..834b4bde 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt @@ -215,7 +215,7 @@ fun CategoryDetailed( } ) { Span(attrs = { classes("mdc-button__label") } - ) { Text("Cancel") } + ) { Text("Go back") } } Button(attrs = { classes("mdc-button", "mdc-button--raised") diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 0e559c84..880d84aa 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -30,7 +30,9 @@ fun Router() { is Screen.Settings -> SettingsComponent() is Screen.Entry -> EntryComponent() is Screen.Category.Detail -> CategoryComponent() //To avoid weird bug where it doesn't refresh itself? I don't understand either ... - is Screen.Category -> CategoryComponent() + is Screen.Category.Edit -> CategoryComponent() //Okay this seems to be necessary or CategoryComponent won't refresh, so no 'is Screen.Category -> ...' + is Screen.Category.Create -> CategoryComponent() + is Screen.Category.Summary -> CategoryComponent() is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister -> Text("Old Category") //CategoryComponent(screenState = screenState) is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview diff --git a/budget-binder-multiplatform-app/src/jsMain/resources/cart.png b/budget-binder-multiplatform-app/src/jsMain/resources/cart.png deleted file mode 100644 index 5eaa26619e8bdf803d0dfa2c7b4a8a3bfa326926..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11357 zcmd^l`8$+f`2RCA#*!^dlzkaZ_R5l-$~MV}C}pc;nXDm%m}y70v1N;QMj0iPwaC*u zOUX8t>`ZpDR|t*oncmmuKluLexvr0kYs`7hIrn|ey}a(_i9UljgsNJxkZ!PhI$^|HU4ieG?7){>qG1W7?S-?$eVAA(9?}T5jnTUw^!+h#c#f`Av-abaS-gtMm4N9~wu-{NMexI?A78 zRH_YMhpk}*TnX29K3XeBh6>uV?g(xkSTXiAC1behzv1&l4Y-gN@{+Y33bW4vm4l>CD4C*N7()B#1A-Ff0P$TK2^29I(t*~lV*btY*05M zgd?}S;q+Hqb$R3y^Nw^UyhfXhNxdveR~WC~JG4IprE3`#i@_<33P0SH@eYjOJkM@U zR#?9>UJr4HehE5uiY%BPUEk@B>_f1bU}cur)=^)H^&ooFECz#fP+yE)!({e7JLv!760YTR z_j{#Wz8vDgpTn~(7@XDDawMHN%c3sLsm6S`hbaD3p!06<++B>kz?-K6hx*UaI6Q4S zq!xJ&$-BHmG$YuMx=2n=#aYbLLaKQK&=bwfS^G0}_|J4H#_#|siMI!uc={`{Mj#uLXLxSOng1gPuFgAQt0iCZZLcVmc=pITC07e-fgfYekM2@wcyk$ch>1v?j{>8^xCj? zuVu1r%p%FHA&T)LrWe*FW|%nY^>$o_S;r-fC#YpV1UD>gRt-#dW(;Ih(CdoyE$aPI z%N>-bo9k)S!Cjl%9Uk&Q?nU9@@tW7o481_ zY>1i;j1eW(-LEMudftah;NOKr=2DJ;!)lBhe%Ef&hyOY0*w^H_CPrK}U=uSI;as~* zwYPXGka&>}&$1k?5cQY#HxH7b4cbDG9(!$ExpjjiN*E<7D{xJo6QV|}ms|Ss5$YeG z6UG7UV1NCnTyx!(@&m;qr_Vlw9AcTadp2SIjx+_QLW8_o$o>aEYqHQUWpYGrqUIbo zEiVsfe5?g@Hq_}6be67=+dcLjvXKiuO1_FU#Vy^|a5K(jty^DK(R?PX_U`>cN32 z4N+ge@3kN-@fvcN*S`)J;EYfs+EMLgMs*;A(5cgC3t3quItgGqw2Dc+#uawgN8FjFXx|%StuHF%=KX zg~MqbZ79lbrOeS2bdJB5MB6^j0RQ?;jslimG>?x@$`dL6dy z#pEdV3n}A{qqn?=%R$CR4WZrVla)m}4oU0wC0hpu@18_-53p9pZgzx^jPtV9^xqiA z!0R=7IwTcej$yHSvq9IoYidM8?#*{MUbBWOFTLz9sfW35_Z-IZxm-wSjGNN5+qb2C zy@MuDZD^zlwASOj@9GmK*VJslHBu;L$kC2|cs#d2?UbLJ+74=UqX@q$#qBIKyVq#@ zC5vw~{;4age^3y=$ROua0qBWjj*(?;^3NAvzY#|lPK%6Q!*CLV10;wsL8pU|)!r{8 zC0XzX#ak$IfBZzYoCZFb5-w`*gO=FsqqMWB@Aq%8%rOoPmx067ydVYzW92c^syK`veFzH3}3z84xc~fDof)y)Nq1sy*7&&G#)JW zz7ZrN(*F^Tr{NOsC%<}xe>y##95%%xGt&Ju%x;=IsvC}aaHif)G$A=GV?o(kcCuWS z{>H-hMawVt)sD_XJlNjP((pTT3sQb=mh*&0fn&6h_72jPYX)H+6QI8$-KBRooy?Qi zGD4+s2(}^f>Xaaii75KL$wi(W9-H&wuOj2rQ)v5zpvBa)2)d0Cbwm>-$%bcd;;K?Gz_*{q60a|9tt-O<3`DAcqAX@JABdaPcA)-%`*<;l(mJ&!61MfRkuA^Ok>A ziNeS)cYZwnv?a4 z#GsAd70cx2lROY+#^9N*2f1&xaoYrYMvxPlQs<)ULAZ$#l%rUVak^7Jb3XAu!UUPI zczmA42+z^Xl)qyOh(z_I?9sE@*%24mIUy&U0U(%vIo!uWq2U*eBZ$!Ysz3;8A;+vCtgd*-U9&vi1@Mo=HfNr%Q3Q6f>>_; zcPu})OBkK#_&9JsjYy-!zIft;WUB&Id0sYP$!>N*NRu*XFYG$0#^=xD?-|5TejQ*R zgmjXK#^)UpfkpFwbDCKKOTsLI?aus2!Ea za?=uu5UW0-6Afel2GK-t(BmS=PmLAT0(m0W2!J)9QH$sWesICLrr0wWPUyxLf*CA( zT_&$5So_BA9W+tITjQoBODkb6fif>HngeU4|2HvihIyLF9@Gl^?;RtByJ%w57lKTl zB7(A>i53%Q?ug8%;RFfif{-ovzh|=2?$PE{)A%bR^IcNMF{k z=oy>y4^TtKSXzPg#BP`IG%CwH)i>zn2bmj3R(R;)@Wt`vXqt;RhWo`Iaewyt=DCKk z`lV3onzqz6f7GgEWtr#qc;Ys4*K{xxvn8>=v2lYaV6AFkw)00MwhiW)(mdbtQ8;=R zj%)O?@b&U_M@HSRU(XWD!sQ;RKl3bDe|6)UlE|BFmt$DOH5u(TlxMdwoMT?UcbE0C zaCU5q8nQOCeEI$l$Agv1{%3;tokS{j{2rl+2gzpRCmdl2JrT|^ zzaOBBC`}T80^h+-)nIqr~gF0=0#vYdTKgJt&`;p$pyrj*p~;DU0Oaw z0KCMUQb$Ilt>c4j!`3n{Dyv7R;krwll z&zxiE=#aQ3d;aip=RoX2P^Kd=*7VL=j~hJHZI}6AJv@7BF;vQCRGbX%0}V5POcxrp z<}3tsm32s$0I?0khAGxsh!e7udw!YttPQ25t%GoT(bm!Ay{3a$8J}foxr)f6PTE51 zJ`ym%_cN6|tig})GN1S+D>&UKUr-bH|||`z`a4atX9yu?XknCy5Uhxoc;PqnO0Gz6|e(epT;J0frH zC97`?0Icv!xwDu(Yj*(AV##FpysEY%Oe0Sb;_AKt6$&%O=q3S2k*zvn*489x94!69 z_JY7_ni7~+7naNX|m3|v4&=mRRvrr5*yiNE(%_ZbNB6fXp`fddCKqSY6^ zYHG*rCLq&+mz}y|P#XR7!^8LoK+$^{lB<0^pJbP?KB2v)!U9o$n#Y^SLz&#+P){rX z;3f8jeL2RYb_lqs6W>fp$CB0`dS(s4)-+rY!DPb__>PeOxP{;m_`A8j(zTKVXvPG~ zH)+16BbvWY00Kg)V=7gb9z^s*_{sj+W4pbhyRtNkK~AYNc!i*@vrOqz*)Fv{Cm!o; z|25{bet@n%Scg%6j=Uu952R${JDvPK`zdzz5t27`_^Ww`G&iTQi);R{JzI9XRGVtd zdr8;T3G$Fa@7G@qQAW*I639a$1nCv)OZuyQ1BVRS3$)D~c)fIOmd$?ZABg2m9U89H zV#$lt;yM#&2TLZu#~47v0$K5UR`#!;=^3y*>{B*(bwX=RXDnZ1Vi#hnWw9e(q@?u& zf0xMC!FR%;sw*B8H=BB-*olj*HHqaB3T$Qwwftnr7y4?7J-#JZgS0nond9%$+4z-& zb5nS}8s$mjH=?>=`NvF-35}`L6wi;yHW>2etG_#6NPTa)6R0M%kv9BwfytL6&ft6R ztpST)nkSq+AV-i%_9{U=3B7O|xOOGhU?BA_cpV)KRLSB+6VnX-1j^)5WV9HPt>FLH zP@?VK>^;OdcpnXC+XhB1GVSM?4~J3(4v&U=LCSw$L+!M1lr#YrZF+_ z6|4dPe}2ds9-hU#E%!xA0mpKf2W2i|%G7Rz)UVcPBKdw2a67jn!ZZ}!5P8Re{Q6N+ zy;flF0!j|#(2O*?;|~}*zG&q9T)Oi0wxklI{|C?CMjJ1tbmf4@;tLN*Wd_JF-ajxm6J?iQqxO}#16^=a~K*WhYY zDbz`SC6yaZe8rMDf7wtEaaa^=*mH3$gS}d~G!S6yv()ZQ!}8F-htL9ws>OGv#Ragb zLkCwN103RhV4MIB*V4gx1Vd$XqRqh$rhnm(Qrm`(2Z5W#i@%=n<7a?i`jE{iAfxto zk^o|Z>8eh2QJ4VB2>}L`(=QYG0BTPu0S{w9e=>`C3W(U(2txG3#FRHcC?N6qL_!nq zSEz#+8PAfkRxVrW2OQ4Du|L2TL`G8qi(Nf{#!2w)9B{WA=*k2@<1FyP^-1NoslSvU z+q;hU5vJxAahNH&|M6tnrO+8BWx`Qe7%1ZG_-51tG%*GUjBu1Ku}?x=2m-$fC%}$Q z98zH2Qj|ZEt_s`@yBA3mEYO1bHFY>}^}wr@BCEA^q8)*8AFAQ{duJ9*(ZV2VsR3lH z1LPt2CS*6XH^-=XYnJ7wU?Az^e{(hf!GMxj8c$2W0pVZzKSerF1(=3@n#VM*{FXQ?QImK+pL5u8j4aUF2F2 z$T1eiLh-K5#kPP44e{2Q35Rj!fcX8ZsA)lg}|68ug&T9QYQGLfTD6q&gdn*{R zx=bqDy#CpzSndI2TMp#p4uSZUc61pbQMj_~!#aA}K$MRV%SV3<%u9=5hyYA0|HpL2 z15$UPulDE|WcYH{k7~$<95TbwfH4%oZyqi$iN|HLb%-(y9T&uxqr$+ zJwQa&v&c1W_|tXuD@b-n#W*53?9G-peANiCW9j2144uyeiOxg*S8CddOD@nj3X=jZ za?sP@o15Az*Dg8G8{t6Q7xfL45V`5+c|-{L>$(d|#Pc8ZcB)xostgP0UESCfFohz}#n~(X|9%`3}S>8g3H!SvTNk^DGbr0YDe4cS_iRS)K)E znIP4MPPDDPIjPanw7M$+_VWhT*D77i3PwE=d4gK*=|lR!{s#WDKbs4{?YOWx0_7HG zPPWJwm>t)HsA3=z=$s1ZB2Y5#gEOoL0(a=iOSFy84ucjL%Sm7?4V){xNxtBqJqr`x zfo-gVe8=t+IF}+laTY_luWg`1y1syz1+$A1yN!)N*3;NR-QNA{)8_wWP6iHIf@u5l zKc7|zY}f8XG|@(_4HkgBzJLk#oWpx_jGL3-m&^^d_5=44ts(^70w=HwIKcYYER28? zaR#6w`gunGET<4ubP6wd`T>G+1>lJz>LrNj@IYRvKwjsO=8a5xzg=>{$UczMw7u4N z0@-{0T?DR<)!h^;-8-!I$?HTh+K4%+0GM7SD^CpmL{SY8$9d?O8P@t3m~W$khP1e( zxD|otd=5{~V&8Mk8bmV|9&xbpnCKt+rYfuJ}Zj~`ss<%^*t^p9cW*-y3 z#DSV!187r%;&}*|$~cC4X9}!a04m7*663sR74DfeJdY^xes{c7W&L_Pe2$lXw{ z{&ph7!l$f9Y-aE7O>s$WaWf@?NIL&+*KE8UOe(0fFRHKN+r1zz=|voH)4XU?W?;M% z>l!f}{R2VyyuznfXRGr-0e%9o9hPn9aq zU4>`Un~lqaLXW*lOsYgN?v*$C{+tPTt@XP6tA#>a!o#SWr}qgXn^V4q$-BHEb(`y7 zq2+$0UOBKdE#KSa@Gy$>li!dPFQ*(u&h)mTJHbv3QA=UbR;hsp20zZ@tc8*yFSkCz zQ_Ql6ilkUvy`IEegXdM7F5)yagwln!ksavu_|u*c7P$*j#GDJzp{@|pj2Tv%8ob1^ z{s9?r2p?oad6O@YXlvmyk-pmrQX@(YEKW)OjiCyQ;zUD6_;Sog22gqC2`ErVIAK$q zeaD4y59BAbU}%XI6giD;l$E3{KlLVprR8SC4&XGVu;erleH>w$kwq;j}0qj(B!)0(s zz5qey0hE&UfTZ>`IWgtl#zcA)K@52&{uL_tpdEueIQIaatDgBg_R2jO&l%wxBtur% z;OychKDhnEQyr8+?cb=4rp=L?|G z|Cr(|qB?*8eX>~!-)akO3K25$C}BfTEuWUIPLk$p=#2OxTQ={4BseZff6tB(p{^bY z0$QE7+**8_#{m?&bMvd;XY^8Qe-dIu{5t)&hQ zKg?E}-gEMKD-h?i8qrNIe?x!4(!-kK)YNk*NmgeLN1^OkicltMM|$r3r^3to3z}U) z0hsNkd>{{^kh_xA*<{co0_U${BQS!Szq!pqxK)1*z=BVpp1;n@Q89_c`>QPe5-SAy zJ4*77t*j7q?L`L6LHU7pMl6VA#oKZwB(_g&O3d}VcPpFo1m!oILF3soHpl&u)O5Pk zPK0??^1)SQw2E9#YmL0R?7k-9Z1pl9;w{}WD{Lid8Zi{YsIjvT?pisQ{C2f389xvK zRmYZ}924-kwjC_p7AiKZP$_Cs^ zQC*;sUB&$oE5UT)T2>*K5)>)Axo1Uc%Fs2R;#_Ejs&Djfyob?f`3G($zN1dN>Df8* z?C?>)oNqhA7K&c6yrf^&(XV5(x+-(YJtHoSBG!h8fzgGZ8%#|?NSLY+jUJ=#4#546n}l&coeB4X;01U%=2`6&Itbgl1H)9 zxFmOkA9@MPaMSfvLgN)S-xk`3Lmnv6=qP8_Xl@u=YG!0}vKFdN+f4VezAizKf4Wwt zK~=oPz1m^MSH>TzdbkSq!T{4W7BNeR%t+(=PTWWg(-i!EwM&AR)?s|$y10MD_4HHZ zmW`ub_YcujJ72rX6BetBj!FJ){RN(J_hvCTk!dK48^~mf0A$=#%XmUv`Gl?X9gxGP zcIrxwzCy06j*sJPXu;UU2%$euAH}>ecW5kfthWek+S&$*F7>0!37kUv58{J|QO8Z2 zrzn3W>}oS$L;k3Qd{?yE(;xz zvl)K=xmIitr4o}mu9dxV%-oSvNsJy=)r*a;_qg%MP;~N&MOTo}*^;w60kJ=>f2TXw zrfr7X_4RY@;CIs<$p?>#RzKVnb{v`T+p1ep4iqbWvbk+LV;}eBjNHCi$%j#88q%8I zlKxE|-~qjh@SeNX{8s!awnUGKi@P!t5|^6aFB$1(o9xsPY$9IPe^JF*X-ZbdZKhx7 z9=G^2d{-#+!0HBtP<9|Z3&Z^_H##awLnE>{VY~C{5G_7GUv@lf7-QZA@qGBjaBFI- zj#H$(nx74)O>TCN`rX6GE!8_m);^zkM?1}i5PewBYZ+fb$$u+H#j46N8hh`D-t9q; zo*Tn3B+8{31%0A2xOBeVu4@+MH~fflp^t6tR#~W3Cgf*7zcOP`!v~8Ct=4{{EucSsM_2LgR1w0vfJb5&pER%aEc+k zCDSjCJ>gtH4ol{ke~vWNAsP4}U&;DJ*JYOn1xnB9JwTC8Qu}mwLx?3z5LMkZ*)c9~ z9^XUvfg`)iJy;2^2V9ULR}({2SJw%Hwjtp*37@0B6ID^F(zgbz+z^DZN2(!=C|Zq` z@OSF@%SzO%oS%2a)^i~&SO5DA_yy5H&9m9|`YLhpMXaF=L&R!dLUR0jiJ#?7PQ(QA z?$Z4d$f?2-nwU~$4mXzzf_7u?W4_f>yVe& zw$YLn$&{Y>2Pi@2_Qa96S_QR&D$z@?>hI5~KX4exMv%rd} zN?Ar`uvyPHi>N-cc(-QOOTHjcOnLVrI_f~2$)w74m&Yr@?{;pD1xe7F@I+tOfWpX&}FgR+43;AE4+39F8qdk2pKImaWgMn%n^=QZMdoy$x*XihB@J+zPZj z%0P=o#Q}7i5nDe91TIEew1{-3&()TSI=b37=mjR$|(zhm!@tOB%Tr zqv9nBRW$-z3wwX3@zu1N9BSd}GKOcr>j-Vw{4vw(@^$&q}e)Vsl40@~tTwke#z7DleS14|(D(Y@pSsmf`#oZI|NqZCF2e(?@! zc7{(P7PAy0t=;dSZV@-VbPYxwuf87|JNAz-!^Ft+AMuGYTN0eSZT=_n&_8=uL!HLt` z%U4C3v4t1fJ$=1#I+!Bya#qt)XiTXvhb(eQ_>$VH>a)*RWLK>3>%R2hSXty6JZk4? zXuLg7?})B%I@{<3Q@P%!gln#_!6OIC-HJk+iHpfSX81TGJgDp~2 zE1{M%yKM7?#GtK*#l!lhx`twk>Sz6M?>+_`{wc(ss;l{nros)nqzD4E3>gUJ7)zdm z3}xzGE@Q-f^peZN=yUKt@DaGSkcG`(%HJZ0U+x``7HFy(46{3)x|nmF*I`db4(TIF z_MxFmo}?iZsR0U>H!m1x?%nr?v!M9;>d&e|zER7a3g5um$SnuTl9>~&ycHcXzqfzCMn@d`pJSHzbKzTsYywQREe#Yiqknv$PfVF96>Z%bvP z;d(%z$fWUj$<3iFYJ~RN7|Z#M=%@=7@|vCP7Y0DXWN}Dv>5nSmVj%8$feFB4ejoAR z-^zcn_%RcUE5l`1RbOg0n9_+7%ed}GkfAga*t3TfsUB)1;2*DR=rgE&qFraOXA-zG z=fy-x`QdfaWR?|~aTjOHcsBF!rmB&?=z3wx_=Jr}MGS${rG2WAaBKL%!6DJmN1NNU zhHAY`<=>W%{xD z^Q~??!>uYS9hKV$|3e)A_tkFnqLmI^ev6?ly@U*2SYET}Y7l~s?cKfdB0S>R80Xkg z)kZtS$0h+d5X4ku_0*3fjfQ&qyhtC?VdGZs(9Fk%u@^ec@3!hE$?A3Izp0iVA3r|$ z?weJ;J4$$ORLA^&mk-yYaB^Y7tEz8x8b!M9ADbUR(gVhqopQ!cbZL%~ZHp54cK>~G z(p$=>kiuBx8a}b3|MKLHSl_lq(I>7hX-%5y`)pT%S05$5zK6vd#=c}vxL=~>3EPud zkDSnHHrPTxcGcsl4Op>wp%Q+{3cQ)YT{=WhKSyRghKwL?3SY*9NPP6Lu$@(zB4MA& z&$>4G_qTYVUu&-{sZ?R{s zEqxe^#kpm0)Mk~lsB9Hn2!1Jb>i{(@yz2?-t_n-A{Pb&_&2PL^u~mHJ&9r?kP3ZyU z7btPma{{}1DSTf@-DO`~Y`EKyqdYHV7;YDBhqgSXr;Zf;ieI~12*n(FB1aUOcY3j5ew5$U$fT}^_+^z01bX@Ae> z#$Ilzz0Ua=%j?XHXr|`mPVowkCGCQhH?!rS&}wkrK-E z`WGUlP-09KyH-m15d8^dsaxDU`G-4V2=yK3_3!x`S2PGwj4V=?`STW^LY?cqO{eKb zm!i4?E5m1U9g=xQGlqU|q*9!VKt{T4M$*M~^jpGpc374FrLVHu+-I;oc{Ue(PJ`+J PfghX+-uTstOSk_YR%3m> From b105357c6630842d7a8406fd117e80704ef32cf1 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 10:36:03 +0200 Subject: [PATCH 307/325] Change location of cancel button in CategoryCreateView --- .../screens/category/CategoryCreateView.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt index d130231f..c6103879 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt @@ -190,22 +190,22 @@ fun CategoryCreateView() { ) { } } } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised") - type(ButtonType.Button) - onClick { viewModel.onEvent(CategoryCreateEvent.OnCancel) } - } - ) { - Span(attrs = { classes("mdc-button__label") } - ) { Text("Cancel") } - } //Submit button Div( attrs = { classes(AppStylesheet.margin) } ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + type(ButtonType.Button) + onClick { viewModel.onEvent(CategoryCreateEvent.OnCancel) } + } + ) { + Span(attrs = { classes("mdc-button__label") } + ) { Text("Cancel") } + } SubmitInput( attrs = { classes("mdc-button", "mdc-button--raised") From 8f26bd701bb306aa0d1a80a9734dfc6c38a3dd0b Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 10:36:32 +0200 Subject: [PATCH 308/325] Remove unused Imports --- .../budgetBinder/screens/category/CategoryCreateView.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt index c6103879..086151e0 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt @@ -1,17 +1,11 @@ package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.CategoryImagesToImageList -import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.create.CategoryCreateEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.create.CategoryCreateViewModel -import de.hsfl.budgetBinder.presentation.viewmodel.category.edit.CategoryEditEvent -import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import di import org.jetbrains.compose.web.attributes.* import org.jetbrains.compose.web.css.* From 22ee4197dba790addd06c174d04696140c96cda4 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 10:54:48 +0200 Subject: [PATCH 309/325] Add h1 style to AppStylesheet and change everywhere, and delete unused Imports --- .../compose/theme/AppStylesheet.kt | 27 ++++++++++++------- .../category/CategoryCreateOnRegisterView.kt | 3 ++- .../screens/category/CategoryCreateView.kt | 7 ++--- .../screens/category/CategoryDetailView.kt | 10 ++----- .../screens/category/CategoryEditView.kt | 7 +---- .../screens/category/CategorySummaryView.kt | 9 ++----- .../screens/entry/EntryCreateView.kt | 6 +---- .../screens/entry/EntryEditView.kt | 19 +++++++------ .../screens/entry/EntryOverviewView.kt | 7 +---- .../screens/login/LoginComponent.kt | 2 +- .../screens/register/RegisterComponent.kt | 6 +---- .../settings/SettingsChangeUserDataView.kt | 7 +---- .../screens/settings/SettingsView.kt | 12 ++++----- 13 files changed, 46 insertions(+), 76 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index 9bf57d2b..a8c11479 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -39,6 +39,7 @@ object AppStylesheet : StyleSheet() { display(DisplayStyle.Flex) justifyContent(JustifyContent.Center) } + //Container for empty sides, used in MainFlexContainer val pufferFlexContainer by style { media(mediaMaxWidth(1000.px)) { @@ -48,15 +49,18 @@ object AppStylesheet : StyleSheet() { } flex("25%") } + //Container for main content, used in MainFlexContainer val contentFlexContainer by style { flex("50%") position(Position.Relative) } + //Container for main content in BudgetBar val budgetBarContainer by style { flex("90%") } + //Container for arrow in BudgetBar val arrowFlexContainer by style { flex("0.1 0.1 5%") @@ -64,7 +68,7 @@ object AppStylesheet : StyleSheet() { } - val categoryImageList by style{ + val categoryImageList by style { justifyContent(JustifyContent.Center) } @@ -72,34 +76,35 @@ object AppStylesheet : StyleSheet() { textAlign("center") padding(10.px) } + //EntryList - val entryListElement by style{ + val entryListElement by style { flexDirection(FlexDirection("row")) alignItems(AlignItems.Center) margin(10.px) marginTop(0.px) } - val entryListElementText by style{ + val entryListElementText by style { flex("2 2 90%") } - val moneyText by style{ + val moneyText by style { textAlign("center") padding(10.px) whiteSpace("nowrap") } - val newEntryButton by style{ + val newEntryButton by style { position(Position.Fixed) bottom(16.px) marginRight(20.px) } - val categoryListElement by style{ + val categoryListElement by style { flexDirection(FlexDirection("row")) alignItems(AlignItems.Center) margin(10.px) marginTop(0.px) } - val categoryListElementText by style{ + val categoryListElementText by style { flex("2 2 90%") } @@ -126,11 +131,15 @@ object AppStylesheet : StyleSheet() { marginRight(1.percent) } - val loadingImage by style{ - property("z-index",1) + val loadingImage by style { + property("z-index", 1) width(20.percent) position(Position.Fixed) top(40.percent) left(40.percent) } + + val h1 by style { + margin(2.percent) + } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateOnRegisterView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateOnRegisterView.kt index 83ad2004..b4ab1069 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateOnRegisterView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateOnRegisterView.kt @@ -1,6 +1,7 @@ package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.UiState import org.jetbrains.compose.web.dom.Button import org.jetbrains.compose.web.dom.Div @@ -14,7 +15,7 @@ fun CategoryCreateOnRegisterView( onFinishedButton: () -> Unit ) { val viewState by remember { state } - H1{Text("CategoryCreateOnRegisterView")} + H1(attrs = { classes(AppStylesheet.h1) }) {Text("CategoryCreateOnRegisterView")} Div { when (viewState) { is UiState.Success<*> -> { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt index 086151e0..7f0aeb7b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryCreateView.kt @@ -32,11 +32,7 @@ fun CategoryCreateView() { } //Webpage Content - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text("Create a new Category") } + H1(attrs = { classes(AppStylesheet.h1) }) { Text("Create a new Category") } Form(attrs = { this.addEventListener("submit") { viewModel.onEvent(CategoryCreateEvent.OnSave) @@ -169,6 +165,7 @@ fun CategoryCreateView() { Input( type = InputType.Number ) { + attr("step", "0.01") classes("mdc-text-field__input") value(categoryBudgetState) required(true) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt index 32329656..c26e8829 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryDetailView.kt @@ -5,12 +5,11 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import de.hsfl.budgetBinder.compose.CategoryDetailed +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.detail.CategoryDetailEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.detail.CategoryDetailViewModel import di -import org.jetbrains.compose.web.css.margin -import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.dom.H1 import org.jetbrains.compose.web.dom.Text import org.kodein.di.instance @@ -23,15 +22,10 @@ fun CategoryDetailView() { //LifeCycle LaunchedEffect(key1 = true) { viewModel.onEvent(CategoryDetailEvent.LifeCycle(LifecycleEvent.OnLaunch)) - console.log("AAAAAAAAAAAAAAAAAAAAAA Category Detail") } //Webpage Content - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Category Detailed") } //TODO: Put these in a "Title" Composable + H1(attrs = { classes(AppStylesheet.h1) }) { Text(" Category Detailed") } CategoryDetailed( category, { viewModel.onEvent(CategoryDetailEvent.OnEdit) }, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt index 54b09b5f..d87afa7a 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt @@ -1,16 +1,11 @@ package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* -import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.compose.CategoryImagesToImageList -import de.hsfl.budgetBinder.compose.MainFlexContainer import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.compose.topBarMain -import de.hsfl.budgetBinder.presentation.UiState import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.edit.CategoryEditEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.edit.CategoryEditViewModel -import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import di import org.jetbrains.compose.web.attributes.* import org.jetbrains.compose.web.css.* @@ -37,7 +32,7 @@ fun CategoryEditView() { } //Webpage Content - H1(attrs = { style { margin(2.percent) } }) { Text("Edit Category") } + H1(attrs = { classes(AppStylesheet.h1) }) { Text("Edit Category") } Form(attrs = { this.addEventListener("submit") { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt index 1527f553..678511d8 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt @@ -2,11 +2,10 @@ package de.hsfl.budgetBinder.screens.category import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.CategoryList +import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.event.LifecycleEvent -import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.summary.CategorySummaryEvent import de.hsfl.budgetBinder.presentation.viewmodel.category.summary.CategorySummaryViewModel -import de.hsfl.budgetBinder.presentation.viewmodel.dashboard.DashboardEvent import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.css.margin @@ -29,11 +28,7 @@ fun CategorySummaryView( } //Webpage Content - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Category Summary") } + H1(attrs = { classes(AppStylesheet.h1) }) { Text(" Category Summary") } Button(attrs = { classes("mdc-button", "mdc-button--raised") onClick { viewModel.onEvent(CategorySummaryEvent.OnCategoryCreate) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt index e58793b5..818d6b3b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt @@ -29,11 +29,7 @@ fun EntryCreateView( //Data val categoryList by viewModel.categoryListState.collectAsState() - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text("Create new Entry") } + H1(attrs = { classes(AppStylesheet.h1) }) { Text("Create new Entry") } Form(attrs = { this.addEventListener("submit") { onCreateButton() diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt index f8605698..018410aa 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt @@ -35,11 +35,8 @@ fun EntryEditView( val entry by viewModel.selectedEntryState.collectAsState() console.log("unser Entry ist $entry") console.log("$entryNameTextField und $entryAmountTextField und $entryCategoryIDTextField") - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text("Edit Entry") } + + H1(attrs = { classes(AppStylesheet.h1) }) { Text("Edit Entry") } Form(attrs = { this.addEventListener("submit") { onEditButton() @@ -174,7 +171,7 @@ fun EntryEditView( Div(attrs = { style { flex(50.percent) } }) { Div(attrs = { classes("mdc-form-field") }) { Div(attrs = { classes("mdc-checkbox") }) { - CheckboxInput (attrs = + CheckboxInput(attrs = { checked(entryRepeat) classes("mdc-checkbox__native-control") @@ -199,10 +196,12 @@ fun EntryEditView( Label(forId = "checkbox-1") { Text("repeat") } } } - Div(attrs = { style { - flex(50.percent) - alignItems(AlignItems.Stretch) - } }) { + Div(attrs = { + style { + flex(50.percent) + alignItems(AlignItems.Stretch) + } + }) { ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt index 2a44902b..920af6d9 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt @@ -4,7 +4,6 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.theme.AppStylesheet -import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di import org.jetbrains.compose.web.css.* @@ -25,11 +24,7 @@ fun EntryOverviewView( val entry by viewModel.selectedEntryState.collectAsState() console.log("Our Entry is $entry") val deleteDialog by viewModel.dialogState.collectAsState() - H1( - attrs = { - style { margin(2.percent) } - } - ) { Text(" Entry") } + H1(attrs = { classes(AppStylesheet.h1) }) { Text(" Entry") } EntryOverview( entry, diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/login/LoginComponent.kt index 15b52831..fe764683 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/login/LoginComponent.kt @@ -100,7 +100,7 @@ fun LoginComponent() { MainFlexContainer { // -- Login Form -- - H1 { Text(" Login") } + H1(attrs = { classes(AppStylesheet.h1) }) { Text("Login") } Form( attrs = { this.addEventListener("submit") { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/register/RegisterComponent.kt index 25654c44..236ebf36 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/register/RegisterComponent.kt @@ -108,11 +108,7 @@ fun RegisterComponent() { MainFlexContainer { // -- Register Form -- - H1( - attrs = { - style { marginLeft(2.percent) } - } - ) { Text("Register") } + H1(attrs = { classes(AppStylesheet.h1) }) { Text("Register") } Form(attrs = { //Probably possible with just a button OnClick instead of Form&Submit this.addEventListener("submit") { console.log("$firstNameTextState, $lastNameTextState, $emailTextState, $passwordTextState") diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsChangeUserDataView.kt index 2f309d01..936e4ae6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsChangeUserDataView.kt @@ -12,7 +12,6 @@ import di import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.required -import org.jetbrains.compose.web.css.marginLeft import org.jetbrains.compose.web.css.percent import org.jetbrains.compose.web.css.width import org.jetbrains.compose.web.dom.* @@ -40,11 +39,7 @@ fun SettingsChangeUserDataView() { } NavBar {} MainFlexContainer { - H1( - attrs = { - style { marginLeft(2.percent) } - } - ) { Text("Change User Data") } + H1(attrs = { classes(AppStylesheet.h1) }) { Text("Change User Data") } Form(attrs = { this.addEventListener("submit") { if (!confirmedPasswordText.value.confirmedPasswordIsValid) { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt index 3edccf32..2aa6480c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt @@ -20,11 +20,7 @@ fun SettingsView() { NavBar { } MainFlexContainer { - H1( - attrs = { - style { marginLeft(2.percent) } - } - ) { Text("Settings") } + H1(attrs = { classes(AppStylesheet.h1) }) { Text("Settings") } Div( attrs = { classes(AppStylesheet.margin, AppStylesheet.flexContainer) @@ -64,8 +60,10 @@ fun SettingsView() { attrs = { classes("mdc-button", "mdc-button--raised") onClick { deleteDialog = true } - style { flex(100.percent) - backgroundColor(Color("#b00020"))} + style { + flex(100.percent) + backgroundColor(Color("#b00020")) + } } ) { Text("Delete User") From a0a71e577d079c6e227f2692d70e3390ea559623 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 11:04:00 +0200 Subject: [PATCH 310/325] Add width to AppStylesheet --- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index a8c11479..d384d1e1 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -142,4 +142,8 @@ object AppStylesheet : StyleSheet() { val h1 by style { margin(2.percent) } + + val width by style { + width(100.percent) + } } From bdc3a427e1fc3c30806d06a15e69be3e0dc902fa Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 11:04:51 +0200 Subject: [PATCH 311/325] Add width from AppStylesheet and change position of cancel button --- .../screens/category/CategoryEditView.kt | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt index d87afa7a..b8c680bd 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt @@ -50,7 +50,7 @@ fun CategoryEditView() { Label( attrs = { classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes(AppStylesheet.width) } ) { Span( @@ -89,7 +89,7 @@ fun CategoryEditView() { Label( attrs = { classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes(AppStylesheet.width) } ) { Span( @@ -127,7 +127,7 @@ fun CategoryEditView() { ) { Label( attrs = { - style { width(100.percent) } + classes(AppStylesheet.width) } ) { Span( @@ -150,7 +150,7 @@ fun CategoryEditView() { Label( attrs = { classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes(AppStylesheet.width) } ) { Span( @@ -181,22 +181,23 @@ fun CategoryEditView() { ) { } } } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised") - type(ButtonType.Button) - onClick { viewModel.onEvent(CategoryEditEvent.OnCancel) } - } - ) { - Span(attrs = { classes("mdc-button__label") } - ) { Text("Cancel") } - } + //Submit button Div( attrs = { classes(AppStylesheet.margin) } ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + type(ButtonType.Button) + onClick { viewModel.onEvent(CategoryEditEvent.OnCancel) } + } + ) { + Span(attrs = { classes("mdc-button__label") } + ) { Text("Cancel") } + } SubmitInput( attrs = { classes("mdc-button", "mdc-button--raised") From 2dd376e4d6304f62d826d697cfde2aa7a92dc519 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 11:06:10 +0200 Subject: [PATCH 312/325] Add comma to category budget on create --- .../de/hsfl/budgetBinder/screens/category/CategoryEditView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt index b8c680bd..b0be876e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategoryEditView.kt @@ -168,6 +168,7 @@ fun CategoryEditView() { ) { classes("mdc-text-field__input") value(categoryBudgetState) + attr("step", "0.01") required(true) min("1") onInput { From 9b0478942c2765e7a2316670d14879efc5651ea4 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 11:10:14 +0200 Subject: [PATCH 313/325] Add space between the buttons --- .../de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt index 818d6b3b..fd2e7595 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt @@ -201,7 +201,7 @@ fun EntryCreateView( ) { Button( attrs = { - classes("mdc-button", "mdc-button--raised") + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) type(ButtonType.Button) onClick { viewModel.onEvent(EntryEvent.OnCancel) } } From e88043b7d098890806064bb66d0083a0e8c4e5d1 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 11:24:53 +0200 Subject: [PATCH 314/325] Change color of switch track --- .../src/jsMain/resources/material-design-override.css | 1 + 1 file changed, 1 insertion(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/resources/material-design-override.css b/budget-binder-multiplatform-app/src/jsMain/resources/material-design-override.css index b1408a0d..fe94bbf8 100644 --- a/budget-binder-multiplatform-app/src/jsMain/resources/material-design-override.css +++ b/budget-binder-multiplatform-app/src/jsMain/resources/material-design-override.css @@ -23,4 +23,5 @@ --mdc-theme-text-hint-on-dark: rgba(255, 255, 255, 0.5); --mdc-theme-text-disabled-on-dark: rgba(255, 255, 255, 0.5); --mdc-theme-text-icon-on-dark: rgba(255, 255, 255, 0.5); + --mdc-switch-selected-track-color: #64b5f6 } From c641c3b4fbb9b16536e82ca7bf9fef71212f7ac2 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 11:31:02 +0200 Subject: [PATCH 315/325] Change position of cancel button --- .../screens/entry/EntryEditView.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt index 018410aa..d4c933b7 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt @@ -207,21 +207,21 @@ fun EntryEditView( } } } - Button( - attrs = { - classes("mdc-button", "mdc-button--raised") - type(ButtonType.Button) - onClick { viewModel.onEvent(EntryEvent.OnCancel) } - } - ) { - Span(attrs = { classes("mdc-button__label") } - ) { Text("Cancel") } - } Div( attrs = { classes(AppStylesheet.margin) } ) { + Button( + attrs = { + classes("mdc-button", "mdc-button--raised", AppStylesheet.marginRight) + type(ButtonType.Button) + onClick { viewModel.onEvent(EntryEvent.OnCancel) } + } + ) { + Span(attrs = { classes("mdc-button__label") } + ) { Text("Cancel") } + } SubmitInput( attrs = { classes("mdc-button", "mdc-button--raised") From 224415e1e4d78f14f8588a28f633527ac72a4bf8 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 11:42:42 +0200 Subject: [PATCH 316/325] Delete most style attr with AppStylesheet classes --- .../compose/theme/AppStylesheet.kt | 17 +++++++++++++++++ .../screens/entry/EntryCreateView.kt | 10 ++++------ .../screens/entry/EntryEditView.kt | 14 +++++--------- .../screens/entry/EntryOverviewView.kt | 19 +++---------------- .../screens/login/LoginComponent.kt | 6 ++---- .../screens/register/RegisterComponent.kt | 15 +++++---------- .../settings/SettingsChangeUserDataView.kt | 12 ++++-------- .../screens/settings/SettingsView.kt | 12 +++--------- 8 files changed, 43 insertions(+), 62 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index d384d1e1..db043547 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -146,4 +146,21 @@ object AppStylesheet : StyleSheet() { val width by style { width(100.percent) } + + val flex50 by style { + flex(50.percent) + } + + val flex100 by style { + flex(100.percent) + } + + val deleteButton by style { + backgroundColor(Color("#b00020")) + } + + val buttonOverview by style { + flex(33.percent) + margin(1.5.percent) + } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt index fd2e7595..58c2841b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt @@ -44,8 +44,7 @@ fun EntryCreateView( ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( @@ -82,8 +81,7 @@ fun EntryCreateView( ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--outlined", AppStylesheet.width) } ) { Span( @@ -161,7 +159,7 @@ fun EntryCreateView( classes(AppStylesheet.margin, AppStylesheet.flexContainer) } ) { - Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { classes(AppStylesheet.flex50) }) { Div(attrs = { classes("mdc-form-field") }) { Div(attrs = { classes("mdc-checkbox") }) { Input(type = InputType.Checkbox) @@ -188,7 +186,7 @@ fun EntryCreateView( Label(forId = "checkbox-1") { Text("repeat") } } } - Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { classes(AppStylesheet.flex50) }) { ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt index d4c933b7..cb143c05 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt @@ -51,8 +51,7 @@ fun EntryEditView( ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( @@ -89,8 +88,7 @@ fun EntryEditView( ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--outlined") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--outlined", AppStylesheet.width) } ) { Span( @@ -168,7 +166,7 @@ fun EntryEditView( classes(AppStylesheet.margin, AppStylesheet.flexContainer) } ) { - Div(attrs = { style { flex(50.percent) } }) { + Div(attrs = { classes(AppStylesheet.flex50) }) { Div(attrs = { classes("mdc-form-field") }) { Div(attrs = { classes("mdc-checkbox") }) { CheckboxInput(attrs = @@ -197,10 +195,8 @@ fun EntryEditView( } } Div(attrs = { - style { - flex(50.percent) - alignItems(AlignItems.Stretch) - } + classes(AppStylesheet.flex50) + style { alignItems(AlignItems.Stretch) } }) { ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt index 920af6d9..8e8b1987 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt @@ -74,35 +74,22 @@ fun EntryOverview( } ) { Button(attrs = { - classes("mdc-button", "mdc-button--raised") + classes("mdc-button", "mdc-button--raised", AppStylesheet.buttonOverview) onClick { onCancel() } - style { - flex(33.percent) - margin(1.5.percent) - } } ) { Span(attrs = { classes("mdc-button__label") } ) { Text("Cancel") } } Button(attrs = { - classes("mdc-button", "mdc-button--raised") + classes("mdc-button", "mdc-button--raised", AppStylesheet.buttonOverview) onClick { onEditButton() } - style { - flex(33.percent) - margin(1.5.percent) - } }) { Text("Edit Entry") } Button(attrs = { - classes("mdc-button", "mdc-button--raised") + classes("mdc-button", "mdc-button--raised", AppStylesheet.deleteButton, AppStylesheet.buttonOverview) onClick { onDeleteButton() } - style { - flex(33.percent) - margin(1.5.percent) - backgroundColor(Color("#b00020")) - } }) { Text("Delete Entry") } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/login/LoginComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/login/LoginComponent.kt index fe764683..d1253c2b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/login/LoginComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/login/LoginComponent.kt @@ -117,8 +117,7 @@ fun LoginComponent() { ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( @@ -153,8 +152,7 @@ fun LoginComponent() { ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/register/RegisterComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/register/RegisterComponent.kt index 236ebf36..68b9b54d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/register/RegisterComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/register/RegisterComponent.kt @@ -127,8 +127,7 @@ fun RegisterComponent() { ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( @@ -165,8 +164,7 @@ fun RegisterComponent() { ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( @@ -203,8 +201,7 @@ fun RegisterComponent() { ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( @@ -240,8 +237,7 @@ fun RegisterComponent() { ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( @@ -276,8 +272,7 @@ fun RegisterComponent() { ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsChangeUserDataView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsChangeUserDataView.kt index 936e4ae6..d86916e6 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsChangeUserDataView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsChangeUserDataView.kt @@ -57,8 +57,7 @@ fun SettingsChangeUserDataView() { ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( @@ -95,8 +94,7 @@ fun SettingsChangeUserDataView() { ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( @@ -133,8 +131,7 @@ fun SettingsChangeUserDataView() { ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( @@ -169,8 +166,7 @@ fun SettingsChangeUserDataView() { ) { Label( attrs = { - classes("mdc-text-field", "mdc-text-field--filled") - style { width(100.percent) } + classes("mdc-text-field", "mdc-text-field--filled", AppStylesheet.width) } ) { Span( diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt index 2aa6480c..0ef63161 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt @@ -28,9 +28,8 @@ fun SettingsView() { ) { Button( attrs = { - classes("mdc-button", "mdc-button--raised") + classes("mdc-button", "mdc-button--raised", AppStylesheet.flex100) onClick { viewModel.onEvent(SettingsEvent.OnChangeToSettingsUserEdit) } - style { flex(100.percent) } } ) { Text("Change Userdata") @@ -43,9 +42,8 @@ fun SettingsView() { ) { Button( attrs = { - classes("mdc-button", "mdc-button--raised") + classes("mdc-button", "mdc-button--raised", AppStylesheet.flex100) onClick { viewModel.onEvent(SettingsEvent.OnLogoutAllDevices) } - style { flex(100.percent) } } ) { Text("Logout on all device") @@ -58,12 +56,8 @@ fun SettingsView() { ) { Button( attrs = { - classes("mdc-button", "mdc-button--raised") + classes("mdc-button", "mdc-button--raised", AppStylesheet.flex100, AppStylesheet.deleteButton) onClick { deleteDialog = true } - style { - flex(100.percent) - backgroundColor(Color("#b00020")) - } } ) { Text("Delete User") From ad856a56a4c0e0d9d2e275eda18d42bfcbfcf53c Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 11:47:52 +0200 Subject: [PATCH 317/325] Add delete button color --- .../de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt | 4 ---- .../de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt | 3 ++- .../de/hsfl/budgetBinder/screens/settings/SettingsView.kt | 3 ++- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt index db043547..2edd1067 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/theme/AppStylesheet.kt @@ -155,10 +155,6 @@ object AppStylesheet : StyleSheet() { flex(100.percent) } - val deleteButton by style { - backgroundColor(Color("#b00020")) - } - val buttonOverview by style { flex(33.percent) margin(1.5.percent) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt index 8e8b1987..2714963c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt @@ -88,8 +88,9 @@ fun EntryOverview( Text("Edit Entry") } Button(attrs = { - classes("mdc-button", "mdc-button--raised", AppStylesheet.deleteButton, AppStylesheet.buttonOverview) + classes("mdc-button", "mdc-button--raised", AppStylesheet.buttonOverview) onClick { onDeleteButton() } + style { backgroundColor(Color("#b00020")) } }) { Text("Delete Entry") } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt index 0ef63161..43db4647 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/settings/SettingsView.kt @@ -56,8 +56,9 @@ fun SettingsView() { ) { Button( attrs = { - classes("mdc-button", "mdc-button--raised", AppStylesheet.flex100, AppStylesheet.deleteButton) + classes("mdc-button", "mdc-button--raised", AppStylesheet.flex100) onClick { deleteDialog = true } + style { backgroundColor(Color("#b00020")) } } ) { Text("Delete User") From ae8e05e02072ff444f0cc0ac85c852975226740d Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 11:51:09 +0200 Subject: [PATCH 318/325] Change style to AppStylesheet classes --- .../compose/CategoryComposables.kt | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt index 834b4bde..d2f57e7d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/CategoryComposables.kt @@ -206,35 +206,23 @@ fun CategoryDetailed( } ) { Button(attrs = { - classes("mdc-button", "mdc-button--raised") + classes("mdc-button", "mdc-button--raised", AppStylesheet.buttonOverview) onClick { onBackButton() } - style { - flex(33.percent) - margin(1.5.percent) - } } ) { Span(attrs = { classes("mdc-button__label") } ) { Text("Go back") } } Button(attrs = { - classes("mdc-button", "mdc-button--raised") + classes("mdc-button", "mdc-button--raised", AppStylesheet.buttonOverview) onClick { onEditButton() } - style { - flex(33.percent) - margin(1.5.percent) - } }) { Text("Edit Category") } Button(attrs = { - classes("mdc-button", "mdc-button--raised") + classes("mdc-button", "mdc-button--raised", AppStylesheet.buttonOverview) onClick { deleteDialog = !deleteDialog } - style { - flex(33.percent) - margin(1.5.percent) - backgroundColor(Color("#b00020")) - } + style { backgroundColor(Color("#b00020")) } }) { Text("Delete Category") } From 3777b93bfcc8782ec6699136139b5645d77727ad Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 12:57:53 +0200 Subject: [PATCH 319/325] Remove Deprecated Screens --- .../hsfl/budgetBinder/presentation/Screen.kt | 21 ------------------- .../de/hsfl/budgetBinder/compose/Router.kt | 4 ---- 2 files changed, 25 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt index db1b855d..e520016e 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/Screen.kt @@ -25,25 +25,4 @@ sealed class Screen { object Login : Screen() object Register : Screen() object Dashboard : Screen() - - @Deprecated(message = "use sealed class Welcome") - object _Welcome : Screen() - @Deprecated(message = "use sealed class Settings") - object _Settings : Screen() - @Deprecated(message = "use sealed class Settings") - object SettingsChangeUserData : Screen() - @Deprecated(message = "use sealed class Category") - object CategorySummary : Screen() - @Deprecated(message = "use sealed class Category") - data class CategoryEdit(val id: Int) : Screen() - @Deprecated(message = "use sealed class Category") - object CategoryCreate : Screen() - @Deprecated(message = "use sealed class Category") - object CategoryCreateOnRegister : Screen() - @Deprecated(message = "use sealed class Category") - data class EntryOverview (val id: Int) : Screen() - @Deprecated(message = "use sealed class Entry") - data class EntryEdit (val id: Int): Screen() - @Deprecated(message = "use sealed class Entry") - data class EntryCreate (val categoryList :List): Screen() } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt index 880d84aa..d7b79080 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Router.kt @@ -33,10 +33,6 @@ fun Router() { is Screen.Category.Edit -> CategoryComponent() //Okay this seems to be necessary or CategoryComponent won't refresh, so no 'is Screen.Category -> ...' is Screen.Category.Create -> CategoryComponent() is Screen.Category.Summary -> CategoryComponent() - is Screen.CategorySummary, is Screen.CategoryEdit, is Screen.CategoryCreate, is Screen.CategoryCreateOnRegister - -> Text("Old Category") //CategoryComponent(screenState = screenState) - is Screen.EntryCreate, is Screen.EntryEdit, is Screen.EntryOverview - -> Text("Old Entry")//EntryComponent(screenState = screenState) else -> { Text("No known Screen! Check if the screen you're trying to reach is in the ScreenRouter") } From fda58854de94b3d3b52279b636bac20236903ace Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 12:59:53 +0200 Subject: [PATCH 320/325] Change Entry-LifeCycle from EntryComponent to each EntryView so onLaunch and onDispose will be invoked properly --- .../viewmodel/entry/EntryViewModel.kt | 8 +++---- .../screens/category/CategorySummaryView.kt | 1 - .../screens/entry/EntryComponent.kt | 23 +++---------------- .../screens/entry/EntryCreateView.kt | 15 ++++++++++++ .../screens/entry/EntryEditView.kt | 15 +++++++++--- .../screens/entry/EntryOverviewView.kt | 16 +++++++++++-- 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index 4b322539..9c81ccca 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -96,14 +96,12 @@ class EntryViewModel( when (routerFlow.state.value) { is Screen.Entry.Overview -> getById((routerFlow.state.value as Screen.Entry.Overview).id) is Screen.Entry.Edit -> getById((routerFlow.state.value as Screen.Entry.Edit).id) - else -> {} + else -> { + } } }, onDispose = { - when (routerFlow.state.value) { - is Screen.Entry.Overview, is Screen.Entry.Edit -> resetFlows() - else -> {} - } + resetFlows() }) } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt index 678511d8..1c3efb7e 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/category/CategorySummaryView.kt @@ -24,7 +24,6 @@ fun CategorySummaryView( LaunchedEffect(key1 = true) { viewModel.onEvent(CategorySummaryEvent.LifeCycle(LifecycleEvent.OnLaunch)) viewModel.eventFlow.collectLatest {} - console.log("CategorySummary Came to Life!") } //Webpage Content diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryComponent.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryComponent.kt index 8d6f4cc0..a2915e71 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryComponent.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryComponent.kt @@ -20,26 +20,8 @@ fun EntryComponent() { val viewModel: EntryViewModel by di.instance() val routerFlow: RouterFlow by di.instance() val screenState = routerFlow.state.collectAsState() - val loadingState = remember { mutableStateOf(false) } - //LifeCycle - LaunchedEffect(Unit) { - viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnLaunch)) - viewModel.eventFlow.collectLatest { event -> - when (event) { - is UiEvent.ShowLoading -> loadingState.value = true - is UiEvent.HideSuccess -> loadingState.value = false - else -> loadingState.value = false - } - } - } - DisposableEffect(Unit) { - onDispose { - viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnDispose)) - } - } - //Webpage content NavBar {} MainFlexContainer { @@ -60,10 +42,11 @@ fun EntryComponent() { } is Screen.Entry.Edit -> { EntryEditView( - onEditButton = { viewModel.onEvent(EntryEvent.OnEditEntry)} + onEditButton = { viewModel.onEvent(EntryEvent.OnEditEntry) } ) } - else -> {} + else -> { + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt index 58c2841b..6e40ff82 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt @@ -3,9 +3,12 @@ package de.hsfl.budgetBinder.screens.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.* import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent +import de.hsfl.budgetBinder.presentation.event.UiEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di +import kotlinx.coroutines.flow.collectLatest import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.* import org.jetbrains.compose.web.css.* @@ -29,6 +32,18 @@ fun EntryCreateView( //Data val categoryList by viewModel.categoryListState.collectAsState() + //LifeCycle + LaunchedEffect(Unit) { + viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnLaunch)) + } + DisposableEffect(Unit) { + onDispose { + viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnDispose)) + } + } + + //Webpage Content + H1(attrs = { classes(AppStylesheet.h1) }) { Text("Create new Entry") } Form(attrs = { this.addEventListener("submit") { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt index cb143c05..6ef110a2 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt @@ -3,6 +3,7 @@ package de.hsfl.budgetBinder.screens.entry import androidx.compose.runtime.* import de.hsfl.budgetBinder.compose.ChooseCategoryMenu import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di @@ -32,10 +33,18 @@ fun EntryEditView( val amountSign by viewModel.amountSignState.collectAsState() //Data val categoryList by viewModel.categoryListState.collectAsState() - val entry by viewModel.selectedEntryState.collectAsState() - console.log("unser Entry ist $entry") - console.log("$entryNameTextField und $entryAmountTextField und $entryCategoryIDTextField") + //LifeCycle + LaunchedEffect(Unit) { + viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnLaunch)) + } + DisposableEffect(Unit) { + onDispose { + viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnDispose)) + } + } + + //Webpage Content H1(attrs = { classes(AppStylesheet.h1) }) { Text("Edit Entry") } Form(attrs = { this.addEventListener("submit") { diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt index 2714963c..364d605d 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt @@ -4,6 +4,8 @@ import androidx.compose.runtime.* import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.event.LifecycleEvent +import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel import di import org.jetbrains.compose.web.css.* @@ -22,10 +24,20 @@ fun EntryOverviewView( val viewModel: EntryViewModel by di.instance() //Data val entry by viewModel.selectedEntryState.collectAsState() - console.log("Our Entry is $entry") val deleteDialog by viewModel.dialogState.collectAsState() - H1(attrs = { classes(AppStylesheet.h1) }) { Text(" Entry") } + //LifeCycle + LaunchedEffect(Unit) { + viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnLaunch)) + } + DisposableEffect(Unit) { + onDispose { + viewModel.onEvent(EntryEvent.LifeCycle(LifecycleEvent.OnDispose)) + } + } + + //Webpage Content + H1(attrs = { classes(AppStylesheet.h1) }) { Text(" Entry") } EntryOverview( entry, deleteDialog, From afa69f2d7f88d4fc53d20dd8caa0ead5d6a4e6b1 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 13:31:25 +0200 Subject: [PATCH 321/325] Add "No Category" to category choose for entry create and edit --- .../de/hsfl/budgetBinder/common/Category.kt | 8 ++++++++ .../de/hsfl/budgetBinder/compose/Composables.kt | 15 +++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/budget-binder-common/src/commonMain/kotlin/de/hsfl/budgetBinder/common/Category.kt b/budget-binder-common/src/commonMain/kotlin/de/hsfl/budgetBinder/common/Category.kt index 876c2d74..9874a2ae 100644 --- a/budget-binder-common/src/commonMain/kotlin/de/hsfl/budgetBinder/common/Category.kt +++ b/budget-binder-common/src/commonMain/kotlin/de/hsfl/budgetBinder/common/Category.kt @@ -72,4 +72,12 @@ data class Category( val image: Image? = null, val budget: Float? = null ) + @Serializable + data class Nullable( + val id: Int?, + val name: String, + val color: String, + val image: Image, + val budget: Float + ) } \ No newline at end of file diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 0fc8ec2f..607ae65c 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -32,7 +32,7 @@ fun MainFlexContainer(content: @Composable () -> Unit) { content() } } - Div (attrs = { classes(AppStylesheet.pufferFlexContainer)}) + Div(attrs = { classes(AppStylesheet.pufferFlexContainer) }) } } @@ -180,7 +180,6 @@ fun CategoryImagesToImageList( } - @Composable fun DeleteDialog( hidden: Boolean, @@ -294,10 +293,14 @@ fun ChooseCategoryMenu( selectedCategory: Int?, getCategoryId: (Int?) -> Unit ) { + var categoryListWN = listOf(Category.Nullable(null, "No Category", "ffffff", Category.Image.DEFAULT, 0f)) + for (category in categoryList) { + categoryListWN = categoryListWN + (Category.Nullable(category.id, category.name, category.color, category.image, category.budget)) + } console.log(categoryList) - var choseCat = categoryList[0] + var choseCat = categoryListWN[0] - for (category in categoryList) { + for (category in categoryListWN) { if (category.id == selectedCategory) { choseCat = category break @@ -330,14 +333,14 @@ fun ChooseCategoryMenu( attr("aria-orientation", "vertical") attr("tabindex", "-1") }) { - for (category in categoryList) { + for (category in categoryListWN) { Li(attrs = { classes("mdc-list-item") attr("role", "menuitem") onClick { chosenCategory = category; getCategoryId(category.id) } }) { Span(attrs = { classes("mdc-list-item__ripple") }) { } - Span(attrs = { classes(AppStylesheet.moneyText)}) { Text(category.name) } + Span(attrs = { classes(AppStylesheet.moneyText) }) { Text(category.name) } } } } From ed9a7241fae3d0d672b861217124ec2200a4fa3c Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 13:46:48 +0200 Subject: [PATCH 322/325] Add "Category: " before category menu in create and edit entry --- .../de/hsfl/budgetBinder/compose/Composables.kt | 3 --- .../screens/entry/EntryCreateView.kt | 11 +++++++++-- .../budgetBinder/screens/entry/EntryEditView.kt | 16 ++++++++++------ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt index 607ae65c..3dd2ebde 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/Composables.kt @@ -5,13 +5,10 @@ import de.hsfl.budgetBinder.common.Category import androidx.compose.runtime.Composable import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.CategoryImageToIcon -import org.jetbrains.compose.web.ExperimentalComposeWebSvgApi import org.jetbrains.compose.web.attributes.ButtonType import org.jetbrains.compose.web.attributes.type import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* -import org.jetbrains.compose.web.svg.Circle -import org.jetbrains.compose.web.svg.Svg /*Main Container for every mayor layout*/ diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt index 6e40ff82..c92de940 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryCreateView.kt @@ -202,8 +202,15 @@ fun EntryCreateView( } } Div(attrs = { classes(AppStylesheet.flex50) }) { - ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> - viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Text("Category: ") + ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> + viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt index 6ef110a2..8d9f4a73 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryEditView.kt @@ -203,12 +203,16 @@ fun EntryEditView( Label(forId = "checkbox-1") { Text("repeat") } } } - Div(attrs = { - classes(AppStylesheet.flex50) - style { alignItems(AlignItems.Stretch) } - }) { - ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> - viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) + Div(attrs = { classes(AppStylesheet.flex50) }) { + Div( + attrs = { + classes(AppStylesheet.margin) + } + ) { + Text("Category: ") + ChooseCategoryMenu(categoryList, entryCategoryIDTextField) { id -> + viewModel.onEvent(EntryEvent.EnteredCategoryID(id)) + } } } } From 3daae548f3864e570480d2d62ea9b49505786312 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 14:05:58 +0200 Subject: [PATCH 323/325] Make Logout button red --- .../src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt index 61cdebde..46a9f651 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/compose/NavBar.kt @@ -5,6 +5,8 @@ import de.hsfl.budgetBinder.compose.theme.AppStylesheet import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerEvent import de.hsfl.budgetBinder.presentation.viewmodel.navdrawer.NavDrawerViewModel import di +import org.jetbrains.compose.web.css.Color +import org.jetbrains.compose.web.css.backgroundColor import org.jetbrains.compose.web.dom.* import org.kodein.di.instance @@ -111,6 +113,7 @@ fun NavBar(content: @Composable () -> Unit) { "mdc-top-app-bar__navigation-icon" ) onClick { viewModel.onEvent(NavDrawerEvent.OnLogout) } + style { backgroundColor(Color("#b00020")) } } ) { Span( From aa9ba12258e64699c5b3eb4d7610ebd9d6bd2183 Mon Sep 17 00:00:00 2001 From: Pascal Friedrichsen Date: Fri, 24 Jun 2022 14:37:45 +0200 Subject: [PATCH 324/325] Fix Loading showing even when it's not loading, add ShowSuccess to EntryViewModels create edit and delete --- .../viewmodel/entry/EntryViewModel.kt | 15 ++++++++++++--- .../src/jsMain/kotlin/main.kt | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt index 9c81ccca..82ca8bdb 100644 --- a/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt +++ b/budget-binder-multiplatform-app/src/commonMain/kotlin/de/hsfl/budgetBinder/presentation/viewmodel/entry/EntryViewModel.kt @@ -131,21 +131,30 @@ class EntryViewModel( private fun create(entry: Entry.In) = scope.launch { entryUseCases.createNewEntryUseCase(entry).collect { it.handleDataResponse( - routerFlow = routerFlow, onSuccess = { routerFlow.navigateTo(Screen.Dashboard) }) + routerFlow = routerFlow, onSuccess = { + routerFlow.navigateTo(Screen.Dashboard) + eventFlow.emit(UiEvent.ShowSuccess("Entry successfully created")) + }) } } private fun update(entry: Entry.Patch, id: Int) = scope.launch { entryUseCases.changeEntryByIdUseCase(entry, id).collect { it.handleDataResponse( - routerFlow = routerFlow, onSuccess = { routerFlow.navigateTo(Screen.Dashboard) }) + routerFlow = routerFlow, onSuccess = { + routerFlow.navigateTo(Screen.Dashboard) + eventFlow.emit(UiEvent.ShowSuccess("Entry successfully updated")) + }) } } private fun delete(id: Int) = scope.launch { entryUseCases.deleteEntryByIdUseCase(id).collect { it.handleDataResponse( - routerFlow = routerFlow, onSuccess = { routerFlow.navigateTo(Screen.Dashboard) }) + routerFlow = routerFlow, onSuccess = { + routerFlow.navigateTo(Screen.Dashboard) + eventFlow.emit(UiEvent.ShowSuccess("Entry successfully deleted")) + }) } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt index 6f034c21..bd2a4a9b 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt @@ -26,7 +26,7 @@ val di = kodein(ktorEngine = Js.create()) @Composable fun App() = withDI(di) { val uiEventFlow: UiEventSharedFlow by di.instance() - val loadingState = remember { mutableStateOf(false) } + val loadingState = remember { mutableStateOf(true) } val snackBarText = remember { mutableStateOf("") } val snackBarHidden = remember { mutableStateOf(true) } LaunchedEffect(key1 = true) { From a65f9a201687cba3a8d9df8d3fbb3e8298419095 Mon Sep 17 00:00:00 2001 From: Dominik Heckner Date: Fri, 24 Jun 2022 14:41:38 +0200 Subject: [PATCH 325/325] Add category, category icon and repeat to EntryOverviewView --- .../screens/entry/EntryOverviewView.kt | 30 +++++++++++++++++-- .../src/jsMain/kotlin/main.kt | 1 - 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt index 364d605d..0bc7fffc 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/de/hsfl/budgetBinder/screens/entry/EntryOverviewView.kt @@ -1,9 +1,11 @@ package de.hsfl.budgetBinder.screens.entry import androidx.compose.runtime.* +import de.hsfl.budgetBinder.common.Category import de.hsfl.budgetBinder.common.Entry import de.hsfl.budgetBinder.compose.DeleteDialog import de.hsfl.budgetBinder.compose.theme.AppStylesheet +import de.hsfl.budgetBinder.presentation.CategoryImageToIcon import de.hsfl.budgetBinder.presentation.event.LifecycleEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryEvent import de.hsfl.budgetBinder.presentation.viewmodel.entry.EntryViewModel @@ -25,6 +27,7 @@ fun EntryOverviewView( //Data val entry by viewModel.selectedEntryState.collectAsState() val deleteDialog by viewModel.dialogState.collectAsState() + val categoryList by viewModel.categoryListState.collectAsState() //LifeCycle LaunchedEffect(Unit) { @@ -40,6 +43,7 @@ fun EntryOverviewView( H1(attrs = { classes(AppStylesheet.h1) }) { Text(" Entry") } EntryOverview( entry, + categoryList, deleteDialog, onEditButton, onDeleteButton, @@ -52,6 +56,7 @@ fun EntryOverviewView( @Composable fun EntryOverview( entry: Entry, + categoryList: List, deleteDialog: Boolean, onEditButton: () -> Unit, onDeleteButton: () -> Unit, @@ -74,9 +79,28 @@ fun EntryOverview( Div(attrs = { classes("mdc-typography--headline4", AppStylesheet.text) }) { Text(entry.name) } - Div(attrs = { - classes("mdc-typography--headline6", AppStylesheet.text) - }) { Text("Amount: ${entry.amount}€") } + Div(attrs = { classes(AppStylesheet.flexContainer) }) { + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text, AppStylesheet.buttonOverview) + }) { + var categoryName = "No Category" + var categoryIcon = Category.Image.DEFAULT + for (category in categoryList) { + if (entry.category_id == category.id) { + categoryName = category.name + categoryIcon = category.image + } + } + Text("Category: $categoryName") + CategoryImageToIcon(categoryIcon) + } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text, AppStylesheet.buttonOverview) + }) { Text("Amount: ${entry.amount}€") } + Div(attrs = { + classes("mdc-typography--headline6", AppStylesheet.text, AppStylesheet.buttonOverview) + }) { Text("Repeat: " + if (entry.repeat) "Yes" else "No") } + } } } } diff --git a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt index 6f034c21..c6b10d59 100644 --- a/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt +++ b/budget-binder-multiplatform-app/src/jsMain/kotlin/main.kt @@ -54,7 +54,6 @@ fun App() = withDI(di) { } ) } - FeedbackSnackbar(snackBarText.value, snackBarHidden.value) { snackBarHidden.value = true }