Skip to content

Commit

Permalink
Implement AdaptSwitch
Browse files Browse the repository at this point in the history
  • Loading branch information
shubhamsinghshubham777 committed May 12, 2024
1 parent b28b45e commit d98e1ed
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 18 deletions.
159 changes: 159 additions & 0 deletions adapt/src/commonMain/kotlin/design/adapt/AdaptSwitch.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* Copyright 2023 Shubham Singh
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package design.adapt

import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material3.Switch
import androidx.compose.material3.SwitchColors
import androidx.compose.material3.SwitchDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.Shape
import design.adapt.cupertino.IOSToggle
import design.adapt.cupertino.IOSToggleColors
import design.adapt.cupertino.IOSToggleDefaults
import design.adapt.cupertino.MacOSSwitch
import design.adapt.cupertino.MacOSSwitchColors
import design.adapt.cupertino.MacOSSwitchDefaults
import design.adapt.windows.WindowsToggleSwitch
import design.adapt.windows.WindowsToggleSwitchColors
import design.adapt.windows.WindowsToggleSwitchDefaults

@Composable
fun AdaptSwitch(
checked: Boolean,
onCheckedChange: (checked: Boolean) -> Unit,
modifier: AdaptModifier = AdaptModifier(),
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
configuration: AdaptSwitchConfiguration = AdaptSwitchDefaults.configuration(),
) {
when (LocalPlatform.current) {
// TODO: Separate Web from Android here
Platform.Android, Platform.Web -> Switch(
checked = checked,
colors = configuration.android.colors,
enabled = enabled,
interactionSource = interactionSource,
modifier = modifier.android,
onCheckedChange = onCheckedChange,
thumbContent = configuration.android.thumbContent,
)

Platform.IOS -> IOSToggle(
checked = checked,
colors = configuration.iOS.colors,
interactionSource = interactionSource,
modifier = modifier.iOS,
onCheckedChange = onCheckedChange,
thumbShape = configuration.iOS.thumbShape,
trackShape = configuration.iOS.trackShape,
)

Platform.MacOS -> MacOSSwitch(
checked = checked,
colors = configuration.macOS.colors,
enabled = enabled,
interactionSource = interactionSource,
modifier = modifier.macOS,
onCheckedChange = onCheckedChange,
thumbShape = configuration.macOS.thumbShape,
trackShape = configuration.macOS.trackShape,
)

Platform.Windows -> WindowsToggleSwitch(
alignTextToStart = configuration.windows.alignTextToStart,
checked = checked,
colors = configuration.windows.colors,
enabled = enabled,
header = configuration.windows.header,
interactionSource = interactionSource,
modifier = modifier.windows,
onCheckedChange = onCheckedChange,
text = configuration.windows.text,
thumbShape = configuration.windows.thumbShape,
trackShape = configuration.windows.trackShape,
)
}
}

object AdaptSwitchDefaults {
@Composable
fun configuration(
android: AndroidSwitchConfiguration = AndroidSwitchConfiguration(
colors = SwitchDefaults.colors(),
thumbContent = null,
),
iOS: IOSToggleConfiguration = IOSToggleConfiguration(
colors = IOSToggleDefaults.colors(),
thumbShape = IOSToggleDefaults.ThumbShape,
trackShape = IOSToggleDefaults.TrackShape,
),
macOS: MacOSSwitchConfiguration = MacOSSwitchConfiguration(
colors = MacOSSwitchDefaults.colors(),
thumbShape = MacOSSwitchDefaults.ThumbShape,
trackShape = MacOSSwitchDefaults.TrackShape,
),
windows: WindowsToggleSwitchConfiguration = WindowsToggleSwitchConfiguration(
alignTextToStart = false,
colors = WindowsToggleSwitchDefaults.colors(),
header = null,
text = null,
thumbShape = WindowsToggleSwitchDefaults.ThumbShape,
trackShape = WindowsToggleSwitchDefaults.TrackShape,
),
) = AdaptSwitchConfiguration(android = android, iOS = iOS, macOS = macOS, windows = windows)
}

