From 18d53d0c277524d41392e0e843b8febe65689ff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20T=C3=B3th?= <tothmiklostibor@gmail.com> Date: Tue, 1 Mar 2022 14:48:48 +0100 Subject: [PATCH] Google Sheets progress --- src/jsMain/kotlin/Main.kt | 73 +--------------- src/jsMain/kotlin/gapi/Gapi.kt | 31 ++++++- src/jsMain/kotlin/pontozas.kt | 125 ++++++++++++++++++++++++++++ src/jsMain/kotlin/ui/Modal.kt | 8 +- src/jsMain/kotlin/ui/Params.kt | 37 -------- src/jsMain/kotlin/ui/SheetsModal.kt | 69 ++++++++------- src/jsMain/kotlin/ui/Utils.kt | 30 +++++++ 7 files changed, 227 insertions(+), 146 deletions(-) create mode 100644 src/jsMain/kotlin/pontozas.kt delete mode 100644 src/jsMain/kotlin/ui/Params.kt create mode 100644 src/jsMain/kotlin/ui/Utils.kt diff --git a/src/jsMain/kotlin/Main.kt b/src/jsMain/kotlin/Main.kt index c044e3b..32ec215 100644 --- a/src/jsMain/kotlin/Main.kt +++ b/src/jsMain/kotlin/Main.kt @@ -2,6 +2,7 @@ import androidx.compose.runtime.* import gapi.initGapi import gapi.loadGapi import kotlinx.browser.document +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.jetbrains.compose.web.attributes.disabled import org.jetbrains.compose.web.dom.* @@ -12,76 +13,6 @@ import ui.State fun main() { - val row = document.querySelector("#content-main > div.uk-clearfix.uk-margin-bottom") - ?: throw Error("couldn't find button row") - val rootDiv = document.createElement("div") - rootDiv.id = "kemence-root" - row.appendChild(rootDiv) - - document.title = document.title.replace("PéK", "PéK \uD83D\uDC68\u200D\uD83C\uDF73") - - renderComposable(root = rootDiv) { - var google by remember { mutableStateOf(false) } - var state by remember { mutableStateOf<State>(Ready) } - val scope = rememberCoroutineScope() - scope.launch { - loadGapi() - initGapi() - google = true - } - - divFloatRight { - val magicId = "csv-magic" - Button({ - classes("uk-button", "uk-button-small", "uk-button-success") - attr("data-uk-ui.modal", "{ target: '#$magicId' }") - if (state != Ready) - disabled() - }){ - var txt = "..." - val curState = state - if (curState == Ready) { - txt = "CSV import \uD83D\uDC68\u200D\uD83C\uDF73" - } else if (curState is ImportInProgress) { - val progress = (curState.progress * 100.0).format() - txt = "Importálás ($progress%)" - } - - Text(txt) - } - Div({ - id(magicId) - classes("uk-ui.modal") - }) { - csvModal { state = it } - } - } - divFloatRight { - val magicId = "google-magic" - Button({ - classes("uk-button", "uk-button-small", "uk-button-success") - attr("data-uk-ui.modal", "{ target: '#$magicId' }") - if (state != Ready || !google) - disabled() - }){ - var txt = "..." - val curState = state - if (curState == Ready) { - txt = "Google Sheets import \uD83D\uDC68\u200D\uD83C\uDF73" - } else if (curState is ImportInProgress) { - val progress = (curState.progress * 100.0).format() - txt = "Importálás ($progress%)" - } - - Text(txt) - } - Div({ - id(magicId) - classes("uk-ui.modal") - }) { - sheetsModal { state = it } - } - } - } + pontozas() } diff --git a/src/jsMain/kotlin/gapi/Gapi.kt b/src/jsMain/kotlin/gapi/Gapi.kt index 92b6da6..b4ecbef 100644 --- a/src/jsMain/kotlin/gapi/Gapi.kt +++ b/src/jsMain/kotlin/gapi/Gapi.kt @@ -1,6 +1,8 @@ package gapi +import kotlinx.coroutines.delay import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine object authObj: client.AuthType { @@ -17,7 +19,13 @@ fun listenForLoginEvents(callback: (Boolean) -> Unit) { } suspend fun loadGapi() = suspendCoroutine<Unit> { cont -> - gapi.load(apiName = "gapi.client:gapi.auth2") { cont.resume(Unit) } + try { + gapi.load(apiName = "client:auth2") { cont.resume(Unit) } + } catch (e: dynamic) { + cont.resumeWithException( + e as? Throwable ?: Error("$e") + ) + } } private fun handleLoginEvent(isSignedIn: Boolean) { @@ -46,6 +54,14 @@ suspend fun initGapi() = suspendCoroutine<Unit> { cont -> gapi.auth2.getAuthInstance().isSignedIn.get() } + username = { + gapi.auth2.getAuthInstance().currentUser.get().getBasicProfile().getName() + } + + email = { + gapi.auth2.getAuthInstance().currentUser.get().getBasicProfile().getEmail() + } + handleLoginEvent(isSignedIn()) }, { error: Throwable -> println(error) @@ -54,6 +70,13 @@ suspend fun initGapi() = suspendCoroutine<Unit> { cont -> Unit } -var logIn: () -> Unit = { throw Error("gapi.getGapi has not been initialized yet") } -var logOut: () -> Unit = { throw Error("gapi.getGapi has not been initialized yet") } -var isSignedIn: () -> Boolean = { false } \ No newline at end of file +var logIn: () -> Unit = { throw Error("Gapi has not been initialized yet") } + private set +var logOut: () -> Unit = { throw Error("Gapi has not been initialized yet") } + private set +var isSignedIn: () -> Boolean = { false } + private set +var username: () -> String = { "" } + private set +var email: () -> String = { "" } + private set \ No newline at end of file diff --git a/src/jsMain/kotlin/pontozas.kt b/src/jsMain/kotlin/pontozas.kt new file mode 100644 index 0000000..901be99 --- /dev/null +++ b/src/jsMain/kotlin/pontozas.kt @@ -0,0 +1,125 @@ +import androidx.compose.runtime.* +import gapi.initGapi +import gapi.loadGapi +import kotlinx.browser.document +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import org.jetbrains.compose.web.attributes.disabled +import org.jetbrains.compose.web.dom.Button +import org.jetbrains.compose.web.dom.Div +import org.jetbrains.compose.web.dom.Text +import org.jetbrains.compose.web.renderComposable +import org.w3c.dom.HTMLStyleElement +import processing.format +import ui.* +import ui.State + +fun pontozas() { + val row = document.querySelector("#content-main > div.uk-clearfix.uk-margin-bottom") + ?: throw Error("couldn't find button row") + val rootDiv = document.createElement("div") + rootDiv.id = "kemence-root" + row.appendChild(rootDiv) + + fixNameSpacing() + + document.title = document.title.replace("PéK", "PéK \uD83D\uDC68\u200D\uD83C\uDF73") + + renderComposable(root = rootDiv) { + var google by remember { mutableStateOf(false) } + var state by remember { mutableStateOf<State>(Ready) } + val scope = rememberCoroutineScope() + scope.launch { + while (true) { + try { + loadGapi() + break + } catch (e: Throwable) { + console.error("Error loading Google API: $e, trying again...") + delay(100) + } + } + initGapi() + google = true + } + + divFloatRight { + val magicId = "csv-magic" + Button({ + classes("uk-button", "uk-button-small", "uk-button-success") + attr("data-uk-modal", "{ target: '#$magicId' }") + if (state != Ready) + disabled() + }){ + var txt = "..." + val curState = state + if (curState == Ready) { + txt = "CSV import \uD83D\uDC68\u200D\uD83C\uDF73" + } else if (curState is ImportInProgress) { + val progress = (curState.progress * 100.0).format() + txt = "Importálás ($progress%)" + } + + Text(txt) + } + Div({ + id(magicId) + classes("uk-modal") + }) { + csvModal { state = it } + } + } + divFloatRight { + val magicId = "google-magic" + Button({ + classes("uk-button", "uk-button-small", "uk-button-success") + attr("data-uk-modal", "{ target: '#$magicId' }") + if (state != Ready || !google) + disabled() + }){ + var txt = "..." + val curState = state + if (curState == Ready) { + txt = "Google Sheets import \uD83D\uDC68\u200D\uD83C\uDF73" + } else if (curState is ImportInProgress) { + val progress = (curState.progress * 100.0).format() + txt = "Importálás ($progress%)" + } + + Text(txt) + } + Div({ + id(magicId) + classes("uk-modal") + }) { + sheetsModal { state = it } + } + } + } +} + +fun fixNameSpacing() { + val tbody = document.querySelector("#points-table > tbody") + val tfoot = document.querySelector("#points-table > tfoot") + if ( + tbody == null || + tfoot == null + ) throw Error("Not in pontozo view") + + val children = tbody.childElementCount + tfoot.childElementCount + val height = tbody.clientHeight.toDouble() + tfoot.clientHeight.toDouble() + + val liHeight = height/children - 10 // padding + + val style = document.createElement("style") as HTMLStyleElement + style.type = "text/css" + + style.appendChild(document.createTextNode(""" + #name-list > li { + height: ${liHeight}px !important; + } + """.trimIndent())) + + document.head!!.appendChild(style) +} + diff --git a/src/jsMain/kotlin/ui/Modal.kt b/src/jsMain/kotlin/ui/Modal.kt index aaf1b6b..4cb8888 100644 --- a/src/jsMain/kotlin/ui/Modal.kt +++ b/src/jsMain/kotlin/ui/Modal.kt @@ -2,7 +2,6 @@ package ui import pekstuff.PekTable import androidx.compose.runtime.* -import clear import kotlinx.browser.document import kotlinx.coroutines.launch import org.jetbrains.compose.web.attributes.disabled @@ -11,6 +10,7 @@ import org.jetbrains.compose.web.css.color import org.jetbrains.compose.web.css.rgb import org.jetbrains.compose.web.dom.* import org.w3c.dom.HTMLElement +import pekstuff.clear interface ModalType { val title: String @@ -21,12 +21,12 @@ interface ModalType { @Composable fun modal(type: ModalType, setState: (State) -> Unit) { Div({ - classes("uk-ui.modal-dialog", "uk-text-justify") + classes("uk-modal-dialog", "uk-text-justify") }) { - val closeId = "kemence${type::class.simpleName}-ui.modal-close" + val closeId = "kemence${type::class.simpleName}-modal-close" A(attrs = { id(closeId) - classes("uk-ui.modal-close", "uk-close") + classes("uk-modal-close", "uk-close") }) { } H2 { Text(type.title) diff --git a/src/jsMain/kotlin/ui/Params.kt b/src/jsMain/kotlin/ui/Params.kt deleted file mode 100644 index 7aee1f4..0000000 --- a/src/jsMain/kotlin/ui/Params.kt +++ /dev/null @@ -1,37 +0,0 @@ -package ui - -import androidx.compose.runtime.* -import org.jetbrains.compose.web.dom.* - -@Composable -fun inputWithLabel( - name: String, - value: String, - updated: (String) -> Unit, -) { - Tr { - val id = "kemence-${id++}" - Td({ - style { - property("vertical-align", "middle") - } - }) { - Label(forId = id, { - classes("uk-form-label") - }) { - Text(name) - } - } - Td { - TextInput(value) { - id(id) - classes("uk-input", "uk-input-width-1-1") - onInput { - updated(it.value) - } - } - } - } -} - -var id = 0 diff --git a/src/jsMain/kotlin/ui/SheetsModal.kt b/src/jsMain/kotlin/ui/SheetsModal.kt index c40ab28..fe9f4c1 100644 --- a/src/jsMain/kotlin/ui/SheetsModal.kt +++ b/src/jsMain/kotlin/ui/SheetsModal.kt @@ -2,12 +2,9 @@ package ui import datasources.GSheet import androidx.compose.runtime.* -import gapi.isSignedIn +import gapi.* import kotlinx.browser.document import kotlinx.coroutines.launch -import gapi.listenForLoginEvents -import gapi.logIn -import gapi.logOut import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.disabled import org.jetbrains.compose.web.dom.* @@ -26,8 +23,14 @@ private object SheetsModal: ModalType { val scope = rememberCoroutineScope() var signedIn by remember { mutableStateOf(isSignedIn()) } + var username by remember { mutableStateOf(username()) } + var email by remember { mutableStateOf(email()) } SideEffect { listenForLoginEvents { signedIn = it } + scope.launch { + username = username() + email = email() + } } var sheet by remember { mutableStateOf<GSheet?>(null) } @@ -38,40 +41,46 @@ private object SheetsModal: ModalType { else "" ) - Button({ - if (signedIn) { - classes("uk-button", "uk-button-danger") - } else { - classes("uk-button", "uk-button-primary") - } - onClick { - if(signedIn) { - logOut() + withLabel( + if (signedIn) "$username ($email)" + else "Google Fiók" + ) { id -> + Button({ + id(id) + if (signedIn) { + classes("uk-button", "uk-button-danger") } else { - logIn() + classes("uk-button", "uk-button-primary") } + onClick { + if (signedIn) { + logOut() + } else { + logIn() + } + } + }) { + Text( + if (signedIn) { + "Kijelentkezés" + } else { + "Bejelentkezés" + } + ) } - }) { - Text( - if(signedIn) { "Kijelentkezés" } else { "Bejelentkezés" } - ) } Br {} - val inputId = "kemence-sheet-input" - Label(inputId, { - classes("form-label-required", "uk-margin-right") - }) { - Text("Google Sheet URL") - } var sheetUrl by remember { mutableStateOf("") } - Input(type = InputType.Text, attrs = { - id(inputId) - classes("uk-input") - onChange { sheetUrl = it.value } - value(sheetUrl) - }) + withLabel("Google Sheet URL") { id -> + Input(type = InputType.Text, attrs = { + id(id) + classes("uk-input") + onChange { sheetUrl = it.value } + value(sheetUrl) + }) + } Hr { } divFloatRight { Button({ diff --git a/src/jsMain/kotlin/ui/Utils.kt b/src/jsMain/kotlin/ui/Utils.kt new file mode 100644 index 0000000..f6073c0 --- /dev/null +++ b/src/jsMain/kotlin/ui/Utils.kt @@ -0,0 +1,30 @@ +package ui + +import androidx.compose.runtime.* +import org.jetbrains.compose.web.dom.* + +@Composable +fun withLabel( + label: String, + content: @Composable (id: String) -> Unit, +) { + Tr { + val id = remember { "kemence-${id++}" } + Td({ + style { + property("vertical-align", "middle") + } + }) { + Label(forId = id, { + classes("uk-form-label", "uk-margin-right") + }) { + Text(label) + } + } + Td { + content(id) + } + } +} + +var id = 0 -- GitLab