Skip to content

Commit

Permalink
Merge branch 'develop' into ci/add-attachments-e2e-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
VelikovPetar authored Feb 13, 2025
2 parents 2e072f5 + a60a95c commit 79ca349
Show file tree
Hide file tree
Showing 19 changed files with 173 additions and 65 deletions.
59 changes: 39 additions & 20 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@

### ❌ Removed

## stream-chat-android-core
### ✅ Added
- Expose `UserId` alias that Represents a user id. [#5616](https://github.com/GetStream/stream-chat-android/pull/5616)

## stream-chat-android-offline
### 🐞 Fixed

Expand Down Expand Up @@ -53,25 +49,61 @@
### ⬆️ Improved

### ✅ Added
- Added `DateFormatter::formatRelativeDate` method to format a relative date. [#5587](https://github.com/GetStream/stream-chat-android/pull/5587)

### ⚠️ Changed

### ❌ Removed

## stream-chat-android-ui-components
### 🐞 Fixed
- Fix poll attachment picker not hidden if disabled in the dashboard. [#5562](https://github.com/GetStream/stream-chat-android/pull/5562)

### ⬆️ Improved
- `DateDividerViewHolder` now uses `DateFormatter::formatRelativeDate` to format the date. [#5587](https://github.com/GetStream/stream-chat-android/pull/5587)

### ✅ Added

### ⚠️ Changed

### ❌ Removed

## stream-chat-android-compose
### 🐞 Fixed

### ⬆️ Improved
- Autofocus the input fields in the poll creation screen. [#5629](https://github.com/GetStream/stream-chat-android/pull/5629)

### ✅ Added

### ⚠️ Changed

### ❌ Removed

## stream-chat-android-markdown-transformer
### 🐞 Fixed

### ⬆️ Improved

### ✅ Added

### ⚠️ Changed

### ❌ Removed

# February 07th, 2025 - 6.11.0
## stream-chat-android-core
### ✅ Added
- Expose `UserId` alias that Represents a user id. [#5616](https://github.com/GetStream/stream-chat-android/pull/5616)

## stream-chat-android-ui-common
### ✅ Added
- Added `DateFormatter::formatRelativeDate` method to format a relative date. [#5587](https://github.com/GetStream/stream-chat-android/pull/5587)

## stream-chat-android-ui-components
### 🐞 Fixed
- Fix poll attachment picker not hidden if disabled in the dashboard. [#5562](https://github.com/GetStream/stream-chat-android/pull/5562)

### ⬆️ Improved
- `DateDividerViewHolder` now uses `DateFormatter::formatRelativeDate` to format the date. [#5587](https://github.com/GetStream/stream-chat-android/pull/5587)

## stream-chat-android-compose
### 🐞 Fixed
- Fix poll attachment picker not hidden if disabled in the dashboard. [#5562](https://github.com/GetStream/stream-chat-android/pull/5562)
Expand Down Expand Up @@ -103,19 +135,6 @@
### ⚠️ Changed
- 🚨 Breaking change: Change `@Composable public fun MessageContainer` function to `@Composable public fun LazyItemScope.MessageContainer`. [#5593](https://github.com/GetStream/stream-chat-android/pull/5593)

### ❌ Removed

## stream-chat-android-markdown-transformer
### 🐞 Fixed

### ⬆️ Improved

### ✅ Added

### ⚠️ Changed

### ❌ Removed

# January 23th, 2025 - 6.10.0
## Common changes for all artifacts
### ⬆️ Improved
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ GEM
puma (6.4.3)
nio4r (~> 2.0)
racc (1.8.1)
rack (3.1.8)
rack (3.1.10)
rack-protection (4.1.0)
base64 (>= 0.1.0)
logger (>= 1.6.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ object Configuration {
const val sampleTargetSdk = 34
const val minSdk = 21
const val majorVersion = 6
const val minorVersion = 10
const val minorVersion = 11
const val patchVersion = 0
const val versionName = "$majorVersion.$minorVersion.$patchVersion"
const val snapshotVersionName = "$majorVersion.$minorVersion.${patchVersion + 1}-SNAPSHOT"
Expand Down
2 changes: 1 addition & 1 deletion metrics/size.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"stream-chat-android-client": 15308,
"stream-chat-android-offline": 15620,
"stream-chat-android-ui-components": 20992,
"stream-chat-android-compose": 22388
"stream-chat-android-compose": 22392
},
"release": {
"stream-chat-android-client": 3244,
Expand Down
13 changes: 0 additions & 13 deletions stream-chat-android-ai-assistant/detekt-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,14 @@
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>FunctionNaming:AiMessageText.kt$@Composable private fun ClickableText( text: AnnotatedString, modifier: Modifier = Modifier, style: TextStyle = TextStyle.Default, maxLines: Int = Int.MAX_VALUE, onLongPress: () -> Unit, onClick: (Int) -> Unit, )</ID>
<ID>FunctionNaming:AiMessageText.kt$@Composable public fun AiMessageText( message: Message, currentUser: User?, typingState: TypingState, modifier: Modifier = Modifier, onAnimationState: (Boolean) -> Unit, onLongItemClick: (Message) -> Unit, onLinkClick: ((Message, String) -> Unit)? = null, )</ID>
<ID>FunctionNaming:AiMessagesScreen.kt$@Composable internal fun BoxScope.DefaultAiStartButton( isAiStarted: Boolean, onStartAiAssistant: () -> Unit, onStopAiAssistant: () -> Unit, )</ID>
<ID>FunctionNaming:AiMessagesScreen.kt$@Composable internal fun DefaultBottomBarContent( viewModelFactory: MessagesViewModelFactory, onComposerLinkPreviewClick: ((LinkPreview) -> Unit)? = null, skipPushNotification: Boolean = false, skipEnrichUrl: Boolean = false, )</ID>
<ID>FunctionNaming:AiMessagesScreen.kt$@Composable internal fun DefaultTopBarContent( viewModelFactory: MessagesViewModelFactory, backAction: BackAction, onHeaderTitleClick: (channel: Channel) -> Unit, onChannelAvatarClick: () -> Unit, )</ID>
<ID>FunctionNaming:AiMessagesScreen.kt$@Composable public fun AiMessagesScreen( viewModelFactory: MessagesViewModelFactory, isAiStarted: Boolean, onStartAiAssistant: () -> Unit, onStopAiAssistant: () -> Unit, showHeader: Boolean = true, typingState: TypingState, reactionSorting: ReactionSorting = ReactionSortingByFirstReactionAt, onBackPressed: () -> Unit = {}, onComposerLinkPreviewClick: ((LinkPreview) -> Unit)? = null, onHeaderTitleClick: (channel: Channel) -> Unit = {}, onChannelAvatarClick: () -> Unit = {}, onMessageLinkClick: ((Message, String) -> Unit)? = null, onUserAvatarClick: (User) -> Unit = {}, skipPushNotification: Boolean = false, skipEnrichUrl: Boolean = false, threadMessagesStart: ThreadMessagesStart = ThreadMessagesStart.BOTTOM, aiStartButton: @Composable BoxScope.() -> Unit = { DefaultAiStartButton( isAiStarted = isAiStarted, onStartAiAssistant = onStartAiAssistant, onStopAiAssistant = onStopAiAssistant, ) }, topBarContent: @Composable (BackAction) -> Unit = { DefaultTopBarContent( viewModelFactory = viewModelFactory, backAction = it, onHeaderTitleClick = onHeaderTitleClick, onChannelAvatarClick = onChannelAvatarClick, ) }, bottomBarContent: @Composable (isAnimating: Boolean) -> Unit = { DefaultBottomBarContent( viewModelFactory = viewModelFactory, onComposerLinkPreviewClick = onComposerLinkPreviewClick, skipPushNotification = skipPushNotification, skipEnrichUrl = skipEnrichUrl, ) }, )</ID>
<ID>FunctionNaming:AiRegularMessageContent.kt$@Composable internal fun DefaultMessageTextContent( message: Message, currentUser: User?, typingState: TypingState, onAnimationState: (Boolean) -> Unit, onLongItemClick: (Message) -> Unit, onLinkClick: ((Message, String) -> Unit)? = null, )</ID>
<ID>FunctionNaming:AiRegularMessageContent.kt$@Composable public fun AiRegularMessageContent( messageItem: MessageItemState, modifier: Modifier = Modifier, onLongItemClick: (Message) -> Unit = {}, onGiphyActionClick: (GiphyAction) -> Unit = {}, onQuotedMessageClick: (Message) -> Unit = {}, onAnimationState: (Boolean) -> Unit, onLinkClick: ((Message, String) -> Unit)? = null, typingState: TypingState, onMediaGalleryPreviewResult: (MediaGalleryPreviewResult?) -> Unit = {}, )</ID>
<ID>FunctionNaming:AiTypingIndicator.kt$@Composable private fun SingleDot( scale: Float, shimmerInstance: Shimmer, )</ID>
<ID>FunctionNaming:AiTypingIndicator.kt$@Composable public fun AiTypingIndicator( modifier: Modifier = Modifier, text: String, textStyle: TextStyle = TextStyle( fontSize = 16.sp, color = ChatTheme.colors.textHighEmphasis, ), )</ID>
<ID>LongMethod:AiMessageContentFactory.kt$AiMessageContentFactory$@Composable override fun MessageFooterContent(messageItem: MessageItemState)</ID>
<ID>LongMethod:AiMessageText.kt$@Composable public fun AiMessageText( message: Message, currentUser: User?, typingState: TypingState, modifier: Modifier = Modifier, onAnimationState: (Boolean) -> Unit, onLongItemClick: (Message) -> Unit, onLinkClick: ((Message, String) -> Unit)? = null, )</ID>
<ID>LongMethod:AiMessagesScreen.kt$@Composable public fun AiMessagesScreen( viewModelFactory: MessagesViewModelFactory, isAiStarted: Boolean, onStartAiAssistant: () -> Unit, onStopAiAssistant: () -> Unit, showHeader: Boolean = true, typingState: TypingState, reactionSorting: ReactionSorting = ReactionSortingByFirstReactionAt, onBackPressed: () -> Unit = {}, onComposerLinkPreviewClick: ((LinkPreview) -> Unit)? = null, onHeaderTitleClick: (channel: Channel) -> Unit = {}, onChannelAvatarClick: () -> Unit = {}, onMessageLinkClick: ((Message, String) -> Unit)? = null, onUserAvatarClick: (User) -> Unit = {}, skipPushNotification: Boolean = false, skipEnrichUrl: Boolean = false, threadMessagesStart: ThreadMessagesStart = ThreadMessagesStart.BOTTOM, aiStartButton: @Composable BoxScope.() -> Unit = { DefaultAiStartButton( isAiStarted = isAiStarted, onStartAiAssistant = onStartAiAssistant, onStopAiAssistant = onStopAiAssistant, ) }, topBarContent: @Composable (BackAction) -> Unit = { DefaultTopBarContent( viewModelFactory = viewModelFactory, backAction = it, onHeaderTitleClick = onHeaderTitleClick, onChannelAvatarClick = onChannelAvatarClick, ) }, bottomBarContent: @Composable (isAnimating: Boolean) -> Unit = { DefaultBottomBarContent( viewModelFactory = viewModelFactory, onComposerLinkPreviewClick = onComposerLinkPreviewClick, skipPushNotification = skipPushNotification, skipEnrichUrl = skipEnrichUrl, ) }, )</ID>
<ID>LongMethod:AiRegularMessageContent.kt$@Composable public fun AiRegularMessageContent( messageItem: MessageItemState, modifier: Modifier = Modifier, onLongItemClick: (Message) -> Unit = {}, onGiphyActionClick: (GiphyAction) -> Unit = {}, onQuotedMessageClick: (Message) -> Unit = {}, onAnimationState: (Boolean) -> Unit, onLinkClick: ((Message, String) -> Unit)? = null, typingState: TypingState, onMediaGalleryPreviewResult: (MediaGalleryPreviewResult?) -> Unit = {}, )</ID>
<ID>MagicNumber:AiMessageText.kt$10</ID>
<ID>MagicNumber:AiMessagesScreen.kt$0.75f</ID>
<ID>MagicNumber:AiMessagesScreen.kt$300f</ID>
<ID>MagicNumber:AiTypingIndicator.kt$0.55f</ID>
<ID>MagicNumber:AiTypingIndicator.kt$4</ID>
<ID>TopLevelPropertyNaming:AiMessageText.kt$/** * The tag used to annotate URLs in the message text. */ internal const val AnnotationTagUrl: AnnotationTag = "URL"</ID>
<ID>TopLevelPropertyNaming:AiMessageText.kt$/** * The tag used to annotate emails in the message text. */ internal const val AnnotationTagEmail: AnnotationTag = "EMAIL"</ID>
<ID>TopLevelPropertyNaming:AiTypingIndicator.kt$private const val delayUnit = 200</ID>
</CurrentIssues>
</SmellBaseline>
12 changes: 7 additions & 5 deletions stream-chat-android-compose/api/stream-chat-android-compose.api
Original file line number Diff line number Diff line change
Expand Up @@ -1774,18 +1774,20 @@ public final class io/getstream/chat/android/compose/ui/messages/attachments/pol

public final class io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInput {
public static final field $stable I
public synthetic fun <init> (Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/Object;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Ljava/lang/Object;
public final fun component4-PjHm6EE ()I
public final fun copy-YyDlPXQ (Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;I)Lio/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInput;
public static synthetic fun copy-YyDlPXQ$default (Lio/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInput;Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;IILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInput;
public final fun component4 ()Ljava/lang/Object;
public final fun component5-PjHm6EE ()I
public final fun copy-l6dddJE (Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;I)Lio/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInput;
public static synthetic fun copy-l6dddJE$default (Lio/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInput;Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;IILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInput;
public fun equals (Ljava/lang/Object;)Z
public final fun getDescription ()Ljava/lang/String;
public final fun getKeyboardType-PjHm6EE ()I
public final fun getMaxValue ()Ljava/lang/Object;
public final fun getMinValue ()Ljava/lang/Object;
public final fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
public final fun setValue (Ljava/lang/Object;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.res.stringResource
Expand Down Expand Up @@ -69,6 +73,7 @@ import io.getstream.chat.android.compose.ui.util.buildAnnotatedMessageText
* @param keyboardOptions The [KeyboardOptions] to be applied to the input.
* @param decorationBox Composable function that represents the input field decoration as it's filled with content.
*/
@Suppress("LongMethod")
@Composable
public fun PollOptionInput(
value: String,
Expand All @@ -86,6 +91,7 @@ public fun PollOptionInput(
val typography = ChatTheme.typography
val colors = ChatTheme.colors
val textColor = ChatTheme.colors.textHighEmphasis
val focusRequester = remember { FocusRequester() }

Box(modifier = modifier.height(ChatTheme.dimens.pollOptionInputHeight)) {
BasicTextField(
Expand All @@ -94,6 +100,7 @@ public fun PollOptionInput(
.clip(shape = shape)
.background(ChatTheme.colors.inputBackground)
.padding(innerPadding)
.focusRequester(focusRequester)
.semantics { contentDescription = description },
value = value,
onValueChange = {
Expand Down Expand Up @@ -139,6 +146,11 @@ public fun PollOptionInput(
)
}
}

// Request focus initially when the Input is first drawn.
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
}

@Preview
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public class AttachmentsPickerPollTabFactory : AttachmentsPickerTabFactory {
val pollSwitchItemFactory = ChatTheme.pollSwitchitemFactory
var optionItemList by remember { mutableStateOf(emptyList<PollOptionItem>()) }
var switchItemList: List<PollSwitchItem> by remember { mutableStateOf(pollSwitchItemFactory.providePollSwitchItemList()) }
var hasErrorOnOptions by remember { mutableStateOf(false) }
var hasError by remember { mutableStateOf(false) }
val nestedScrollConnection = remember {
object : NestedScrollConnection {
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
Expand All @@ -139,7 +139,7 @@ public class AttachmentsPickerPollTabFactory : AttachmentsPickerTabFactory {
.background(ChatTheme.colors.appBackground),
) {
val (question, onQuestionChanged) = rememberSaveable { mutableStateOf("") }
val isEnabled = question.isNotBlank() && optionItemList.any { it.title.isNotBlank() } && !hasErrorOnOptions
val isEnabled = question.isNotBlank() && optionItemList.any { it.title.isNotBlank() } && !hasError
val hasChanges = question.isNotBlank() || optionItemList.any { it.title.isNotBlank() }
var isShowingDiscardDialog by remember { mutableStateOf(false) }

Expand Down Expand Up @@ -175,7 +175,7 @@ public class AttachmentsPickerPollTabFactory : AttachmentsPickerTabFactory {
onQuestionsChanged = {
optionItemList = it
switchItemList = updateMaxVotesAllowedSwitch(optionItemList, switchItemList)
hasErrorOnOptions = it.fastAny { item -> item.pollOptionError != null }
hasError = hasError(optionItemList, switchItemList)
},
)

Expand All @@ -185,7 +185,7 @@ public class AttachmentsPickerPollTabFactory : AttachmentsPickerTabFactory {
pollSwitchItems = switchItemList,
onSwitchesChanged = {
switchItemList = it
hasErrorOnOptions = it.fastAny { item -> item.pollOptionError != null }
hasError = hasError(optionItemList, switchItemList)
},
)

Expand All @@ -202,6 +202,28 @@ public class AttachmentsPickerPollTabFactory : AttachmentsPickerTabFactory {
}
}

/**
* Checks if there are any errors in the 'options' list, or any errors or missing fields in the 'switches' list.
*/
private fun hasError(
options: List<PollOptionItem>,
switches: List<PollSwitchItem>,
): Boolean {
// Check errors in options
val hasErrorInOptions = options.fastAny { item ->
item.pollOptionError != null
}
// Check errors or missing fields in switches
val hasErrorInSwitches = switches.fastAny { item ->
val hasError = item.pollOptionError != null
val isMissingMandatoryInput = item.enabled &&
item.pollSwitchInput != null &&
item.pollSwitchInput.value.toString().isEmpty()
hasError || isMissingMandatoryInput
}
return hasErrorInOptions || hasErrorInSwitches
}

/**
* Updates the max votes allowed switch based on the number of options available.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import java.util.UUID
* @property title The title of this poll item.
* @property enabled Indicates if this switch is enabled or not.
* @property key The key that identifies this poll item.
* @property pollSwitchInput Optional input field to be presented when the switch is enabled.
* @property pollOptionError Indicates this option has an error.
*/
@Immutable
Expand All @@ -42,12 +43,14 @@ public data class PollSwitchItem(
*
* @property value The default value of the switch.
* @property description The description of the input in the switch (shown as hint/contentDescription).
* @property maxValue The maximum vale of the switch. Normally, you can use the limit of the decimal format of the [value].
* @property minValue The minimum value of the switch. Normally, you can use the limit of the decimal format of the [value].
* @property maxValue The maximum value of the switch. Normally, you can use the limit of the decimal format of the [value].
* @property keyboardType The type of the input of the switch and decide the keyboard type of the input.
*/
public data class PollSwitchInput(
public var value: Any,
public val description: String = "",
public val minValue: Any? = null,
public val maxValue: Any? = null,
public val keyboardType: KeyboardType = KeyboardType.Text,
)
Loading

0 comments on commit 79ca349

Please sign in to comment.