Badge, TabBar implementation
This commit is contained in:
Родитель
1fdbe1c8d1
Коммит
a4b74347f1
|
@ -27,49 +27,51 @@
|
|||
</activity>
|
||||
|
||||
<!-- Demo activities -->
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.ActionBarLayoutActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2AppBarLayoutActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2AvatarActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2AvatarCarouselActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2AvatarGroupActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2BadgeActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2BasicInputsActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2BasicControlsActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2BottomSheetActivity" />
|
||||
<activity
|
||||
android:name="com.microsoft.fluentuidemo.demos.V2ContextualCommandBarActivity"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2DrawerActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2ListItemActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2PersonaActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2PersonaChipActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2PersonaListActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2ProgressActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2SearchBarActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2SegmentedControlActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2TabBarActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.ActionBarLayoutActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.AppBarLayoutActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.AvatarViewActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.AvatarGroupViewActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.BasicInputsActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2AvatarActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2AvatarCarouselActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2AvatarGroupActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2BasicInputsActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2BasicControlsActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.BottomNavigationActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.BottomSheetActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.CalendarViewActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.ContextualCommandBarActivity" />
|
||||
<activity
|
||||
android:name="com.microsoft.fluentuidemo.demos.V2ContextualCommandBarActivity"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.DateTimePickerActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.DrawerActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2DrawerActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.ListItemViewActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2ListItemActivity" />
|
||||
<activity
|
||||
android:name="com.microsoft.fluentuidemo.demos.PeoplePickerViewActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<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" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2PersonaActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.PopupMenuActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.ProgressActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2ProgressActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.SnackbarActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2SegmentedControlActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.V2SearchBarActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.TabLayoutActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.TemplateViewActivity" />
|
||||
<activity android:name="com.microsoft.fluentuidemo.demos.TooltipActivity" />
|
||||
|
|
|
@ -9,42 +9,44 @@ import com.microsoft.fluentuidemo.demos.*
|
|||
import java.util.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
const val V2AVATAR = "V2 Avatar"
|
||||
const val V2AVATAR_CAROUSEL = "V2 Avatar Carousel"
|
||||
const val V2AVATAR_GROUP = "V2 Avatar Group"
|
||||
const val V2Badge = "V2 Badge"
|
||||
const val V2BASIC_CONTROLS = "V2 Basic Controls"
|
||||
const val V2BASIC_INPUTS = "V2 Basic Inputs"
|
||||
const val V2BOTTOM_SHEET = "V2 BottomSheet"
|
||||
const val V2CONTEXTUAL_COMMAND_BAR = "V2 ContextualCommandBar"
|
||||
const val V2DRAWER = "V2 Drawer"
|
||||
const val V2LIST_ITEM = "V2 ListItem"
|
||||
const val V2PERSONA = "V2 Persona"
|
||||
const val V2PERSONA_CHIP = "V2 PersonaChip"
|
||||
const val V2PERSONA_LIST = "V2 PersonaList"
|
||||
const val V2PROGRESS = "V2 Progress"
|
||||
const val V2SEARCHBAR = "V2 SearchBar"
|
||||
const val V2SEGMENTED_CONTROL = "V2 SegmentedControl"
|
||||
const val V2TABBAR = "V2 TabBar"
|
||||
const val ACTION_BAR_LAYOUT = "ActionBarLayout"
|
||||
const val APP_BAR_LAYOUT = "AppBarLayout"
|
||||
const val V2APP_BAR_LAYOUT = "V2 AppBarLayout"
|
||||
const val AVATAR_VIEW = "AvatarView"
|
||||
const val AVATAR_GROUP_VIEW = "AvatarGroupView"
|
||||
const val BASIC_INPUTS = "Basic Inputs"
|
||||
const val V2AVATAR = "V2 Avatar"
|
||||
const val V2AVATAR_CAROUSEL = "V2 Avatar Carousel"
|
||||
const val V2AVATAR_GROUP = "V2 Avatar Group"
|
||||
const val V2BASIC_INPUTS = "V2 Basic Inputs"
|
||||
const val V2BASIC_CONTROLS = "V2 Basic Controls"
|
||||
const val BOTTOM_NAVIGATION = "BottomNavigation"
|
||||
const val BOTTOM_SHEET = "BottomSheet"
|
||||
const val CALENDAR_VIEW = "CalendarView"
|
||||
const val CONTEXTUAL_COMMAND_BAR = "ContextualCommandBar"
|
||||
const val V2CONTEXTUAL_COMMAND_BAR = "V2 ContextualCommandBar"
|
||||
const val DATE_TIME_PICKER = "DateTimePicker"
|
||||
const val DRAWER = "Drawer"
|
||||
const val V2DRAWER = "V2 Drawer"
|
||||
const val LIST_ITEM_VIEW = "ListItemView"
|
||||
const val V2LIST_ITEM = "V2 ListItem"
|
||||
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"
|
||||
const val V2PERSONA = "V2 Persona"
|
||||
const val POPUP_MENU = "PopupMenu"
|
||||
const val PROGRESS = "Progress"
|
||||
const val V2PROGRESS = "V2 Progress"
|
||||
const val SNACKBAR = "Snackbar"
|
||||
const val V2SEGMENTED_CONTROL = "V2 SegmentedControl"
|
||||
const val V2SEARCHBAR = "V2 SearchBar"
|
||||
const val TAB_LAYOUT = "TabLayout"
|
||||
const val TEMPLATE_VIEW = "TemplateView"
|
||||
const val TOOLTIP = "Tooltip"
|
||||
|
@ -55,6 +57,7 @@ val DEMOS = arrayListOf(
|
|||
Demo(V2AVATAR, V2AvatarActivity::class),
|
||||
Demo(V2AVATAR_CAROUSEL, V2AvatarCarouselActivity::class),
|
||||
Demo(V2AVATAR_GROUP, V2AvatarGroupActivity::class),
|
||||
Demo(V2Badge, V2BadgeActivity::class),
|
||||
Demo(V2BASIC_INPUTS, V2BasicInputsActivity::class),
|
||||
Demo(V2BASIC_CONTROLS, V2BasicControlsActivity::class),
|
||||
Demo(V2BOTTOM_SHEET, V2BottomSheetActivity::class),
|
||||
|
@ -67,6 +70,7 @@ val DEMOS = arrayListOf(
|
|||
Demo(V2PROGRESS, V2ProgressActivity::class),
|
||||
Demo(V2SEARCHBAR, V2SearchBarActivity::class),
|
||||
Demo(V2SEGMENTED_CONTROL, V2SegmentedControlActivity::class),
|
||||
Demo(V2TABBAR, V2TabBarActivity::class),
|
||||
Demo(ACTION_BAR_LAYOUT, ActionBarLayoutActivity::class),
|
||||
Demo(APP_BAR_LAYOUT, AppBarLayoutActivity::class),
|
||||
Demo(AVATAR_VIEW, AvatarViewActivity::class),
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
package com.microsoft.fluentuidemo.demos
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.ThemeMode
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.BadgeType
|
||||
import com.microsoft.fluentui.tokenized.notification.Badge
|
||||
import com.microsoft.fluentuidemo.DemoActivity
|
||||
import com.microsoft.fluentuidemo.R
|
||||
|
||||
|
||||
class V2BadgeActivity : 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 composeHere = findViewById<ComposeView>(R.id.compose_here)
|
||||
|
||||
composeHere.setContent {
|
||||
FluentTheme {
|
||||
val title1Font =
|
||||
FluentTheme.aliasTokens.typography[AliasTokens.TypographyTokens.Title1]
|
||||
val title2Font =
|
||||
FluentTheme.aliasTokens.typography[AliasTokens.TypographyTokens.Title2]
|
||||
|
||||
Column(Modifier.background(Color.Gray)) {
|
||||
Text(
|
||||
text = resources.getString(R.string.badge_notification_badge),
|
||||
fontWeight = title1Font.weight,
|
||||
fontSize = title1Font.fontSize.size,
|
||||
lineHeight = title1Font.fontSize.lineHeight,
|
||||
color = FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.Foreground1].value(),
|
||||
modifier = Modifier.padding(8.dp)
|
||||
|
||||
)
|
||||
Row(Modifier.padding(16.dp)) {
|
||||
Text(
|
||||
text = resources.getString(R.string.badge_notification_dot),
|
||||
fontWeight = title2Font.weight,
|
||||
fontSize = title2Font.fontSize.size,
|
||||
lineHeight = title2Font.fontSize.lineHeight,
|
||||
color = FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.Foreground1].value()
|
||||
)
|
||||
Badge()
|
||||
}
|
||||
|
||||
Row(Modifier.padding(16.dp)) {
|
||||
Text(
|
||||
text = resources.getString(R.string.badge_notification_character),
|
||||
fontWeight = title2Font.weight,
|
||||
fontSize = title2Font.fontSize.size,
|
||||
lineHeight = title2Font.fontSize.lineHeight,
|
||||
color = FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.Foreground1].value()
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("1", badgeType = BadgeType.Character)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("2", badgeType = BadgeType.Character)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("8", badgeType = BadgeType.Character)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("12", badgeType = BadgeType.Character)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("123", badgeType = BadgeType.Character)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("12345678910", badgeType = BadgeType.Character)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("Badge", badgeType = BadgeType.Character)
|
||||
}
|
||||
Row(Modifier.padding(16.dp)) {
|
||||
Text(
|
||||
text = "List",
|
||||
fontWeight = title2Font.weight,
|
||||
fontSize = title2Font.fontSize.size,
|
||||
lineHeight = title2Font.fontSize.lineHeight,
|
||||
color = FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.Foreground1].value(
|
||||
themeMode = ThemeMode.Auto
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("1", badgeType = BadgeType.List)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("2", badgeType = BadgeType.List)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("8", badgeType = BadgeType.List)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("12", badgeType = BadgeType.List)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("123", badgeType = BadgeType.List)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("12345678910", badgeType = BadgeType.List)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Badge("Badge", badgeType = BadgeType.List)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
package com.microsoft.fluentuidemo.demos
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material.icons.outlined.*
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.microsoft.fluentui.theme.AppThemeController
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.ThemeMode
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.BadgeType
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.ButtonSize
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.ButtonStyle
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.TabTextAlignment
|
||||
import com.microsoft.fluentui.tokenized.controls.Button
|
||||
import com.microsoft.fluentui.tokenized.controls.RadioButton
|
||||
import com.microsoft.fluentui.tokenized.listitem.ListItem
|
||||
import com.microsoft.fluentui.tokenized.navigation.TabBar
|
||||
import com.microsoft.fluentui.tokenized.navigation.TabData
|
||||
import com.microsoft.fluentui.tokenized.notification.Badge
|
||||
import com.microsoft.fluentuidemo.DemoActivity
|
||||
import com.microsoft.fluentuidemo.R
|
||||
|
||||
class V2TabBarActivity : 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 composeHere = findViewById<ComposeView>(R.id.compose_here)
|
||||
val context = this
|
||||
|
||||
composeHere.setContent {
|
||||
var selectedIndex by rememberSaveable { mutableStateOf(0) }
|
||||
val tabDataList = arrayListOf(
|
||||
TabData(
|
||||
title = resources.getString(R.string.tabBar_home),
|
||||
icon = Icons.Outlined.Home,
|
||||
selectedIcon = Icons.Filled.Home,
|
||||
onClick = {
|
||||
invokeToast(resources.getString(R.string.tabBar_home), context)
|
||||
Toast.makeText(context, "Home Tab Clicked", Toast.LENGTH_SHORT).show()
|
||||
selectedIndex = 0
|
||||
},
|
||||
badge = { Badge() }
|
||||
),
|
||||
TabData(
|
||||
title = resources.getString(R.string.tabBar_mail),
|
||||
icon = Icons.Outlined.Email,
|
||||
selectedIcon = Icons.Filled.Email,
|
||||
onClick = {
|
||||
invokeToast(resources.getString(R.string.tabBar_mail), context)
|
||||
selectedIndex = 1
|
||||
},
|
||||
badge = { Badge("123+", badgeType = BadgeType.Character) }
|
||||
),
|
||||
TabData(
|
||||
title = resources.getString(R.string.tabBar_settings),
|
||||
icon = Icons.Outlined.Settings,
|
||||
selectedIcon = Icons.Filled.Settings,
|
||||
onClick = {
|
||||
invokeToast(resources.getString(R.string.tabBar_settings), context)
|
||||
selectedIndex = 2
|
||||
}
|
||||
),
|
||||
TabData(
|
||||
title = resources.getString(R.string.tabBar_notification),
|
||||
icon = Icons.Outlined.Notifications,
|
||||
selectedIcon = Icons.Filled.Notifications,
|
||||
onClick = {
|
||||
invokeToast(resources.getString(R.string.tabBar_notification), context)
|
||||
selectedIndex = 3
|
||||
},
|
||||
badge = { Badge("10", badgeType = BadgeType.Character) }
|
||||
),
|
||||
TabData(
|
||||
title = resources.getString(R.string.tabBar_more),
|
||||
icon = Icons.Outlined.List,
|
||||
selectedIcon = Icons.Filled.List,
|
||||
onClick = {
|
||||
invokeToast(resources.getString(R.string.tabBar_more), context)
|
||||
selectedIndex = 4
|
||||
},
|
||||
badge = { Badge() }
|
||||
)
|
||||
)
|
||||
FluentTheme {
|
||||
val content = listOf(0, 1, 2)
|
||||
var selectedOption by rememberSaveable { mutableStateOf(content[0]) }
|
||||
var tabTextAlignment by rememberSaveable { mutableStateOf(TabTextAlignment.VERTICAL) }
|
||||
var tabItemsCount by rememberSaveable { mutableStateOf(5) }
|
||||
|
||||
Column {
|
||||
ListItem.Header(title = resources.getString(R.string.tabBar_text_alignment))
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
text = resources.getString(R.string.tabBar_vertical),
|
||||
modifier = Modifier.weight(1F),
|
||||
color = AppThemeController.aliasTokens.value!!.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.Foreground1].value(
|
||||
themeMode = ThemeMode.Auto
|
||||
)
|
||||
)
|
||||
RadioButton(
|
||||
selected = (selectedOption == content[0]),
|
||||
onClick = {
|
||||
selectedOption = content[0]
|
||||
tabTextAlignment = TabTextAlignment.VERTICAL
|
||||
}
|
||||
)
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
text = resources.getString(R.string.tabBar_horizontal),
|
||||
modifier = Modifier.weight(1F),
|
||||
color = AppThemeController.aliasTokens.value!!.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.Foreground1].value(
|
||||
themeMode = ThemeMode.Auto
|
||||
)
|
||||
)
|
||||
RadioButton(
|
||||
selected = (selectedOption == content[1]),
|
||||
onClick = {
|
||||
selectedOption = content[1]
|
||||
tabTextAlignment = TabTextAlignment.HORIZONTAL
|
||||
}
|
||||
)
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
text = resources.getString(R.string.tabBar_no_text),
|
||||
modifier = Modifier.weight(1F),
|
||||
color = AppThemeController.aliasTokens.value!!.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.Foreground1].value(
|
||||
themeMode = ThemeMode.Auto
|
||||
)
|
||||
)
|
||||
RadioButton(
|
||||
selected = (selectedOption == content[2]),
|
||||
onClick = {
|
||||
selectedOption = content[2]
|
||||
tabTextAlignment = TabTextAlignment.NO_TEXT
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
ListItem.Header(title = resources.getString(R.string.tabBar_tab_items),
|
||||
trailingAccessoryView =
|
||||
{
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Button(
|
||||
style = ButtonStyle.Button,
|
||||
size = ButtonSize.Medium,
|
||||
text = "+",
|
||||
enabled = tabItemsCount < 5,
|
||||
onClick = { tabItemsCount++ })
|
||||
|
||||
Button(
|
||||
style = ButtonStyle.Button,
|
||||
size = ButtonSize.Medium,
|
||||
text = "-",
|
||||
enabled = tabItemsCount > 1,
|
||||
onClick = { tabItemsCount-- })
|
||||
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Column(verticalArrangement = Arrangement.Bottom) {
|
||||
TabBar(
|
||||
tabDataList = tabDataList.take(tabItemsCount),
|
||||
selectedIndex = selectedIndex,
|
||||
tabTextAlignment = tabTextAlignment
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun invokeToast(string: String, context: Context) {
|
||||
Toast.makeText(context, "$string Tab Clicked", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
|
@ -101,6 +101,13 @@
|
|||
<!-- UI label denoting the avatar view clicked action performed by the user at a specific index-->
|
||||
<string name="avatar_group_avatar_clicked">AvatarView at index %d clicked</string>
|
||||
|
||||
<!--Badge-->
|
||||
<!--UI Labels -->
|
||||
<string name="badge_notification_badge">Notification Badge</string>
|
||||
<string name="badge_notification_dot">Dot</string>
|
||||
<string name="badge_notification_list">List</string>
|
||||
<string name="badge_notification_character">Character</string>
|
||||
|
||||
<!--BottomNavigation-->
|
||||
<!--UI Labels -->
|
||||
<string name="bottom_navigation_menu_item_photos">Photos</string>
|
||||
|
@ -643,6 +650,19 @@
|
|||
<!-- UI Text denoting Danger style snackbar -->
|
||||
<string name="snackbar_headline_danger_style">Danger style</string>
|
||||
|
||||
<!-- TabBar-->
|
||||
<!-- UI labels -->
|
||||
<string name="tabBar_home">Home</string>
|
||||
<string name="tabBar_mail">Mail</string>
|
||||
<string name="tabBar_settings">Settings</string>
|
||||
<string name="tabBar_notification">Notification</string>
|
||||
<string name="tabBar_more">More</string>
|
||||
<string name="tabBar_text_alignment">Text Alignment</string>
|
||||
<string name="tabBar_vertical">Vertical</string>
|
||||
<string name="tabBar_horizontal">Horizontal</string>
|
||||
<string name="tabBar_no_text">No Text</string>
|
||||
<string name="tabBar_tab_items">Tab Items</string>
|
||||
|
||||
<!--TemplateView-->
|
||||
<!-- UI labels and descriptions -->
|
||||
<string name="cell_sample_title">Title</string>
|
||||
|
|
|
@ -37,6 +37,7 @@ dependencies {
|
|||
api project(':fluentui_icons')
|
||||
api project(':fluentui_listitem')
|
||||
api project(':fluentui_menus')
|
||||
api project(':fluentui_notification')
|
||||
api project(':fluentui_others')
|
||||
api project(':fluentui_peoplepicker')
|
||||
api project(':fluentui_persona')
|
||||
|
|
|
@ -26,6 +26,7 @@ project.ext.fluentui_peoplepicker_versionid = '0.0.25'
|
|||
project.ext.fluentui_persona_versionid = '0.1.4'
|
||||
project.ext.fluentui_progress_versionid = '0.1.1'
|
||||
project.ext.fluentui_icons_versionid = '0.1.2'
|
||||
project.ext.fluentui_notification_versionid = '0.1.0'
|
||||
project.ext.FluentUI_versionid = '0.1.15'
|
||||
project.ext.fluentui_calendar_version_code = 25
|
||||
project.ext.fluentui_controls_version_code = 8
|
||||
|
@ -42,6 +43,7 @@ project.ext.fluentui_peoplepicker_version_code = 25
|
|||
project.ext.fluentui_persona_version_code = 30
|
||||
project.ext.fluentui_progress_version_code = 26
|
||||
project.ext.fluentui_icons_version_code = 3
|
||||
project.ext.fluentui_notification_version_code = 1
|
||||
project.ext.FluentUI_version_code = 50
|
||||
project.ext.license_type = 'MIT License'
|
||||
project.ext.license_url = 'https://github.com/microsoft/fluentui-android/blob/master/LICENSE'
|
||||
|
|
|
@ -19,6 +19,7 @@ class ControlTokens {
|
|||
Avatar,
|
||||
AvatarCarousel,
|
||||
AvatarGroup,
|
||||
Badge,
|
||||
BottomSheet,
|
||||
Button,
|
||||
CheckBox,
|
||||
|
@ -38,6 +39,8 @@ class ControlTokens {
|
|||
SearchBarPersonaChip,
|
||||
SearchBar,
|
||||
Shimmer,
|
||||
TabBar,
|
||||
TabBarTabItem,
|
||||
TabItem,
|
||||
ToggleSwitch
|
||||
}
|
||||
|
@ -49,6 +52,7 @@ class ControlTokens {
|
|||
ControlType.Avatar -> AvatarTokens()
|
||||
ControlType.AvatarCarousel -> AvatarCarouselTokens()
|
||||
ControlType.AvatarGroup -> AvatarGroupTokens()
|
||||
ControlType.Badge -> BadgeTokens()
|
||||
ControlType.BottomSheet -> BottomSheetTokens()
|
||||
ControlType.Button -> ButtonTokens()
|
||||
ControlType.CheckBox -> CheckBoxTokens()
|
||||
|
@ -68,6 +72,8 @@ class ControlTokens {
|
|||
ControlType.SearchBarPersonaChip -> SearchBarPersonaChipTokens()
|
||||
ControlType.SearchBar -> SearchBarTokens()
|
||||
ControlType.Shimmer -> ShimmerTokens()
|
||||
ControlType.TabBar -> TabBarTokens()
|
||||
ControlType.TabBarTabItem -> TabBarTabItemsTokens()
|
||||
ControlType.TabItem -> TabItemTokens()
|
||||
ControlType.ToggleSwitch -> ToggleSwitchTokens()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package com.microsoft.fluentui.theme.token.controlTokens
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.token.*
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
enum class BadgeType {
|
||||
Character,
|
||||
List
|
||||
}
|
||||
|
||||
class BadgeInfo(val type: BadgeType) : ControlInfo
|
||||
|
||||
@Parcelize
|
||||
open class BadgeTokens : ControlToken, Parcelable {
|
||||
|
||||
@Composable
|
||||
open fun backgroundColor(badgeInfo: BadgeInfo): Color {
|
||||
return FluentTheme.aliasTokens.errorAndStatusColor[AliasTokens.ErrorAndStatusColorTokens.DangerBackground2].value()
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun textColor(badgeInfo: BadgeInfo): Color {
|
||||
return FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.ForegroundLightStatic].value()
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun typography(badgeInfo: BadgeInfo): FontInfo {
|
||||
return when (badgeInfo.type) {
|
||||
BadgeType.Character -> FluentTheme.aliasTokens.typography[AliasTokens.TypographyTokens.Caption2]
|
||||
BadgeType.List -> FluentTheme.aliasTokens.typography[AliasTokens.TypographyTokens.Caption1Strong]
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun padding(badgeInfo: BadgeInfo): PaddingValues {
|
||||
return when (badgeInfo.type) {
|
||||
BadgeType.Character -> PaddingValues(
|
||||
horizontal = GlobalTokens.size(GlobalTokens.SizeTokens.Size60) + borderStroke(
|
||||
badgeInfo
|
||||
).width
|
||||
)
|
||||
BadgeType.List -> PaddingValues(
|
||||
start = GlobalTokens.size(GlobalTokens.SizeTokens.Size80) + borderStroke(badgeInfo).width,
|
||||
end = GlobalTokens.size(GlobalTokens.SizeTokens.Size80) + borderStroke(badgeInfo).width,
|
||||
top = 3.dp + borderStroke(badgeInfo).width,
|
||||
bottom = 3.dp + borderStroke(badgeInfo).width
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun borderStroke(badgeInfo: BadgeInfo): BorderStroke {
|
||||
return BorderStroke(
|
||||
GlobalTokens.strokeWidth(GlobalTokens.StrokeWidthTokens.StrokeWidth20),
|
||||
FluentTheme.aliasTokens.neutralStrokeColor[AliasTokens.NeutralStrokeColorTokens.StrokeFocus1].value()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.microsoft.fluentui.theme.token.controlTokens
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens
|
||||
import com.microsoft.fluentui.theme.token.StateColor
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
open class TabBarTabItemsTokens : TabItemTokens() {
|
||||
|
||||
@Composable
|
||||
override fun backgroundColor(tabItemInfo: TabItemInfo): Color {
|
||||
return FluentTheme.aliasTokens.neutralBackgroundColor[AliasTokens.NeutralBackgroundColorTokens.Background1].value()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun iconColor(tabItemInfo: TabItemInfo): StateColor {
|
||||
return StateColor(
|
||||
rest = FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.Foreground2].value(),
|
||||
selected = FluentTheme.aliasTokens.brandForegroundColor[AliasTokens.BrandForegroundColorTokens.BrandForeground1].value()
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun textColor(tabItemInfo: TabItemInfo): StateColor {
|
||||
return StateColor(
|
||||
rest = FluentTheme.aliasTokens.neutralForegroundColor[AliasTokens.NeutralForegroundColorTokens.Foreground2].value(),
|
||||
selected = FluentTheme.aliasTokens.brandForegroundColor[AliasTokens.BrandForegroundColorTokens.BrandForeground1].value()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.microsoft.fluentui.theme.token.controlTokens
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.token.AliasTokens
|
||||
import com.microsoft.fluentui.theme.token.ControlInfo
|
||||
import com.microsoft.fluentui.theme.token.ControlToken
|
||||
import com.microsoft.fluentui.theme.token.GlobalTokens
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
class TabBarInfo : ControlInfo
|
||||
|
||||
@Parcelize
|
||||
open class TabBarTokens : ControlToken, Parcelable {
|
||||
|
||||
@Composable
|
||||
open fun topBorderColor(tabBarInfo: TabBarInfo): Color {
|
||||
return FluentTheme.aliasTokens.neutralStrokeColor[AliasTokens.NeutralStrokeColorTokens.Stroke2].value()
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun topBorderWidth(tabBarInfo: TabBarInfo): Dp {
|
||||
return GlobalTokens.strokeWidth(GlobalTokens.StrokeWidthTokens.StrokeWidth05)
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ open class TabItemTokens : ControlToken, Parcelable {
|
|||
}
|
||||
|
||||
@Composable
|
||||
open fun background(tabItemInfo: TabItemInfo): Color {
|
||||
open fun backgroundColor(tabItemInfo: TabItemInfo): Color {
|
||||
return FluentTheme.aliasTokens.neutralBackgroundColor[AliasTokens.NeutralBackgroundColorTokens.Background1].value(
|
||||
FluentTheme.themeMode
|
||||
)
|
||||
|
|
|
@ -59,7 +59,7 @@ dependencies {
|
|||
implementation("androidx.compose.material:material:$composeVersion")
|
||||
implementation("androidx.compose.runtime:runtime:$composeVersion")
|
||||
implementation("androidx.compose.ui:ui:$composeVersion")
|
||||
|
||||
implementation "androidx.constraintlayout:constraintlayout-compose:$constraintLayoutComposeVersion"
|
||||
}
|
||||
|
||||
task sourceJar(type: Jar) {
|
||||
|
|
|
@ -31,7 +31,7 @@ data class ItemData(
|
|||
var enabled: Boolean = true,
|
||||
var onClick: () -> Unit,
|
||||
var accessory: @Composable (() -> Unit)? = null,
|
||||
var icon: ImageVector? = null
|
||||
var icon: ImageVector
|
||||
)
|
||||
|
||||
// marker interface
|
||||
|
@ -174,7 +174,7 @@ class ListContentBuilder {
|
|||
Layout(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
token.background(
|
||||
token.backgroundColor(
|
||||
TabItemInfo(
|
||||
TabTextAlignment.VERTICAL,
|
||||
FluentStyle.Brand
|
||||
|
@ -250,7 +250,7 @@ class ListContentBuilder {
|
|||
LazyRow(
|
||||
state = rowLazyListState, modifier = Modifier
|
||||
.background(
|
||||
token.background(
|
||||
token.backgroundColor(
|
||||
TabItemInfo(
|
||||
TabTextAlignment.VERTICAL,
|
||||
FluentStyle.Brand
|
||||
|
|
|
@ -786,7 +786,7 @@ object ListItem {
|
|||
.focusable(false)
|
||||
) {
|
||||
Row(
|
||||
modifier
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = cellHeight)
|
||||
.background(backgroundColor)
|
||||
|
@ -811,7 +811,7 @@ object ListItem {
|
|||
|
||||
if (accessoryTextTitle != null) {
|
||||
Text(text = accessoryTextTitle,
|
||||
modifier
|
||||
Modifier
|
||||
.padding(end = horizontalPadding, bottom = verticalPadding)
|
||||
.clickable(
|
||||
role = Role.Button,
|
||||
|
|
|
@ -14,9 +14,15 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.constraintlayout.compose.ChainStyle
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.token.ControlTokens
|
||||
import com.microsoft.fluentui.theme.token.FluentStyle
|
||||
|
@ -39,13 +45,14 @@ fun getTabItemInfo(): TabItemInfo {
|
|||
}
|
||||
|
||||
@Composable
|
||||
internal fun TabItem(
|
||||
fun TabItem(
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
icon: ImageVector? = null,
|
||||
icon: ImageVector,
|
||||
style: FluentStyle = FluentStyle.Neutral,
|
||||
textAlignment: TabTextAlignment = TabTextAlignment.VERTICAL,
|
||||
enabled: Boolean = true,
|
||||
selected: Boolean = false,
|
||||
fixedWidth: Boolean = false,
|
||||
onClick: () -> Unit,
|
||||
accessory: (@Composable () -> Unit)?,
|
||||
|
@ -60,18 +67,20 @@ internal fun TabItem(
|
|||
LocalTabItemTokens provides token,
|
||||
LocalTabItemInfo provides TabItemInfo(textAlignment, style)
|
||||
) {
|
||||
val textColor = getTabItemTokens().textColor(tabItemInfo = getTabItemInfo()).getColorByState(
|
||||
enabled = enabled,
|
||||
selected = false,
|
||||
interactionSource = interactionSource
|
||||
)
|
||||
val iconColor = getTabItemTokens().iconColor(tabItemInfo = getTabItemInfo()).getColorByState(
|
||||
enabled = enabled,
|
||||
selected = false,
|
||||
interactionSource = interactionSource
|
||||
)
|
||||
val textColor =
|
||||
getTabItemTokens().textColor(tabItemInfo = getTabItemInfo()).getColorByState(
|
||||
enabled = enabled,
|
||||
selected = selected,
|
||||
interactionSource = interactionSource
|
||||
)
|
||||
val iconColor =
|
||||
getTabItemTokens().iconColor(tabItemInfo = getTabItemInfo()).getColorByState(
|
||||
enabled = enabled,
|
||||
selected = selected,
|
||||
interactionSource = interactionSource
|
||||
)
|
||||
|
||||
val backgroundColor = getTabItemTokens().background(tabItemInfo = getTabItemInfo())
|
||||
val backgroundColor = getTabItemTokens().backgroundColor(tabItemInfo = getTabItemInfo())
|
||||
val rippleColor = getTabItemTokens().rippleColor(tabItemInfo = getTabItemInfo())
|
||||
|
||||
val clickableModifier = Modifier
|
||||
|
@ -90,41 +99,115 @@ internal fun TabItem(
|
|||
Modifier
|
||||
}
|
||||
val iconContent: @Composable () -> Unit = {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (icon != null) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
modifier = Modifier.height(if (textAlignment == TabTextAlignment.NO_TEXT) 28.dp else 24.dp),
|
||||
contentDescription = if (textAlignment == TabTextAlignment.NO_TEXT) title else null,
|
||||
tint = iconColor
|
||||
)
|
||||
}
|
||||
if (accessory != null) {
|
||||
accessory()
|
||||
}
|
||||
}
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
modifier = Modifier.size(if (textAlignment == TabTextAlignment.NO_TEXT) 28.dp else 24.dp),
|
||||
contentDescription = if (textAlignment == TabTextAlignment.NO_TEXT) title else null,
|
||||
tint = iconColor
|
||||
)
|
||||
}
|
||||
|
||||
if (textAlignment == TabTextAlignment.HORIZONTAL) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
ConstraintLayout(
|
||||
modifier = modifier
|
||||
.then(clickableModifier)
|
||||
.background(backgroundColor)
|
||||
.padding(top = 8.dp, start = 4.dp, bottom = 4.dp, end = 8.dp)
|
||||
.then(widthModifier)
|
||||
) {
|
||||
iconContent()
|
||||
Spacer(modifier = Modifier.width(2.dp))
|
||||
)
|
||||
{
|
||||
val (iconConstrain, textConstrain, badgeConstrain) = createRefs()
|
||||
|
||||
Box(modifier = Modifier.constrainAs(iconConstrain) {
|
||||
start.linkTo(parent.start)
|
||||
end.linkTo(textConstrain.start)
|
||||
}
|
||||
) {
|
||||
iconContent()
|
||||
}
|
||||
|
||||
Text(
|
||||
text = title,
|
||||
modifier = Modifier
|
||||
.constrainAs(textConstrain) {
|
||||
start.linkTo(iconConstrain.end)
|
||||
end.linkTo(badgeConstrain.start)
|
||||
width = Dimension.preferredWrapContent
|
||||
}
|
||||
.padding(start = 8.dp),
|
||||
color = textColor,
|
||||
textAlign = TextAlign.Justify
|
||||
textAlign = TextAlign.Center,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1
|
||||
)
|
||||
|
||||
if (accessory != null) {
|
||||
Box(modifier = Modifier
|
||||
.constrainAs(badgeConstrain) {
|
||||
start.linkTo(textConstrain.end)
|
||||
end.linkTo(parent.end)
|
||||
}
|
||||
) {
|
||||
accessory()
|
||||
}
|
||||
}
|
||||
createHorizontalChain(
|
||||
iconConstrain,
|
||||
textConstrain,
|
||||
badgeConstrain,
|
||||
chainStyle = ChainStyle.Packed
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val badgeWithIcon: @Composable () -> Unit = {
|
||||
Layout(
|
||||
{
|
||||
Box(
|
||||
modifier = Modifier.layoutId("anchor"),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
iconContent()
|
||||
}
|
||||
|
||||
Box(modifier = Modifier.layoutId("badge")) {
|
||||
if (accessory != null)
|
||||
accessory()
|
||||
}
|
||||
|
||||
}
|
||||
) { measurables, constraints ->
|
||||
val badgePlaceable = measurables.first { it.layoutId == "badge" }.measure(
|
||||
// Measure with loose constraints for height as we don't want the text to take up more
|
||||
// space than it needs.
|
||||
constraints.copy(minHeight = 0)
|
||||
)
|
||||
|
||||
val anchorPlaceable =
|
||||
measurables.first { it.layoutId == "anchor" }.measure(constraints)
|
||||
|
||||
// Use the width of the badge to infer whether it has any content (based on radius used
|
||||
// in [Badge]) and determine its horizontal offset.
|
||||
val hasContent = badgePlaceable.width > 16.dp.roundToPx()
|
||||
val contentOffset = if (hasContent) -2.dp.roundToPx() else 0
|
||||
val badgeHorizontalOffset = -anchorPlaceable.width / 2 + contentOffset
|
||||
val badgeVerticalOffset = (-4).dp
|
||||
|
||||
val totalWidth = anchorPlaceable.width
|
||||
val totalHeight = anchorPlaceable.height
|
||||
|
||||
layout(
|
||||
totalWidth,
|
||||
totalHeight
|
||||
) {
|
||||
|
||||
anchorPlaceable.placeRelative(0, 0)
|
||||
val badgeX = anchorPlaceable.width + badgeHorizontalOffset
|
||||
val badgeY = badgeVerticalOffset.roundToPx()
|
||||
badgePlaceable.placeRelative(badgeX, badgeY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
|
@ -134,7 +217,7 @@ internal fun TabItem(
|
|||
.padding(top = 8.dp, start = 8.dp, bottom = 4.dp, end = 8.dp)
|
||||
.then(widthModifier)
|
||||
) {
|
||||
iconContent()
|
||||
badgeWithIcon()
|
||||
if (textAlignment == TabTextAlignment.VERTICAL) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Text(
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -0,0 +1,71 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
apply from: '../config.gradle'
|
||||
apply from: '../publish.gradle'
|
||||
|
||||
android {
|
||||
compileSdkVersion constants.compileSdkVersion
|
||||
defaultConfig {
|
||||
minSdkVersion constants.minSdkVersion
|
||||
targetSdkVersion constants.targetSdkVersion
|
||||
versionCode project.ext.fluentui_notification_version_code
|
||||
versionName project.ext.fluentui_notification_versionid
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
testOptions {
|
||||
unitTests {
|
||||
includeAndroidResources = true
|
||||
}
|
||||
}
|
||||
productFlavors {
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
useIR = true
|
||||
}
|
||||
buildFeatures {
|
||||
compose true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion composeVersion
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation project(':fluentui_core')
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
|
||||
implementation("androidx.compose.foundation:foundation:$composeVersion")
|
||||
implementation("androidx.compose.material:material:$composeVersion")
|
||||
implementation("androidx.compose.runtime:runtime:$composeVersion")
|
||||
implementation("androidx.compose.ui:ui:$composeVersion")
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
}
|
||||
|
||||
task sourceJar(type: Jar) {
|
||||
from android.sourceSets.main.java.srcDirs
|
||||
classifier "sources"
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
project.ext.publishingFunc('fluentui_notification')
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
~ Licensed under the MIT License.
|
||||
-->
|
||||
|
||||
<manifest
|
||||
package="com.microsoft.fluentui.notification" />
|
|
@ -0,0 +1,113 @@
|
|||
package com.microsoft.fluentui.tokenized.notification
|
||||
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.LocalTextStyle
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.drawscope.Fill
|
||||
import androidx.compose.ui.text.ExperimentalTextApi
|
||||
import androidx.compose.ui.text.PlatformTextStyle
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.token.ControlTokens
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.BadgeInfo
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.BadgeTokens
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.BadgeType
|
||||
import com.microsoft.fluentui.util.dpToPx
|
||||
|
||||
val LocalBadgeInfo = compositionLocalOf { BadgeInfo(BadgeType.Character) }
|
||||
val LocalBadgeToken = compositionLocalOf { BadgeTokens() }
|
||||
|
||||
@Composable
|
||||
fun getBadgeInfo(): BadgeInfo {
|
||||
return LocalBadgeInfo.current
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun getBadgeTokens(): BadgeTokens {
|
||||
return LocalBadgeToken.current
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTextApi::class)
|
||||
@Composable
|
||||
fun Badge(
|
||||
text: String? = null,
|
||||
modifier: Modifier = Modifier,
|
||||
badgeType: BadgeType = BadgeType.List,
|
||||
badgeTokens: BadgeTokens? = null
|
||||
) {
|
||||
val token = badgeTokens
|
||||
?: FluentTheme.controlTokens.tokens[ControlTokens.ControlType.Badge] as BadgeTokens
|
||||
CompositionLocalProvider(
|
||||
LocalBadgeToken provides token,
|
||||
LocalBadgeInfo provides BadgeInfo(badgeType)
|
||||
) {
|
||||
val background = getBadgeTokens().backgroundColor(badgeInfo = getBadgeInfo())
|
||||
val borderStroke = getBadgeTokens().borderStroke(badgeInfo = getBadgeInfo())
|
||||
if (text.isNullOrEmpty()) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.defaultMinSize(16.dp, 16.dp)
|
||||
) {
|
||||
Canvas(
|
||||
modifier = Modifier
|
||||
.padding(start = 5.dp, end = 3.dp, top = 3.dp, bottom = 5.dp)
|
||||
.sizeIn(minWidth = 8.dp, minHeight = 8.dp)
|
||||
) {
|
||||
drawCircle(
|
||||
brush = borderStroke.brush,
|
||||
radius = dpToPx(borderStroke.width + 4.dp)
|
||||
)
|
||||
drawCircle(
|
||||
color = background,
|
||||
style = Fill,
|
||||
radius = dpToPx(4.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val textColor = getBadgeTokens().textColor(badgeInfo = getBadgeInfo())
|
||||
val typography = getBadgeTokens().typography(badgeInfo = getBadgeInfo())
|
||||
val paddingValues = getBadgeTokens().padding(badgeInfo = getBadgeInfo())
|
||||
|
||||
Row(
|
||||
modifier
|
||||
.requiredHeight(if (badgeType == BadgeType.Character) 20.dp else 27.dp)
|
||||
.border(borderStroke.width, borderStroke.brush, CircleShape)
|
||||
.padding(0.5.dp) //TODO to check fix for https://issuetracker.google.com/issues/228985905
|
||||
.background(background, CircleShape)
|
||||
.clip(RoundedCornerShape(100.dp)),
|
||||
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
text,
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
style = LocalTextStyle.current.merge(
|
||||
TextStyle(
|
||||
color = textColor,
|
||||
lineHeight = typography.fontSize.lineHeight,
|
||||
fontSize = typography.fontSize.size,
|
||||
fontWeight = typography.weight,
|
||||
platformStyle = PlatformTextStyle(
|
||||
includeFontPadding = false
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
|
@ -45,6 +45,7 @@ dependencies {
|
|||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation project(':fluentui_core')
|
||||
implementation project(':fluentui_icons')
|
||||
implementation project(':fluentui_listitem')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation "androidx.appcompat:appcompat:$appCompatVersion"
|
||||
implementation "com.google.android.material:material:$materialVersion"
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package com.microsoft.fluentui.tokenized.navigation
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.microsoft.fluentui.theme.FluentTheme
|
||||
import com.microsoft.fluentui.theme.token.ControlTokens
|
||||
import com.microsoft.fluentui.theme.token.controlTokens.*
|
||||
import com.microsoft.fluentui.tokenized.tabItem.TabItem
|
||||
|
||||
|
||||
data class TabData(
|
||||
var title: String,
|
||||
var icon: ImageVector,
|
||||
var selectedIcon: ImageVector = icon,
|
||||
var selected: Boolean = false,
|
||||
var onClick: () -> Unit,
|
||||
var badge: @Composable (() -> Unit)? = null
|
||||
)
|
||||
|
||||
val LocalTabBarInfo = compositionLocalOf { TabBarInfo() }
|
||||
val LocalTabBarToken = compositionLocalOf { TabBarTokens() }
|
||||
|
||||
@Composable
|
||||
fun getTabBarInfo(): TabBarInfo {
|
||||
return LocalTabBarInfo.current
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun getTabBarToken(): TabBarTokens {
|
||||
return LocalTabBarToken.current
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabBar(
|
||||
tabDataList: List<TabData>,
|
||||
modifier: Modifier = Modifier,
|
||||
selectedIndex: Int = 0,
|
||||
tabTextAlignment: TabTextAlignment = TabTextAlignment.VERTICAL,
|
||||
tabItemTokens: TabBarTabItemsTokens? = null,
|
||||
tabBarTokens: TabBarTokens? = null
|
||||
) {
|
||||
val token = tabBarTokens
|
||||
?: FluentTheme.controlTokens.tokens[ControlTokens.ControlType.TabBar] as TabBarTokens
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalTabBarToken provides token
|
||||
) {
|
||||
Column {
|
||||
Box(
|
||||
modifier
|
||||
.fillMaxWidth()
|
||||
.height(getTabBarToken().topBorderWidth(tabBarInfo = getTabBarInfo()))
|
||||
.background(color = getTabBarToken().topBorderColor(tabBarInfo = getTabBarInfo()))
|
||||
)
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
tabDataList.forEachIndexed { index, tabData ->
|
||||
tabData.selected = index == selectedIndex
|
||||
TabItem(
|
||||
title = tabData.title,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1F),
|
||||
icon = if (tabData.selected) tabData.selectedIcon else tabData.icon,
|
||||
textAlignment = tabTextAlignment,
|
||||
selected = tabData.selected,
|
||||
onClick = tabData.onClick,
|
||||
accessory = tabData.badge,
|
||||
tabItemTokens = tabItemTokens
|
||||
?: FluentTheme.controlTokens.tokens[ControlTokens.ControlType.TabBarTabItem] as TabItemTokens
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,3 +15,4 @@ include ':FluentUI'
|
|||
include ':fluentui_ccb'
|
||||
include ':fluentui_controls'
|
||||
include ':fluentui_icons'
|
||||
include ':fluentui_notification'
|
||||
|
|
Загрузка…
Ссылка в новой задаче