feat: only show appropriate buttons in channel info sheet
Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
parent
f0461b3bfe
commit
551be72a94
|
|
@ -67,6 +67,10 @@ fun Long.hasPermission(permission: PermissionBit): Boolean {
|
||||||
return this and permission.value == permission.value
|
return this and permission.value == permission.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infix fun Long?.has(permission: PermissionBit): Boolean {
|
||||||
|
return this != null && this.hasPermission(permission)
|
||||||
|
}
|
||||||
|
|
||||||
object BitDefaults {
|
object BitDefaults {
|
||||||
val AllowedInTimeout =
|
val AllowedInTimeout =
|
||||||
PermissionBit.ViewChannel + PermissionBit.ReadMessageHistory
|
PermissionBit.ViewChannel + PermissionBit.ReadMessageHistory
|
||||||
|
|
@ -76,30 +80,30 @@ object BitDefaults {
|
||||||
|
|
||||||
val Default =
|
val Default =
|
||||||
ViewOnly +
|
ViewOnly +
|
||||||
PermissionBit.SendMessage +
|
PermissionBit.SendMessage +
|
||||||
PermissionBit.InviteOthers +
|
PermissionBit.InviteOthers +
|
||||||
PermissionBit.SendEmbeds +
|
PermissionBit.SendEmbeds +
|
||||||
PermissionBit.UploadFiles +
|
PermissionBit.UploadFiles +
|
||||||
PermissionBit.Connect +
|
PermissionBit.Connect +
|
||||||
PermissionBit.Speak
|
PermissionBit.Speak
|
||||||
|
|
||||||
val SavedMessages =
|
val SavedMessages =
|
||||||
PermissionBit.GrantAllSafe.value
|
PermissionBit.GrantAllSafe.value
|
||||||
|
|
||||||
val DirectMessages =
|
val DirectMessages =
|
||||||
Default +
|
Default +
|
||||||
PermissionBit.ManageChannel +
|
PermissionBit.ManageChannel +
|
||||||
PermissionBit.React
|
PermissionBit.React
|
||||||
|
|
||||||
val Server =
|
val Server =
|
||||||
Default +
|
Default +
|
||||||
PermissionBit.React +
|
PermissionBit.React +
|
||||||
PermissionBit.ChangeNickname +
|
PermissionBit.ChangeNickname +
|
||||||
PermissionBit.ChangeAvatar
|
PermissionBit.ChangeAvatar
|
||||||
|
|
||||||
val Webhook =
|
val Webhook =
|
||||||
PermissionBit.SendMessage +
|
PermissionBit.SendMessage +
|
||||||
PermissionBit.SendEmbeds +
|
PermissionBit.SendEmbeds +
|
||||||
PermissionBit.Masquerade +
|
PermissionBit.Masquerade +
|
||||||
PermissionBit.React
|
PermissionBit.React
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,12 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
|
@ -21,14 +21,16 @@ import androidx.compose.ui.unit.dp
|
||||||
import chat.revolt.api.REVOLT_FILES
|
import chat.revolt.api.REVOLT_FILES
|
||||||
import chat.revolt.api.schemas.AutumnResource
|
import chat.revolt.api.schemas.AutumnResource
|
||||||
import chat.revolt.api.schemas.ChannelType
|
import chat.revolt.api.schemas.ChannelType
|
||||||
|
import chat.revolt.api.schemas.User
|
||||||
import chat.revolt.components.generic.RemoteImage
|
import chat.revolt.components.generic.RemoteImage
|
||||||
|
import chat.revolt.components.generic.UserAvatar
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChannelSheetHeader(
|
fun ChannelSheetHeader(
|
||||||
channelName: String,
|
channelName: String,
|
||||||
channelIcon: AutumnResource? = null,
|
channelIcon: AutumnResource? = null,
|
||||||
channelType: ChannelType,
|
channelType: ChannelType,
|
||||||
channelId: String
|
dmPartner: User? = null
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.padding(vertical = 4.dp),
|
modifier = Modifier.padding(vertical = 4.dp),
|
||||||
|
|
@ -39,8 +41,7 @@ fun ChannelSheetHeader(
|
||||||
.size(48.dp)
|
.size(48.dp)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.background(
|
.background(
|
||||||
getIconBackColour(channelId)
|
MaterialTheme.colorScheme.primary.copy(alpha = 0.2f)
|
||||||
.copy(alpha = if (channelIcon != null) 0.6f else 0.2f)
|
|
||||||
),
|
),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
|
|
@ -54,57 +55,28 @@ fun ChannelSheetHeader(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
)
|
)
|
||||||
|
} else if (dmPartner != null) {
|
||||||
|
UserAvatar(
|
||||||
|
username = User.resolveDefaultName(dmPartner),
|
||||||
|
userId = dmPartner.id ?: "",
|
||||||
|
avatar = dmPartner.avatar,
|
||||||
|
presence = null,
|
||||||
|
size = 48.dp,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
ChannelIcon(channelType = channelType)
|
ChannelIcon(channelType = channelType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = channelName,
|
text = channelName,
|
||||||
fontWeight = FontWeight.Medium,
|
fontWeight = FontWeight.SemiBold,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getIconBackColour(channelId: String): Color {
|
|
||||||
// The ULID alphabet does not include I, L, O, or U.
|
|
||||||
return when (channelId.uppercase().last()) {
|
|
||||||
'0' -> Color(0xFFE91E63)
|
|
||||||
'1' -> Color(0xFF9C27B0)
|
|
||||||
'2' -> Color(0xFF673AB7)
|
|
||||||
'3' -> Color(0xFF3F51B5)
|
|
||||||
'4' -> Color(0xFF2196F3)
|
|
||||||
'5' -> Color(0xFF03A9F4)
|
|
||||||
'6' -> Color(0xFF00BCD4)
|
|
||||||
'7' -> Color(0xFF009688)
|
|
||||||
'8' -> Color(0xFF4CAF50)
|
|
||||||
'9' -> Color(0xFF8BC34A)
|
|
||||||
'A' -> Color(0xFFCDDC39)
|
|
||||||
'B' -> Color(0xFFFFEB3B)
|
|
||||||
'C' -> Color(0xFFFFC107)
|
|
||||||
'D' -> Color(0xFFFF9800)
|
|
||||||
'E' -> Color(0xFFFF5722)
|
|
||||||
'F' -> Color(0xFF795548)
|
|
||||||
'G' -> Color(0xFF9E9E9E)
|
|
||||||
'H' -> Color(0xFF607D8B)
|
|
||||||
'J' -> Color(0xFF9FA8DA)
|
|
||||||
'K' -> Color(0xFF90CAF9)
|
|
||||||
'M' -> Color(0xFF81D4FA)
|
|
||||||
'N' -> Color(0xFF80DEEA)
|
|
||||||
'P' -> Color(0xFF80CBC4)
|
|
||||||
'Q' -> Color(0xFFA5D6A7)
|
|
||||||
'R' -> Color(0xFFC5E1A5)
|
|
||||||
'S' -> Color(0xFFE6EE9C)
|
|
||||||
'T' -> Color(0xFFFFF59D)
|
|
||||||
'V' -> Color(0xFFFFE082)
|
|
||||||
'W' -> Color(0xFFFFCC80)
|
|
||||||
'X' -> Color(0xFFFFAB91)
|
|
||||||
'Y' -> Color(0xFFFF8A65)
|
|
||||||
'Z' -> Color(0xFFFF8A80)
|
|
||||||
else -> Color(0xFFFFFFFF)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -463,8 +463,8 @@ class ChannelScreenViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val newContent = currentContent.substring(0, currentSelection.start) +
|
val newContent = currentContent.substring(0, currentSelection.start) +
|
||||||
content +
|
content +
|
||||||
currentContent.substring(currentSelection.end)
|
currentContent.substring(currentSelection.end)
|
||||||
|
|
||||||
pendingMessageContent = newContent
|
pendingMessageContent = newContent
|
||||||
textSelection = TextRange(currentSelection.start + content.length)
|
textSelection = TextRange(currentSelection.start + content.length)
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@ import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.api.RevoltAPI
|
import chat.revolt.api.RevoltAPI
|
||||||
|
import chat.revolt.api.internals.ChannelUtils
|
||||||
|
import chat.revolt.api.internals.PermissionBit
|
||||||
|
import chat.revolt.api.internals.Roles
|
||||||
|
import chat.revolt.api.internals.has
|
||||||
import chat.revolt.api.schemas.ChannelType
|
import chat.revolt.api.schemas.ChannelType
|
||||||
import chat.revolt.components.generic.SheetClickable
|
import chat.revolt.components.generic.SheetClickable
|
||||||
import chat.revolt.components.screens.chat.ChannelSheetHeader
|
import chat.revolt.components.screens.chat.ChannelSheetHeader
|
||||||
|
|
@ -72,32 +76,43 @@ fun ChannelInfoSheet(channelId: String) {
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
) {
|
) {
|
||||||
|
val isDM = ChannelUtils.resolveDMPartner(channel) != null
|
||||||
|
val partner = ChannelUtils
|
||||||
|
.resolveDMPartner(channel)
|
||||||
|
?.let {
|
||||||
|
RevoltAPI.userCache[it]
|
||||||
|
}
|
||||||
|
|
||||||
ChannelSheetHeader(
|
ChannelSheetHeader(
|
||||||
channelName = channel.name ?: stringResource(id = R.string.unknown),
|
channelName = channel.name
|
||||||
|
?: ChannelUtils.resolveDMName(channel)
|
||||||
|
?: stringResource(id = R.string.unknown),
|
||||||
channelIcon = channel.icon,
|
channelIcon = channel.icon,
|
||||||
channelType = channel.channelType ?: ChannelType.TextChannel,
|
channelType = channel.channelType ?: ChannelType.TextChannel,
|
||||||
channelId = channel.id ?: "9"
|
dmPartner = partner
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
if (!isDM) {
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.channel_info_sheet_description),
|
text = stringResource(id = R.string.channel_info_sheet_description),
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
modifier = Modifier.padding(bottom = 10.dp)
|
modifier = Modifier.padding(bottom = 10.dp)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = if (channel.description.isNullOrBlank()) {
|
text = if (channel.description.isNullOrBlank()) {
|
||||||
stringResource(
|
stringResource(
|
||||||
id = R.string.channel_info_sheet_description_empty
|
id = R.string.channel_info_sheet_description_empty
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
channel.description
|
channel.description
|
||||||
},
|
},
|
||||||
modifier = Modifier.padding(bottom = 10.dp)
|
modifier = Modifier.padding(bottom = 10.dp)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.channel_info_sheet_options),
|
text = stringResource(id = R.string.channel_info_sheet_options),
|
||||||
|
|
@ -129,21 +144,53 @@ fun ChannelInfoSheet(channelId: String) {
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
SheetClickable(
|
if (
|
||||||
icon = { modifier ->
|
Roles.permissionFor(
|
||||||
Icon(
|
channel,
|
||||||
imageVector = Icons.Default.Add,
|
RevoltAPI.userCache[RevoltAPI.selfId]
|
||||||
contentDescription = null,
|
) has PermissionBit.InviteOthers
|
||||||
modifier = modifier
|
|
||||||
)
|
|
||||||
},
|
|
||||||
label = { style ->
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.channel_info_sheet_options_invite),
|
|
||||||
style = style
|
|
||||||
)
|
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
|
when (channel.channelType) {
|
||||||
|
ChannelType.TextChannel, ChannelType.VoiceChannel -> {
|
||||||
|
SheetClickable(
|
||||||
|
icon = { modifier ->
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Add,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = { style ->
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.channel_info_sheet_options_invite),
|
||||||
|
style = style
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelType.Group -> {
|
||||||
|
SheetClickable(
|
||||||
|
icon = { modifier ->
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Add,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = { style ->
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.channel_info_sheet_options_add),
|
||||||
|
style = style
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SheetClickable(
|
SheetClickable(
|
||||||
|
|
|
||||||
|
|
@ -233,6 +233,7 @@
|
||||||
<string name="channel_info_sheet_options">Options</string>
|
<string name="channel_info_sheet_options">Options</string>
|
||||||
<string name="channel_info_sheet_options_members">Members</string>
|
<string name="channel_info_sheet_options_members">Members</string>
|
||||||
<string name="channel_info_sheet_options_invite">Invite</string>
|
<string name="channel_info_sheet_options_invite">Invite</string>
|
||||||
|
<string name="channel_info_sheet_options_add">Add members</string>
|
||||||
<string name="channel_info_sheet_options_notifications_manage">Manage notifications</string>
|
<string name="channel_info_sheet_options_notifications_manage">Manage notifications</string>
|
||||||
|
|
||||||
<string name="message_context_sheet_actions_copy">Copy</string>
|
<string name="message_context_sheet_actions_copy">Copy</string>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue