Skip to content

Commit

Permalink
Merge pull request #26 from bn-tw2020/featrue/layout-25
Browse files Browse the repository at this point in the history
[feat] 레이아웃 전체 구성 및 달력 구현(20, 25)
  • Loading branch information
shncder committed May 31, 2022
2 parents c098e45 + 36d04ae commit a59e961
Show file tree
Hide file tree
Showing 28 changed files with 1,047 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package com.example.todo.airbnb.data

data class Accommodations(
val imageURL: String,
val description: String
val description: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.example.todo.airbnb.data.datasource

import android.annotation.SuppressLint
import android.os.Build
import androidx.annotation.RequiresApi
import com.example.todo.airbnb.presentation.search.date.components.CalendarMonth
import com.example.todo.airbnb.presentation.search.date.components.DatesSelectedState
import com.example.todo.airbnb.presentation.search.date.components.DayOfWeek
import com.example.todo.airbnb.presentation.search.date.components.DaySelected
import java.time.LocalDate
import java.time.temporal.TemporalAdjusters

typealias CalendarYear = List<CalendarMonth>

@RequiresApi(Build.VERSION_CODES.O)
class DatesLocalDataSource {

private val dayOfWeek = listOf(
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
)

val calendarYear = getDayList()
val datesSelected = DatesSelectedState(calendarYear)

fun onDaySelected(daySelected: DaySelected) {
datesSelected.daySelected(daySelected)
}

private fun getDayList(): List<CalendarMonth> {
val list = mutableListOf<CalendarMonth>()
for (month in 1..12) {
val date = LocalDate.of(2021, month, 1)
list.add(
CalendarMonth(
name = dayOfWeek[month - 1],
year = date.year.toString(),
numDays = date.with(TemporalAdjusters.lastDayOfMonth()).dayOfMonth,
monthNumber = month,
startDayOfWeek = DayOfWeek.values(date.dayOfWeek.toString()) ?: DayOfWeek.Sunday
)
)
}
return list
}

@SuppressLint("VisibleForTests")
fun onClear() {
datesSelected.clearDates()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.example.todo.airbnb.data.repository

import android.os.Build
import androidx.annotation.RequiresApi
import com.example.todo.airbnb.data.datasource.CalendarYear
import com.example.todo.airbnb.data.datasource.DatesLocalDataSource
import com.example.todo.airbnb.domain.repository.DateRepository
import com.example.todo.airbnb.presentation.search.date.components.DatesSelectedState
import com.example.todo.airbnb.presentation.search.date.components.DaySelected
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

@RequiresApi(Build.VERSION_CODES.O)
class DateRepositoryImpl(
private val datesLocalDataSource: DatesLocalDataSource,
) : DateRepository {

override fun getDate(): CalendarYear {
return datesLocalDataSource.calendarYear
}

override fun getDatesSelected(): DatesSelectedState {
return datesLocalDataSource.datesSelected
}

override suspend fun onDaySelected(daySelected: DaySelected) {
withContext(Dispatchers.IO) {
datesLocalDataSource.onDaySelected(daySelected)
}
}

override suspend fun onClear() {
withContext(Dispatchers.IO) {
datesLocalDataSource.onClear()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.example.todo.airbnb.domain.repository

import com.example.todo.airbnb.data.datasource.CalendarYear
import com.example.todo.airbnb.presentation.search.date.components.DatesSelectedState
import com.example.todo.airbnb.presentation.search.date.components.DaySelected

interface DateRepository {
fun getDate(): CalendarYear

fun getDatesSelected(): DatesSelectedState

suspend fun onDaySelected(daySelected: DaySelected)

suspend fun onClear()
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,60 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.lifecycle.Lifecycle
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.navigation
import com.example.todo.airbnb.R
import com.example.todo.airbnb.data.Travel
import com.example.todo.airbnb.presentation.reservation.components.ReservationScreen
import com.example.todo.airbnb.presentation.search.SearchViewModel
import com.example.todo.airbnb.presentation.search.date.DateScreen
import com.example.todo.airbnb.presentation.search.detail.DetailScreen
import com.example.todo.airbnb.presentation.search.fare.FareScreen
import com.example.todo.airbnb.presentation.search.personnel.PersonnelScreen
import com.example.todo.airbnb.presentation.search.searchmap.SearchMapScreen
import com.example.todo.airbnb.presentation.search.searchresult.SearchResultScreen
import com.example.todo.airbnb.presentation.search.serachcondition.SearchConditionScreen
import com.example.todo.airbnb.presentation.wishlist.components.WishListScreen
import com.example.todo.airbnb.ui.theme.Gray

sealed class NavigationItem(
object Destinations {
const val search = "search"
const val calendar = "calendar"
const val fare = "fare"
const val personnel = "personnel"
const val searchResult = "result"
const val searchMap = "map"
const val searchCondition = "condition"
const val detail = "detail"
}

sealed class HomeSections(
var route: String,
var icon: Int,
var title: String,
) {
object Search : NavigationItem("검색", R.drawable.ic_search, "검색")
object WishList : NavigationItem("위시리스트", R.drawable.ic_favorite, "위시리스트")
object Reservation : NavigationItem("내 예약", R.drawable.ic_reservation, "내 예약")
object Search : HomeSections("검색", R.drawable.ic_search, "검색")
object WishList : HomeSections("위시리스트", R.drawable.ic_favorite, "위시리스트")
object Reservation : HomeSections("내 예약", R.drawable.ic_reservation, "내 예약")
}

@Composable
fun BottomBar(navController: NavController) {
val items = listOf(NavigationItem.Search, NavigationItem.WishList, NavigationItem.Reservation)

fun BottomBar(
navController: NavController,
bottomBarTabs: List<HomeSections>,
) {
BottomNavigation(backgroundColor = Gray) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route

items.forEach { item ->
bottomBarTabs.forEach { item ->
BottomNavigationItem(
icon = {
Icon(painter = painterResource(id = item.icon), contentDescription = item.title)
Expand All @@ -47,7 +71,7 @@ fun BottomBar(navController: NavController) {
selectedContentColor = Color.Red,
unselectedContentColor = Color.Black,
alwaysShowLabel = true,
selected = currentRoute == item.route,
selected = (currentRoute == item.route) || selectNavigation(currentRoute, item),
onClick = {
navController.navigate(item.route) {
launchSingleTop = true
Expand All @@ -63,10 +87,49 @@ fun BottomBar(navController: NavController) {
fun BottomNavGraph(navController: NavHostController, viewModel: SearchViewModel) {
NavHost(
navController = navController,
startDestination = NavigationItem.Search.route
startDestination = Destinations.search
) {
airbnbNavGraph(
navController = navController,
viewModel = viewModel
)
}
}

private fun NavGraphBuilder.airbnbNavGraph(
navController: NavController,
viewModel: SearchViewModel,
) {
navigation(
route = Destinations.search,
startDestination = HomeSections.Search.route
) {
composable(NavigationItem.Search.route) { SearchScreen(viewModel) }
composable(NavigationItem.WishList.route) { WishListScreen() }
composable(NavigationItem.Reservation.route) { ReservationScreen() }
composable(HomeSections.Search.route) { SearchScreen(viewModel, navController) }
composable(HomeSections.WishList.route) { WishListScreen() }
composable(HomeSections.Reservation.route) { ReservationScreen() }

}
composable(route = Destinations.calendar) { DateScreen(navController = navController) }
composable(route = Destinations.fare) { FareScreen(navController = navController) }
composable(route = Destinations.personnel) { PersonnelScreen(navController = navController) }
composable(route = Destinations.searchResult) { SearchResultScreen(navController = navController) }
composable(route = Destinations.searchMap) { SearchMapScreen(navController = navController) }
composable(route = Destinations.searchCondition) { SearchConditionScreen(navController = navController) }
composable(route = Destinations.detail) { DetailScreen(navController = navController) }
}

fun navigateToCalendar(location: Travel, navController: NavController, from: NavBackStackEntry) {
if (from.lifecycle.currentState == Lifecycle.State.RESUMED) {
navController.navigate(Destinations.calendar)
}
}

private fun selectNavigation(
currentRoute: String?,
item: HomeSections,
): Boolean {
return when (item.route) {
"검색" -> currentRoute == Destinations.searchResult
else -> false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,29 @@ package com.example.todo.airbnb.presentation.main.components

import androidx.compose.material.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import coil.annotation.ExperimentalCoilApi
import com.example.todo.airbnb.presentation.search.SearchViewModel
import com.example.todo.airbnb.presentation.search.SearchWidgetState

@Composable
fun MainScreen(viewModel: SearchViewModel) {

val navController = rememberNavController()
val bottomBarTabs = listOf(HomeSections.Search, HomeSections.WishList, HomeSections.Reservation)
val bottomBarRoutes = bottomBarTabs.map { it.route }
val shouldShowBottomBar: Boolean =
(navController.currentBackStackEntryAsState().value?.destination?.route in bottomBarRoutes) or (navController.currentBackStackEntryAsState().value?.destination?.route == Destinations.searchResult)


Scaffold(
bottomBar = { BottomBar(navController) }
bottomBar = {
if (shouldShowBottomBar) {
BottomBar(
navController,
bottomBarTabs = bottomBarTabs
)
}
}
) {
BottomNavGraph(navController, viewModel)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
Expand All @@ -13,13 +12,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil.annotation.ExperimentalCoilApi
import coil.compose.ImagePainter
import coil.compose.rememberImagePainter
import com.example.todo.airbnb.R
import com.example.todo.airbnb.common.components.DefaultError
import com.example.todo.airbnb.common.components.DefaultLoading

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.MaterialTheme
Expand All @@ -14,15 +15,17 @@ import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.example.todo.airbnb.data.Travel
import com.example.todo.airbnb.presentation.main.components.MainAppBar
import com.example.todo.airbnb.presentation.main.components.navigateToCalendar
import com.example.todo.airbnb.presentation.search.SearchViewModel
import com.example.todo.airbnb.presentation.search.SearchWidgetState
import com.example.todo.airbnb.presentation.search.components.*
import com.example.todo.airbnb.presentation.search.components.navigation.SearchNavGraph
import com.example.todo.airbnb.presentation.search.components.navigation.SearchScreens
import com.example.todo.airbnb.presentation.search.components.AccommodationsScreen
import com.example.todo.airbnb.presentation.search.components.LoadMainImage
import com.example.todo.airbnb.presentation.search.components.MakeItem
import com.example.todo.airbnb.presentation.search.components.TravelScreen

@Composable
fun SearchScreen(viewModel: SearchViewModel) {
SearchNavGraph(viewModel)
fun SearchScreen(viewModel: SearchViewModel, navController: NavController) {
SearchMainScreen(navController, viewModel)
}

@Composable
Expand Down Expand Up @@ -84,7 +87,10 @@ private fun SearchList(navController: NavController, travelLocations: List<Trave
items(travelLocations) { location ->
Row(
modifier = Modifier
.clickable { navController.navigate(SearchScreens.Date.route) }
.clickable {
val backStackEntry = requireNotNull(navController.currentBackStackEntry)
navigateToCalendar(location, navController, backStackEntry)
}
.fillMaxWidth()
) { MakeItem(location = location) }
Spacer(modifier = Modifier.height(16.dp))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fun MainAppBar(
onCloseClicked: () -> Unit,
onSearchClicked: (String) -> Unit,
onOpenTriggered: () -> Unit,
onCloseTriggered: () -> Unit
onCloseTriggered: () -> Unit,
) {
when (searchWidgetState) {
SearchWidgetState.CLOSED -> {
Expand Down Expand Up @@ -62,7 +62,8 @@ private fun DefaultAppBar(onSearchClicked: () -> Unit) {
tint = Color.Red
)
}
}
},
elevation = 0.dp
)
}

Expand All @@ -72,13 +73,13 @@ private fun SearchAppBar(
onTextChange: (String) -> Unit,
onCloseClicked: () -> Unit,
onSearchClicked: (String) -> Unit,
onCloseTriggered: () -> Unit
onCloseTriggered: () -> Unit,
) {
Surface(
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
elevation = AppBarDefaults.TopAppBarElevation,
elevation = 0.dp,
color = Gray
) {
TextField(
Expand Down
Loading

0 comments on commit a59e961

Please sign in to comment.