Skip to content

Commit

Permalink
1.3.1
Browse files Browse the repository at this point in the history
feat: app - ListScreen Animation(TagList, TagMemoList)
feat: app - buddy calendar
feat: server - buddy calendar
  • Loading branch information
taetae98coding committed Dec 10, 2024
1 parent ee6f9bf commit f6c950d
Show file tree
Hide file tree
Showing 133 changed files with 4,051 additions and 2,977 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ import kotlinx.coroutines.launch
@Composable
public fun CalendarTopBar(
state: CalendarState,
actions: @Composable RowScope.() -> Unit = {},
modifier: Modifier = Modifier,
navigationIcon: @Composable () -> Unit = {},
actions: @Composable RowScope.() -> Unit = {},
) {
CenterAlignedTopAppBar(
title = {
Expand Down Expand Up @@ -60,6 +61,7 @@ public fun CalendarTopBar(
}
},
modifier = modifier,
navigationIcon = navigationIcon,
actions = actions,
)
}
Expand Down
6 changes: 6 additions & 0 deletions app/core/compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@ kotlin {
sourceSets {
commonMain {
dependencies {
implementation(project(":app:core:calendar-compose"))
implementation(project(":app:core:design-system"))
implementation(project(":app:core:model"))

implementation(project(":library:color"))
implementation(project(":library:datetime"))

implementation(compose.material3)
implementation(libs.compose.material3.adaptive.navigation)
implementation(libs.lifecycle.compose)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.github.taetae98coding.diary.core.compose.calendar

import androidx.compose.runtime.Composable
import io.github.taetae98coding.diary.core.design.system.preview.DiaryPreview
import io.github.taetae98coding.diary.core.design.system.theme.DiaryTheme

@DiaryPreview
@Composable
private fun CalendarHomeScreenPreview() {
DiaryTheme {
CalendarScaffold(
state = rememberCalendarScaffoldState(
onFilter = {},
),
onSelectDate = {},
hasFilterProvider = { false },
textItemListProvider = { emptyList() },
holidayListProvider = { emptyList() },
onCalendarItemClick = {},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package io.github.taetae98coding.diary.core.compose.calendar

import androidx.compose.animation.Crossfade
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
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.Modifier
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.lifecycle.compose.LifecycleResumeEffect
import io.github.taetae98coding.diary.core.calendar.compose.Calendar
import io.github.taetae98coding.diary.core.calendar.compose.item.CalendarItemUiState
import io.github.taetae98coding.diary.core.calendar.compose.modifier.calendarDateRangeSelectable
import io.github.taetae98coding.diary.core.calendar.compose.topbar.CalendarTopBar
import io.github.taetae98coding.diary.core.calendar.compose.topbar.TodayIcon
import io.github.taetae98coding.diary.core.design.system.icon.FilterIcon
import io.github.taetae98coding.diary.core.design.system.icon.FilterOffIcon
import io.github.taetae98coding.diary.core.design.system.theme.DiaryTheme
import io.github.taetae98coding.diary.library.datetime.todayIn
import kotlinx.coroutines.launch
import kotlinx.datetime.LocalDate

@Composable
public fun CalendarScaffold(
state: CalendarScaffoldState,
onSelectDate: (ClosedRange<LocalDate>) -> Unit,
hasFilterProvider: () -> Boolean,
textItemListProvider: () -> List<CalendarItemUiState.Text>,
holidayListProvider: () -> List<CalendarItemUiState.Holiday>,
onCalendarItemClick: (Any) -> Unit,
modifier: Modifier = Modifier,
navigationIcon: @Composable () -> Unit = {},
) {
val coroutineScope = rememberCoroutineScope()

Scaffold(
modifier = modifier
.onPreviewKeyEvent {
when {
!state.calendarState.isScrollInProgress && it.key == Key.DirectionRight -> {
coroutineScope.launch { state.calendarState.animateScrollToForward() }
true
}

!state.calendarState.isScrollInProgress && it.key == Key.DirectionLeft -> {
coroutineScope.launch { state.calendarState.animateScrollToBackward() }
true
}

it.key == Key.F1 -> {
state.onFilter()
true
}

!state.calendarState.isScrollInProgress && it.key == Key.F2 -> {
coroutineScope.launch { state.calendarState.animateScrollToToday() }
true
}

else -> false
}
}
.focusRequester(state.focusRequester)
.focusable(),
topBar = {
CalendarTopBar(
state = state.calendarState,
actions = {
IconButton(onClick = state.onFilter) {
Crossfade(hasFilterProvider()) { hasFilter ->
if (hasFilter) {
FilterIcon(tint = DiaryTheme.color.primary)
} else {
FilterOffIcon()
}
}
}

IconButton(onClick = { coroutineScope.launch { state.calendarState.animateScrollToToday() } }) {
TodayIcon()
}
},
navigationIcon = navigationIcon,
)
},
) {
var today by remember { mutableStateOf(LocalDate.todayIn()) }

Calendar(
state = state.calendarState,
primaryDateListProvider = { listOf(today) },
textItemListProvider = textItemListProvider,
holidayListProvider = holidayListProvider,
onCalendarItemClick = onCalendarItemClick,
modifier = Modifier
.fillMaxSize()
.padding(it)
.calendarDateRangeSelectable(
state = state.calendarState,
onSelectDate = onSelectDate,
),
)

LifecycleResumeEffect(Unit) {
today = LocalDate.todayIn()
onPauseOrDispose { }
}
}

LifecycleResumeEffect(state.focusRequester) {
state.focusRequester.requestFocus()
onPauseOrDispose { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.github.taetae98coding.diary.core.compose.calendar

import androidx.compose.ui.focus.FocusRequester
import io.github.taetae98coding.diary.core.calendar.compose.state.CalendarState

public class CalendarScaffoldState(
public val onFilter: () -> Unit,
public val calendarState: CalendarState,
) {
public val focusRequester: FocusRequester = FocusRequester()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.github.taetae98coding.diary.core.compose.calendar

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import io.github.taetae98coding.diary.core.calendar.compose.state.rememberCalendarState

@Composable
public fun rememberCalendarScaffoldState(
onFilter: () -> Unit,
): CalendarScaffoldState {
val calendarState = rememberCalendarState()

return remember {
CalendarScaffoldState(
onFilter = onFilter,
calendarState = calendarState,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package io.github.taetae98coding.diary.core.compose.memo

import androidx.compose.material3.IconButton
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.material3.adaptive.layout.AnimatedPane
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold
import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole
import androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import io.github.taetae98coding.diary.core.compose.adaptive.isListVisible
import io.github.taetae98coding.diary.core.compose.back.KBackHandler
import io.github.taetae98coding.diary.core.compose.memo.detail.MemoDetailScaffold
import io.github.taetae98coding.diary.core.compose.memo.detail.MemoDetailScaffoldState
import io.github.taetae98coding.diary.core.compose.memo.detail.MemoDetailScaffoldUiState
import io.github.taetae98coding.diary.core.compose.memo.tag.MemoTagScaffold
import io.github.taetae98coding.diary.core.compose.tag.TagCardItemUiState
import io.github.taetae98coding.diary.core.design.system.icon.NavigateUpIcon

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
public fun MemoListDetailPaneScaffold(
onNavigateUp: () -> Unit,
onDetailTag: (String) -> Unit,
detailScaffoldStateProvider: () -> MemoDetailScaffoldState,
detailUiStateProvider: () -> MemoDetailScaffoldUiState,
detailTagListProvider: () -> List<TagCardItemUiState>?,
detailTitle: @Composable () -> Unit,
onTagAdd: () -> Unit,
tagListProvider: () -> List<TagCardItemUiState>?,
modifier: Modifier = Modifier,
detailFloatingActionButton: @Composable () -> Unit = {},
) {
val windowAdaptiveInfo = currentWindowAdaptiveInfo()
val navigator = rememberListDetailPaneScaffoldNavigator(scaffoldDirective = calculatePaneScaffoldDirective(windowAdaptiveInfo))

ListDetailPaneScaffold(
directive = navigator.scaffoldDirective.copy(defaultPanePreferredWidth = 500.dp),
value = navigator.scaffoldValue,
listPane = {
AnimatedPane {
MemoDetailScaffold(
onTagTitle = { navigator.navigateTo(ThreePaneScaffoldRole.Primary) },
onTag = onDetailTag,
state = detailScaffoldStateProvider(),
uiStateProvider = detailUiStateProvider,
tagListProvider = detailTagListProvider,
title = detailTitle,
navigationIcon = {
IconButton(onClick = onNavigateUp) {
NavigateUpIcon()
}
},
floatingActionButton = detailFloatingActionButton,
)
}
},
detailPane = {
AnimatedPane {
MemoTagScaffold(
onTagAdd = onTagAdd,
navigationIcon = {
if (!navigator.isListVisible()) {
IconButton(onClick = navigator::navigateBack) {
NavigateUpIcon()
}
}
},
primaryTagListProvider = detailTagListProvider,
tagListProvider = tagListProvider,
)
}
},
modifier = modifier,
)

KBackHandler(
isEnabled = navigator.canNavigateBack(),
onBack = navigator::navigateBack,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.github.taetae98coding.diary.core.compose.memo.add

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import io.github.taetae98coding.diary.core.compose.memo.detail.MemoDetailScaffoldState
import io.github.taetae98coding.diary.core.design.system.diary.color.rememberDiaryColorState
import io.github.taetae98coding.diary.core.design.system.diary.component.rememberDiaryComponentState
import io.github.taetae98coding.diary.core.design.system.diary.date.rememberDiaryDateState
import kotlinx.datetime.LocalDate

@Composable
public fun rememberMemoDetailScaffoldAddState(
initialStart: LocalDate?,
initialEndInclusive: LocalDate?,
): MemoDetailScaffoldState.Add {
val coroutineScope = rememberCoroutineScope()
val componentState = rememberDiaryComponentState()
val dateState =
rememberDiaryDateState(
initialStart = initialStart,
initialEndInclusive = initialEndInclusive,
)
val colorState = rememberDiaryColorState()

return remember {
MemoDetailScaffoldState.Add(
coroutineScope = coroutineScope,
componentState = componentState,
dateState = dateState,
colorState = colorState,
)
}
}
Loading

0 comments on commit f6c950d

Please sign in to comment.