Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,11 @@ Or use the run configuration in Android Studio / Fleet.
### iOS

Open `iosApp/` in Xcode and run, or use the KMP run configuration in Fleet.

## Buy Me New Socks

If Worn saved you from wearing mismatched socks, consider a tiny Bitcoin tip via Lightning Network:

```
jvsena42@blink.sv
```
1 change: 1 addition & 0 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ kotlin {
androidMain.dependencies {
implementation(libs.compose.uiToolingPreview)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.splashscreen)
}
commonMain.dependencies {
implementation(libs.compose.runtime)
Expand Down
3 changes: 2 additions & 1 deletion composeApp/src/androidMain/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
android:theme="@style/Theme.Worn">
<activity
android:exported="true"
android:name=".MainActivity">
android:name=".MainActivity"
android:theme="@style/Theme.Worn.Splash">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
enableEdgeToEdge()
super.onCreate(savedInstanceState)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.github.worn.R
Expand Down Expand Up @@ -129,10 +131,14 @@ private fun TabItem(
}
Text(
text = label,
color = if (isActive) WornColors.TextOnColor else WornColors.TextSecondary,
fontSize = 10.sp,
fontWeight = FontWeight.SemiBold,
letterSpacing = 0.5.sp,
style = TextStyle(
color = if (isActive) WornColors.TextOnColor else WornColors.TextSecondary,
fontSize = 10.sp,
fontWeight = FontWeight.SemiBold,
letterSpacing = 0.5.sp,
),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import com.github.worn.ui.components.displayLabel
import com.github.worn.ui.components.displayName
import com.github.worn.ui.components.iconRes
import com.github.worn.ui.theme.WornColors
import com.github.worn.ui.theme.WornDimens
import com.github.worn.ui.theme.WornTheme
import org.koin.compose.viewmodel.koinViewModel

Expand Down Expand Up @@ -174,7 +175,7 @@ private fun GapsScaffold(
)
}

Spacer(Modifier.height(32.dp))
Spacer(Modifier.height(WornDimens.BottomBarClearance))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
Expand Down Expand Up @@ -60,6 +61,7 @@ import com.github.worn.presentation.viewmodel.OutfitViewModel
import com.github.worn.ui.components.OutfitCard
import com.github.worn.ui.components.Tab
import com.github.worn.ui.theme.WornColors
import com.github.worn.ui.theme.WornDimens
import com.github.worn.ui.theme.WornTheme
import org.koin.compose.viewmodel.koinViewModel

Expand Down Expand Up @@ -309,6 +311,7 @@ private fun OutfitsContent(

LazyColumn(
verticalArrangement = Arrangement.spacedBy(12.dp),
contentPadding = PaddingValues(bottom = WornDimens.BottomBarClearance),
modifier = Modifier.fillMaxSize(),
) {
items(state.outfits, key = { it.id }) { outfit ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
Expand All @@ -71,6 +73,7 @@ import com.github.worn.presentation.viewmodel.SettingsState
import com.github.worn.presentation.viewmodel.SettingsViewModel
import com.github.worn.ui.components.Tab
import com.github.worn.ui.theme.WornColors
import com.github.worn.ui.theme.WornDimens
import com.github.worn.ui.theme.WornTheme
import org.koin.compose.viewmodel.koinViewModel

Expand Down Expand Up @@ -172,7 +175,10 @@ private fun SettingsScaffold(
Spacer(Modifier.height(10.dp))
AboutCard()

Spacer(Modifier.height(32.dp))
Spacer(Modifier.height(24.dp))
DonationCard()

Spacer(Modifier.height(WornDimens.BottomBarClearance))
}
}
}
Expand Down Expand Up @@ -266,25 +272,81 @@ private fun AboutCard() {
Text(versionName ?: "1.0", color = WornColors.TextSecondary, fontSize = 15.sp)
}
HorizontalDivider(color = WornColors.BorderSubtle.copy(alpha = 0.5f))
AboutLinkRow(stringResource(R.string.settings_suggestions_bugs)) { uriHandler.openUri(FEEDBACK_URL) }
HorizontalDivider(color = WornColors.BorderSubtle.copy(alpha = 0.5f))
AboutLinkRow(stringResource(R.string.settings_licenses)) { uriHandler.openUri(LICENSE_URL) }
}
}
}

@Composable
private fun AboutLinkRow(label: String, onClick: () -> Unit) {
Surface(onClick = onClick, color = Color.Transparent) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().padding(16.dp),
) {
Text(label, color = WornColors.TextPrimary, fontSize = 15.sp, modifier = Modifier.weight(1f))
Icon(
imageVector = Icons.AutoMirrored.Outlined.KeyboardArrowRight,
contentDescription = null,
tint = WornColors.IconMuted,
modifier = Modifier.size(20.dp),
)
}
}
}

