Skip to content

Commit

Permalink
Merge pull request #54 from mori-atsushi/app-bar
Browse files Browse the repository at this point in the history
Add TopAppBar
  • Loading branch information
mori-atsushi authored Nov 24, 2023
2 parents 262d18a + 85c773f commit 55e8555
Show file tree
Hide file tree
Showing 18 changed files with 398 additions and 21 deletions.
8 changes: 8 additions & 0 deletions .idea/artifacts/compose_stylesheet_appbar_desktop.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 52 additions & 0 deletions component/compose-stylesheet-appbar/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.compose.multiplatform)
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.maven.publish)
}

kotlin {
androidTarget {
publishLibraryVariants("release")
}
jvm("desktop")
iosX64("uikitX64")
iosArm64("uikitArm64")
iosSimulatorArm64("uikitSimArm64")
macosX64()
macosArm64()

sourceSets {
val commonMain by getting {
dependencies {
implementation(compose.foundation)
implementation(project(":compose-stylesheet-core"))
}
}

val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}

all {
languageSettings.optIn(
"com.moriatsushi.compose.stylesheet.component.StyleSheetComponentApi",
)
}
}
}

android {
namespace = "com.moriatsushi.compose.stylesheet.appbar"
compileSdk = 34
defaultConfig {
minSdk = 21
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
}
4 changes: 4 additions & 0 deletions component/compose-stylesheet-appbar/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
POM_ARTIFACT_ID=compose-stylesheet-appbar
POM_NAME=Compose StyleSheet
POM_DESCRIPTION=A flexible UI component library for Jetpack Compose
POM_PACKAGING=aar
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package com.moriatsushi.compose.stylesheet.appbar

import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.isSpecified
import com.moriatsushi.compose.stylesheet.StyleSheet
import com.moriatsushi.compose.stylesheet.component.Component
import com.moriatsushi.compose.stylesheet.component.componentCommonStyle
import com.moriatsushi.compose.stylesheet.content.ProvideContentStyle
import com.moriatsushi.compose.stylesheet.tag.TagModifier
import com.moriatsushi.compose.stylesheet.token.value

@Composable
fun TopAppBar(
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
navigationIcon: (@Composable () -> Unit)? = null,
actions: (@Composable RowScope.() -> Unit)? = null,
tags: TagModifier<TopAppBarStyle> = TagModifier(),
topAppBarStyle: TopAppBarStyle = TopAppBarStyle.Default,
windowInsets: WindowInsets = topAppBarWindowInsets,
) {
val localStyle = StyleSheet.getStyle(topAppBar, tags)
val mergedStyle = TopAppBarStyle {
this += localStyle
this += topAppBarStyle
}
Row(
modifier = modifier
.componentCommonStyle(mergedStyle.commonStyle)
.padding(windowInsets.asPaddingValues()),
verticalAlignment = Alignment.CenterVertically,
) {
ProvideContentStyle(mergedStyle.contentStyle) {
if (navigationIcon != null) {
HorizontalSpacer(
width = mergedStyle.layout.spaceBetweenNavigationIconAndContainer?.value,
)
navigationIcon()
HorizontalSpacer(
width = mergedStyle.layout.spaceBetweenNavigationIconAndTitle?.value,
)
} else {
HorizontalSpacer(
width = mergedStyle.layout.spaceBetweenTitleAndContainer?.value,
)
}
Row(modifier = Modifier.weight(1F)) {
title()
}
if (actions != null) {
HorizontalSpacer(
width = mergedStyle.layout.spaceBetweenActionsAndContent?.value,
)
actions()
HorizontalSpacer(
width = mergedStyle.layout.spaceBetweenActionsAndContainer?.value,
)
} else {
HorizontalSpacer(
width = mergedStyle.layout.spaceBetweenTitleAndContainer?.value,
)
}
}
}
}

@Composable
private fun HorizontalSpacer(width: Dp?) {
if (width != null && width.isSpecified && width > 0.dp) {
Spacer(modifier = Modifier.width(width))
}
}

private val topAppBarWindowInsets: WindowInsets
@Composable
get() = WindowInsets.systemBars
.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top)

/**
* An object for [TopAppBar].
*/
object TopAppBar

