feat: consolidate poll creation into a single screen with poll type selector
Replace the two-button expandable FAB (Regular Poll / Zap Poll) with a single FAB navigating to one unified poll screen. The poll type (Regular vs Zap) is now selected via FilterChip options within the post form, eliminating the Route.NewZapPoll route entirely. https://claude.ai/code/session_01PqBSYZvCLBBUCifUFRoLmD
This commit is contained in:
@@ -412,17 +412,6 @@ fun BuildNavigation(
|
|||||||
|
|
||||||
composableFromBottomArgs<Route.NewPoll> {
|
composableFromBottomArgs<Route.NewPoll> {
|
||||||
PollPostScreen(
|
PollPostScreen(
|
||||||
isZapPoll = false,
|
|
||||||
message = it.message,
|
|
||||||
draftId = it.draft,
|
|
||||||
accountViewModel = accountViewModel,
|
|
||||||
nav = nav,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
composableFromBottomArgs<Route.NewZapPoll> {
|
|
||||||
PollPostScreen(
|
|
||||||
isZapPoll = true,
|
|
||||||
message = it.message,
|
message = it.message,
|
||||||
draftId = it.draft,
|
draftId = it.draft,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
|
|||||||
@@ -373,12 +373,6 @@ sealed class Route {
|
|||||||
val draft: String? = null,
|
val draft: String? = null,
|
||||||
) : Route()
|
) : Route()
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class NewZapPoll(
|
|
||||||
val message: String? = null,
|
|
||||||
val draft: String? = null,
|
|
||||||
) : Route()
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class VoiceReply(
|
data class VoiceReply(
|
||||||
val replyToNoteId: String,
|
val replyToNoteId: String,
|
||||||
|
|||||||
+42
-58
@@ -26,6 +26,7 @@ import android.net.Uri
|
|||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.horizontalScroll
|
import androidx.compose.foundation.horizontalScroll
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@@ -42,12 +43,14 @@ import androidx.compose.foundation.verticalScroll
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Poll
|
import androidx.compose.material.icons.outlined.Poll
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.FilterChip
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.Switch
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -108,7 +111,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow
|
||||||
import com.vitorpamplona.amethyst.ui.stringRes
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size19Modifier
|
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size30Modifier
|
import com.vitorpamplona.amethyst.ui.theme.Size30Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size35Modifier
|
import com.vitorpamplona.amethyst.ui.theme.Size35Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||||
@@ -334,21 +336,39 @@ private fun NewPostScreenBody(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (postViewModel.wantsPoll) {
|
if (postViewModel.wantsPoll || postViewModel.wantsZapPoll) {
|
||||||
Row(
|
Column(
|
||||||
verticalAlignment = CenterVertically,
|
|
||||||
modifier = Modifier.padding(vertical = Size10dp, horizontal = Size10dp),
|
modifier = Modifier.padding(vertical = Size10dp, horizontal = Size10dp),
|
||||||
) {
|
) {
|
||||||
PollOptionsField(postViewModel)
|
Row(
|
||||||
}
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
}
|
) {
|
||||||
|
FilterChip(
|
||||||
if (postViewModel.wantsZapPoll) {
|
selected = postViewModel.wantsPoll,
|
||||||
Row(
|
onClick = {
|
||||||
verticalAlignment = CenterVertically,
|
postViewModel.wantsPoll = true
|
||||||
modifier = Modifier.padding(vertical = Size10dp, horizontal = Size10dp),
|
postViewModel.wantsZapPoll = false
|
||||||
) {
|
},
|
||||||
ZapPollField(postViewModel)
|
label = { Text(stringRes(R.string.kind_poll)) },
|
||||||
|
)
|
||||||
|
FilterChip(
|
||||||
|
selected = postViewModel.wantsZapPoll,
|
||||||
|
onClick = {
|
||||||
|
postViewModel.wantsZapPoll = true
|
||||||
|
postViewModel.wantsPoll = false
|
||||||
|
},
|
||||||
|
label = { Text(stringRes(R.string.kind_zap_poll)) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (postViewModel.wantsPoll) {
|
||||||
|
Row(verticalAlignment = CenterVertically) {
|
||||||
|
PollOptionsField(postViewModel)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Row(verticalAlignment = CenterVertically) {
|
||||||
|
ZapPollField(postViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -588,24 +608,14 @@ private fun BottomRowActions(postViewModel: ShortNotePostViewModel) {
|
|||||||
maxDurationSeconds = MAX_VOICE_RECORD_SECONDS,
|
maxDurationSeconds = MAX_VOICE_RECORD_SECONDS,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (postViewModel.canUsePoll) {
|
if (postViewModel.canUsePoll || postViewModel.canUseZapPoll) {
|
||||||
AddPollButton(postViewModel.wantsPoll) {
|
AddPollButton(postViewModel.wantsPoll || postViewModel.wantsZapPoll) {
|
||||||
postViewModel.wantsPoll = !postViewModel.wantsPoll
|
val isActive = postViewModel.wantsPoll || postViewModel.wantsZapPoll
|
||||||
if (postViewModel.wantsPoll) {
|
if (isActive) {
|
||||||
if (postViewModel.wantsZapPoll) {
|
postViewModel.wantsPoll = false
|
||||||
postViewModel.wantsZapPoll = false
|
postViewModel.wantsZapPoll = false
|
||||||
}
|
} else {
|
||||||
}
|
postViewModel.wantsPoll = true
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (postViewModel.canUseZapPoll) {
|
|
||||||
AddZapPollButton(postViewModel.wantsZapPoll) {
|
|
||||||
postViewModel.wantsZapPoll = !postViewModel.wantsZapPoll
|
|
||||||
if (postViewModel.wantsZapPoll) {
|
|
||||||
if (postViewModel.wantsPoll) {
|
|
||||||
postViewModel.wantsPoll = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -655,32 +665,6 @@ private fun BottomRowActionsPreview() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun AddZapPollButton(
|
|
||||||
isPollActive: Boolean,
|
|
||||||
onClick: () -> Unit,
|
|
||||||
) {
|
|
||||||
IconButton(
|
|
||||||
onClick = { onClick() },
|
|
||||||
) {
|
|
||||||
if (!isPollActive) {
|
|
||||||
Icon(
|
|
||||||
painter = painterRes(R.drawable.ic_poll, 1),
|
|
||||||
contentDescription = stringRes(id = R.string.poll),
|
|
||||||
modifier = Size19Modifier,
|
|
||||||
tint = MaterialTheme.colorScheme.onBackground,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Icon(
|
|
||||||
painter = painterRes(R.drawable.ic_poll, 1),
|
|
||||||
contentDescription = stringRes(id = R.string.disable_poll),
|
|
||||||
modifier = Size19Modifier,
|
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun AddPollButton(
|
private fun AddPollButton(
|
||||||
isPollActive: Boolean,
|
isPollActive: Boolean,
|
||||||
|
|||||||
+12
-98
@@ -20,29 +20,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
|
||||||
import androidx.compose.animation.fadeIn
|
|
||||||
import androidx.compose.animation.fadeOut
|
|
||||||
import androidx.compose.animation.slideInVertically
|
|
||||||
import androidx.compose.animation.slideOutVertically
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.outlined.Close
|
|
||||||
import androidx.compose.material.icons.outlined.Poll
|
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
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.Modifier
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||||
@@ -53,86 +36,17 @@ import com.vitorpamplona.amethyst.ui.theme.Size55Modifier
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NewPollButton(nav: INav) {
|
fun NewPollButton(nav: INav) {
|
||||||
var isOpen by remember { mutableStateOf(false) }
|
FloatingActionButton(
|
||||||
|
onClick = { nav.nav(Route.NewPoll()) },
|
||||||
Column {
|
modifier = Size55Modifier,
|
||||||
AnimatedVisibility(
|
shape = CircleShape,
|
||||||
visible = isOpen,
|
containerColor = MaterialTheme.colorScheme.primary,
|
||||||
enter = slideInVertically(initialOffsetY = { it / 2 }) + fadeIn(),
|
) {
|
||||||
exit = slideOutVertically(targetOffsetY = { it / 2 }) + fadeOut(),
|
Icon(
|
||||||
) {
|
painter = painterRes(R.drawable.ic_compose, 4),
|
||||||
Column {
|
contentDescription = stringRes(id = R.string.new_poll),
|
||||||
FloatingActionButton(
|
modifier = Size26Modifier,
|
||||||
onClick = {
|
tint = Color.White,
|
||||||
nav.nav(Route.NewPoll())
|
)
|
||||||
isOpen = false
|
|
||||||
},
|
|
||||||
modifier = Size55Modifier,
|
|
||||||
shape = CircleShape,
|
|
||||||
containerColor = MaterialTheme.colorScheme.primary,
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Outlined.Poll,
|
|
||||||
contentDescription = stringRes(id = R.string.new_regular_poll),
|
|
||||||
modifier = Size26Modifier,
|
|
||||||
tint = Color.White,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(20.dp))
|
|
||||||
|
|
||||||
FloatingActionButton(
|
|
||||||
onClick = {
|
|
||||||
nav.nav(Route.NewZapPoll())
|
|
||||||
isOpen = false
|
|
||||||
},
|
|
||||||
modifier = Size55Modifier,
|
|
||||||
shape = CircleShape,
|
|
||||||
containerColor = MaterialTheme.colorScheme.primary,
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painter = painterRes(R.drawable.ic_poll, 1),
|
|
||||||
contentDescription = stringRes(id = R.string.new_zap_poll),
|
|
||||||
modifier = Size26Modifier,
|
|
||||||
tint = Color.White,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(20.dp))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FloatingActionButton(
|
|
||||||
onClick = { isOpen = !isOpen },
|
|
||||||
modifier = Size55Modifier,
|
|
||||||
shape = CircleShape,
|
|
||||||
containerColor = MaterialTheme.colorScheme.primary,
|
|
||||||
) {
|
|
||||||
AnimatedVisibility(
|
|
||||||
visible = isOpen,
|
|
||||||
enter = fadeIn(),
|
|
||||||
exit = fadeOut(),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Outlined.Close,
|
|
||||||
contentDescription = stringRes(id = R.string.new_poll),
|
|
||||||
modifier = Size26Modifier,
|
|
||||||
tint = Color.White,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility(
|
|
||||||
visible = !isOpen,
|
|
||||||
enter = fadeIn(),
|
|
||||||
exit = fadeOut(),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painter = painterRes(R.drawable.ic_compose, 4),
|
|
||||||
contentDescription = stringRes(id = R.string.new_poll),
|
|
||||||
modifier = Size26Modifier,
|
|
||||||
tint = Color.White,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-6
@@ -35,7 +35,6 @@ import kotlinx.coroutines.FlowPreview
|
|||||||
@OptIn(ExperimentalMaterial3Api::class, FlowPreview::class)
|
@OptIn(ExperimentalMaterial3Api::class, FlowPreview::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun PollPostScreen(
|
fun PollPostScreen(
|
||||||
isZapPoll: Boolean,
|
|
||||||
message: String? = null,
|
message: String? = null,
|
||||||
draftId: HexKey? = null,
|
draftId: HexKey? = null,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
@@ -51,11 +50,7 @@ fun PollPostScreen(
|
|||||||
postViewModel.message.setTextAndPlaceCursorAtEnd(it)
|
postViewModel.message.setTextAndPlaceCursorAtEnd(it)
|
||||||
postViewModel.onMessageChanged()
|
postViewModel.onMessageChanged()
|
||||||
}
|
}
|
||||||
if (isZapPoll) {
|
postViewModel.wantsPoll = true
|
||||||
postViewModel.wantsZapPoll = true
|
|
||||||
} else {
|
|
||||||
postViewModel.wantsPoll = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NewPostScreenInner(postViewModel, accountViewModel, nav)
|
NewPostScreenInner(postViewModel, accountViewModel, nav)
|
||||||
|
|||||||
Reference in New Issue
Block a user