Skip to content

Commit

Permalink
publish favourites
Browse files Browse the repository at this point in the history
  • Loading branch information
avan1235 committed May 9, 2024
1 parent 408afbb commit 0da91ed
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 62 deletions.
Binary file not shown.
63 changes: 28 additions & 35 deletions composeApp/src/commonMain/kotlin/in/procyk/shin/ShinApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.filled.QrCodeScanner
import androidx.compose.material.icons.outlined.Favorite
import androidx.compose.material.icons.outlined.Home
import androidx.compose.material.icons.outlined.QrCodeScanner
Expand All @@ -17,7 +20,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.unit.dp
import com.arkivanov.decompose.extensions.compose.stack.Children
import com.arkivanov.decompose.extensions.compose.stack.animation.slide
Expand All @@ -27,6 +29,8 @@ import `in`.procyk.compose.camera.permission.rememberCameraPermissionState
import `in`.procyk.shin.component.ShinAppComponent
import `in`.procyk.shin.component.ShinAppComponent.Child
import `in`.procyk.shin.component.ShinAppComponent.MenuItem
import `in`.procyk.shin.ui.component.BottomBanner
import `in`.procyk.shin.ui.component.BottomBannerItem
import `in`.procyk.shin.ui.component.ShinBanner
import `in`.procyk.shin.ui.icons.Github
import `in`.procyk.shin.ui.icons.Html5
Expand Down Expand Up @@ -72,10 +76,12 @@ private inline fun NavigationDrawer(
val activeMenuItem by component.activeMenuItem.subscribeAsState()
ModalNavigationDrawer(
modifier = Modifier
.onKeyEvent { event ->
(drawerState.isOpen && event.isEscDown).also { isConsumed ->
if (isConsumed) scope.launch { drawerState.close() }
.onKeyEvent handle@{ event ->
when {
drawerState.isOpen && event.isEscDown -> scope.launch { drawerState.close() }
else -> return@handle false
}
return@handle true
},
drawerState = drawerState,
drawerContent = {
Expand All @@ -97,7 +103,10 @@ private inline fun NavigationDrawer(
).forEach { item ->
NavigationDrawerItem(
icon = {
Icon(item.icon, contentDescription = "Menu item icon")
Icon(
if (item == activeMenuItem) item.filledIcon else item.outlinedIcon,
contentDescription = "Menu item icon"
)
},
label = {
Text(item.presentableName)
Expand All @@ -114,23 +123,12 @@ private inline fun NavigationDrawer(
Spacer(
modifier = Modifier.weight(1f)
)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 12.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text("Find Me On")
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterHorizontally)
) {
FindMeOn(ShinIcons.Github, "https://github.com/avan1235/", "Github")
FindMeOn(ShinIcons.LinkedIn, "https://www.linkedin.com/in/maciej-procyk/", "LinkedIn")
FindMeOn(ShinIcons.Html5, "https://procyk.in", "web")
}
}
BottomBanner(
title = "Find Me On",
BottomBannerItem("https://github.com/avan1235/", ShinIcons.Github),
BottomBannerItem("https://www.linkedin.com/in/maciej-procyk/", ShinIcons.LinkedIn),
BottomBannerItem("https://procyk.in", ShinIcons.Html5),
)
}
},
) {
Expand Down Expand Up @@ -180,25 +178,20 @@ private inline fun NavigationDrawer(
}
}

@Composable
private inline fun FindMeOn(
icon: ImageVector,
url: String,
name: String,
) {
val uriHandler = LocalUriHandler.current
IconButton(onClick = { uriHandler.openUri(url) }) {
Icon(icon, "Find me on $name")
}
}

private inline val MenuItem.icon: ImageVector
private inline val MenuItem.outlinedIcon: ImageVector
get() = when (this) {
MenuItem.Main -> Icons.Outlined.Home
MenuItem.ScanQRCode -> Icons.Outlined.QrCodeScanner
MenuItem.Favourites -> Icons.Outlined.Favorite
}

private inline val MenuItem.filledIcon: ImageVector
get() = when (this) {
MenuItem.Main -> Icons.Filled.Home
MenuItem.ScanQRCode -> Icons.Filled.QrCodeScanner
MenuItem.Favourites -> Icons.Filled.Favorite
}

private inline val MenuItem.presentableName: String
get() = when (this) {
MenuItem.Main -> "Home"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ interface ShinAppComponent : Component {

val activeMenuItem: Value<MenuItem>

fun onBackClicked(toIndex: Int)

fun navigateTo(item: MenuItem)

enum class MenuItem {
Expand Down Expand Up @@ -83,11 +81,6 @@ class ShinAppComponentImpl(
)
}


override fun onBackClicked(toIndex: Int) {
navigation.popTo(index = toIndex)
}

override fun navigateTo(item: MenuItem) {
when (item) {
MenuItem.Main -> navigation.popTo(index = 0)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package `in`.procyk.shin.ui.component

import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.unit.dp

data class BottomBannerItem(
val url: String,
val icon: ImageVector,
) {
}

@Composable
internal fun BottomBanner(
title: String?,
vararg items: BottomBannerItem,
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 12.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
title?.let { Text(it) }
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterHorizontally)
) {
val uriHandler = LocalUriHandler.current
for (item in items) {
ShinIconButton(
onClick = { uriHandler.openUri(item.url) },
icon = item.icon,
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.sp
import org.jetbrains.compose.resources.Font
import shin.composeapp.generated.resources.Mansalva_Regular
import shin.composeapp.generated.resources.PoetsenOne_Regular
import shin.composeapp.generated.resources.Res

@Composable
Expand All @@ -33,6 +34,8 @@ internal fun ShinBanner(
)
Text(
text = "Shorten Your URL with Kotlin",
fontFamily = FontFamily(Font(Res.font.PoetsenOne_Regular)),
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.onSurface),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package `in`.procyk.shin.ui.component

import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

@Composable
internal fun ShinIconButton(
onClick: () -> Unit,
icon: ImageVector,
iconOutlined: ImageVector = icon,
contentDescription: String? = null,
size: Dp = 24.dp,
hoveredColor: Color = LocalContentColor.current,
notHoveredColor: Color = hoveredColor.copy(alpha = 0.6f),
) {
val interactionSource = remember { MutableInteractionSource() }
val isHovered by interactionSource.collectIsHoveredAsState()
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(12.dp)
.clickable(
onClick = onClick,
interactionSource = interactionSource,
indication = null,
)
) {
Icon(
imageVector = if (isHovered) icon else iconOutlined,
contentDescription = contentDescription,
modifier = Modifier.size(size),
tint = when {
isHovered -> hoveredColor
else -> notHoveredColor
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,26 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.*
import androidx.compose.material3.Card
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import `in`.procyk.shin.component.FavouritesComponent
import `in`.procyk.shin.ui.component.ShinIconButton

@Composable
internal fun FavouritesScreen(component: FavouritesComponent) {
Expand All @@ -28,13 +36,16 @@ internal fun FavouritesScreen(component: FavouritesComponent) {
Text("No Favourites")
}
} else {
LazyColumn {
LazyColumn(
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
items(favourites, key = { it.shortUrl }) { item ->
val clipboardManager = LocalClipboardManager.current
Card(
shape = MaterialTheme.shapes.small,
modifier = Modifier
.padding(top = 16.dp, start = 16.dp, end = 16.dp)
.clip(RoundedCornerShape(12.dp))
.clickable { component.onFavouriteClick(clipboardManager, item.shortUrl) }
) {
Row(
Expand All @@ -44,21 +55,35 @@ internal fun FavouritesScreen(component: FavouritesComponent) {
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
IconButton(
onClick = { component.removeFavourite(item.shortUrl) }
ShinIconButton(
onClick = { component.removeFavourite(item.shortUrl) },
icon = Icons.Filled.Delete,
iconOutlined = Icons.Outlined.Delete,
contentDescription = "Delete favourite",
hoveredColor = MaterialTheme.colorScheme.error.copy(alpha = 0.5f),
notHoveredColor = LocalContentColor.current,
)
Row(
modifier = Modifier.fillMaxWidth()
) {
Icon(Icons.Outlined.Delete, contentDescription = "Delete favourite")
Text(
text = item.fullUrl,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.weight(2f),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Text(
text = item.shortUrl,
style = MaterialTheme.typography.bodyMedium.let {
it.copy(color = it.color.copy(alpha = 0.3f))
},
textAlign = TextAlign.End,
modifier = Modifier.weight(1f),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
Text(
text = item.fullUrl,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.weight(1f)
)
Text(
text = item.shortUrl,
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.End
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.unit.dp
import `in`.procyk.shin.component.MainComponent
import `in`.procyk.shin.shared.applyIf
import `in`.procyk.shin.ui.component.ShinBanner
import `in`.procyk.shin.ui.component.ShortenRequestItems
import `in`.procyk.shin.ui.component.ShortenResponse
import `in`.procyk.shin.ui.component.*
import `in`.procyk.shin.ui.util.isEscDown

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ package `in`.procyk.shin.ui.util
import androidx.compose.ui.input.key.*

internal val KeyEvent.isEscDown: Boolean
get() = key == Key.Escape && type == KeyEventType.KeyDown
get() = this.key == Key.Escape && this.type == KeyEventType.KeyDown

internal fun KeyEvent.isKeyDown(key: Key): Boolean =
this.key == key && this.type == KeyEventType.KeyDown

0 comments on commit 0da91ed

Please sign in to comment.