/**
* A symbol for [TopAppBar].
*/
val topAppBar = Component(
name = "TopAppBar",
defaultStyle = TopAppBarStyle.Default,
createBuilder = ::TopAppBarStyleBuilder,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.moriatsushi.compose.stylesheet.appbar

import androidx.compose.ui.unit.Dp
import com.moriatsushi.compose.stylesheet.token.Token

/**
* A layout properties for [TopAppBar].
*/
sealed interface TopAppBarLayout {
val spaceBetweenNavigationIconAndContainer: Token<Dp>?
val spaceBetweenNavigationIconAndTitle: Token<Dp>?
val spaceBetweenTitleAndContainer: Token<Dp>?
val spaceBetweenActionsAndContent: Token<Dp>?
val spaceBetweenActionsAndContainer: Token<Dp>?

companion object {
/**
* Constant for a default [TopAppBarLayout].
*/
val Default: TopAppBarLayout = TopAppBarLayout()
}
}

internal fun TopAppBarLayout(
spaceBetweenNavigationIconAndContainer: Token<Dp>? = null,
spaceBetweenNavigationIconAndTitle: Token<Dp>? = null,
spaceBetweenTitleAndContainer: Token<Dp>? = null,
spaceBetweenActionsAndContent: Token<Dp>? = null,
spaceBetweenActionsAndContainer: Token<Dp>? = null,
): TopAppBarLayout = TopAppBarLayoutImpl(
spaceBetweenNavigationIconAndContainer = spaceBetweenNavigationIconAndContainer,
spaceBetweenNavigationIconAndTitle = spaceBetweenNavigationIconAndTitle,
spaceBetweenTitleAndContainer = spaceBetweenTitleAndContainer,
spaceBetweenActionsAndContent = spaceBetweenActionsAndContent,
spaceBetweenActionsAndContainer = spaceBetweenActionsAndContainer,
)

private data class TopAppBarLayoutImpl(
override val spaceBetweenNavigationIconAndContainer: Token<Dp>?,
override val spaceBetweenNavigationIconAndTitle: Token<Dp>?,
override val spaceBetweenTitleAndContainer: Token<Dp>?,
override val spaceBetweenActionsAndContent: Token<Dp>?,
override val spaceBetweenActionsAndContainer: Token<Dp>?,
) : TopAppBarLayout
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.moriatsushi.compose.stylesheet.appbar

import androidx.compose.ui.unit.Dp
import com.moriatsushi.compose.stylesheet.StyleBuilder
import com.moriatsushi.compose.stylesheet.token.TokenSetter

/**
* A builder for [TopAppBarLayout].
*/
class TopAppBarLayoutBuilder internal constructor() : StyleBuilder<TopAppBarLayout> {
val spaceBetweenNavigationIconAndContainer: TokenSetter<Dp> = TokenSetter()
val spaceBetweenNavigationIconAndTitle: TokenSetter<Dp> = TokenSetter()
val spaceBetweenTitleAndContainer: TokenSetter<Dp> = TokenSetter()
val spaceBetweenActionsAndContent: TokenSetter<Dp> = TokenSetter()
val spaceBetweenActionsAndContainer: TokenSetter<Dp> = TokenSetter()

override fun plusAssign(other: TopAppBarLayout) {
spaceBetweenNavigationIconAndContainer += other.spaceBetweenNavigationIconAndContainer
spaceBetweenNavigationIconAndTitle += other.spaceBetweenNavigationIconAndTitle
spaceBetweenTitleAndContainer += other.spaceBetweenTitleAndContainer
spaceBetweenActionsAndContent += other.spaceBetweenActionsAndContent
spaceBetweenActionsAndContainer += other.spaceBetweenActionsAndContainer
}

operator fun invoke(builder: TopAppBarLayoutBuilder.() -> Unit) {
builder()
}

override fun build(): TopAppBarLayout = TopAppBarLayout(
spaceBetweenNavigationIconAndContainer = spaceBetweenNavigationIconAndContainer.token,
spaceBetweenNavigationIconAndTitle = spaceBetweenNavigationIconAndTitle.token,
spaceBetweenTitleAndContainer = spaceBetweenTitleAndContainer.token,
spaceBetweenActionsAndContent = spaceBetweenActionsAndContent.token,
spaceBetweenActionsAndContainer = spaceBetweenActionsAndContainer.token,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.moriatsushi.compose.stylesheet.appbar

import androidx.compose.runtime.Immutable
import com.moriatsushi.compose.stylesheet.component.ComponentCommonStyle
import com.moriatsushi.compose.stylesheet.component.ComponentStyle
import com.moriatsushi.compose.stylesheet.content.ContentStyle

/**
* A style for [TopAppBar].
*/
@Immutable
sealed interface TopAppBarStyle : ComponentStyle {
val layout: TopAppBarLayout
val contentStyle: ContentStyle

companion object {
/**
* Constant for a default [TopAppBarStyle].
*/
val Default: TopAppBarStyle = TopAppBarStyle()
}
}

/**
* Creates a [TopAppBarStyle] using the [builder].
*/
fun TopAppBarStyle(builder: TopAppBarStyleBuilder.() -> Unit): TopAppBarStyle =
TopAppBarStyleBuilder().apply(builder).build()

internal fun TopAppBarStyle(
layout: TopAppBarLayout = TopAppBarLayout.Default,
commonStyle: ComponentCommonStyle = ComponentCommonStyle.Default,
contentStyle: ContentStyle = ContentStyle.Default,
): TopAppBarStyle = TopAppBarStyleImpl(
layout = layout,
commonStyle = commonStyle,
contentStyle = contentStyle,
)

private data class TopAppBarStyleImpl(
override val layout: TopAppBarLayout,
override val commonStyle: ComponentCommonStyle,
override val contentStyle: ContentStyle,
) : TopAppBarStyle
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.moriatsushi.compose.stylesheet.appbar

import com.moriatsushi.compose.stylesheet.component.ComponentStyleBuilder
import com.moriatsushi.compose.stylesheet.content.ContentStyleBuilder

/**
* A builder for [TopAppBarStyle].
*/
class TopAppBarStyleBuilder internal constructor() : ComponentStyleBuilder<TopAppBarStyle>() {
/**
* A layout of the top app bar.
*/
val layout: TopAppBarLayoutBuilder = TopAppBarLayoutBuilder()

/**
* A content style.
*/
val content: ContentStyleBuilder = ContentStyleBuilder()

override fun plusAssign(other: TopAppBarStyle) {
layout += other.layout
this += other.commonStyle
content += other.contentStyle
}

override fun build(): TopAppBarStyle = TopAppBarStyle(
layout = layout.build(),
commonStyle = buildCommonStyle(),
contentStyle = content.build(),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ abstract class ComponentStyleBuilder<T : ComponentStyle> : StyleBuilder<T> {
}

@StyleSheetComponentApi
fun buildCommonStyle(): ComponentCommonStyle = ComponentCommonStyle(
protected fun buildCommonStyle(): ComponentCommonStyle = ComponentCommonStyle(
size = _size,
padding = padding.value,
background = background.token,
Expand Down
1 change: 1 addition & 0 deletions compose-stylesheet-theme/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ kotlin {
dependencies {
implementation(compose.foundation)
implementation(project(":compose-stylesheet-core"))
api(project(":component:compose-stylesheet-appbar"))
api(project(":component:compose-stylesheet-button"))
api(project(":component:compose-stylesheet-text"))
api(project(":component:compose-stylesheet-surface"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.moriatsushi.compose.stylesheet.StyleSheet
import com.moriatsushi.compose.stylesheet.theme.appbar.topAppBarStyleSheet
import com.moriatsushi.compose.stylesheet.theme.button.buttonStyleSheet
import com.moriatsushi.compose.stylesheet.theme.button.iconButtonStyleSheet
import com.moriatsushi.compose.stylesheet.theme.surface.surfaceStyleSheet
Expand Down Expand Up @@ -40,6 +41,7 @@ fun themeStyleSheet(
color += Colors.semantic.onBackground
}

this += topAppBarStyleSheet
this += buttonStyleSheet
this += iconButtonStyleSheet
this += surfaceStyleSheet
Expand Down
Loading

0 comments on commit 55e8555

Please sign in to comment.