Persona Chip (#304)
* init personachip * searchbox persona and ui fixes * indentation fix * code review modifications * code review changes 2 * code review 3 * pading for text alignmnet * overriding personatokens for searchbar tokens * modifying chip info data class * review changes infinite :) * revert dogfood * persona chip activity modifications Co-authored-by: PraveenKumar Yeruva <pyeruva@microsoft.com>
This commit is contained in:
Родитель
8b35393664
Коммит
af9a9c2d6e
|
@ -55,6 +55,7 @@
|
|||
<activity android:name="com.microsoft.fluentuidemo.demos.PersistentBottomSheetActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2BottomSheetActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.PersonaChipViewActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2PersonaChipActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.PersonaListViewActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2PersonaListActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.PersonaViewActivity" />
|
||||
|
|
|
@ -33,6 +33,7 @@ const val PEOPLE_PICKER_VIEW = "PeoplePickerView"
|
|||
const val PERSISTENT_BOTTOM_SHEET = "PersistentBottomSheet"
|
||||
const val V2BOTTOM_SHEET = "V2 BottomSheet"
|
||||
const val PERSONA_CHIP_VIEW = "PersonaChipView"
|
||||
const val V2PERSONA_CHIP = "V2 PersonaChip"
|
||||
const val PERSONA_LIST_VIEW = "PersonaListView"
|
||||
const val V2PERSONA_LIST = "V2 PersonaList"
|
||||
const val PERSONA_VIEW = "PersonaView"
|
||||
|
@ -72,6 +73,7 @@ val DEMOS = arrayListOf(
|
|||
Demo(PERSISTENT_BOTTOM_SHEET, PersistentBottomSheetActivity::class),
|
||||
Demo(V2BOTTOM_SHEET, V2BottomSheetActivity::class),
|
||||
Demo(PERSONA_CHIP_VIEW, PersonaChipViewActivity::class),
|
||||
Demo(V2PERSONA_CHIP, V2PersonaChipActivity::class),
|
||||
Demo(PERSONA_LIST_VIEW, PersonaListViewActivity::class),
|
||||
Demo(V2PERSONA_LIST, V2PersonaListActivity::class),
|
||||
Demo(PERSONA_VIEW, PersonaViewActivity::class),
|
||||
|
|
|
@ -0,0 +1,338 @@
|
|||
package com.microsoft.fluentuidemo.demos
|
||||
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.listSaver
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens
|
||||
import com.microsoft.fluentui.theme.token.FluentStyle
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.AvatarStatus.Available
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.PersonaChipSize
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.PersonaChipStyle.*
|
||||
import com.microsoft.fluentui.tokenized.controls.ToggleSwitch
|
||||
import com.microsoft.fluentui.tokenized.persona.Person
|
||||
import com.microsoft.fluentui.tokenized.persona.PersonaChip
|
||||
import com.microsoft.fluentui.tokenized.persona.SearchBarPersonaChip
|
||||
import com.microsoft.fluentuidemo.DemoActivity
|
||||
import com.microsoft.fluentuidemo.R
|
||||
import com.microsoft.fluentuidemo.R.drawable
|
||||
|
||||
class V2PersonaChipActivity : DemoActivity() {
|
||||
override val contentLayoutId: Int
|
||||
get() = R.layout.v2_activity_compose
|
||||
override val contentNeedsScrollableContainer: Boolean
|
||||
get() = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val compose_here = findViewById<ComposeView>(R.id.compose_here)
|
||||
|
||||
compose_here.setContent {
|
||||
FluentTheme {
|
||||
createPersonaChipActivityUI()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPersonWithName(): Person {
|
||||
return Person(
|
||||
"Allan",
|
||||
"Munger",
|
||||
image = drawable.avatar_allan_munger,
|
||||
email = "allan.munger@microsoft.com",
|
||||
isActive = true,
|
||||
status = Available,
|
||||
isOOO = false
|
||||
)
|
||||
}
|
||||
|
||||
private fun createPersonWithEmail(): Person {
|
||||
return Person(
|
||||
"",
|
||||
"",
|
||||
image = drawable.avatar_allan_munger,
|
||||
email = "allan.munger@microsoft.com",
|
||||
isActive = true,
|
||||
status = Available,
|
||||
isOOO = false
|
||||
)
|
||||
}
|
||||
|
||||
private fun createPersonWithNothing(): Person {
|
||||
return Person(
|
||||
"",
|
||||
"",
|
||||
image = drawable.avatar_allan_munger,
|
||||
email = "",
|
||||
isActive = true,
|
||||
status = Available,
|
||||
isOOO = false
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun createPersonaChipActivityUI() {
|
||||
val textColor =
|
||||
FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.Foreground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
val brandTextColor =
|
||||
FluentTheme.aliasTokens.brandForegroundColor[AliasTokens.BrandForegroundColorTokens.BrandForeground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
var showCloseButton by remember { mutableStateOf(false) }
|
||||
var selectedList = rememberSaveable(
|
||||
saver = listSaver(
|
||||
save = { stateList ->
|
||||
if (stateList.isNotEmpty()) {
|
||||
val first = stateList.first()
|
||||
if (!canBeSaved(first)) {
|
||||
throw IllegalStateException("${first::class} cannot be saved. By default only types which can be stored in the Bundle class can be saved.")
|
||||
}
|
||||
}
|
||||
stateList.toList()
|
||||
},
|
||||
restore = { it.toMutableStateList() }
|
||||
)) {
|
||||
mutableStateListOf(
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
//TODO: Clean Activity using for loops
|
||||
Box(Modifier.padding(16.dp)) {
|
||||
LazyColumn(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
item {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "Enable/Disable close button on selected state",
|
||||
color = brandTextColor,
|
||||
fontSize = 10.sp
|
||||
)
|
||||
ToggleSwitch(
|
||||
onValueChange = { showCloseButton = !showCloseButton },
|
||||
checkedState = showCloseButton
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
Text(text = "Basic Persona chip", color = brandTextColor, fontSize = 20.sp)
|
||||
}
|
||||
item {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text(text = "Person Chip Neutral", color = textColor)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
PersonaChip(
|
||||
person = createPersonWithName(),
|
||||
size = PersonaChipSize.Small,
|
||||
style = Neutral,
|
||||
selected = selectedList[0],
|
||||
onClick = { selectedList[0] = !selectedList[0] })
|
||||
PersonaChip(
|
||||
person = createPersonWithName(),
|
||||
style = Neutral,
|
||||
selected = selectedList[1],
|
||||
onClick = { selectedList[1] = !selectedList[1] },
|
||||
onCloseClick = if (showCloseButton) {
|
||||
{ onClickToast() }
|
||||
} else null
|
||||
)
|
||||
}
|
||||
Text(text = "Person Chip Brand", color = textColor)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
PersonaChip(
|
||||
person = createPersonWithName(),
|
||||
size = PersonaChipSize.Small,
|
||||
style = Brand,
|
||||
selected = selectedList[2],
|
||||
onClick = { selectedList[2] = !selectedList[2] })
|
||||
PersonaChip(
|
||||
person = createPersonWithName(),
|
||||
style = Brand,
|
||||
selected = selectedList[3],
|
||||
onClick = { selectedList[3] = !selectedList[3] },
|
||||
onCloseClick = if (showCloseButton) {
|
||||
{ onClickToast() }
|
||||
} else null
|
||||
)
|
||||
}
|
||||
Text(text = "Person Chip Danger", color = textColor)
|
||||
LazyRow(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
item {
|
||||
PersonaChip(
|
||||
person = createPersonWithEmail(),
|
||||
size = PersonaChipSize.Small,
|
||||
style = Danger,
|
||||
selected = selectedList[4],
|
||||
onClick = { selectedList[4] = !selectedList[4] })
|
||||
}
|
||||
item {
|
||||
PersonaChip(
|
||||
person = createPersonWithEmail(),
|
||||
style = Danger,
|
||||
selected = selectedList[5],
|
||||
onClick = { selectedList[5] = !selectedList[5] },
|
||||
onCloseClick = if (showCloseButton) {
|
||||
{ onClickToast() }
|
||||
} else null
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(text = "Person Chip Severe Warning", color = textColor)
|
||||
LazyRow(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
item {
|
||||
PersonaChip(
|
||||
person = createPersonWithEmail(),
|
||||
size = PersonaChipSize.Small,
|
||||
style = SevereWarning,
|
||||
selected = selectedList[6],
|
||||
onClick = { selectedList[6] = !selectedList[6] })
|
||||
}
|
||||
item {
|
||||
PersonaChip(
|
||||
person = createPersonWithEmail(),
|
||||
style = SevereWarning,
|
||||
selected = selectedList[7],
|
||||
onClick = { selectedList[7] = !selectedList[7] },
|
||||
onCloseClick = if (showCloseButton) {
|
||||
{ onClickToast() }
|
||||
} else null
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(text = "Person Chip Warning", color = textColor)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
PersonaChip(
|
||||
person = createPersonWithNothing(),
|
||||
size = PersonaChipSize.Small,
|
||||
style = Warning,
|
||||
selected = selectedList[8],
|
||||
onClick = { selectedList[8] = !selectedList[8] })
|
||||
PersonaChip(
|
||||
person = createPersonWithNothing(),
|
||||
style = Warning,
|
||||
selected = selectedList[9],
|
||||
onClick = { selectedList[9] = !selectedList[9] },
|
||||
onCloseClick = if (showCloseButton) {
|
||||
{ onClickToast() }
|
||||
} else null
|
||||
)
|
||||
}
|
||||
Text(text = "Person Chip Success", color = textColor)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
PersonaChip(
|
||||
person = createPersonWithName(),
|
||||
size = PersonaChipSize.Small,
|
||||
style = Success,
|
||||
selected = selectedList[10],
|
||||
onClick = { selectedList[10] = !selectedList[10] })
|
||||
PersonaChip(
|
||||
person = createPersonWithName(),
|
||||
style = Success,
|
||||
selected = selectedList[11],
|
||||
onClick = { selectedList[11] = !selectedList[11] },
|
||||
onCloseClick = if (showCloseButton) {
|
||||
{ onClickToast() }
|
||||
} else null
|
||||
)
|
||||
}
|
||||
Text(text = "Person Chip Disabled", color = textColor)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
PersonaChip(
|
||||
person = createPersonWithName(),
|
||||
size = PersonaChipSize.Small,
|
||||
style = Neutral,
|
||||
enabled = false,
|
||||
selected = selectedList[12],
|
||||
onClick = { selectedList[12] = !selectedList[12] },
|
||||
onCloseClick = if (showCloseButton) {
|
||||
{ onClickToast() }
|
||||
} else null
|
||||
)
|
||||
PersonaChip(
|
||||
person = createPersonWithName(),
|
||||
style = Neutral,
|
||||
enabled = false,
|
||||
selected = selectedList[13],
|
||||
onClick = { selectedList[13] = !selectedList[13] },
|
||||
onCloseClick = if (showCloseButton) {
|
||||
{ onClickToast() }
|
||||
} else null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
item {
|
||||
Text(
|
||||
text = "SearchBox Basic Persona chip",
|
||||
color = brandTextColor,
|
||||
fontSize = 20.sp
|
||||
)
|
||||
}
|
||||
item {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text(text = "Persona chip Neutral", color = textColor)
|
||||
SearchBarPersonaChip(
|
||||
person = createPersonWithName(),
|
||||
size = PersonaChipSize.Small,
|
||||
selected = selectedList[14],
|
||||
onClick = { selectedList[14] = !selectedList[14] },
|
||||
onCloseClick = if (showCloseButton) {
|
||||
{ onClickToast() }
|
||||
} else null
|
||||
)
|
||||
Text(text = "Persona chip Brand", color = textColor)
|
||||
SearchBarPersonaChip(
|
||||
person = createPersonWithName(),
|
||||
style = FluentStyle.Brand,
|
||||
selected = selectedList[15],
|
||||
onClick = { selectedList[15] = !selectedList[15] },
|
||||
onCloseClick = if (showCloseButton) {
|
||||
{ onClickToast() }
|
||||
} else null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onClickToast() {
|
||||
Toast.makeText(
|
||||
this,
|
||||
"Clicked on close icon",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ fun getString(string: Strings): String {
|
|||
Strings.NotSelected -> resources.getString(R.string.fluentui_not_selected)
|
||||
Strings.Disabled -> resources.getString(R.string.fluentui_disabled)
|
||||
Strings.Enabled -> resources.getString(R.string.fluentui_enabled)
|
||||
Strings.Close -> resources.getString(R.string.fluentui_close)
|
||||
else -> ""
|
||||
}
|
||||
}
|
|
@ -11,5 +11,6 @@ value class Strings private constructor(@Suppress("unused") private val value: I
|
|||
val NotSelected = Strings(2)
|
||||
val Disabled = Strings(3)
|
||||
val Enabled = Strings(4)
|
||||
val Close = Strings(5)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,12 +28,14 @@ class ControlTokens {
|
|||
FloatingActionButton,
|
||||
LinearProgressIndicator,
|
||||
ListItem,
|
||||
PersonaChip,
|
||||
PillButton,
|
||||
PillBar,
|
||||
RadioButton,
|
||||
PillSwitch,
|
||||
PillTabs,
|
||||
TabItem,
|
||||
SearchBarPersonaChip,
|
||||
Shimmer,
|
||||
ToggleSwitch
|
||||
}
|
||||
|
@ -54,6 +56,8 @@ class ControlTokens {
|
|||
ControlType.FloatingActionButton -> FABTokens()
|
||||
ControlType.LinearProgressIndicator -> LinearProgressIndicatorTokens()
|
||||
ControlType.ListItem -> ListItemTokens()
|
||||
ControlType.PersonaChip -> PersonaChipTokens()
|
||||
ControlType.SearchBarPersonaChip -> SearchBarPersonaChipTokens()
|
||||
ControlType.PillButton -> PillButtonTokens()
|
||||
ControlType.PillBar -> PillBarTokens()
|
||||
ControlType.RadioButton -> RadioButtonTokens()
|
||||
|
|
|
@ -286,6 +286,52 @@ object GlobalTokens : Parcelable {
|
|||
}
|
||||
}
|
||||
|
||||
enum class SizeTokens {
|
||||
SizeNone,
|
||||
Size20,
|
||||
Size40,
|
||||
Size60,
|
||||
Size80,
|
||||
Size100,
|
||||
Size120,
|
||||
Size140,
|
||||
Size160,
|
||||
Size180,
|
||||
Size200,
|
||||
Size240,
|
||||
Size280,
|
||||
Size320,
|
||||
Size360,
|
||||
Size400,
|
||||
Size480,
|
||||
Size520,
|
||||
Size560
|
||||
}
|
||||
|
||||
fun size(token: SizeTokens): Dp {
|
||||
return when(token) {
|
||||
SizeTokens.SizeNone -> 0.dp
|
||||
SizeTokens.Size20 -> 2.dp
|
||||
SizeTokens.Size40 -> 4.dp
|
||||
SizeTokens.Size60 -> 6.dp
|
||||
SizeTokens.Size80 -> 8.dp
|
||||
SizeTokens.Size100 -> 10.dp
|
||||
SizeTokens.Size120 -> 12.dp
|
||||
SizeTokens.Size140 -> 14.dp
|
||||
SizeTokens.Size160 -> 16.dp
|
||||
SizeTokens.Size180 -> 18.dp
|
||||
SizeTokens.Size200 -> 20.dp
|
||||
SizeTokens.Size240 -> 24.dp
|
||||
SizeTokens.Size280 -> 28.dp
|
||||
SizeTokens.Size320 -> 32.dp
|
||||
SizeTokens.Size360 -> 36.dp
|
||||
SizeTokens.Size400 -> 40.dp
|
||||
SizeTokens.Size480 -> 48.dp
|
||||
SizeTokens.Size520 -> 52.dp
|
||||
SizeTokens.Size560 -> 56.dp
|
||||
}
|
||||
}
|
||||
|
||||
enum class ShadowTokens {
|
||||
Shadow02,
|
||||
Shadow04,
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
package com.microsoft.fluentui.theme.token.controlTokens
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.token.*
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens.BrandBackgroundColorTokens.BrandBackground1
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens.BrandBackgroundColorTokens.BrandBackgroundTint
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens.BrandForegroundColorTokens.BrandForegroundTint
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens.ErrorAndStatusColorTokens.*
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens.NeutralBackgroundColorTokens.Background5
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens.NeutralBackgroundColorTokens.Background5Selected
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens.NeutralForegroundColorTokens.*
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.PersonaChipSize.Medium
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.PersonaChipSize.Small
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
enum class PersonaChipStyle {
|
||||
Neutral,
|
||||
Brand,
|
||||
Danger,
|
||||
SevereWarning,
|
||||
Warning,
|
||||
Success
|
||||
}
|
||||
|
||||
enum class PersonaChipSize {
|
||||
Small,
|
||||
Medium
|
||||
}
|
||||
|
||||
abstract class PersonaChipControlInfo : ControlInfo {
|
||||
abstract val size: PersonaChipSize
|
||||
abstract val enabled: Boolean
|
||||
}
|
||||
|
||||
data class PersonaChipInfo(
|
||||
val style: PersonaChipStyle = PersonaChipStyle.Neutral,
|
||||
override val enabled: Boolean = true,
|
||||
override val size: PersonaChipSize = Small
|
||||
) : PersonaChipControlInfo()
|
||||
|
||||
@Parcelize
|
||||
open class PersonaChipTokens : ControlToken, Parcelable {
|
||||
|
||||
@Composable
|
||||
open fun backgroundColor(personaChipInfo: PersonaChipControlInfo): StateColor {
|
||||
personaChipInfo as PersonaChipInfo
|
||||
when (personaChipInfo.style) {
|
||||
PersonaChipStyle.Neutral -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.neutralBackgroundColor[Background5].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.neutralBackgroundColor[Background5Selected].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
disabled = FluentTheme.aliasTokens.neutralBackgroundColor[Background5].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
PersonaChipStyle.Brand -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.brandBackgroundColor[BrandBackgroundTint].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.brandBackgroundColor[BrandBackground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
disabled = FluentTheme.aliasTokens.neutralBackgroundColor[Background5].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
PersonaChipStyle.Danger -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.ErrorAndStatusColor[DangerBackground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.ErrorAndStatusColor[DangerBackground2].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
PersonaChipStyle.SevereWarning -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.ErrorAndStatusColor[SevereBackground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.ErrorAndStatusColor[SevereBackground2].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
PersonaChipStyle.Warning -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.ErrorAndStatusColor[WarningBackground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.ErrorAndStatusColor[WarningBackground2].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
PersonaChipStyle.Success -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.ErrorAndStatusColor[SuccessBackground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.ErrorAndStatusColor[SuccessBackground2].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun textColor(personaChipInfo: PersonaChipControlInfo): StateColor {
|
||||
|
||||
personaChipInfo as PersonaChipInfo
|
||||
when (personaChipInfo.style) {
|
||||
PersonaChipStyle.Neutral -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.neutralForegroundColor[Foreground2].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.neutralForegroundColor[Foreground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
disabled = FluentTheme.aliasTokens.neutralForegroundColor[ForegroundDisable1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
PersonaChipStyle.Brand -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.brandForegroundColor[BrandForegroundTint].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.neutralForegroundColor[ForegroundOnColor].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
disabled = FluentTheme.aliasTokens.neutralForegroundColor[ForegroundDisable1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
PersonaChipStyle.Danger -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.ErrorAndStatusColor[DangerForeground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.neutralForegroundColor[ForegroundLightStatic].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
PersonaChipStyle.SevereWarning -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.ErrorAndStatusColor[SevereForeground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.neutralForegroundColor[ForegroundLightStatic].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
PersonaChipStyle.Warning -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.ErrorAndStatusColor[WarningForeground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.neutralForegroundColor[ForegroundDarkStatic].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
PersonaChipStyle.Success -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.ErrorAndStatusColor[SuccessForeground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.neutralForegroundColor[ForegroundLightStatic].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun borderRadius(personaChipInfo: PersonaChipControlInfo): Dp {
|
||||
return when (personaChipInfo.size) {
|
||||
Small -> GlobalTokens.borderRadius(GlobalTokens.BorderRadiusTokens.Small)
|
||||
Medium -> GlobalTokens.borderRadius(GlobalTokens.BorderRadiusTokens.Medium)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun fontSize(personaChipInfo: PersonaChipControlInfo): FontInfo {
|
||||
return when (personaChipInfo.size) {
|
||||
Small -> FluentTheme.aliasTokens.typography[AliasTokens.TypographyTokens.Caption1]
|
||||
Medium -> FluentTheme.aliasTokens.typography[AliasTokens.TypographyTokens.Body2]
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun verticalPadding(personaChipInfo: PersonaChipControlInfo): Dp {
|
||||
return when (personaChipInfo.size) {
|
||||
Small -> GlobalTokens.size(GlobalTokens.SizeTokens.Size20)
|
||||
Medium -> GlobalTokens.size(GlobalTokens.SizeTokens.Size20)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun horizontalPadding(personaChipInfo: PersonaChipControlInfo): Dp {
|
||||
return when (personaChipInfo.size) {
|
||||
Small -> GlobalTokens.size(GlobalTokens.SizeTokens.Size40)
|
||||
Medium -> GlobalTokens.size(GlobalTokens.SizeTokens.Size80)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun avatarToTextSpacing(personaChipInfo: PersonaChipControlInfo): Dp {
|
||||
return GlobalTokens.size(GlobalTokens.SizeTokens.Size80)
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun avatarSize(personaChipInfo: PersonaChipControlInfo): AvatarSize {
|
||||
return AvatarSize.Size16
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.microsoft.fluentui.theme.token.controlTokens
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens
|
||||
import com.microsoft.fluentui.theme.token.FluentStyle
|
||||
import com.microsoft.fluentui.theme.token.StateColor
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
data class SearchBarPersonaChipInfo(
|
||||
val style: FluentStyle = FluentStyle.Neutral,
|
||||
override val enabled: Boolean = true,
|
||||
override val size: PersonaChipSize = PersonaChipSize.Small
|
||||
) : PersonaChipControlInfo()
|
||||
|
||||
@Parcelize
|
||||
open class SearchBarPersonaChipTokens : PersonaChipTokens() {
|
||||
@Composable
|
||||
override fun backgroundColor(searchBarPersonaChipInfo: PersonaChipControlInfo): StateColor {
|
||||
searchBarPersonaChipInfo as SearchBarPersonaChipInfo
|
||||
when (searchBarPersonaChipInfo.style) {
|
||||
FluentStyle.Neutral -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.neutralBackgroundColor[AliasTokens.NeutralBackgroundColorTokens.Background6].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.neutralBackgroundColor[AliasTokens.NeutralBackgroundColorTokens.BackgroundInverted].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
disabled = FluentTheme.aliasTokens.neutralBackgroundColor[AliasTokens.NeutralBackgroundColorTokens.Background6].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
FluentStyle.Brand -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.brandBackgroundColor[AliasTokens.BrandBackgroundColorTokens.BrandBackground3].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.neutralBackgroundColor[AliasTokens.NeutralBackgroundColorTokens.Background1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
disabled = FluentTheme.aliasTokens.brandBackgroundColor[AliasTokens.BrandBackgroundColorTokens.BrandBackground3].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun textColor(searchBarPersonaChipInfo: PersonaChipControlInfo): StateColor {
|
||||
searchBarPersonaChipInfo as SearchBarPersonaChipInfo
|
||||
when (searchBarPersonaChipInfo.style) {
|
||||
FluentStyle.Neutral -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.Foreground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.ForegroundOnColor].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
disabled = FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.ForegroundDisable2].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
FluentStyle.Brand -> return StateColor(
|
||||
rest = FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.ForegroundOnColor].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
selected = FluentTheme.aliasTokens.brandForegroundColor[AliasTokens.BrandForegroundColorTokens.BrandForeground1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
),
|
||||
disabled = FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.ForegroundDisable1].value(
|
||||
themeMode = FluentTheme.themeMode
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,4 +5,5 @@
|
|||
<string name="fluentui_disabled">Disabled</string>
|
||||
<string name="fluentui_enabled">Enabled</string>
|
||||
<string name="fluentui_close_sheet">Close Sheet</string>
|
||||
<string name="fluentui_close">Close</string>
|
||||
</resources>
|
|
@ -98,6 +98,7 @@ fun AvatarCarousel(
|
|||
val backgroundColor = getColorByState(
|
||||
stateData = getAvatarCarouselTokens().backgroundColor(getAvatarCarouselInfo()),
|
||||
enabled = item.enabled,
|
||||
selected = false,
|
||||
interactionSource = interactionSource
|
||||
)
|
||||
val textColor = getAvatarCarouselTokens().getTextColor(getAvatarCarouselInfo())
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
package com.microsoft.fluentui.tokenized.persona
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
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.semantics.Role
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.microsoft.fluentui.compose.Strings
|
||||
import com.microsoft.fluentui.compose.getString
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.token.ControlTokens
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.PersonaChipInfo
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.PersonaChipSize
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.PersonaChipSize.Medium
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.PersonaChipStyle
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.PersonaChipTokens
|
||||
|
||||
private val LocalPersonaChipTokens = compositionLocalOf { PersonaChipTokens() }
|
||||
private val LocalPersonaChipInfo = compositionLocalOf { PersonaChipInfo() }
|
||||
|
||||
/**
|
||||
* [PersonaChip] is a compact representations of entities(most commonly, people)that can be types in, deleted or dragged easily
|
||||
*
|
||||
* @param person Person data for the persona chip
|
||||
* @param modifier Modifier for the persona chip
|
||||
* @param style Optional persona chip style. See [PersonaChipStyle]
|
||||
* @param size Option persona chip size. See [PersonaChipSize]
|
||||
* @param enabled Whether persona chip is enabled or disabled. Enabled by default.
|
||||
* @param selected Whether persona chip is selected or unselected. Unselected by default.
|
||||
* @param onClick onClick action for persona chip
|
||||
* @param onCloseClick onClick action for close button. This action is performed after the chip is selected and on the close icon
|
||||
* @param interactionSource Optional interactionSource
|
||||
* @param personaChipTokens Optional tokens for persona chip
|
||||
*/
|
||||
@Composable
|
||||
fun PersonaChip(
|
||||
person: Person,
|
||||
modifier: Modifier = Modifier,
|
||||
style: PersonaChipStyle = PersonaChipStyle.Neutral,
|
||||
size: PersonaChipSize = Medium,
|
||||
enabled: Boolean = true,
|
||||
selected: Boolean = false,
|
||||
onClick: (() -> Unit)? = null,
|
||||
onCloseClick: (() -> Unit)? = null,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
personaChipTokens: PersonaChipTokens? = null
|
||||
) {
|
||||
val token = personaChipTokens
|
||||
?: FluentTheme.controlTokens.tokens[ControlTokens.ControlType.PersonaChip] as PersonaChipTokens
|
||||
CompositionLocalProvider(
|
||||
LocalPersonaChipTokens provides token,
|
||||
LocalPersonaChipInfo provides PersonaChipInfo(
|
||||
style,
|
||||
enabled,
|
||||
size
|
||||
)
|
||||
) {
|
||||
val backgroundColor = getColorByState(
|
||||
stateData = getPersonaChipTokens().backgroundColor(personaChipInfo = getPersonaChipInfo()),
|
||||
enabled = enabled, selected = selected, interactionSource = interactionSource
|
||||
)
|
||||
val textColor = getColorByState(
|
||||
stateData = getPersonaChipTokens().textColor(personaChipInfo = getPersonaChipInfo()),
|
||||
enabled = enabled, selected = selected, interactionSource = interactionSource
|
||||
)
|
||||
val font = getPersonaChipTokens().fontSize(personaChipInfo = getPersonaChipInfo())
|
||||
val avatarSize = getPersonaChipTokens().avatarSize(personaChipInfo = getPersonaChipInfo())
|
||||
val verticalPadding =
|
||||
getPersonaChipTokens().verticalPadding(personaChipInfo = getPersonaChipInfo())
|
||||
val horizontalPadding =
|
||||
getPersonaChipTokens().horizontalPadding(personaChipInfo = getPersonaChipInfo())
|
||||
val avatarToTextSpacing =
|
||||
getPersonaChipTokens().avatarToTextSpacing(personaChipInfo = getPersonaChipInfo())
|
||||
val cornerRadius =
|
||||
getPersonaChipTokens().borderRadius(personaChipInfo = getPersonaChipInfo())
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(cornerRadius))
|
||||
.background(backgroundColor)
|
||||
.clickable(
|
||||
enabled = enabled,
|
||||
onClick = onClick ?: {},
|
||||
interactionSource = interactionSource,
|
||||
indication = rememberRipple()
|
||||
)
|
||||
)
|
||||
{
|
||||
Row(
|
||||
Modifier
|
||||
.padding(
|
||||
horizontal = horizontalPadding,
|
||||
vertical = verticalPadding
|
||||
),
|
||||
horizontalArrangement = Arrangement.spacedBy(avatarToTextSpacing),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (size == Medium) {
|
||||
if (onCloseClick!=null && selected) {
|
||||
Icon(
|
||||
Icons.Filled.Close,
|
||||
modifier = Modifier
|
||||
.size(16.dp)
|
||||
.clickable(
|
||||
enabled = true,
|
||||
onClick = onCloseClick,
|
||||
role = Role.Button
|
||||
),
|
||||
contentDescription = getString(string = Strings.Close),
|
||||
tint = textColor
|
||||
)
|
||||
} else {
|
||||
Avatar(person = person, size = avatarSize)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.padding(bottom = 2.dp),//Vertically center align text
|
||||
text = person.getLabel(),
|
||||
color = textColor,
|
||||
lineHeight = font.fontSize.lineHeight,
|
||||
fontSize = font.fontSize.size,
|
||||
fontWeight = font.weight
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getPersonaChipTokens(): PersonaChipTokens {
|
||||
return LocalPersonaChipTokens.current
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getPersonaChipInfo(): PersonaChipInfo {
|
||||
return LocalPersonaChipInfo.current
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
package com.microsoft.fluentui.tokenized.persona
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
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.semantics.Role
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.microsoft.fluentui.compose.Strings
|
||||
import com.microsoft.fluentui.compose.getString
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.token.ControlTokens
|
||||
import com.microsoft.fluentui.theme.token.FluentStyle
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.PersonaChipSize
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.SearchBarPersonaChipInfo
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.SearchBarPersonaChipTokens
|
||||
|
||||
private val LocalSearchBarPersonaChipTokens = compositionLocalOf { SearchBarPersonaChipTokens() }
|
||||
private val LocalSearchBarPersonaChipInfo = compositionLocalOf { SearchBarPersonaChipInfo() }
|
||||
|
||||
/**
|
||||
* [SearchBarPersonaChip] is a compact representations of entities(most commonly, people)that can be types in, deleted or dragged easily
|
||||
*
|
||||
* @param person Person data for the persona chip
|
||||
* @param modifier Modifier for the persona chip
|
||||
* @param style Optional persona chip style. See [FluentStyle]
|
||||
* @param size Option persona chip size. See [PersonaChipSize]
|
||||
* @param enabled Whether persona chip is enabled or disabled. Enabled by default.
|
||||
* @param selected Whether persona chip is selected or unselected. Unselected by default.
|
||||
* @param onClick onClick action for persona chip
|
||||
* @param onCloseClick onClick action for close button. This action is performed after the chip is selected and on the close icon
|
||||
* @param interactionSource Optional interactionSource
|
||||
* @param searchbarPersonaChipTokens Optional tokens for persona chip
|
||||
*/
|
||||
@Composable
|
||||
fun SearchBarPersonaChip(
|
||||
person: Person,
|
||||
modifier: Modifier = Modifier,
|
||||
style: FluentStyle = FluentStyle.Neutral,
|
||||
size: PersonaChipSize = PersonaChipSize.Medium,
|
||||
enabled: Boolean = true,
|
||||
selected: Boolean = false,
|
||||
onClick: (() -> Unit)? = null,
|
||||
onCloseClick: (() -> Unit)? = null,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
searchbarPersonaChipTokens: SearchBarPersonaChipTokens? = null
|
||||
) {
|
||||
val token = searchbarPersonaChipTokens
|
||||
?: FluentTheme.controlTokens.tokens[ControlTokens.ControlType.SearchBarPersonaChip] as SearchBarPersonaChipTokens
|
||||
CompositionLocalProvider(
|
||||
LocalSearchBarPersonaChipTokens provides token,
|
||||
LocalSearchBarPersonaChipInfo provides SearchBarPersonaChipInfo(
|
||||
style,
|
||||
enabled,
|
||||
size = size
|
||||
)
|
||||
) {
|
||||
val backgroundColor = getColorByState(
|
||||
stateData = getSearchBarPersonaChipTokens().backgroundColor(searchBarPersonaChipInfo = getSearchBarPersonaChipInfo()),
|
||||
enabled = enabled, selected = selected, interactionSource = interactionSource
|
||||
)
|
||||
val textColor = getColorByState(
|
||||
stateData = getSearchBarPersonaChipTokens().textColor(searchBarPersonaChipInfo = getSearchBarPersonaChipInfo()),
|
||||
enabled = enabled, selected = selected, interactionSource = interactionSource
|
||||
)
|
||||
val font =
|
||||
getSearchBarPersonaChipTokens().fontSize(personaChipInfo = getSearchBarPersonaChipInfo())
|
||||
val avatarSize =
|
||||
getSearchBarPersonaChipTokens().avatarSize(personaChipInfo = getSearchBarPersonaChipInfo())
|
||||
val verticalPadding =
|
||||
getSearchBarPersonaChipTokens().verticalPadding(personaChipInfo = getSearchBarPersonaChipInfo())
|
||||
val horizontalPadding =
|
||||
getSearchBarPersonaChipTokens().horizontalPadding(personaChipInfo = getSearchBarPersonaChipInfo())
|
||||
val avatarToTextSpacing =
|
||||
getSearchBarPersonaChipTokens().avatarToTextSpacing(personaChipInfo = getSearchBarPersonaChipInfo())
|
||||
val cornerRadius =
|
||||
getSearchBarPersonaChipTokens().borderRadius(personaChipInfo = getSearchBarPersonaChipInfo())
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(cornerRadius))
|
||||
.background(backgroundColor)
|
||||
.clickable(
|
||||
enabled = enabled,
|
||||
onClick = onClick ?: {},
|
||||
interactionSource = interactionSource,
|
||||
indication = rememberRipple()
|
||||
)
|
||||
)
|
||||
{
|
||||
Row(
|
||||
Modifier
|
||||
.padding(
|
||||
horizontal = horizontalPadding,
|
||||
vertical = verticalPadding
|
||||
),
|
||||
horizontalArrangement = Arrangement.spacedBy(avatarToTextSpacing),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (size == PersonaChipSize.Medium) {
|
||||
if (onCloseClick != null && selected) {
|
||||
Icon(
|
||||
Icons.Filled.Close,
|
||||
modifier = Modifier
|
||||
.size(16.dp)
|
||||
.clickable(
|
||||
enabled = true,
|
||||
onClick = onCloseClick,
|
||||
role = Role.Button
|
||||
),
|
||||
contentDescription = getString(string = Strings.Close),
|
||||
tint = textColor
|
||||
)
|
||||
} else {
|
||||
Avatar(person = person, size = avatarSize)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.padding(bottom = 2.dp),//Vertically center align text
|
||||
text = person.getLabel(),
|
||||
color = textColor,
|
||||
lineHeight = font.fontSize.lineHeight,
|
||||
fontSize = font.fontSize.size
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getSearchBarPersonaChipTokens(): SearchBarPersonaChipTokens {
|
||||
return LocalSearchBarPersonaChipTokens.current
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getSearchBarPersonaChipInfo(): SearchBarPersonaChipInfo {
|
||||
return LocalSearchBarPersonaChipInfo.current
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
package com.microsoft.fluentui.tokenized.persona
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.interaction.*
|
||||
import androidx.compose.foundation.interaction.InteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsFocusedAsState
|
||||
import androidx.compose.foundation.interaction.collectIsHoveredAsState
|
||||
import androidx.compose.foundation.interaction.collectIsPressedAsState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
@ -39,6 +42,15 @@ class Person(
|
|||
return name
|
||||
}
|
||||
|
||||
fun getLabel(): String {
|
||||
val label = "$firstName $lastName"
|
||||
if (label.trim().isNotBlank())
|
||||
return label
|
||||
if(!email.isNullOrBlank())
|
||||
return email
|
||||
return "Anonymous"
|
||||
}
|
||||
|
||||
fun isImageAvailable(): Boolean {
|
||||
return image != null || imageBitmap != null
|
||||
}
|
||||
|
@ -111,6 +123,7 @@ class Group(
|
|||
return initial.uppercase()
|
||||
}
|
||||
}
|
||||
|
||||
class Persona(
|
||||
val person: Person,
|
||||
val title: String,
|
||||
|
@ -127,34 +140,48 @@ class AvatarCarouselItem(
|
|||
val enableActivityRing: Boolean = false,
|
||||
val onItemClick: (() -> Unit)? = null
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun getColorByState(
|
||||
stateData: StateColor,
|
||||
enabled: Boolean,
|
||||
selected: Boolean,
|
||||
interactionSource: InteractionSource
|
||||
): Color {
|
||||
if (enabled) {
|
||||
val isPressed by interactionSource.collectIsPressedAsState()
|
||||
if (isPressed)
|
||||
if (selected && isPressed)
|
||||
return stateData.selectedPressed
|
||||
else if (isPressed)
|
||||
return stateData.pressed
|
||||
|
||||
val isFocused by interactionSource.collectIsFocusedAsState()
|
||||
if (isFocused)
|
||||
return stateData.pressed
|
||||
if (selected && isFocused)
|
||||
return stateData.selectedFocused
|
||||
else if (isFocused)
|
||||
return stateData.focused
|
||||
|
||||
val isHovered by interactionSource.collectIsHoveredAsState()
|
||||
if (selected && isHovered)
|
||||
return stateData.selectedFocused
|
||||
if (isHovered)
|
||||
return stateData.pressed
|
||||
return stateData.focused
|
||||
|
||||
if (selected)
|
||||
return stateData.selected
|
||||
|
||||
return stateData.rest
|
||||
} else
|
||||
} else if (selected)
|
||||
return stateData.selectedDisabled
|
||||
else
|
||||
return stateData.disabled
|
||||
}
|
||||
|
||||
fun getAvatarSize(secondaryText: String?, tertiaryText: String?): AvatarSize {
|
||||
if(secondaryText == null && tertiaryText == null){
|
||||
if (secondaryText == null && tertiaryText == null) {
|
||||
return AvatarSize.Size24
|
||||
}
|
||||
if(secondaryText != null && tertiaryText == null){
|
||||
if (secondaryText != null && tertiaryText == null) {
|
||||
return AvatarSize.Size40
|
||||
}
|
||||
return AvatarSize.Size56
|
||||
|
|
Загрузка…
Ссылка в новой задаче