@Immutable
data class AdaptSwitchConfiguration(
val android: AndroidSwitchConfiguration,
val iOS: IOSToggleConfiguration,
val macOS: MacOSSwitchConfiguration,
val windows: WindowsToggleSwitchConfiguration,
)

@Immutable
data class AndroidSwitchConfiguration(
val colors: SwitchColors,
val thumbContent: @Composable (() -> Unit)?,
)

@Immutable
data class IOSToggleConfiguration(
val colors: IOSToggleColors,
val thumbShape: Shape,
val trackShape: Shape,
)

@Immutable
data class MacOSSwitchConfiguration(
val colors: MacOSSwitchColors,
val thumbShape: Shape,
val trackShape: Shape,
)

@Immutable
data class WindowsToggleSwitchConfiguration(
val alignTextToStart: Boolean,
val colors: WindowsToggleSwitchColors,
val header: @Composable (() -> Unit)?,
val text: @Composable (() -> Unit)?,
val thumbShape: Shape,
val trackShape: Shape,
)
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ fun IOSToggle(
onCheckedChange: (checked: Boolean) -> Unit,
modifier: Modifier = Modifier,
colors: IOSToggleColors = IOSToggleDefaults.colors(),
trackShape: Shape = CircleShape,
thumbShape: Shape = CircleShape,
trackShape: Shape = IOSToggleDefaults.TrackShape,
thumbShape: Shape = IOSToggleDefaults.ThumbShape,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) {
val density = LocalDensity.current
Expand Down Expand Up @@ -196,6 +196,8 @@ object IOSToggleDefaults {
val ExpandedThumbWidth = ThumbWidth * 1.25f
val ThumbHeight = 27.dp
val ToggleSize = DpSize(51.dp, 31.dp)
val TrackShape = CircleShape
val ThumbShape = CircleShape

@Composable
fun colors(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ fun MacOSSwitch(
onCheckedChange: (checked: Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
trackShape: Shape = CircleShape,
thumbShape: Shape = CircleShape,
trackShape: Shape = MacOSSwitchDefaults.TrackShape,
thumbShape: Shape = MacOSSwitchDefaults.ThumbShape,
colors: MacOSSwitchColors = MacOSSwitchDefaults.colors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
) {
Expand Down Expand Up @@ -207,6 +207,8 @@ data class MacOSSwitchColors(
object MacOSSwitchDefaults {
val SwitchSize = DpSize(width = 26.dp, height = 15.dp)
val ThumbSize = DpSize(width = 13.dp, height = 13.dp)
val TrackShape = CircleShape
val ThumbShape = CircleShape

@Composable
fun colors(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ fun WindowsToggleSwitch(
text: @Composable (() -> Unit)? = null,
alignTextToStart: Boolean = false,
enabled: Boolean = true,
trackShape: Shape = CircleShape,
thumbShape: Shape = CircleShape,
trackShape: Shape = WindowsToggleSwitchDefaults.TrackShape,
thumbShape: Shape = WindowsToggleSwitchDefaults.ThumbShape,
colors: WindowsToggleSwitchColors = WindowsToggleSwitchDefaults.colors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) {
Expand Down Expand Up @@ -127,18 +127,18 @@ fun WindowsToggleSwitch(
)

val animatedThumbWidth by animateDpAsState(
targetValue = if (isPressed || isDragged) {
WindowsToggleSwitchDefaults.ThumbExtendedSize.width
} else {
WindowsToggleSwitchDefaults.ThumbSize.width
targetValue = when {
isPressed || isDragged -> WindowsToggleSwitchDefaults.ThumbPressedSize
isHovered -> WindowsToggleSwitchDefaults.ThumbHoveredSize
else -> WindowsToggleSwitchDefaults.ThumbSize
}
)

val animatedThumbHeight by animateDpAsState(
targetValue = if (isPressed || isDragged) {
WindowsToggleSwitchDefaults.ThumbExtendedSize.height
targetValue = if (isPressed || isDragged || isHovered) {
WindowsToggleSwitchDefaults.ThumbHoveredSize
} else {
WindowsToggleSwitchDefaults.ThumbSize.height
WindowsToggleSwitchDefaults.ThumbSize
}
)

Expand Down Expand Up @@ -365,9 +365,12 @@ data class WindowsToggleSwitchColors(
)

object WindowsToggleSwitchDefaults {
val ThumbSize = DpSize(width = 12.dp, height = 12.dp)
val ThumbExtendedSize = DpSize(width = 17.dp, height = 14.dp)
val ThumbSize = 12.dp
val ThumbHoveredSize = 14.dp
val ThumbPressedSize = 17.dp
val ToggleSize = DpSize(width = 38.dp, height = 18.dp)
val ThumbShape = CircleShape
val TrackShape = CircleShape

@Composable
fun colors(
Expand Down
82 changes: 79 additions & 3 deletions sample/composeApp/src/commonMain/kotlin/design/adapt/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
Expand All @@ -39,9 +40,14 @@ import androidx.compose.material.icons.automirrored.outlined.ArrowForward
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.IconButton
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
Expand All @@ -52,16 +58,19 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import design.adapt.cupertino.CupertinoSpinner
import design.adapt.cupertino.IOSButton
import design.adapt.cupertino.IOSToggle
import design.adapt.cupertino.MacOSButton
import design.adapt.cupertino.MacOSSwitch
import design.adapt.windows.WindowsButton
import design.adapt.windows.WindowsProgressRing
import design.adapt.windows.WindowsToggleSwitch
import kotlinx.coroutines.launch

@OptIn(ExperimentalFoundationApi::class)
@Composable
internal fun App() {
val coroutineScope = rememberCoroutineScope()
val horizontalPagerState = rememberPagerState { 2 }
val horizontalPagerState = rememberPagerState { 3 }

AdaptTheme {
Box(
Expand Down Expand Up @@ -121,10 +130,14 @@ internal fun App() {
}
)
}
HorizontalPager(state = horizontalPagerState) { page ->
HorizontalPager(
state = horizontalPagerState,
beyondBoundsPageCount = 1,
) { page ->
when (page) {
0 -> ButtonsDemoPage()
else -> IndicatorsDemoPage()
1 -> IndicatorsDemoPage()
else -> SwitchesDemoPage()
}
}
}
Expand Down Expand Up @@ -230,3 +243,66 @@ fun IndicatorsDemoPage() {
}
}
}

@Composable
fun SwitchesDemoPage() {
var checked by remember { mutableStateOf(true) }

ColumnScaffold(title = "Switches") {
AdaptText(text = "This switch should look native-like on all platforms")
SpacedRow {
AdaptSwitch(checked = checked, onCheckedChange = { checked = it })
AdaptSwitch(checked = checked, onCheckedChange = { checked = it }, enabled = false)
}
AdaptText(text = "This switch should use the Material design system on all platforms")
SpacedRow {
Switch(checked = checked, onCheckedChange = { checked = it })
Switch(checked = checked, onCheckedChange = { checked = it }, enabled = false)
}
AdaptText(
text = "This switch should use iOS' variant of the Cupertino design system on all " +
"platforms"
)
SpacedRow {
IOSToggle(checked = checked, onCheckedChange = { checked = it })
}
AdaptText(
text = "This switch should use macOS' variant of the Cupertino design system on all " +
"platforms"
)
SpacedRow {
MacOSSwitch(checked = checked, onCheckedChange = { checked = it })
MacOSSwitch(checked = checked, onCheckedChange = { checked = it }, enabled = false)
}
AdaptText(text = "This switch should use the WinUI design system on all platforms")
SpacedRow {
WindowsToggleSwitch(checked = checked, onCheckedChange = { checked = it })
WindowsToggleSwitch(
checked = checked,
onCheckedChange = { checked = it },
enabled = false
)
WindowsToggleSwitch(
checked = checked,
onCheckedChange = { checked = it },
text = {
AdaptText(
modifier = Modifier.width(20.dp),
text = if (checked) "On" else "Off"
)
},
)
WindowsToggleSwitch(
checked = checked,
onCheckedChange = { checked = it },
text = {
AdaptText(
modifier = Modifier.width(20.dp),
text = if (checked) "On" else "Off"
)
},
header = { AdaptText(text = "Header") }
)
}
}
}

0 comments on commit d98e1ed

Please sign in to comment.