Skip to content

System Level Chat messages

Tristan Elliott edited this page May 7, 2024 · 6 revisions

System Level Chat messages

Modderz logo Modderz logo

Twitch's unoffical mobile Android modview 🚀

GitHub Code:

Table Of Content

System level chats

  • We define System level chats as messages sent from the Twitch IRC servers and that are not sent by individual users

Design Philosophy

  • All System level chat messages should have a distinct gradient color
  • Naming conventions follow the Google naming convention standard, HERE
  • All text sizes are defined at the ChatScope level

ChatScope

NoticeMessages

  • NoticeMessages is a wrapper composable around the internal SystemMessageBox class

  • Composable function meant to display a system level event sent from the Twitch IRC servers. Read more about the NOTICE process

  • UI demonstration with code below:

NoticeMessage
val titleFontSize = MaterialTheme.typography.headlineMedium.fontSize
val messageFontSize = MaterialTheme.typography.headlineSmall.fontSize
val chatScope = remember(){ ChatScope(titleFontSize,messageFontSize) }

with(chatScope){
    NoticeMessages(
      systemMessage="",
      message =twitchUser.userType
    )
}

AnnounceMessages

  • AnnounceMessagesis a wrapper composable around the internal SystemMessageBox class

  • Composable function meant to display a system level event sent from the Twitch IRC servers. Read more about the USERNOTICE tags of announcement

  • UI demonstration with code below:

Announcement
val titleFontSize = MaterialTheme.typography.headlineMedium.fontSize
val messageFontSize = MaterialTheme.typography.headlineSmall.fontSize
val chatScope = remember(){ ChatScope(titleFontSize,messageFontSize) }
with(chatScope){
    AnnouncementMessages(
        message = "${twitchUser.displayName}: ${twitchUser.systemMessage}"
    )
}

ReSubMessage

  • ReSubMessage is a wrapper composable around the internal SystemMessageBox class

  • Composable function meant to display a message to the user indicating a reSub event has occurred

  • UI demonstration with code below:

ReSubMessage
val titleFontSize = MaterialTheme.typography.headlineMedium.fontSize
val messageFontSize = MaterialTheme.typography.headlineSmall.fontSize
val chatScope = remember(){ ChatScope(titleFontSize,messageFontSize) }
with(chatScope){
    ReSubMessage(
       systemMessage = twitchUser.systemMessage,
       message = twitchUser.userType,
    )
}

SubMessages

  • SubMessages is a wrapper composable around the internal SystemMessageBox class

  • Composable function meant to display a message to the user once a USERNOTICE tags of sub

  • UI demonstration with code below:

SubMessages
val titleFontSize = MaterialTheme.typography.headlineMedium.fontSize
val messageFontSize = MaterialTheme.typography.headlineSmall.fontSize
val chatScope = remember(){ ChatScope(titleFontSize,messageFontSize) }
with(chatScope){
    SubMessages(
      systemMessage = twitchUser.systemMessage,
      message = twitchUser.userType,
    )
}

AnonGiftMessages

  • AnonGiftMessagesis a wrapper composable around the internal SystemMessageBox class

  • Composable function meant to display a message to the user once a USERNOTICE tags of submysterygift

  • UI demonstration with code below:

AnonGiftMessages
val titleFontSize = MaterialTheme.typography.headlineMedium.fontSize
val messageFontSize = MaterialTheme.typography.headlineSmall.fontSize
val chatScope = remember(){ ChatScope(titleFontSize,messageFontSize) }
with(chatScope){
    AnonGiftMessages(
        message = twitchUser.userType,
        systemMessage = twitchUser.systemMessage
    )
}

GiftSubMessages

  • GiftSubMessages is a wrapper composable around the internal SystemMessageBox class

  • Composable function meant to display a message to the user once a USERNOTICE tags of subgift

  • UI demonstration with code below:

AnonGiftMessages
val titleFontSize = MaterialTheme.typography.headlineMedium.fontSize
val messageFontSize = MaterialTheme.typography.headlineSmall.fontSize
val chatScope = remember(){ ChatScope(titleFontSize,messageFontSize) }
with(chatScope){
    GiftSubMessages(
        message = twitchUser.userType,
        systemMessage = twitchUser.systemMessage
    )
}

JoinMessage

  • Composable function meant to display a message indicating that we have successfully joined the chat room. This composable is shown after the Joining a Chat Room process

  • UI demonstration with code below:

JoinMessage
val titleFontSize = MaterialTheme.typography.headlineMedium.fontSize
val messageFontSize = MaterialTheme.typography.headlineSmall.fontSize
val chatScope = remember(){ ChatScope(titleFontSize,messageFontSize) }
with(chatScope){
    JoinMessage(
       message = twitchUser.userType ?:""
    )
}

ChatErrorMessage

  • ChatErrorMessage is a composable meant to signify to the user that an error has occurred relating to chat, ie, the intended action has not taken place

  • UI demonstration with code below:

