-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
VEEEEEEEEEERY basic it doesn't even have persistency this'll be added in a few commits I'll be adding localization first
- Loading branch information
1 parent
54f5686
commit 44c1737
Showing
29 changed files
with
780 additions
and
66 deletions.
There are no files selected for viewing
7 changes: 0 additions & 7 deletions
7
api/src/commonMain/kotlin/mehiz/abdallah/progres/api/ProgresApi.kt
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,15 @@ | ||
import androidx.compose.animation.AnimatedVisibility | ||
import androidx.compose.foundation.Image | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.material.Button | ||
import androidx.compose.material.MaterialTheme | ||
import androidx.compose.material.Text | ||
import androidx.compose.material3.MaterialTheme | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.setValue | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import org.jetbrains.compose.resources.painterResource | ||
import cafe.adriel.voyager.navigator.Navigator | ||
import org.jetbrains.compose.ui.tooling.preview.Preview | ||
import progres.composeapp.generated.resources.Res | ||
import progres.composeapp.generated.resources.compose_multiplatform | ||
import ui.onboarding.LoginScreen | ||
|
||
@Composable | ||
@Preview | ||
fun App() { | ||
MaterialTheme { | ||
var showContent by remember { mutableStateOf(false) } | ||
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { | ||
Button(onClick = { showContent = !showContent }) { | ||
Text("Click me!") | ||
} | ||
AnimatedVisibility(showContent) { | ||
val greeting = remember { Greeting().greet() } | ||
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { | ||
Image(painterResource(Res.drawable.compose_multiplatform), null) | ||
Text("Compose: $greeting") | ||
} | ||
} | ||
} | ||
Navigator( | ||
screen = LoginScreen | ||
) | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
4 changes: 3 additions & 1 deletion
4
...pp/src/commonMain/kotlin/di/initKodein.kt → ...pp/src/commonMain/kotlin/di/InitKodein.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
249 changes: 249 additions & 0 deletions
249
composeApp/src/commonMain/kotlin/presentation/WheelPicker.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
package presentation | ||
|
||
import androidx.compose.foundation.BorderStroke | ||
import androidx.compose.foundation.ExperimentalFoundationApi | ||
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.PaddingValues | ||
import androidx.compose.foundation.layout.height | ||
import androidx.compose.foundation.layout.size | ||
import androidx.compose.foundation.layout.width | ||
import androidx.compose.foundation.lazy.LazyColumn | ||
import androidx.compose.foundation.lazy.LazyItemScope | ||
import androidx.compose.foundation.lazy.LazyListItemInfo | ||
import androidx.compose.foundation.lazy.LazyListState | ||
import androidx.compose.foundation.lazy.itemsIndexed | ||
import androidx.compose.foundation.lazy.rememberLazyListState | ||
import androidx.compose.foundation.shape.RoundedCornerShape | ||
import androidx.compose.foundation.text.BasicTextField | ||
import androidx.compose.foundation.text.KeyboardOptions | ||
import androidx.compose.material3.MaterialTheme | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableIntStateOf | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.rememberCoroutineScope | ||
import androidx.compose.runtime.setValue | ||
import androidx.compose.runtime.snapshotFlow | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.draw.alpha | ||
import androidx.compose.ui.graphics.SolidColor | ||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType | ||
import androidx.compose.ui.platform.LocalHapticFeedback | ||
import androidx.compose.ui.text.TextRange | ||
import androidx.compose.ui.text.TextStyle | ||
import androidx.compose.ui.text.input.ImeAction | ||
import androidx.compose.ui.text.input.KeyboardType | ||
import androidx.compose.ui.text.input.TextFieldValue | ||
import androidx.compose.ui.text.style.TextAlign | ||
import androidx.compose.ui.unit.DpSize | ||
import androidx.compose.ui.unit.dp | ||
import kotlinx.collections.immutable.ImmutableList | ||
import kotlinx.coroutines.flow.collectLatest | ||
import kotlinx.coroutines.flow.distinctUntilChanged | ||
import kotlinx.coroutines.flow.map | ||
import kotlin.math.absoluteValue | ||
|
||
@Composable | ||
fun WheelNumberPicker( | ||
items: ImmutableList<Number>, | ||
modifier: Modifier = Modifier, | ||
startIndex: Int = 0, | ||
size: DpSize = DpSize(128.dp, 128.dp), | ||
onSelectionChanged: (index: Int) -> Unit = {}, | ||
backgroundContent: (@Composable (size: DpSize) -> Unit)? = { | ||
WheelPickerDefaults.Background(size = it) | ||
}, | ||
) { | ||
WheelPicker( | ||
modifier = modifier, | ||
startIndex = startIndex, | ||
items = items, | ||
size = size, | ||
onSelectionChanged = onSelectionChanged, | ||
manualInputType = KeyboardType.Number, | ||
backgroundContent = backgroundContent, | ||
) { | ||
WheelPickerDefaults.Item(text = "$it") | ||
} | ||
} | ||
|
||
@Composable | ||
fun WheelTextPicker( | ||
items: ImmutableList<String>, | ||
modifier: Modifier = Modifier, | ||
startIndex: Int = 0, | ||
size: DpSize = DpSize(128.dp, 128.dp), | ||
onSelectionChanged: (index: Int) -> Unit = {}, | ||
backgroundContent: (@Composable (size: DpSize) -> Unit)? = { | ||
WheelPickerDefaults.Background(size = it) | ||
}, | ||
) { | ||
WheelPicker( | ||
modifier = modifier, | ||
startIndex = startIndex, | ||
items = items, | ||
size = size, | ||
onSelectionChanged = onSelectionChanged, | ||
backgroundContent = backgroundContent, | ||
) { | ||
WheelPickerDefaults.Item(text = it) | ||
} | ||
} | ||
|
||
@OptIn(ExperimentalFoundationApi::class) | ||
@Composable | ||
private fun <T> WheelPicker( | ||
items: ImmutableList<T>, | ||
modifier: Modifier = Modifier, | ||
startIndex: Int = 0, | ||
size: DpSize = DpSize(128.dp, 128.dp), | ||
onSelectionChanged: (index: Int) -> Unit = {}, | ||
manualInputType: KeyboardType? = null, | ||
backgroundContent: (@Composable (size: DpSize) -> Unit)? = { | ||
WheelPickerDefaults.Background(size = it) | ||
}, | ||
itemContent: @Composable LazyItemScope.(item: T) -> Unit, | ||
) { | ||
val haptic = LocalHapticFeedback.current | ||
val lazyListState = rememberLazyListState(startIndex) | ||
|
||
var internalIndex by remember { mutableIntStateOf(startIndex) } | ||
val internalOnSelectionChanged: (Int) -> Unit = { | ||
internalIndex = it | ||
onSelectionChanged(it) | ||
} | ||
|
||
LaunchedEffect(lazyListState, onSelectionChanged) { | ||
snapshotFlow { lazyListState.firstVisibleItemScrollOffset } | ||
.map { calculateSnappedItemIndex(lazyListState) } | ||
.distinctUntilChanged() | ||
.collectLatest { | ||
haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) | ||
internalOnSelectionChanged(it) | ||
} | ||
} | ||
|
||
Box( | ||
modifier = modifier | ||
.height(size.height) | ||
.width(size.width), | ||
contentAlignment = Alignment.Center, | ||
) { | ||
backgroundContent?.invoke(size) | ||
|
||
var showManualInput by remember { mutableStateOf(false) } | ||
if (showManualInput) { | ||
var value by remember { | ||
val currentString = items[internalIndex].toString() | ||
mutableStateOf(TextFieldValue(text = currentString, selection = TextRange(currentString.length))) | ||
} | ||
|
||
val scope = rememberCoroutineScope() | ||
BasicTextField( | ||
modifier = Modifier | ||
.align(Alignment.Center), | ||
value = value, | ||
onValueChange = { value = it }, | ||
singleLine = true, | ||
keyboardOptions = KeyboardOptions( | ||
keyboardType = manualInputType!!, | ||
imeAction = ImeAction.Done, | ||
), | ||
textStyle = MaterialTheme.typography.titleMedium + | ||
TextStyle( | ||
color = MaterialTheme.colorScheme.onSurface, | ||
textAlign = TextAlign.Center, | ||
), | ||
cursorBrush = SolidColor(MaterialTheme.colorScheme.primary), | ||
) | ||
} else { | ||
LazyColumn( | ||
modifier = Modifier, | ||
state = lazyListState, | ||
contentPadding = PaddingValues(vertical = size.height / RowCount * ((RowCount - 1) / 2)), | ||
flingBehavior = rememberSnapFlingBehavior(lazyListState = lazyListState), | ||
) { | ||
itemsIndexed(items) { index, item -> | ||
Box( | ||
modifier = Modifier | ||
.height(size.height / RowCount) | ||
.width(size.width) | ||
.alpha( | ||
calculateAnimatedAlpha( | ||
lazyListState = lazyListState, | ||
index = index, | ||
), | ||
), | ||
contentAlignment = Alignment.Center, | ||
) { | ||
itemContent(item) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private fun LazyListState.snapOffsetForItem(itemInfo: LazyListItemInfo): Int { | ||
val startScrollOffset = 0 | ||
val endScrollOffset = layoutInfo.let { it.viewportEndOffset - it.afterContentPadding } | ||
return startScrollOffset + (endScrollOffset - startScrollOffset - itemInfo.size) / 2 | ||
} | ||
|
||
private fun LazyListState.distanceToSnapForIndex(index: Int): Int { | ||
val itemInfo = layoutInfo.visibleItemsInfo.firstOrNull { it.index == index } | ||
if (itemInfo != null) { | ||
return itemInfo.offset - snapOffsetForItem(itemInfo) | ||
} | ||
return 0 | ||
} | ||
|
||
private fun calculateAnimatedAlpha( | ||
lazyListState: LazyListState, | ||
index: Int, | ||
): Float { | ||
val distanceToIndexSnap = lazyListState.distanceToSnapForIndex(index).absoluteValue | ||
val viewPortHeight = lazyListState.layoutInfo.viewportSize.height.toFloat() | ||
val singleViewPortHeight = viewPortHeight / RowCount | ||
return if (distanceToIndexSnap in 0..singleViewPortHeight.toInt()) { | ||
1.2f - (distanceToIndexSnap / singleViewPortHeight) | ||
} else { | ||
0.2f | ||
} | ||
} | ||
|
||
private fun calculateSnappedItemIndex(lazyListState: LazyListState): Int { | ||
return lazyListState.layoutInfo.visibleItemsInfo | ||
.maxBy { calculateAnimatedAlpha(lazyListState, it.index) } | ||
.index | ||
} | ||
|
||
object WheelPickerDefaults { | ||
@Composable | ||
fun Background(size: DpSize) { | ||
androidx.compose.material3.Surface( | ||
modifier = Modifier | ||
.size(size.width, size.height / RowCount), | ||
shape = RoundedCornerShape(24.dp), | ||
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.2f), | ||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary), | ||
content = {}, | ||
) | ||
} | ||
|
||
@Composable | ||
fun Item(text: String) { | ||
Text( | ||
text = text, | ||
style = MaterialTheme.typography.titleMedium, | ||
maxLines = 1, | ||
) | ||
} | ||
} | ||
|
||
private const val RowCount = 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package ui.home | ||
|
||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Alignment | ||
import cafe.adriel.voyager.core.screen.Screen | ||
|
||
object HomeScreen: Screen { | ||
@Composable | ||
override fun Content() { | ||
Box( | ||
contentAlignment = Alignment.Center | ||
) { | ||
Text("Home Screen") | ||
} | ||
} | ||
} |
Oops, something went wrong.