Skip to content

Commit

Permalink
feat: sketching prototype pt1 - module (WPB-6243) (#2811)
Browse files Browse the repository at this point in the history
  • Loading branch information
yamilmedina authored Apr 5, 2024
1 parent 930b7af commit ad1880f
Show file tree
Hide file tree
Showing 85 changed files with 1,314 additions and 156 deletions.
9 changes: 9 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ plugins {
id(ScriptPlugins.compilation)
id(ScriptPlugins.testing)
id(ScriptPlugins.spotless)
id(libs.plugins.wire.kover.get().pluginId)
}

repositories {
Expand Down Expand Up @@ -83,6 +84,14 @@ dependencies {
implementation("com.wire.kalium:kalium-logic")
implementation("com.wire.kalium:kalium-util")

// features
implementation(project(":features:sketch"))
implementation(project(":core:ui-common"))

// kover
kover(project(":features:sketch"))
kover(project(":core:ui-common"))

// Application dependencies
implementation(libs.androidx.appcompat)
implementation(libs.androidx.core)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,20 @@

package com.wire.android.ui.common

import android.widget.Toast
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.semantics.Role
import androidx.lifecycle.Lifecycle
Expand All @@ -45,13 +40,10 @@ import androidx.lifecycle.flowWithLifecycle
import com.google.accompanist.placeholder.PlaceholderHighlight
import com.google.accompanist.placeholder.placeholder
import com.google.accompanist.placeholder.shimmer
import com.wire.android.R
import com.wire.android.model.ClickBlockParams
import com.wire.android.model.Clickable
import com.wire.android.ui.home.conversations.model.messagetypes.asset.UIAssetMessage
import com.wire.android.ui.theme.wireColorScheme
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.util.LocalSyncStateObserver
import com.wire.kalium.logic.data.message.Message
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
Expand All @@ -65,6 +57,8 @@ import java.util.Locale
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext

// todo try to move as much as we can to common

@Composable
fun Modifier.selectableBackground(isSelected: Boolean, onClick: () -> Unit): Modifier =
this.selectable(
Expand All @@ -75,15 +69,6 @@ fun Modifier.selectableBackground(isSelected: Boolean, onClick: () -> Unit): Mod
role = Role.Tab
)

@Composable
fun Tint(contentColor: Color, content: @Composable () -> Unit) {
CompositionLocalProvider(LocalContentColor provides contentColor, content = content)
}

@Composable
fun ImageVector.Icon(modifier: Modifier = Modifier): @Composable (() -> Unit) =
{ androidx.compose.material3.Icon(imageVector = this, contentDescription = "", modifier = modifier) }

@Composable
fun Modifier.shimmerPlaceholder(
visible: Boolean,
Expand Down Expand Up @@ -111,29 +96,14 @@ fun Modifier.clickable(clickable: Clickable?) = clickable?.let {
)
} ?: this

@Composable
fun rememberClickBlockAction(clickBlockParams: ClickBlockParams, clickAction: () -> Unit): () -> Unit {
val syncStateObserver = LocalSyncStateObserver.current
val context = LocalContext.current
return remember(clickBlockParams, syncStateObserver, clickAction) {
{
when {
clickBlockParams.blockWhenConnecting && syncStateObserver.isConnecting ->
Toast.makeText(context, context.getString(R.string.label_wait_until_connected), Toast.LENGTH_SHORT).show()
clickBlockParams.blockWhenSyncing && syncStateObserver.isSyncing ->
Toast.makeText(context, context.getString(R.string.label_wait_until_synchronised), Toast.LENGTH_SHORT).show()
else -> clickAction()
}
}
}
}

@Composable
fun <T> rememberFlow(
flow: Flow<T>,
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current
): Flow<T> {
return remember(key1 = flow, key2 = lifecycleOwner) { flow.flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED) }
return remember(key1 = flow, key2 = lifecycleOwner) {
flow.flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED)
}
}

// TODO replace by collectAsStateWithLifecycle() after updating lifecycle version to 2.6.0-alpha01 or newer
Expand All @@ -154,8 +124,7 @@ fun <T> StateFlow<T>.collectAsStateLifecycleAware(
): State<T> = collectAsStateLifecycleAware(value, context)

fun monthYearHeader(month: Int, year: Int): String {
val currentYear = Instant.fromEpochMilliseconds(System.currentTimeMillis()).toLocalDateTime(
TimeZone.currentSystemDefault()).year
val currentYear = Instant.fromEpochMilliseconds(System.currentTimeMillis()).toLocalDateTime(TimeZone.currentSystemDefault()).year
val monthYearInstant = LocalDateTime(year = year, monthNumber = month, 1, 0, 0, 0)

val monthName = monthYearInstant.month.getDisplayName(TextStyle.FULL_STANDALONE, Locale.getDefault())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,12 @@

package com.wire.android.ui.common

import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import com.wire.android.ui.theme.WireColorScheme
import com.wire.android.ui.theme.wireColorScheme
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.theme.wireTypography
import com.wire.kalium.logic.data.id.ConversationId
import kotlin.math.absoluteValue

@Composable
internal fun dimensions() = MaterialTheme.wireDimensions

@Composable
internal fun colorsScheme() = MaterialTheme.wireColorScheme

@Composable
internal fun typography() = MaterialTheme.wireTypography

@Composable
internal fun WireColorScheme.conversationColor(id: ConversationId): Color {
val colors = this.groupAvatarColors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*/
package com.wire.android.ui.common.scaffold

import SwipeableSnackbar
import com.wire.android.ui.common.snackbar.SwipeableSnackbar
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.imePadding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.compose.ui.platform.LocalContext
import com.wire.android.util.ui.UIText
import kotlinx.coroutines.flow.SharedFlow

// TODO: moved to commons, when deciding about [UIText]
@Composable
fun SnackbarHostState.collectAndShowSnackbar(
snackbarFlow: SharedFlow<UIText>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

package com.wire.android.ui.home.conversations

import SwipeableSnackbar
import com.wire.android.ui.common.snackbar.SwipeableSnackbar
import android.annotation.SuppressLint
import android.net.Uri
import androidx.activity.compose.BackHandler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

package com.wire.android.ui.home.conversations.details

import SwipeableSnackbar
import com.wire.android.ui.common.snackbar.SwipeableSnackbar
import androidx.annotation.StringRes
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.LocalOverscrollConfiguration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ fun AdditionalOptionsMenu(
onRichEditingButtonClicked: () -> Unit,
onCloseRichEditingButtonClicked: () -> Unit,
onRichOptionButtonClicked: (RichTextMarkdown) -> Unit,
onDrawingModeClicked: () -> Unit,
modifier: Modifier = Modifier
) {
Box(modifier.background(colorsScheme().messageComposerBackgroundColor)) {
Expand All @@ -71,7 +72,8 @@ fun AdditionalOptionsMenu(
onGifButtonClicked = onGifOptionClicked ?: {},
onSelfDeletionOptionButtonClicked = onOnSelfDeletingOptionClicked ?: {},
onRichEditingButtonClicked = onRichEditingButtonClicked,
onPingClicked = onPingOptionClicked
onPingClicked = onPingOptionClicked,
onDrawingModeClicked = onDrawingModeClicked
)
}

Expand Down Expand Up @@ -153,6 +155,7 @@ fun AttachmentAndAdditionalOptionsMenuItems(
isSelfDeletingActive: Boolean,
onGifButtonClicked: () -> Unit = {},
onRichEditingButtonClicked: () -> Unit = {},
onDrawingModeClicked: () -> Unit = {},
modifier: Modifier = Modifier
) {
Column(modifier.wrapContentSize()) {
Expand All @@ -168,7 +171,8 @@ fun AttachmentAndAdditionalOptionsMenuItems(
isSelfDeletingSettingEnabled = isSelfDeletingSettingEnabled,
isSelfDeletingActive = isSelfDeletingActive,
onGifButtonClicked = onGifButtonClicked,
onRichEditingButtonClicked = onRichEditingButtonClicked
onRichEditingButtonClicked = onRichEditingButtonClicked,
onDrawingModeClicked = onDrawingModeClicked
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import com.wire.android.feature.sketch.DrawingCanvasBottomSheet
import com.wire.android.ui.common.banner.SecurityClassificationBannerForConversation
import com.wire.android.ui.common.bottombar.BottomNavigationBarHeight
import com.wire.android.ui.common.colorsScheme
Expand Down Expand Up @@ -257,6 +258,7 @@ fun EnabledMessageComposer(
additionalOptionStateHolder.toRichTextEditing()
},
onCloseRichEditingButtonClicked = additionalOptionStateHolder::toAttachmentAndAdditionalOptionsMenu,
onDrawingModeClicked = additionalOptionStateHolder::toDrawingMode
)
}
Box(
Expand Down Expand Up @@ -288,6 +290,18 @@ fun EnabledMessageComposer(
)
}
}

if (additionalOptionStateHolder.selectedOption == AdditionalOptionSelectItem.DrawingMode) {
DrawingCanvasBottomSheet(
onDismissSketch = {
inputStateHolder.handleBackPressed(
isImeVisible,
additionalOptionStateHolder.additionalOptionsSubMenuState
)
},
onSendSketch = onSendButtonClicked
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ fun MessageComposeActions(
onPingButtonClicked: () -> Unit,
onSelfDeletionOptionButtonClicked: () -> Unit,
onGifButtonClicked: () -> Unit,
onRichEditingButtonClicked: () -> Unit
onRichEditingButtonClicked: () -> Unit,
onDrawingModeClicked: () -> Unit
) {
if (isEditing) {
EditingActions(
Expand All @@ -71,7 +72,8 @@ fun MessageComposeActions(
isSelfDeletingActive,
onSelfDeletionOptionButtonClicked,
onPingButtonClicked,
onMentionButtonClicked
onMentionButtonClicked,
onDrawingModeClicked
)
}
}
Expand All @@ -87,7 +89,8 @@ private fun ComposingActions(
isSelfDeletingActive: Boolean,
onSelfDeletionOptionButtonClicked: () -> Unit,
onPingButtonClicked: () -> Unit,
onMentionButtonClicked: () -> Unit
onMentionButtonClicked: () -> Unit,
onDrawingModeClicked: () -> Unit
) {
val localFeatureVisibilityFlags = LocalFeatureVisibilityFlags.current

Expand All @@ -107,6 +110,12 @@ private fun ComposingActions(
isSelected = selectedOption == AdditionalOptionSelectItem.RichTextEditing,
onRichEditingButtonClicked
)
if (DrawingIcon) {
DrawingModeAction(
isSelected = selectedOption == AdditionalOptionSelectItem.DrawingMode,
onDrawingModeClicked
)
}
if (EmojiIcon) AddEmojiAction({})
if (GifIcon) AddGifAction(onGifButtonClicked)
if (isSelfDeletingSettingEnabled) SelfDeletingMessageAction(
Expand Down Expand Up @@ -158,6 +167,17 @@ private fun RichTextEditingAction(isSelected: Boolean, onButtonClicked: () -> Un
)
}

@Composable
private fun DrawingModeAction(isSelected: Boolean, onButtonClicked: () -> Unit) {
WireSecondaryIconButton(
onButtonClicked = onButtonClicked,
clickBlockParams = ClickBlockParams(blockWhenSyncing = true, blockWhenConnecting = true),
iconResource = R.drawable.ic_drawing,
state = if (isSelected) WireButtonState.Selected else WireButtonState.Default,
contentDescription = R.string.content_description_conversation_enable_drawing_mode
)
}

@Composable
private fun AddEmojiAction(onButtonClicked: () -> Unit) {
var isSelected by remember { mutableStateOf(false) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ enum class AdditionalOptionSubMenuState {

enum class AdditionalOptionSelectItem {
RichTextEditing,
DrawingMode,

// it's only used to show keyboard after self deleting bottom sheet collapses
SelfDeleting,
Expand Down Expand Up @@ -94,6 +95,10 @@ class AdditionalOptionStateHolder {
selectedOption = AdditionalOptionSelectItem.SelfDeleting
}

fun toDrawingMode() {
selectedOption = AdditionalOptionSelectItem.DrawingMode
}

companion object {
fun saver(): Saver<AdditionalOptionStateHolder, *> = Saver(
save = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ object FeatureVisibilityFlags {
const val UserProfileEditIcon = false
const val MessageEditIcon = true
const val SearchConversationMessages = true
const val DrawingIcon = false
}

val LocalFeatureVisibilityFlags = staticCompositionLocalOf { FeatureVisibilityFlags }
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_drawing.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="17dp"
android:height="16dp"
android:viewportWidth="17"
android:viewportHeight="16">
<path
android:pathData="M14.477,13.849C15.547,13.285 16.26,12.761 16.578,12.179C17.246,10.953 16.329,10.121 14.89,9.922C13.757,9.765 12.723,9.985 9.058,10.963C8.838,11.021 8.662,11.068 8.493,11.113C6.227,11.71 4.886,11.976 3.896,11.969C3.024,11.963 2.909,11.87 2.976,11.381C2.963,11.47 2.977,11.454 3.116,11.372C3.376,11.218 3.79,11.058 4.346,10.9C5.308,10.628 6.361,10.426 8.644,10.047C8.82,10.018 8.82,10.018 8.996,9.989C11.567,9.562 12.779,9.324 13.928,8.973C15.794,8.402 16.846,7.65 16.709,6.322C16.577,5.041 15.474,4.78 13.449,4.823C12.303,4.847 11.024,4.972 8.634,5.262C8.479,5.28 8.479,5.28 8.324,5.299C6.481,5.523 5.479,5.638 4.698,5.7C5.622,5.427 6.797,5.17 8.586,4.82C8.848,4.769 9.137,4.713 9.686,4.607C10.131,4.521 10.453,4.458 10.765,4.395C15.09,3.53 16.231,3.145 15.958,1.57C15.711,0.154 13.479,-0.114 9.673,0.038C6.499,0.165 3.411,0.672 1.743,1.441C1.232,1.677 1.01,2.28 1.249,2.786C1.487,3.293 2.095,3.512 2.606,3.276C3.969,2.647 6.831,2.177 9.756,2.06C10.588,2.027 12.032,2.05 12.032,2.05C11.564,2.163 11.014,2.28 10.36,2.411C10.054,2.473 9.735,2.535 9.293,2.621C8.746,2.727 8.455,2.783 8.191,2.834C2.535,3.938 0.799,4.501 0.8,6.306C0.8,7.66 1.832,7.862 3.917,7.775C4.98,7.731 5.931,7.63 8.573,7.309C8.727,7.29 8.727,7.29 8.882,7.271C11.201,6.99 12.44,6.869 13.493,6.847C13.637,6.844 13.773,6.843 13.899,6.845C13.728,6.908 13.538,6.974 13.325,7.038C12.296,7.353 11.132,7.581 8.658,7.992C8.482,8.021 8.482,8.021 8.306,8.051C2.625,8.994 1.184,9.403 0.951,11.109C0.692,13.003 1.914,13.979 3.882,13.993C5.119,14.002 6.57,13.714 9.018,13.069C9.19,13.024 9.367,12.977 9.589,12.917C11.767,12.336 13.736,11.944 13.736,11.944C13.756,11.944 13.573,12.032 13.519,12.061C11.9,12.912 9.46,13.76 7.968,13.987C7.41,14.072 7.028,14.589 7.113,15.142C7.199,15.694 7.721,16.073 8.279,15.988C10.01,15.724 12.665,14.802 14.477,13.849Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
</vector>
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
<string name="content_description_conversation_search_icon">Search icon</string>
<string name="content_description_conversation_search_input">Search input</string>
<string name="content_description_conversation_enable_rich_text_mode">Enable rich text mode button</string>
<string name="content_description_conversation_enable_drawing_mode">Enable drawing mode button</string>
<string name="content_description_conversation_rich_text_header">Rich text formatting Header</string>
<string name="content_description_conversation_rich_text_bold">Rich text formatting Bold</string>
<string name="content_description_conversation_rich_text_italic">Rich text formatting Italic</string>
Expand Down
5 changes: 5 additions & 0 deletions build-logic/plugins/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ tasks.withType<KotlinCompile>().configureEach {
dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
compileOnly(libs.kover.gradlePlugin)

testImplementation(libs.junit4)
testImplementation(libs.kluent.core)
Expand All @@ -54,5 +55,9 @@ gradlePlugin {
id = libs.plugins.wire.hilt.get().pluginId
implementationClass = "HiltConventionPlugin"
}
register("wireKoverConventionPlugin") {
id = libs.plugins.wire.kover.get().pluginId
implementationClass = "KoverConventionPlugin"
}
}
}
Loading

0 comments on commit ad1880f

Please sign in to comment.