diff --git a/composeApp/src/androidMain/kotlin/org/comixedproject/variant/MainActivityScreen.kt b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/MainActivityScreen.kt index 288a737..adebd71 100644 --- a/composeApp/src/androidMain/kotlin/org/comixedproject/variant/MainActivityScreen.kt +++ b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/MainActivityScreen.kt @@ -57,22 +57,27 @@ fun MainActivityScreen( composable(Screen.ServerAdd.route) { EditServer( serverTemplate, - onSave = { name, url, username, password -> + onSave = { name, url, username, password, serverColor -> mainViewModel.createServer( name, url, username, - password + password, + serverColor ) navController.navigate(Screen.ServerList.route) }, onCancel = { navController.navigate(Screen.ServerList.route) }) } composable(Screen.ServerEdit.route) { EditServer(mainViewModel.currentServer!!, - onSave = { name, url, username, password -> + onSave = { name, url, username, password, serverColor -> mainViewModel.updateServer( mainViewModel.currentServer!!.copy( - name = name, url = url, username = username, password = password + name = name, + url = url, + username = username, + password = password, + serverColor = serverColor ) ) navController.navigate(Screen.ServerList.route) diff --git a/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/EditServer.kt b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/EditServer.kt index 3d88770..245f8dd 100644 --- a/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/EditServer.kt +++ b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/EditServer.kt @@ -65,7 +65,7 @@ import org.comixedproject.variant.model.Server @Composable fun EditServer( entry: Server, - onSave: (String, String, String, String) -> Unit, + onSave: (String, String, String, String, String) -> Unit, onCancel: () -> Unit ) { Surface( @@ -85,6 +85,7 @@ fun EditServer( var url by remember { mutableStateOf(entry.url) } var username by remember { mutableStateOf(entry.username) } var password by remember { mutableStateOf(entry.password) } + var serverColor by remember { mutableStateOf(entry.serverColor) } var passwordVisible by remember { mutableStateOf(false) } var isValid by remember { mutableStateOf(false) } @@ -132,6 +133,11 @@ fun EditServer( Icon(imageVector = image, "") } }) + ServerColorPicker( + currentColor = serverColor, + onColorPicked = { input -> + serverColor = input.hex + }) Spacer( modifier = Modifier.weight(1.0f) ) @@ -144,7 +150,7 @@ fun EditServer( } Spacer(modifier = Modifier.size(8.dp)) Button(onClick = { - onSave(name, url, username, password) + onSave(name, url, username, password, serverColor) }) { Text(text = stringResource(id = R.string.save_button)) } @@ -170,7 +176,7 @@ fun EditServerAndroidPreview() { "admin@comixedproject.org", "password" ), - onSave = { _, _, _, _ -> {} }, onCancel = {} + onSave = { _, _, _, _, _ -> {} }, onCancel = {} ) } } \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/Extensions.kt b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/Extensions.kt new file mode 100644 index 0000000..d9d0435 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/Extensions.kt @@ -0,0 +1,29 @@ +/* + * Variant - A digital comic book reading application for iPad, Android, and desktops. + * Copyright (C) 2023, The ComiXed Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package org.comixedproject.variant.ui.server + +import androidx.compose.ui.graphics.Color +import org.comixedproject.variant.model.ServerColorOption + +/** + * Converts a hex string to a color. + */ +fun ServerColorOption.Companion.fromHex(hex: String): Color { + return Color(android.graphics.Color.parseColor(hex)) +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerColor.kt b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerColor.kt new file mode 100644 index 0000000..eb64183 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerColor.kt @@ -0,0 +1,65 @@ +/* + * Variant - A digital comic book reading application for iPad, Android, and desktops. + * Copyright (C) 2023, The ComiXed Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package org.comixedproject.variant.ui.server + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import org.comixedproject.variant.VariantTheme + + +/** + * Displays a color indicator next to the name of a server. + * + * @author Darryl L. Pierce + */ +@Composable +fun ServerColor( + modifier: Modifier = Modifier, + color: Color, + size: Dp, + border: Dp +) { + Box( + modifier = modifier + .size(size) + .clip(CircleShape) + .background(color) + .border(BorderStroke(border, SolidColor(Color.Black)), CircleShape) + ) +} + +@Preview +@Composable +fun ServerColorPreview() { + VariantTheme { + ServerColor(color = Color.Blue, size = 40.dp, border = 2.dp) + } +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerColorOption.kt b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerColorOption.kt new file mode 100644 index 0000000..f90db4f --- /dev/null +++ b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerColorOption.kt @@ -0,0 +1,67 @@ +package org.comixedproject.variant.ui.server + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import org.comixedproject.variant.model.ServerColorOption + +@Composable +fun ServerColorOption( + color: ServerColorOption, + currentColor: String, + onColorPicked: (ServerColorOption) -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable( + onClick = { + onColorPicked(color) + } + ) + ) { + val fontWeight = if (currentColor == color.hex) FontWeight.Bold else FontWeight.Normal + ServerColor( + modifier = Modifier.padding(10.dp), + color = ServerColorOption.fromHex(color.hex), + size = 40.dp, + border = 2.dp + ) + Text( + text = color.name, + fontWeight = fontWeight, + fontSize = 22.sp, + modifier = Modifier + .padding(2.dp) + .align(Alignment.CenterVertically) + ) + + } +} + +@Preview +@Composable +fun ServerColorItemPreview() { + ServerColorOption( + color = ServerColorOption.COLORS[0], + ServerColorOption.COLORS[1].hex, + onColorPicked = {}) +} + +@Preview +@Composable +fun ServerColorItemCurrentPreview() { + ServerColorOption( + color = ServerColorOption.COLORS[0], + ServerColorOption.COLORS[0].hex, + onColorPicked = {}) +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerColorPicker.kt b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerColorPicker.kt new file mode 100644 index 0000000..05c0568 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerColorPicker.kt @@ -0,0 +1,56 @@ +/* + * Variant - A digital comic book reading application for iPad, Android, and desktops. + * Copyright (C) 2023, The ComiXed Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package org.comixedproject.variant.ui.server + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import org.comixedproject.variant.VariantTheme +import org.comixedproject.variant.model.ServerColorOption + +@Composable +fun ServerColorPicker( + modifier: Modifier = Modifier, + currentColor: String, + onColorPicked: (ServerColorOption) -> Unit +) { + LazyRow( + modifier = Modifier + .fillMaxWidth() + ) { + items(ServerColorOption.COLORS.size) { itemIndex -> + val color = ServerColorOption.COLORS[itemIndex] + ServerColorOption( + color = color, + currentColor = currentColor, + onColorPicked = onColorPicked + ) + } + } +} + +@Preview +@Composable +fun ServerColorPickerPreview() { + VariantTheme { + ServerColorPicker(currentColor = ServerColorOption.COLORS[0].hex, onColorPicked = {}) + } +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerListEntry.kt b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerListEntry.kt index d2b74b7..73f238c 100644 --- a/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerListEntry.kt +++ b/composeApp/src/androidMain/kotlin/org/comixedproject/variant/ui/server/ServerListEntry.kt @@ -24,8 +24,6 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -47,6 +45,7 @@ import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime import org.comixedproject.variant.data.IdGenerator import org.comixedproject.variant.model.Server +import org.comixedproject.variant.model.ServerColorOption /** * Displays a single server in the list of servers. @@ -63,55 +62,57 @@ fun ServerListEntry(entry: Server, onClick: (Server) -> Unit) { .background(MaterialTheme.colorScheme.background) .padding(8.dp) ) { - Box( - modifier = Modifier - .fillMaxSize() - .height(120.dp) - .background(Color.White) - .padding(8.dp) + Card( + shape = RoundedCornerShape(8.dp), + border = BorderStroke(1.dp, Color.Gray), + modifier = Modifier.fillMaxWidth() ) { - Card( - shape = RoundedCornerShape(8.dp), - border = BorderStroke(1.dp, Color.Gray), - modifier = Modifier.fillMaxWidth() - ) { - Box( - modifier = - Modifier - .background(color = Color.White) - .padding(16.dp) - ) + Box( + modifier = + Modifier + .background(color = Color.White) + .padding(16.dp) + ) + { + Row(modifier = Modifier.fillMaxWidth()) { - Row(modifier = Modifier.fillMaxWidth()) - { - Column(horizontalAlignment = Alignment.Start) { - Text( - text = entry.name, - style = TextStyle( - color = Color.Black, - fontWeight = FontWeight.Bold, - fontSize = 20.sp - ) + ServerColor( + modifier = Modifier + .align(Alignment.CenterVertically) + .padding(8.dp), + color = ServerColorOption.fromHex(entry.serverColor), + size = 40.dp, + border = 1.dp + ) + Column( + horizontalAlignment = Alignment.Start + ) { + Text( + text = entry.name, + style = TextStyle( + color = Color.Black, + fontWeight = FontWeight.Bold, + fontSize = 20.sp ) - if (entry.lastAccessedOn != null) { - Text( - entry.lastAccessedOn!!.toString(), - style = TextStyle( - color = Color.Black, - fontWeight = FontWeight.Bold, - fontSize = 14.sp - ) - ) - } - Spacer(modifier = Modifier.weight(1.0f)) + ) + Text(text = entry.url) + if (entry.lastAccessedOn != null) { Text( - entry.username, style = TextStyle( + entry.lastAccessedOn!!.toString(), + style = TextStyle( color = Color.Black, fontWeight = FontWeight.Bold, fontSize = 14.sp ) ) } + Text( + entry.username, style = TextStyle( + color = Color.Black, + fontWeight = FontWeight.Bold, + fontSize = 14.sp + ) + ) } } } diff --git a/composeApp/src/commonMain/kotlin/org/comixedproject/variant/data/DatabaseHelper.kt b/composeApp/src/commonMain/kotlin/org/comixedproject/variant/data/DatabaseHelper.kt index 0a577ff..a171f71 100644 --- a/composeApp/src/commonMain/kotlin/org/comixedproject/variant/data/DatabaseHelper.kt +++ b/composeApp/src/commonMain/kotlin/org/comixedproject/variant/data/DatabaseHelper.kt @@ -32,12 +32,26 @@ class DatabaseHelper(sqlDriver: SqlDriver) { fun loadAll(): List = database.tableQueries.loadServers().executeAsList() - fun save(id: String, name: String, url: String, username: String, password: String) { - database.tableQueries.saveServer(id, name, url, username, password) + fun save( + id: String, + name: String, + url: String, + username: String, + password: String, + serverColor: String + ) { + database.tableQueries.saveServer(id, name, url, username, password, serverColor) } - fun update(id: String, name: String, url: String, username: String, password: String) { - database.tableQueries.updateServer(name, url, username, password, id) + fun update( + id: String, + name: String, + url: String, + username: String, + password: String, + serverColor: String + ) { + database.tableQueries.updateServer(name, url, username, password, serverColor, id) } fun delete(id: String) { diff --git a/composeApp/src/commonMain/kotlin/org/comixedproject/variant/data/ServerRepository.kt b/composeApp/src/commonMain/kotlin/org/comixedproject/variant/data/ServerRepository.kt index 032b81c..a7b4b08 100644 --- a/composeApp/src/commonMain/kotlin/org/comixedproject/variant/data/ServerRepository.kt +++ b/composeApp/src/commonMain/kotlin/org/comixedproject/variant/data/ServerRepository.kt @@ -25,12 +25,25 @@ class ServerRepository(private val databaseHelper: DatabaseHelper) { val serverList: List get() = databaseHelper.loadAll().map(ServerDb::map) - fun createServer(name: String, url: String, username: String, password: String) { - databaseHelper.save(IdGenerator().toString(), name, url, username, password) + fun createServer( + name: String, + url: String, + username: String, + password: String, + serverColor: String + ) { + databaseHelper.save(IdGenerator().toString(), name, url, username, password, serverColor) } fun updateServer(server: Server) { - databaseHelper.update(server.id, server.name, server.url, server.username, server.password) + databaseHelper.update( + server.id, + server.name, + server.url, + server.username, + server.password, + server.serverColor + ) } fun removeServer(server: Server) { @@ -46,5 +59,6 @@ fun ServerDb.map() = Server( name = this.name, url = this.url, username = this.username, - password = this.password + password = this.password, + serverColor = this.serverColor ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/org/comixedproject/variant/model/Server.kt b/composeApp/src/commonMain/kotlin/org/comixedproject/variant/model/Server.kt index 5a1c4e5..6d0fd1d 100644 --- a/composeApp/src/commonMain/kotlin/org/comixedproject/variant/model/Server.kt +++ b/composeApp/src/commonMain/kotlin/org/comixedproject/variant/model/Server.kt @@ -30,7 +30,8 @@ data class Server( val name: String, val url: String, val username: String, - val password: String + val password: String, + val serverColor: String = ServerColorOption.DEFAULT.hex ) { private var _lastAccessedOn: LocalDateTime? = null var lastAccessedOn: LocalDateTime? diff --git a/composeApp/src/commonMain/kotlin/org/comixedproject/variant/model/ServerColorOption.kt b/composeApp/src/commonMain/kotlin/org/comixedproject/variant/model/ServerColorOption.kt new file mode 100644 index 0000000..25b7da4 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/comixedproject/variant/model/ServerColorOption.kt @@ -0,0 +1,54 @@ +/* + * Variant - A digital comic book reading application for iPad, Android, and desktops. + * Copyright (C) 2023, The ComiXed Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package org.comixedproject.variant.model + +/** + * ServerColorOption defines a type representing the color indicator for a server. + * + * @author Darryl L. Pierce + */ +data class ServerColorOption( + val name: String, + val hex: String +) { + companion object { + val COLORS = listOf( + ServerColorOption("WHITE", "#FFFFFF"), + ServerColorOption("RED", "#E57373"), + ServerColorOption("PINK", "#F06292"), + ServerColorOption("PURPLE", "#CE93D8"), + ServerColorOption("BLUE", "#2196F3"), + ServerColorOption("CYAN", "#00ACC1"), + ServerColorOption("TEAL", "#26A69A"), + ServerColorOption("GREEN", "#4CAF50"), + ServerColorOption("LIGHT GREEN", "#8BC34A"), + ServerColorOption("LIME", "#CDDC39"), + ServerColorOption("YELLOW", "#FFEB3B"), + ServerColorOption("ORANGE", "#FF9800"), + ServerColorOption("BROWN", "#BCAAA4"), + ServerColorOption("GREY", "#9E9E9E"), + ) + val DEFAULT = COLORS.get(0) + + fun forName(name: String): ServerColorOption? { + val result = COLORS.find { it.name == name } + return result ?: DEFAULT + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/org/comixedproject/variant/viewmodel/MainViewModel.kt b/composeApp/src/commonMain/kotlin/org/comixedproject/variant/viewmodel/MainViewModel.kt index 156988c..ddee212 100644 --- a/composeApp/src/commonMain/kotlin/org/comixedproject/variant/viewmodel/MainViewModel.kt +++ b/composeApp/src/commonMain/kotlin/org/comixedproject/variant/viewmodel/MainViewModel.kt @@ -32,8 +32,14 @@ class MainViewModel(private val serverRepository: ServerRepository) : BaseViewMo var currentServer: Server? = null - fun createServer(name: String, url: String, username: String, password: String) { - serverRepository.createServer(name, url, username, password) + fun createServer( + name: String, + url: String, + username: String, + password: String, + serverColor: String + ) { + serverRepository.createServer(name, url, username, password, serverColor) } fun updateServer(server: Server) { diff --git a/composeApp/src/commonMain/sqldelight/org/comixedproject/variant/db/Table.sq b/composeApp/src/commonMain/sqldelight/org/comixedproject/variant/db/Table.sq index 004a8b4..58c6cb2 100644 --- a/composeApp/src/commonMain/sqldelight/org/comixedproject/variant/db/Table.sq +++ b/composeApp/src/commonMain/sqldelight/org/comixedproject/variant/db/Table.sq @@ -2,6 +2,7 @@ CREATE TABLE ServerDb ( id TEXT NOT NULL PRIMARY KEY, name TEXT NOT NULL UNIQUE, url TEXT NOT NULL, +serverColor TEXT NOT NULL, username TEXT NOT NULL DEFAULT "", password TEXT NOT NULL DEFAULT "", lastAccessedOn INTEGER @@ -11,10 +12,10 @@ loadServers: SELECT * FROM ServerDb; saveServer: -INSERT OR IGNORE INTO ServerDb (id, name, url, username, password) VALUES(?, ?, ?, ?, ?); +INSERT OR IGNORE INTO ServerDb (id, name, url, username, password, serverColor) VALUES(?, ?, ?, ?, ?, ?); updateServer: -UPDATE ServerDb SET name = ?, url = ?, username = ?, password = ? WHERE id = ?; +UPDATE ServerDb SET name = ?, url = ?, username = ?, password = ?, serverColor = ? WHERE id = ?; deleteServer: DELETE FROM ServerDb WHERE id = ?; \ No newline at end of file