@Composable
private fun DonationCard() {
val clipboardManager = LocalClipboardManager.current
val copiedText = stringResource(R.string.settings_donate_copied)
var showCopied by remember { mutableStateOf(false) }

Surface(
shape = RoundedCornerShape(16.dp),
color = WornColors.BgCard,
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
stringResource(R.string.settings_donate_title),
color = WornColors.TextPrimary,
fontSize = 15.sp,
fontWeight = FontWeight.Medium,
)
Spacer(Modifier.height(4.dp))
Text(
stringResource(R.string.settings_donate_subtitle),
color = WornColors.TextSecondary,
fontSize = 13.sp,
)
Spacer(Modifier.height(12.dp))
Surface(
onClick = { uriHandler.openUri(LICENSE_URL) },
color = Color.Transparent,
onClick = {
clipboardManager.setText(AnnotatedString(DONATION_LN_ADDRESS))
showCopied = true
},
shape = RoundedCornerShape(12.dp),
color = WornColors.BgElevated,
border = BorderStroke(1.dp, WornColors.BorderSubtle),
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().padding(16.dp),
modifier = Modifier.fillMaxWidth().padding(12.dp),
) {
Text(
stringResource(R.string.settings_licenses),
color = WornColors.TextPrimary,
fontSize = 15.sp,
DONATION_LN_ADDRESS,
color = WornColors.AccentGreen,
fontSize = 13.sp,
fontWeight = FontWeight.Medium,
modifier = Modifier.weight(1f),
)
Icon(
imageVector = Icons.AutoMirrored.Outlined.KeyboardArrowRight,
contentDescription = null,
tint = WornColors.IconMuted,
modifier = Modifier.size(20.dp),
Spacer(Modifier.width(8.dp))
Text(
if (showCopied) copiedText else stringResource(R.string.settings_donate_copy),
color = WornColors.TextSecondary,
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
)
}
}
Expand Down Expand Up @@ -656,6 +718,7 @@ private fun BodyType.displayName(): String = when (this) {
BodyType.STOCKY -> stringResource(R.string.body_type_stocky)
BodyType.SHORT -> stringResource(R.string.body_type_short)
BodyType.TALL_AND_SLIM -> stringResource(R.string.body_type_tall_and_slim)
BodyType.TALL_AND_FIT -> stringResource(R.string.body_type_tall_and_fit)
BodyType.BIG_AND_TALL -> stringResource(R.string.body_type_big_and_tall)
}

Expand Down Expand Up @@ -695,6 +758,8 @@ private fun Lifestyle.displayName(): String = when (this) {

// endregion

private const val DONATION_LN_ADDRESS = "jvsena42@blink.sv"
private const val FEEDBACK_URL = "https://github.com/jvsena42/worn/issues/new"
private const val LICENSE_URL = "https://github.com/jvsena42/worn/blob/main/LICENSE"

@Preview(showSystemUi = true, device = "id:pixel_8")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ import com.github.worn.presentation.viewmodel.TryItState
import com.github.worn.presentation.viewmodel.TryItViewModel
import com.github.worn.ui.components.Tab
import com.github.worn.ui.theme.WornColors
import com.github.worn.ui.theme.WornDimens
import com.github.worn.ui.theme.WornTheme
import org.koin.compose.viewmodel.koinViewModel
import java.io.ByteArrayOutputStream
Expand Down Expand Up @@ -465,7 +466,7 @@ private fun TryItTabletContent(
}
}
}
Spacer(Modifier.height(32.dp))
Spacer(Modifier.height(WornDimens.BottomBarClearance))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ 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.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
Expand Down Expand Up @@ -65,14 +66,13 @@ import com.github.worn.ui.components.CategoryFilterChips
import com.github.worn.ui.components.ClothingCard
import com.github.worn.ui.components.Tab
import com.github.worn.ui.theme.WornColors
import com.github.worn.ui.theme.WornDimens
import com.github.worn.ui.theme.WornTheme
import org.koin.compose.viewmodel.koinViewModel

private val GRID_MIN_CELL_WIDTH = 160.dp
private val GRID_GAP_COMPACT = 12.dp
private val GRID_GAP_EXPANDED = 16.dp
private val BOTTOM_BAR_HEIGHT = 95.dp
@Suppress("UnusedParameter")
@Composable
fun WardrobeScreen(
onTabSelected: (Tab) -> Unit = {},
Expand Down Expand Up @@ -186,7 +186,10 @@ private fun WardrobeScaffold(
Scaffold(
containerColor = WornColors.BgPage,
floatingActionButton = {
if (!isSelectionMode) AddItemFab(onAddItemClick, Modifier.padding(bottom = BOTTOM_BAR_HEIGHT))
val isWardrobeEmpty = !state.isLoading && state.totalItemCount == 0
if (!isSelectionMode && !isWardrobeEmpty) {
AddItemFab(onAddItemClick, Modifier.padding(bottom = WornDimens.BottomBarClearance))
}
},
) { paddingValues ->
val isWardrobeEmpty = !state.isLoading && state.totalItemCount == 0
Expand Down Expand Up @@ -323,6 +326,7 @@ private fun WardrobeContent(
columns = GridCells.Adaptive(minSize = GRID_MIN_CELL_WIDTH),
horizontalArrangement = Arrangement.spacedBy(gridGap),
verticalArrangement = Arrangement.spacedBy(gridGap),
contentPadding = PaddingValues(bottom = WornDimens.BottomBarClearance),
modifier = Modifier.fillMaxSize(),
) {
items(state.items, key = { it.id }) { item ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ package com.github.worn.ui.theme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import androidx.compose.ui.graphics.Color

object WornDimens {
val BottomBarClearance = 95.dp
}

object WornColors {
// Backgrounds
val BgPage = Color(0xFFF5F0EB)
Expand Down
Loading
Loading