Skip to content

Commit 5462658

Browse files
authored
Merge pull request #768 from microsoft/dhruvMishra/drawerAndSheetAccessibilityAnnouncement
[Fluent v2] Added Drawer Talkback Announcement
2 parents 7c6c4b2 + f8a7599 commit 5462658

File tree

5 files changed

+99
-14
lines changed

5 files changed

+99
-14
lines changed

fluentui_core/src/main/java/com/microsoft/fluentui/compose/ModalPopup.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ fun ModalPopup(
7070
windowInsetsType: Int = WindowInsetsCompat.Type.systemBars(),
7171
content: @Composable () -> Unit,
7272
) {
73-
val properties = PopupProperties()
73+
val properties = PopupProperties(
74+
focusable = true,
75+
)
7476
val view = LocalView.current
7577
val density = LocalDensity.current
7678
val layoutDirection = LocalLayoutDirection.current

fluentui_core/src/main/java/com/microsoft/fluentui/theme/token/controlTokens/BottomSheetTokens.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,17 @@ import kotlinx.parcelize.Parcelize
1515

1616
open class BottomSheetInfo : ControlInfo
1717

18+
data class SheetAccessibilityAnnouncement(
19+
var expandedToShown: String = "",
20+
var expandedToCollapsed: String = "Bottom Sheet Collapsed",
21+
var shownToExpanded: String = "Bottom Sheet Expanded",
22+
var shownToCollapsed: String = "Bottom Sheet Collapsed",
23+
var collapsedToExpanded: String = "Bottom Sheet Expanded",
24+
var collapsedToShown: String = "Bottom Sheet Opened",
25+
)
26+
1827
@Parcelize
1928
open class BottomSheetTokens : IControlToken, Parcelable {
20-
2129
@Composable
2230
open fun backgroundBrush(bottomSheetInfo: BottomSheetInfo): Brush =
2331
SolidColor(

fluentui_core/src/main/java/com/microsoft/fluentui/theme/token/controlTokens/DrawerTokens.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@ enum class BehaviorType {
2222

2323
open class DrawerInfo(val type: BehaviorType = BehaviorType.LEFT_SLIDE_OVER) : ControlInfo
2424

25+
data class DrawerAccessibilityAnnouncement(
26+
var opened: String = "Drawer Opened",
27+
var closed: String = "Drawer Closed",
28+
)
29+
2530
@Parcelize
2631
open class DrawerTokens : IControlToken, Parcelable {
27-
2832
@Composable
2933
open fun backgroundBrush(drawerInfo: DrawerInfo): Brush =
3034
SolidColor(

fluentui_drawer/src/main/java/com/microsoft/fluentui/tokenized/bottomsheet/BottomSheet.kt

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
3434
import androidx.compose.ui.layout.*
3535
import androidx.compose.ui.platform.LocalConfiguration
3636
import androidx.compose.ui.platform.LocalContext
37+
import androidx.compose.ui.platform.LocalView
3738
import androidx.compose.ui.platform.testTag
3839
import androidx.compose.ui.res.painterResource
3940
import androidx.compose.ui.semantics.*
@@ -49,6 +50,7 @@ import com.microsoft.fluentui.theme.FluentTheme
4950
import com.microsoft.fluentui.theme.token.ControlTokens
5051
import com.microsoft.fluentui.theme.token.controlTokens.BottomSheetInfo
5152
import com.microsoft.fluentui.theme.token.controlTokens.BottomSheetTokens
53+
import com.microsoft.fluentui.theme.token.controlTokens.SheetAccessibilityAnnouncement
5254
import com.microsoft.fluentui.tokenized.calculateFraction
5355
import com.microsoft.fluentui.util.dpToPx
5456
import com.microsoft.fluentui.util.pxToDp
@@ -192,6 +194,51 @@ const val BOTTOMSHEET_SCRIM_TAG = "Fluent Bottom Sheet Scrim"
192194

193195
private const val BottomSheetOpenFraction = 0.5f
194196

197+
@Composable
198+
internal fun AccesibilityBottomsheetAnnouncement(sheetState: BottomSheetState, talkbackAnnouncement: SheetAccessibilityAnnouncement){
199+
val view = LocalView.current
200+
var previousState by remember { mutableStateOf(sheetState.currentValue) }
201+
202+
LaunchedEffect(sheetState.currentValue) {
203+
when (sheetState.currentValue) {
204+
BottomSheetValue.Expanded -> {
205+
when (previousState) {
206+
BottomSheetValue.Shown -> {
207+
view.announceForAccessibility(talkbackAnnouncement.shownToExpanded)
208+
}
209+
BottomSheetValue.Hidden -> {
210+
view.announceForAccessibility(talkbackAnnouncement.collapsedToExpanded)
211+
}
212+
BottomSheetValue.Expanded -> {}
213+
}
214+
}
215+
BottomSheetValue.Shown -> {
216+
when (previousState) {
217+
BottomSheetValue.Expanded -> {
218+
view.announceForAccessibility(talkbackAnnouncement.expandedToShown)
219+
}
220+
BottomSheetValue.Hidden -> {
221+
view.announceForAccessibility(talkbackAnnouncement.collapsedToShown)
222+
}
223+
BottomSheetValue.Shown -> {}
224+
}
225+
}
226+
BottomSheetValue.Hidden -> {
227+
when (previousState) {
228+
BottomSheetValue.Expanded -> {
229+
view.announceForAccessibility(talkbackAnnouncement.expandedToCollapsed)
230+
}
231+
BottomSheetValue.Shown -> {
232+
view.announceForAccessibility(talkbackAnnouncement.shownToCollapsed)
233+
}
234+
BottomSheetValue.Hidden -> {}
235+
}
236+
}
237+
}
238+
previousState = sheetState.currentValue // Update previous state
239+
}
240+
}
241+
195242
/**
196243
*
197244
* Bottom sheets present a set of choices while blocking interaction with the rest of the
@@ -236,6 +283,7 @@ fun BottomSheet(
236283
preventDismissalOnScrimClick: Boolean = false, // if true, the sheet will not be dismissed when the scrim is clicked
237284
stickyThresholdUpward: Float = 56f,
238285
stickyThresholdDownward: Float = 56f,
286+
talkbackAnnouncement: SheetAccessibilityAnnouncement = SheetAccessibilityAnnouncement(),
239287
bottomSheetTokens: BottomSheetTokens? = null,
240288
onDismiss: () -> Unit = {}, // callback to be invoked after the sheet is closed
241289
content: @Composable () -> Unit
@@ -244,8 +292,8 @@ fun BottomSheet(
244292
FluentTheme.themeID //Adding This only for recomposition in case of Token Updates. Unused otherwise.
245293
val tokens = bottomSheetTokens
246294
?: FluentTheme.controlTokens.tokens[ControlTokens.ControlType.BottomSheetControlType] as BottomSheetTokens
247-
248295
val bottomSheetInfo = BottomSheetInfo()
296+
AccesibilityBottomsheetAnnouncement(sheetState, talkbackAnnouncement)
249297
val sheetShape: Shape = RoundedCornerShape(
250298
topStart = tokens.cornerRadius(bottomSheetInfo),
251299
topEnd = tokens.cornerRadius(bottomSheetInfo)

fluentui_drawer/src/main/java/com/microsoft/fluentui/tokenized/drawer/Drawer.kt

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import androidx.compose.foundation.gestures.detectTapGestures
66
import androidx.compose.foundation.layout.fillMaxSize
77
import androidx.compose.foundation.shape.RoundedCornerShape
88
import androidx.compose.runtime.Composable
9+
import androidx.compose.runtime.LaunchedEffect
910
import androidx.compose.runtime.getValue
1011
import androidx.compose.runtime.mutableStateOf
1112
import androidx.compose.runtime.remember
@@ -18,6 +19,7 @@ import androidx.compose.ui.graphics.Brush
1819
import androidx.compose.ui.graphics.Color
1920
import androidx.compose.ui.graphics.Shape
2021
import androidx.compose.ui.input.pointer.pointerInput
22+
import androidx.compose.ui.platform.LocalView
2123
import androidx.compose.ui.platform.testTag
2224
import androidx.compose.ui.unit.Dp
2325
import androidx.compose.ui.unit.IntOffset
@@ -34,6 +36,7 @@ import com.microsoft.fluentui.compose.SwipeableState
3436
import com.microsoft.fluentui.theme.FluentTheme
3537
import com.microsoft.fluentui.theme.token.ControlTokens
3638
import com.microsoft.fluentui.theme.token.controlTokens.BehaviorType
39+
import com.microsoft.fluentui.theme.token.controlTokens.DrawerAccessibilityAnnouncement
3740
import com.microsoft.fluentui.theme.token.controlTokens.DrawerInfo
3841
import com.microsoft.fluentui.theme.token.controlTokens.DrawerTokens
3942
import kotlinx.coroutines.CancellationException
@@ -323,6 +326,23 @@ internal fun Scrim(
323326
}
324327
}
325328

329+
@Composable
330+
internal fun AnnounceDrawerActions(drawerState: DrawerState, talkbackAnnouncement: DrawerAccessibilityAnnouncement){ // Announces actions for drawer through Talkback
331+
val view = LocalView.current
332+
var previousState by remember { mutableStateOf(drawerState.enable) }
333+
334+
LaunchedEffect(drawerState.enable) {
335+
if (drawerState.enable != previousState) {
336+
if (drawerState.enable) {
337+
view.announceForAccessibility(talkbackAnnouncement.opened)
338+
} else {
339+
view.announceForAccessibility(talkbackAnnouncement.closed)
340+
}
341+
previousState = drawerState.enable
342+
}
343+
}
344+
345+
}
326346
/**
327347
*
328348
* Drawer block interaction with the rest of an app’s content with a scrim.
@@ -348,25 +368,27 @@ fun Drawer(
348368
drawerState: DrawerState = rememberDrawerState(),
349369
scrimVisible: Boolean = true,
350370
offset: IntOffset? = null,
371+
talkbackAnnouncement: DrawerAccessibilityAnnouncement = DrawerAccessibilityAnnouncement(),
351372
drawerTokens: DrawerTokens? = null,
352373
drawerContent: @Composable () -> Unit,
353374
preventDismissalOnScrimClick: Boolean = false,
354375
onScrimClick: () -> Unit = {}
355376
) {
377+
val tokens = drawerTokens
378+
?: FluentTheme.controlTokens.tokens[ControlTokens.ControlType.DrawerControlType] as DrawerTokens
379+
val drawerInfo = DrawerInfo(type = behaviorType)
380+
AnnounceDrawerActions(drawerState, talkbackAnnouncement = talkbackAnnouncement)
381+
356382
if (drawerState.enable) {
357383
val themeID =
358384
FluentTheme.themeID //Adding This only for recomposition in case of Token Updates. Unused otherwise.
359-
val tokens = drawerTokens
360-
?: FluentTheme.controlTokens.tokens[ControlTokens.ControlType.DrawerControlType] as DrawerTokens
361-
362385
val popupPositionProvider = DrawerPositionProvider(offset)
363386
val scope = rememberCoroutineScope()
364387
val close: () -> Unit = {
365388
if (drawerState.confirmStateChange(DrawerValue.Closed)) {
366389
scope.launch { drawerState.close() }
367390
}
368391
}
369-
val drawerInfo = DrawerInfo(type = behaviorType)
370392
Popup(
371393
onDismissRequest = close,
372394
popupPositionProvider = popupPositionProvider,
@@ -478,27 +500,28 @@ fun BottomDrawer(
478500
showHandle: Boolean = true,
479501
enableSwipeDismiss: Boolean = true,
480502
windowInsetsType: Int = WindowInsetsCompat.Type.systemBars(),
503+
talkbackAnnouncement: DrawerAccessibilityAnnouncement = DrawerAccessibilityAnnouncement(),
481504
drawerTokens: DrawerTokens? = null,
482505
drawerContent: @Composable () -> Unit,
483506
maxLandscapeWidthFraction: Float = 1F,
484507
preventDismissalOnScrimClick: Boolean = false,
485508
onScrimClick: () -> Unit = {},
486509
) {
487-
510+
val behaviorType =
511+
if (slideOver) BehaviorType.BOTTOM_SLIDE_OVER else BehaviorType.BOTTOM
512+
val drawerInfo = DrawerInfo(type = behaviorType)
513+
val tokens = drawerTokens
514+
?: FluentTheme.controlTokens.tokens[ControlTokens.ControlType.DrawerControlType] as DrawerTokens
515+
AnnounceDrawerActions(drawerState, talkbackAnnouncement = talkbackAnnouncement)
488516
if (drawerState.enable) {
489517
val themeID =
490518
FluentTheme.themeID //Adding This only for recomposition in case of Token Updates. Unused otherwise.
491-
val tokens = drawerTokens
492-
?: FluentTheme.controlTokens.tokens[ControlTokens.ControlType.DrawerControlType] as DrawerTokens
493519
val scope = rememberCoroutineScope()
494520
val close: () -> Unit = {
495521
if (drawerState.confirmStateChange(DrawerValue.Closed)) {
496522
scope.launch { drawerState.close() }
497523
}
498524
}
499-
val behaviorType =
500-
if (slideOver) BehaviorType.BOTTOM_SLIDE_OVER else BehaviorType.BOTTOM
501-
val drawerInfo = DrawerInfo(type = behaviorType)
502525
BackHandler { //TODO: Add pull down animation with predictive back
503526
close()
504527
}

0 commit comments

Comments
 (0)