chatErrorMessage
val titleFontSize = MaterialTheme.typography.headlineMedium.fontSize
val messageFontSize = MaterialTheme.typography.headlineSmall.fontSize
val chatScope = remember(){ ChatScope(titleFontSize,messageFontSize) }
with(chatScope){
    ChatErrorMessage(
         message = twitchChatMessage.userType ?:""
    )
}

Entire System level chats library

/**
 * ChatScope contains all the System level(sent from the Twitch servers) chat messages used throughout the application. ChatScope
 * contains 8 properties
 *
 * @param titleFontSize a [TextUnit] that is used to determine the the size of the messageType parameter used in all the composables
 * @param messageFontSize a [TextUnit] that is used to determine the the size of the message parameter used in all the composables
 *
 * @property NoticeMessages
 * @property AnnouncementMessages
 * @property ReSubMessage
 * @property SubMessages
 * @property GiftSubMessages
 * @property AnonGiftMessages
 * @property JoinMessage
 * @property ChatErrorMessage
 * */
@Stable
class ChatScope(
    private val titleFontSize: TextUnit,
    private val messageFontSize:TextUnit
) {
    /**
     * NoticeMessages is a wrapper composable around the [SystemMessageBox]
     * - Composable function meant to display a system level event sent from the Twitch IRC servers. Read more about the
     * [NOTICE](https://dev.twitch.tv/docs/irc/commands/#notice) process
     * */
    @Composable
    fun NoticeMessages(
        systemMessage: String?,
        message: String?
    ){
        SystemMessageBox(
            systemMessage =systemMessage?:"",
            message=message?:"",
            painter=painterResource(id = R.drawable.baseline_location_on_24),
            color= Color.Yellow,
            messageType = "Alert!"
        )
    }

    /**
     * AnnouncementMessages is a wrapper composable around the [SystemMessageBox]
     * - Composable function meant to display a message to the user once a
     * [USERNOTICE tags](https://dev.twitch.tv/docs/irc/tags/#usernotice-tags) of ***announcement***
     * */
    @Composable
    fun AnnouncementMessages(
        message: String?
    ){
        SystemMessageBox(
            systemMessage ="",
            message=message?:"",
            painter=painterResource(id = R.drawable.baseline_announcement_24),
            color= Color.Blue,
            messageType = "Announcement"
        )
    }

    /**
     * ReSubMessage is a wrapper composable around the [SystemMessageBox]
     * - Composable function meant to display a message to the user indicating a reSub event has occurred
     * */
    @Composable
    fun ReSubMessage(
        systemMessage: String?,
        message: String?
    ){
        SystemMessageBox(
            systemMessage =systemMessage?:"",
            message=message?:"",
            painter=painterResource(id = R.drawable.baseline_new_releases_24),
            color= MaterialTheme.colorScheme.secondary,
            messageType = "Re-Sub"
        )
    }

    /**
     * SubMessages is a wrapper composable around the [SystemMessageBox]
     * - Composable function meant to display a message to the user once a [USERNOTICE tags](https://dev.twitch.tv/docs/irc/tags/#usernotice-tags) of ***sub***
     * */
    @Composable
    fun SubMessages(
        systemMessage: String?,
        message: String?
    ){
        SystemMessageBox(
            systemMessage =systemMessage?:"",
            message=message?:"",
            painter=painterResource(id = R.drawable.baseline_star_outline),
            color= MaterialTheme.colorScheme.secondary,
            messageType = "Sub"
        )
    }

    /**
     * GiftSubMessages is a wrapper composable around the [SystemMessageBox]
     * -  Composable function meant to display a message to the user once a [USERNOTICE tags](https://dev.twitch.tv/docs/irc/tags/#usernotice-tags) of ***subgift***
     * */
    @Composable
    fun GiftSubMessages(
        systemMessage: String?,
        message: String?
    ){
        SystemMessageBox(
            systemMessage =systemMessage?:"",
            message=message?:"",
            painter=painterResource(id = R.drawable.gift),
            color= MaterialTheme.colorScheme.secondary,
            messageType = "Gift Sub"
        )
    }


    /**
     * AnonGiftMessages is a wrapper composable around the [SystemMessageBox]
     - Composable function meant to display a message to the user once a [USERNOTICE tags](https://dev.twitch.tv/docs/irc/tags/#usernotice-tags) of ***submysterygift***
     * */
    @Composable
    fun AnonGiftMessages(
        systemMessage: String?,
        message: String?
    ){
        SystemMessageBox(
            systemMessage =systemMessage?:"",
            message=message?:"",
            painter=painterResource(id = R.drawable.baseline_question_mark_24),
            color= MaterialTheme.colorScheme.secondary,
            messageType = "Anonymous gift sub"
        )
    }

    /**
     * Composable function meant to display a message indicating that we have successfully joined the chat room. This composable
     * is shown after the [Joining a Chat Room](https://dev.twitch.tv/docs/irc/join-chat-room/) process
     *
     * @param message String personal message sent from the user. Meant to be displayed to the rest of chat
     * */
    @Composable
    fun JoinMessage(message: String) {
        SimpleText(message = message)
    }

     /**
     * ChatErrorMessage is a composable meant to signify to the user that an error has occurred relating to chat, ie, the intended
     * action has not taken place
     * 
     * @param message a String meant to display the error information to the user
     * */
    @Composable
    fun ChatErrorMessage(
        message:String
    ){

        val sideFade = Brush.horizontalGradient(
            listOf(
                Color.Red, Color.Red.copy(alpha = 0.8f), Color.Red.copy(alpha = 0.6f),
                Color.Red.copy(alpha = 0.4f), Color.Red.copy(alpha = 0.2f), Color.Red.copy(alpha = 0.0f)
            ),
            startX = 0.0f,
            endX = 130.0f
        )
        Box(
            modifier = Modifier.fillMaxWidth().background(MaterialTheme.colorScheme.primary)
        ){
            Spacer(modifier = Modifier.align(Alignment.CenterStart)
                .width(130.dp)
                .fadingEdge(sideFade)
                .clip(RoundedCornerShape(4.dp))
                .background(Color.Red)
                .height(80.dp)

            )
            Row(){
                Spacer(modifier = Modifier
                    .height(80.dp)

                )
                Spacer(modifier = Modifier
                    .width(17.dp)
                )
                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                ) {
                    Row(verticalAlignment = Alignment.CenterVertically){
                        Text("Error", color = MaterialTheme.colorScheme.onPrimary,fontSize=titleFontSize)
                        Spacer(modifier = Modifier
                            .width(6.dp)
                        )
                        Icon(
                            painter = painterResource(id = R.drawable.error_outline_24),
                            contentDescription = "Chat error",
                            tint = Color.Red,
                            modifier = Modifier.size(20.dp)
                        )
                    }

                    Text(message, color = MaterialTheme.colorScheme.onPrimary,fontSize=messageFontSize)
                }
            }

        }


    }



    /**
     * SystemMessageBox is a private [Box] composable that is used internally to give the System level chat messages their gradient styling
     *
     * @param systemMessage a String representing the message that is sent from the Twitch IRC servers
     * @param message a String representing the message sent from the individual user
     * @param messageType A String representing the type of system level chat being sent
     * @param painter the [Painter] value shown in an icon to the right of [messageType]
     * @param color the color of the Gradient
     * */
    @Composable
   private fun SystemMessageBox(
        systemMessage:String,
        message:String,
        messageType: String,
        painter: Painter,
        color: Color,
    ){

        var height by remember { mutableStateOf(80.dp) }
        val localDensity = LocalDensity.current

        val sideFade = Brush.horizontalGradient(
            listOf(
                color, color.copy(alpha = 0.8f), color.copy(alpha = 0.6f),
                color.copy(alpha = 0.4f), color.copy(alpha = 0.2f), color.copy(alpha = 0.0f)
            ),
            startX = 0.0f,
            endX = 130.0f
        )
        Box(
            modifier = Modifier.fillMaxWidth().background(MaterialTheme.colorScheme.primary)
        ){
            Spacer(modifier = Modifier.align(Alignment.CenterStart)
                .width(130.dp)
                .fadingEdge(sideFade)
                .clip(RoundedCornerShape(4.dp))
                .background(color)
                .height(height)

            )
            Row(){
                Spacer(modifier = Modifier
                    .height(height)

                )
                Spacer(modifier = Modifier
                    .width(17.dp)
                )
                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                ) {
                    Row(verticalAlignment = Alignment.CenterVertically){
                        //todo: this should be message type
                        Text("$messageType", color = MaterialTheme.colorScheme.onPrimary,fontSize=titleFontSize)
                        Spacer(modifier = Modifier
                            .width(6.dp)
                        )
                        Icon(
                            painter = painter,
                            contentDescription = messageType,
                            tint = color,
                            modifier = Modifier.size(25.dp)
                        )
                    }
                    Text(
                        //todo: this should be message type
                        "$systemMessage $message",
                        color = MaterialTheme.colorScheme.onPrimary,
                        fontSize=messageFontSize,
                        modifier = Modifier.onGloballyPositioned {
                            height = with(localDensity) { it.size.height.toDp() + 30.dp }
                        }
                    )
                }
            }

        }


    }



    /**
     * SimpleText is a simple composable used to give the styling of [JoinMessage]
     *
     * @param message a String representing a large amount of information
     * */
    @Composable
    private fun SimpleText(message: String){
        Text(
            message,
            fontSize = titleFontSize,
            color = MaterialTheme.colorScheme.onPrimary,
            modifier = Modifier.padding(start = 5.dp)
        )
    }

}