mirror of
https://github.com/bitfireAT/davx5-ose
synced 2024-10-03 01:44:16 +00:00
Migrated into to compose
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
This commit is contained in:
parent
ea035fa931
commit
e2ee0f459a
|
@ -0,0 +1,64 @@
|
||||||
|
package at.bitfire.davdroid.ui.composable
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.ArrowForward
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.contentColorFor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import at.bitfire.davdroid.ui.AppTheme
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ButtonWithIcon(
|
||||||
|
icon: ImageVector,
|
||||||
|
contentDescription: String?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
size: Dp = 56.dp,
|
||||||
|
color: Color = MaterialTheme.colorScheme.tertiary,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
color = color,
|
||||||
|
contentColor = contentColorFor(backgroundColor = color),
|
||||||
|
modifier = modifier
|
||||||
|
.size(size)
|
||||||
|
.aspectRatio(1f),
|
||||||
|
onClick = onClick,
|
||||||
|
shape = CircleShape
|
||||||
|
) {
|
||||||
|
AnimatedContent(
|
||||||
|
targetState = icon,
|
||||||
|
label = "Button Icon"
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = it,
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
modifier = Modifier.padding(12.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ButtonWithIcon_Preview() {
|
||||||
|
AppTheme {
|
||||||
|
ButtonWithIcon(
|
||||||
|
icon = Icons.AutoMirrored.Filled.ArrowForward,
|
||||||
|
contentDescription = null
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package at.bitfire.davdroid.ui.composable
|
||||||
|
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
|
import androidx.compose.foundation.Canvas
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.contentColorFor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PositionIndicator(
|
||||||
|
index: Int,
|
||||||
|
max: Int,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
selectedIndicatorColor: Color = MaterialTheme.colorScheme.tertiary,
|
||||||
|
unselectedIndicatorColor: Color = contentColorFor(selectedIndicatorColor),
|
||||||
|
indicatorSize: Float = 20f
|
||||||
|
) {
|
||||||
|
val selectedPosition by animateFloatAsState(
|
||||||
|
targetValue = index.toFloat(),
|
||||||
|
label = "position"
|
||||||
|
)
|
||||||
|
|
||||||
|
Canvas(modifier = modifier) {
|
||||||
|
val padding = size.width / (max + 1)
|
||||||
|
|
||||||
|
for (idx in 0 until max) {
|
||||||
|
drawCircle(
|
||||||
|
color = unselectedIndicatorColor,
|
||||||
|
radius = indicatorSize,
|
||||||
|
center = Offset(
|
||||||
|
x = (idx + 1) * padding,
|
||||||
|
y = size.height / 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
drawCircle(
|
||||||
|
color = selectedIndicatorColor,
|
||||||
|
radius = indicatorSize,
|
||||||
|
center = Offset(
|
||||||
|
x = (selectedPosition + 1) * padding,
|
||||||
|
y = size.height / 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(
|
||||||
|
showBackground = true,
|
||||||
|
backgroundColor = 0xff000000
|
||||||
|
)
|
||||||
|
@Composable
|
||||||
|
fun PositionIndicator_Preview() {
|
||||||
|
var index by remember { mutableIntStateOf(0) }
|
||||||
|
|
||||||
|
PositionIndicator(
|
||||||
|
index = index,
|
||||||
|
max = 5,
|
||||||
|
modifier = Modifier
|
||||||
|
.width(200.dp)
|
||||||
|
.height(50.dp)
|
||||||
|
.clickable { if (index == 4) index = 0 else index++ }
|
||||||
|
)
|
||||||
|
}
|
|
@ -11,12 +11,18 @@ import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.activity.addCallback
|
import androidx.activity.addCallback
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.result.contract.ActivityResultContract
|
import androidx.activity.result.contract.ActivityResultContract
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.ComposeView
|
import androidx.compose.ui.platform.ComposeView
|
||||||
|
@ -32,75 +38,45 @@ import com.github.appintro.AppIntro2
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class IntroActivity : AppIntro2() {
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
class IntroActivity : AppCompatActivity() {
|
||||||
|
|
||||||
val model by viewModels<Model>()
|
val model by viewModels<Model>()
|
||||||
private var currentSlide = 0
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
model.pages.forEachIndexed { idx, _ ->
|
val pages = model.pages
|
||||||
addSlide(PageFragment().apply {
|
|
||||||
arguments = Bundle(1).apply {
|
|
||||||
putInt(PageFragment.ARG_PAGE_IDX, idx)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
setBarColor(M3ColorScheme.primaryLight.toArgb())
|
setContent {
|
||||||
isSkipButtonEnabled = false
|
AppTheme {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val pagerState = rememberPagerState { pages.size }
|
||||||
|
|
||||||
onBackPressedDispatcher.addCallback(this) {
|
BackHandler {
|
||||||
if (currentSlide == 0) {
|
if (pagerState.settledPage == 0) {
|
||||||
setResult(Activity.RESULT_CANCELED)
|
setResult(Activity.RESULT_CANCELED)
|
||||||
finish()
|
finish()
|
||||||
} else {
|
} else scope.launch {
|
||||||
goToPreviousSlide()
|
pagerState.animateScrollToPage(pagerState.settledPage - 1)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPageSelected(position: Int) {
|
IntroScreen(
|
||||||
super.onPageSelected(position)
|
pages = pages,
|
||||||
currentSlide = position
|
pagerState = pagerState,
|
||||||
}
|
onDonePressed = {
|
||||||
|
|
||||||
override fun onDonePressed(currentFragment: Fragment?) {
|
|
||||||
super.onDonePressed(currentFragment)
|
|
||||||
setResult(Activity.RESULT_OK)
|
setResult(Activity.RESULT_OK)
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class PageFragment: Fragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val ARG_PAGE_IDX = "page"
|
|
||||||
}
|
|
||||||
|
|
||||||
val model by activityViewModels<Model>()
|
|
||||||
val page by lazy { model.pages[requireArguments().getInt(ARG_PAGE_IDX)] }
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) =
|
|
||||||
ComposeView(requireActivity()).apply {
|
|
||||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
|
||||||
setContent {
|
|
||||||
AppTheme {
|
|
||||||
Surface(Modifier.fillMaxSize()) {
|
|
||||||
Box(Modifier.padding(bottom = dimensionResource(com.github.appintro.R.dimen.appintro2_bottombar_height))) {
|
|
||||||
page.ComposePage()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
129
app/src/main/kotlin/at/bitfire/davdroid/ui/intro/IntroScreen.kt
Normal file
129
app/src/main/kotlin/at/bitfire/davdroid/ui/intro/IntroScreen.kt
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
package at.bitfire.davdroid.ui.intro
|
||||||
|
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
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.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
|
import androidx.compose.foundation.pager.PagerState
|
||||||
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.ArrowForward
|
||||||
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.zIndex
|
||||||
|
import at.bitfire.davdroid.ui.AppTheme
|
||||||
|
import at.bitfire.davdroid.ui.composable.ButtonWithIcon
|
||||||
|
import at.bitfire.davdroid.ui.composable.PositionIndicator
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
fun IntroScreen(
|
||||||
|
pages: List<IntroPage>,
|
||||||
|
pagerState: PagerState = rememberPagerState { pages.size },
|
||||||
|
onDonePressed: () -> Unit
|
||||||
|
) {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
|
HorizontalPager(
|
||||||
|
state = pagerState,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f)
|
||||||
|
) { pages[it].ComposePage() }
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(90.dp)
|
||||||
|
.background(MaterialTheme.colorScheme.primary)
|
||||||
|
) {
|
||||||
|
PositionIndicator(
|
||||||
|
index = pagerState.currentPage,
|
||||||
|
max = pages.size,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.padding(horizontal = 128.dp)
|
||||||
|
.align(Alignment.Center)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
selectedIndicatorColor = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
unselectedIndicatorColor = MaterialTheme.colorScheme.tertiary,
|
||||||
|
indicatorSize = 15f
|
||||||
|
)
|
||||||
|
|
||||||
|
ButtonWithIcon(
|
||||||
|
icon = if (pagerState.currentPage + 1 == pagerState.pageCount) {
|
||||||
|
Icons.Default.Check
|
||||||
|
} else {
|
||||||
|
Icons.AutoMirrored.Default.ArrowForward
|
||||||
|
},
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(end = 16.dp)
|
||||||
|
.align(Alignment.CenterEnd)
|
||||||
|
) {
|
||||||
|
if (pagerState.currentPage + 1 == pagerState.pageCount) {
|
||||||
|
onDonePressed()
|
||||||
|
} else scope.launch {
|
||||||
|
pagerState.animateScrollToPage(pagerState.currentPage + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(
|
||||||
|
showSystemUi = true
|
||||||
|
)
|
||||||
|
@Composable
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
fun IntroScreen_Preview() {
|
||||||
|
AppTheme {
|
||||||
|
IntroScreen(
|
||||||
|
listOf(
|
||||||
|
object : IntroPage {
|
||||||
|
override fun getShowPolicy(): IntroPage.ShowPolicy =
|
||||||
|
IntroPage.ShowPolicy.SHOW_ALWAYS
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun ComposePage() {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(MaterialTheme.colorScheme.surface)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
object : IntroPage {
|
||||||
|
override fun getShowPolicy(): IntroPage.ShowPolicy =
|
||||||
|
IntroPage.ShowPolicy.SHOW_ALWAYS
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun ComposePage() {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(MaterialTheme.colorScheme.primary)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
onDonePressed = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue