diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3f17a5da..91d7e548 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -79,7 +79,7 @@ android:screenOrientation="portrait" /> diff --git a/app/src/main/java/com/going/doorip/di/DataSourceModule.kt b/app/src/main/java/com/going/doorip/di/DataSourceModule.kt index 7bbd0e8c..295c4a9c 100644 --- a/app/src/main/java/com/going/doorip/di/DataSourceModule.kt +++ b/app/src/main/java/com/going/doorip/di/DataSourceModule.kt @@ -1,12 +1,14 @@ package com.going.doorip.di import com.going.data.datasource.AuthDataSource +import com.going.data.datasource.DashBoardDataSource import com.going.data.datasource.EnterTripDataSource import com.going.data.datasource.MockDataSource import com.going.data.datasource.SettingDataSource import com.going.data.datasource.TendencyDataSource import com.going.data.datasource.TodoDataSource import com.going.data.datasourceImpl.AuthDataSourceImpl +import com.going.data.datasourceImpl.DashBoardDataSourceImpl import com.going.data.datasourceImpl.EnterTripDataSourceImpl import com.going.data.datasourceImpl.MockDataSourceImpl import com.going.data.datasourceImpl.SettingDataSourceImpl @@ -42,6 +44,11 @@ object DataSourceModule { fun provideTodoDataSource(todoDataSourceImpl: TodoDataSourceImpl): TodoDataSource = todoDataSourceImpl + @Provides + @Singleton + fun provideDashBoardDataSource(dashBoardDataSourceImpl: DashBoardDataSourceImpl): DashBoardDataSource = + dashBoardDataSourceImpl + @Provides @Singleton fun provideTendencyDataSource(tendencyDataSourceImpl: TendencyDataSourceImpl): TendencyDataSource = diff --git a/app/src/main/java/com/going/doorip/di/RepositoryModule.kt b/app/src/main/java/com/going/doorip/di/RepositoryModule.kt index 19f60974..1b25ae23 100644 --- a/app/src/main/java/com/going/doorip/di/RepositoryModule.kt +++ b/app/src/main/java/com/going/doorip/di/RepositoryModule.kt @@ -1,6 +1,7 @@ package com.going.doorip.di import com.going.data.repositoryImpl.AuthRepositoryImpl +import com.going.data.repositoryImpl.DashBoardRepositoryImpl import com.going.data.repositoryImpl.EnterTripRepositoryImpl import com.going.data.repositoryImpl.MockRepositoryImpl import com.going.data.repositoryImpl.SettingRepositoryImpl @@ -8,6 +9,7 @@ import com.going.data.repositoryImpl.TendencyRepositoryImpl import com.going.data.repositoryImpl.TodoRepositoryImpl import com.going.data.repositoryImpl.TokenRepositoryImpl import com.going.domain.repository.AuthRepository +import com.going.domain.repository.DashBoardRepository import com.going.domain.repository.EnterTripRepository import com.going.domain.repository.MockRepository import com.going.domain.repository.SettingRepository @@ -49,6 +51,11 @@ object RepositoryModule { fun provideTodoRepository(todoRepositoryImpl: TodoRepositoryImpl): TodoRepository = todoRepositoryImpl + @Provides + @Singleton + fun providesDashBoardRepository(dashBoardRepositoryImpl: DashBoardRepositoryImpl): DashBoardRepository = + dashBoardRepositoryImpl + @Provides @Singleton fun provideEnterTripRepository(entertripRepositoryImpl: EnterTripRepositoryImpl): EnterTripRepository = diff --git a/app/src/main/java/com/going/doorip/di/ServiceModule.kt b/app/src/main/java/com/going/doorip/di/ServiceModule.kt index 7447dd6d..a68cd331 100644 --- a/app/src/main/java/com/going/doorip/di/ServiceModule.kt +++ b/app/src/main/java/com/going/doorip/di/ServiceModule.kt @@ -1,6 +1,7 @@ package com.going.doorip.di import com.going.data.service.AuthService +import com.going.data.service.DashBoardService import com.going.data.service.EnterTripService import com.going.data.service.MockService import com.going.data.service.SettingService @@ -37,6 +38,11 @@ object ServiceModule { fun provideTodoService(retrofit: Retrofit): TodoService = retrofit.create(TodoService::class.java) + @Provides + @Singleton + fun provideDashBoardService(retrofit: Retrofit): DashBoardService = + retrofit.create(DashBoardService::class.java) + @Provides @Singleton fun provideEnterTripService(retrofit: Retrofit): EnterTripService = diff --git a/data/src/main/java/com/going/data/datasource/DashBoardDataSource.kt b/data/src/main/java/com/going/data/datasource/DashBoardDataSource.kt new file mode 100644 index 00000000..699a50dd --- /dev/null +++ b/data/src/main/java/com/going/data/datasource/DashBoardDataSource.kt @@ -0,0 +1,12 @@ +package com.going.data.datasource + +import com.going.data.dto.BaseResponse +import com.going.data.dto.response.DashBoardResponseDto + +interface DashBoardDataSource { + + suspend fun getTripList( + progress: String + ): BaseResponse + +} \ No newline at end of file diff --git a/data/src/main/java/com/going/data/datasource/SettingDataSource.kt b/data/src/main/java/com/going/data/datasource/SettingDataSource.kt index da5ec881..43cee88e 100644 --- a/data/src/main/java/com/going/data/datasource/SettingDataSource.kt +++ b/data/src/main/java/com/going/data/datasource/SettingDataSource.kt @@ -3,7 +3,7 @@ package com.going.data.datasource import com.going.data.dto.NonDataBaseResponse interface SettingDataSource { - suspend fun patchSignOut(): NonDataBaseResponse + suspend fun patchSignOut(): NonDataBaseResponse - suspend fun deleteWithDraw(): NonDataBaseResponse + suspend fun deleteWithDraw(): NonDataBaseResponse } diff --git a/data/src/main/java/com/going/data/datasource/TendencyDataSource.kt b/data/src/main/java/com/going/data/datasource/TendencyDataSource.kt index 320da64e..2b9fb929 100644 --- a/data/src/main/java/com/going/data/datasource/TendencyDataSource.kt +++ b/data/src/main/java/com/going/data/datasource/TendencyDataSource.kt @@ -4,5 +4,5 @@ import com.going.data.dto.NonDataBaseResponse import com.going.data.dto.request.TendencyTestRequestDto interface TendencyDataSource { - suspend fun patchTendencyTest(result: TendencyTestRequestDto): NonDataBaseResponse + suspend fun patchTendencyTest(result: TendencyTestRequestDto): NonDataBaseResponse } diff --git a/data/src/main/java/com/going/data/datasource/TodoDataSource.kt b/data/src/main/java/com/going/data/datasource/TodoDataSource.kt index 3acfe274..b3b258b6 100644 --- a/data/src/main/java/com/going/data/datasource/TodoDataSource.kt +++ b/data/src/main/java/com/going/data/datasource/TodoDataSource.kt @@ -17,11 +17,11 @@ interface TodoDataSource { suspend fun postToCreateTodoData( tripId: Long, request: TodoCreateRequestDto - ): NonDataBaseResponse + ): NonDataBaseResponse suspend fun deleteTodoData( todoId: Long - ): NonDataBaseResponse + ): NonDataBaseResponse suspend fun getTodoDetailData( todoId: Long diff --git a/data/src/main/java/com/going/data/datasourceImpl/DashBoardDataSourceImpl.kt b/data/src/main/java/com/going/data/datasourceImpl/DashBoardDataSourceImpl.kt new file mode 100644 index 00000000..6bafedb2 --- /dev/null +++ b/data/src/main/java/com/going/data/datasourceImpl/DashBoardDataSourceImpl.kt @@ -0,0 +1,16 @@ +package com.going.data.datasourceImpl + +import com.going.data.datasource.DashBoardDataSource +import com.going.data.dto.BaseResponse +import com.going.data.dto.response.DashBoardResponseDto +import com.going.data.service.DashBoardService +import javax.inject.Inject + +class DashBoardDataSourceImpl @Inject constructor( + private val dashBoardService: DashBoardService +) : DashBoardDataSource { + + override suspend fun getTripList(progress: String): BaseResponse = + dashBoardService.getTripList(progress) + +} diff --git a/data/src/main/java/com/going/data/datasourceImpl/SettingDataSourceImpl.kt b/data/src/main/java/com/going/data/datasourceImpl/SettingDataSourceImpl.kt index af959b78..7bde298b 100644 --- a/data/src/main/java/com/going/data/datasourceImpl/SettingDataSourceImpl.kt +++ b/data/src/main/java/com/going/data/datasourceImpl/SettingDataSourceImpl.kt @@ -8,6 +8,6 @@ import javax.inject.Inject class SettingDataSourceImpl @Inject constructor( private val settingService: SettingService, ) : SettingDataSource { - override suspend fun patchSignOut(): NonDataBaseResponse = settingService.patchSignOut() - override suspend fun deleteWithDraw(): NonDataBaseResponse = settingService.deleteWithDraw() + override suspend fun patchSignOut(): NonDataBaseResponse = settingService.patchSignOut() + override suspend fun deleteWithDraw(): NonDataBaseResponse = settingService.deleteWithDraw() } diff --git a/data/src/main/java/com/going/data/datasourceImpl/TendencyDataSourceImpl.kt b/data/src/main/java/com/going/data/datasourceImpl/TendencyDataSourceImpl.kt index 125e883f..4b789df5 100644 --- a/data/src/main/java/com/going/data/datasourceImpl/TendencyDataSourceImpl.kt +++ b/data/src/main/java/com/going/data/datasourceImpl/TendencyDataSourceImpl.kt @@ -9,6 +9,6 @@ import javax.inject.Inject class TendencyDataSourceImpl @Inject constructor( private val tendencyService: TendencyService, ) : TendencyDataSource { - override suspend fun patchTendencyTest(result: TendencyTestRequestDto): NonDataBaseResponse = + override suspend fun patchTendencyTest(result: TendencyTestRequestDto): NonDataBaseResponse = tendencyService.patchTendencyTest(result) } diff --git a/data/src/main/java/com/going/data/datasourceImpl/TodoDataSourceImpl.kt b/data/src/main/java/com/going/data/datasourceImpl/TodoDataSourceImpl.kt index 12d63835..18babff3 100644 --- a/data/src/main/java/com/going/data/datasourceImpl/TodoDataSourceImpl.kt +++ b/data/src/main/java/com/going/data/datasourceImpl/TodoDataSourceImpl.kt @@ -23,12 +23,12 @@ class TodoDataSourceImpl @Inject constructor( override suspend fun postToCreateTodoData( tripId: Long, request: TodoCreateRequestDto - ): NonDataBaseResponse = + ): NonDataBaseResponse = todoService.postToCreateTodo(tripId, request) override suspend fun deleteTodoData( todoId: Long - ): NonDataBaseResponse = + ): NonDataBaseResponse = todoService.deleteTodo(todoId) override suspend fun getTodoDetailData( diff --git a/data/src/main/java/com/going/data/dto/NonDataBaseResponse.kt b/data/src/main/java/com/going/data/dto/NonDataBaseResponse.kt index 24f56e49..3138cd55 100644 --- a/data/src/main/java/com/going/data/dto/NonDataBaseResponse.kt +++ b/data/src/main/java/com/going/data/dto/NonDataBaseResponse.kt @@ -4,7 +4,7 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class NonDataBaseResponse( +data class NonDataBaseResponse( @SerialName("status") val status: Int, @SerialName("code") diff --git a/data/src/main/java/com/going/data/dto/response/DashBoardResponseDto.kt b/data/src/main/java/com/going/data/dto/response/DashBoardResponseDto.kt new file mode 100644 index 00000000..3dbd4a9d --- /dev/null +++ b/data/src/main/java/com/going/data/dto/response/DashBoardResponseDto.kt @@ -0,0 +1,37 @@ +package com.going.data.dto.response + +import com.going.domain.entity.response.DashBoardModel +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class DashBoardResponseDto( + @SerialName("name") + val name: String, + @SerialName("trips") + val trips: List + +) { + @Serializable + data class TripsResponseDto( + @SerialName("tripId") + val tripId: Long, + @SerialName("title") + val title: String, + @SerialName("startDate") + val startDate: String, + @SerialName("endDate") + val endDate: String, + @SerialName("day") + val day: Int + ) { + fun toTripsModel() = + DashBoardModel.DashBoardTripModel(tripId, title, startDate, endDate, day) + } + + fun toDashBoardModel() = + DashBoardModel(name, trips.map { + it.toTripsModel() + }) +} + diff --git a/data/src/main/java/com/going/data/interceptor/AuthInterceptor.kt b/data/src/main/java/com/going/data/interceptor/AuthInterceptor.kt index 408de13e..a1eb76e1 100644 --- a/data/src/main/java/com/going/data/interceptor/AuthInterceptor.kt +++ b/data/src/main/java/com/going/data/interceptor/AuthInterceptor.kt @@ -22,6 +22,7 @@ class AuthInterceptor @Inject constructor( Timber.d("GET ACCESS TOKEN : ${dataStore.accessToken}") + val authRequest = if (dataStore.accessToken.isNotBlank()) { originalRequest.newAuthBuilder().build() } else { diff --git a/data/src/main/java/com/going/data/repositoryImpl/DashBoardRepositoryImpl.kt b/data/src/main/java/com/going/data/repositoryImpl/DashBoardRepositoryImpl.kt new file mode 100644 index 00000000..17cd4168 --- /dev/null +++ b/data/src/main/java/com/going/data/repositoryImpl/DashBoardRepositoryImpl.kt @@ -0,0 +1,19 @@ +package com.going.data.repositoryImpl + +import com.going.data.datasource.DashBoardDataSource +import com.going.domain.entity.response.DashBoardModel +import com.going.domain.repository.DashBoardRepository +import javax.inject.Inject + +class DashBoardRepositoryImpl @Inject constructor( + private val dashBoardSource: DashBoardDataSource +) : DashBoardRepository { + + override suspend fun getDashBoardList( + progress: String + ): Result = + runCatching { + dashBoardSource.getTripList(progress).data.toDashBoardModel() + } + +} \ No newline at end of file diff --git a/data/src/main/java/com/going/data/service/DashBoardService.kt b/data/src/main/java/com/going/data/service/DashBoardService.kt new file mode 100644 index 00000000..52729f88 --- /dev/null +++ b/data/src/main/java/com/going/data/service/DashBoardService.kt @@ -0,0 +1,15 @@ +package com.going.data.service + +import com.going.data.dto.BaseResponse +import com.going.data.dto.response.DashBoardResponseDto +import retrofit2.http.GET +import retrofit2.http.Query + +interface DashBoardService { + + @GET("api/trips") + suspend fun getTripList( + @Query("progress") progress: String + ) : BaseResponse + +} \ No newline at end of file diff --git a/data/src/main/java/com/going/data/service/SettingService.kt b/data/src/main/java/com/going/data/service/SettingService.kt index 43ef8bd2..e7c7fafb 100644 --- a/data/src/main/java/com/going/data/service/SettingService.kt +++ b/data/src/main/java/com/going/data/service/SettingService.kt @@ -6,8 +6,8 @@ import retrofit2.http.PATCH interface SettingService { @PATCH("api/users/signout") - suspend fun patchSignOut(): NonDataBaseResponse + suspend fun patchSignOut(): NonDataBaseResponse @DELETE("api/users/withdraw") - suspend fun deleteWithDraw(): NonDataBaseResponse + suspend fun deleteWithDraw(): NonDataBaseResponse } diff --git a/data/src/main/java/com/going/data/service/TendencyService.kt b/data/src/main/java/com/going/data/service/TendencyService.kt index 5ed0eb84..4c0f6141 100644 --- a/data/src/main/java/com/going/data/service/TendencyService.kt +++ b/data/src/main/java/com/going/data/service/TendencyService.kt @@ -9,5 +9,5 @@ interface TendencyService { @PATCH("api/users/test") suspend fun patchTendencyTest( @Body result: TendencyTestRequestDto, - ): NonDataBaseResponse + ): NonDataBaseResponse } diff --git a/data/src/main/java/com/going/data/service/TodoService.kt b/data/src/main/java/com/going/data/service/TodoService.kt index 74e8f8aa..7c1c7d9c 100644 --- a/data/src/main/java/com/going/data/service/TodoService.kt +++ b/data/src/main/java/com/going/data/service/TodoService.kt @@ -25,12 +25,12 @@ interface TodoService { suspend fun postToCreateTodo( @Path("tripId") tripId: Long, @Body request: TodoCreateRequestDto - ): NonDataBaseResponse + ): NonDataBaseResponse @DELETE("api/trips/todos/{todoId}") suspend fun deleteTodo( @Path("todoId") todoId: Long - ): NonDataBaseResponse + ): NonDataBaseResponse @GET("api/trips/todos/{todoId}") suspend fun getTodoDetail( diff --git a/domain/src/main/kotlin/com/going/domain/entity/response/CompletedListModel.kt b/domain/src/main/kotlin/com/going/domain/entity/response/CompletedListModel.kt deleted file mode 100644 index b0c99d80..00000000 --- a/domain/src/main/kotlin/com/going/domain/entity/response/CompletedListModel.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.going.domain.entity.response - -data class CompletedListModel( - val title: String, - val startDate: String, - val endDate: String -) \ No newline at end of file diff --git a/domain/src/main/kotlin/com/going/domain/entity/response/DashBoardModel.kt b/domain/src/main/kotlin/com/going/domain/entity/response/DashBoardModel.kt new file mode 100644 index 00000000..357ad258 --- /dev/null +++ b/domain/src/main/kotlin/com/going/domain/entity/response/DashBoardModel.kt @@ -0,0 +1,14 @@ +package com.going.domain.entity.response + +data class DashBoardModel( + val name: String, + val trips: List +){ + data class DashBoardTripModel( + val tripId: Long, + val title: String, + val startDate: String, + val endDate: String, + val day: Int + ) +} \ No newline at end of file diff --git a/domain/src/main/kotlin/com/going/domain/entity/response/OngoingListModel.kt b/domain/src/main/kotlin/com/going/domain/entity/response/OngoingListModel.kt deleted file mode 100644 index e132f47d..00000000 --- a/domain/src/main/kotlin/com/going/domain/entity/response/OngoingListModel.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.going.domain.entity.response - -data class OngoingListModel( - val title: String, - val startDate: String, - val endDate: String, - val day: Int -) diff --git a/domain/src/main/kotlin/com/going/domain/repository/DashBoardRepository.kt b/domain/src/main/kotlin/com/going/domain/repository/DashBoardRepository.kt new file mode 100644 index 00000000..361b3f5b --- /dev/null +++ b/domain/src/main/kotlin/com/going/domain/repository/DashBoardRepository.kt @@ -0,0 +1,9 @@ +package com.going.domain.repository + +import com.going.domain.entity.response.DashBoardModel + +interface DashBoardRepository { + suspend fun getDashBoardList( + progress : String, + ) : Result +} \ No newline at end of file diff --git a/presentation/src/main/java/com/going/presentation/tripdashboard/TripDashBoardActivity.kt b/presentation/src/main/java/com/going/presentation/dashboard/DashBoardActivity.kt similarity index 60% rename from presentation/src/main/java/com/going/presentation/tripdashboard/TripDashBoardActivity.kt rename to presentation/src/main/java/com/going/presentation/dashboard/DashBoardActivity.kt index 658a1cf3..6053cdb2 100644 --- a/presentation/src/main/java/com/going/presentation/tripdashboard/TripDashBoardActivity.kt +++ b/presentation/src/main/java/com/going/presentation/dashboard/DashBoardActivity.kt @@ -1,21 +1,28 @@ -package com.going.presentation.tripdashboard +package com.going.presentation.dashboard import android.os.Bundle +import androidx.activity.viewModels import com.going.presentation.R +import com.going.presentation.dashboard.triplist.OngoingTripFragment import com.going.presentation.databinding.ActivityTripDashBoardBinding import com.going.ui.base.BaseActivity import com.google.android.material.tabs.TabLayoutMediator +import dagger.hilt.android.AndroidEntryPoint -class TripDashBoardActivity : +@AndroidEntryPoint +class DashBoardActivity : BaseActivity(R.layout.activity_trip_dash_board) { private val tabTextList = listOf(TAB_ONGOING, TAB_COMPLETED) + private val viewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setTabLayout() setViewPager() + setTravelerName() } @@ -31,14 +38,23 @@ class TripDashBoardActivity : private fun setViewPager() { binding.vpDashboard.adapter = DashBoardViewPagerAdapter(this) + binding.vpDashboard.isUserInputEnabled = false TabLayoutMediator(binding.tabDashboard, binding.vpDashboard) { tab, pos -> tab.text = tabTextList[pos] }.attach() } + private fun setTravelerName() { + val progress = DashBoardViewModel.COMPLETED + viewModel.getTravelerNameFromServer(progress) + viewModel.name.observe(this) { travelerName -> + binding.tvDashboardTitle.text = getString(R.string.dashboard_tv_title, travelerName) + } + } + companion object { const val TAB_ONGOING = "진행중인 여행" - const val TAB_COMPLETED = "완료된 여행" + const val TAB_COMPLETED = "지나간 여행" } } \ No newline at end of file diff --git a/presentation/src/main/java/com/going/presentation/dashboard/DashBoardViewModel.kt b/presentation/src/main/java/com/going/presentation/dashboard/DashBoardViewModel.kt new file mode 100644 index 00000000..427939de --- /dev/null +++ b/presentation/src/main/java/com/going/presentation/dashboard/DashBoardViewModel.kt @@ -0,0 +1,68 @@ +package com.going.presentation.dashboard + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.going.domain.entity.response.DashBoardModel +import com.going.domain.repository.DashBoardRepository +import com.going.ui.extension.UiState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class DashBoardViewModel @Inject constructor( + private val dashBoardRepository: DashBoardRepository +) : ViewModel() { + private val _dashBoardOngoingListState = + MutableStateFlow>(UiState.Empty) + val dashBoardOngoingListState: StateFlow> get() = _dashBoardOngoingListState + + private val _dashBoardCompletedListState = + MutableStateFlow>(UiState.Empty) + + val name = MutableLiveData("") + + val dashBoardCompletedListState: StateFlow> get() = _dashBoardCompletedListState + + fun getTripListFromServer( + progress: String + ) { + val dashBoardListState = if (progress == ONGOING) { + _dashBoardOngoingListState + } else { + _dashBoardCompletedListState + } + dashBoardListState.value = UiState.Loading + viewModelScope.launch { + dashBoardRepository.getDashBoardList(progress) + .onSuccess { + dashBoardListState.value = UiState.Success(it) + } + .onFailure { + dashBoardListState.value = UiState.Failure(it.message.orEmpty()) + } + } + } + + fun getTravelerNameFromServer(progress: String) { + viewModelScope.launch { + dashBoardRepository.getDashBoardList(progress) + .onSuccess { + name.value = it.name + } + .onFailure { + name.value = null + } + } + } + + + companion object { + const val ONGOING = "incomplete" + const val COMPLETED = "complete" + } + +} \ No newline at end of file diff --git a/presentation/src/main/java/com/going/presentation/tripdashboard/DashBoardViewPagerAdapter.kt b/presentation/src/main/java/com/going/presentation/dashboard/DashBoardViewPagerAdapter.kt similarity index 70% rename from presentation/src/main/java/com/going/presentation/tripdashboard/DashBoardViewPagerAdapter.kt rename to presentation/src/main/java/com/going/presentation/dashboard/DashBoardViewPagerAdapter.kt index 9f121083..a0baf469 100644 --- a/presentation/src/main/java/com/going/presentation/tripdashboard/DashBoardViewPagerAdapter.kt +++ b/presentation/src/main/java/com/going/presentation/dashboard/DashBoardViewPagerAdapter.kt @@ -1,10 +1,10 @@ -package com.going.presentation.tripdashboard +package com.going.presentation.dashboard import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.viewpager2.adapter.FragmentStateAdapter -import com.going.presentation.tripdashboard.triplist.CompletedTripFragment -import com.going.presentation.tripdashboard.triplist.OngoingTripFragment +import com.going.presentation.dashboard.triplist.CompletedTripFragment +import com.going.presentation.dashboard.triplist.OngoingTripFragment class DashBoardViewPagerAdapter(fragment: FragmentActivity) : FragmentStateAdapter(fragment) { override fun getItemCount(): Int = 2 diff --git a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/CompletedAdapter.kt b/presentation/src/main/java/com/going/presentation/dashboard/triplist/CompletedAdapter.kt similarity index 76% rename from presentation/src/main/java/com/going/presentation/tripdashboard/triplist/CompletedAdapter.kt rename to presentation/src/main/java/com/going/presentation/dashboard/triplist/CompletedAdapter.kt index 333c39a9..d4af5574 100644 --- a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/CompletedAdapter.kt +++ b/presentation/src/main/java/com/going/presentation/dashboard/triplist/CompletedAdapter.kt @@ -1,18 +1,18 @@ -package com.going.presentation.tripdashboard.triplist +package com.going.presentation.dashboard.triplist import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.ListAdapter -import com.going.domain.entity.response.CompletedListModel +import com.going.domain.entity.response.DashBoardModel.DashBoardTripModel import com.going.presentation.databinding.ItemDashBoardCompletedBinding import com.going.ui.extension.ItemDiffCallback class CompletedAdapter( private val listener: OnDashBoardSelectedListener -) : ListAdapter(diffUtil) { +) : ListAdapter(diffUtil) { interface OnDashBoardSelectedListener { - fun onDashBoardSelectedListener(tripCreate: CompletedListModel) + fun onDashBoardSelectedListener(tripCreate: DashBoardTripModel) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CompletedViewHolder { @@ -30,7 +30,7 @@ class CompletedAdapter( } companion object { - private val diffUtil = ItemDiffCallback( + private val diffUtil = ItemDiffCallback( onItemsTheSame = { old, new -> old.title == new.title }, onContentsTheSame = { old, new -> old == new }, ) diff --git a/presentation/src/main/java/com/going/presentation/dashboard/triplist/CompletedTripFragment.kt b/presentation/src/main/java/com/going/presentation/dashboard/triplist/CompletedTripFragment.kt new file mode 100644 index 00000000..ecbd0419 --- /dev/null +++ b/presentation/src/main/java/com/going/presentation/dashboard/triplist/CompletedTripFragment.kt @@ -0,0 +1,87 @@ +package com.going.presentation.dashboard.triplist + +import android.os.Bundle +import android.view.View +import androidx.core.view.isVisible +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope +import com.going.domain.entity.response.DashBoardModel.DashBoardTripModel +import com.going.presentation.R +import com.going.presentation.dashboard.DashBoardViewModel +import com.going.presentation.databinding.FragmentCompletedTripBinding +import com.going.ui.base.BaseFragment +import com.going.ui.extension.UiState +import com.going.ui.extension.toast +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +@AndroidEntryPoint +class CompletedTripFragment : + BaseFragment(R.layout.fragment_completed_trip), + CompletedAdapter.OnDashBoardSelectedListener { + + private val viewModel by activityViewModels() + + private var _adapter: CompletedAdapter? = null + private val adapter get() = requireNotNull(_adapter) { getString(R.string.adapter_not_initialized_error_msg) } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + initAdapter() + initItemDecoration() + setTripList() + observeDashBoardListState() + + } + + private fun initAdapter() { + _adapter = CompletedAdapter(this) + binding.rvDashboardCompletedTrip.adapter = adapter + } + + private fun initItemDecoration() { + val itemDeco = DashBoardDecoration(requireContext()) + binding.rvDashboardCompletedTrip.addItemDecoration(itemDeco) + } + + private fun setTripList() { + val progress = DashBoardViewModel.COMPLETED + viewModel.getTripListFromServer(progress) + } + + private fun observeDashBoardListState() { + viewModel.dashBoardCompletedListState.flowWithLifecycle(lifecycle).onEach { state -> + when (state) { + is UiState.Success -> { + setEmptyView(false) + adapter.submitList(state.data.trips) + } + + is UiState.Failure -> toast(getString(R.string.server_error)) + + is UiState.Loading -> return@onEach + + is UiState.Empty -> setEmptyView(true) + } + }.launchIn(lifecycleScope) + } + + private fun setEmptyView(isEmpty: Boolean) { + binding.rvDashboardCompletedTrip.isVisible = !isEmpty + binding.layoutDashboardEmpty.isVisible = isEmpty + } + + + override fun onDestroyView() { + super.onDestroyView() + _adapter = null + } + + override fun onDashBoardSelectedListener(tripCreate: DashBoardTripModel) { + + } + +} \ No newline at end of file diff --git a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/CompletedViewHolder.kt b/presentation/src/main/java/com/going/presentation/dashboard/triplist/CompletedViewHolder.kt similarity index 67% rename from presentation/src/main/java/com/going/presentation/tripdashboard/triplist/CompletedViewHolder.kt rename to presentation/src/main/java/com/going/presentation/dashboard/triplist/CompletedViewHolder.kt index 8d38ed17..5ff5e9cb 100644 --- a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/CompletedViewHolder.kt +++ b/presentation/src/main/java/com/going/presentation/dashboard/triplist/CompletedViewHolder.kt @@ -1,7 +1,8 @@ -package com.going.presentation.tripdashboard.triplist +package com.going.presentation.dashboard.triplist import androidx.recyclerview.widget.RecyclerView -import com.going.domain.entity.response.CompletedListModel +import com.going.domain.entity.response.DashBoardModel.DashBoardTripModel +import com.going.presentation.R import com.going.presentation.databinding.ItemDashBoardCompletedBinding import com.going.ui.extension.setOnSingleClickListener @@ -10,12 +11,14 @@ class CompletedViewHolder( private val listener: CompletedAdapter.OnDashBoardSelectedListener ) : RecyclerView.ViewHolder(binding.root) { - fun onBind(item: CompletedListModel) { + fun onBind(item: DashBoardTripModel) { binding.run { tvDashboardTripTitle.text = item.title tvDashboardDateStart.text = item.startDate tvDashboardDateEnd.text = item.endDate + tvDashboardDeadlineCompleted.text = + itemView.context.getString(R.string.dashboard_tv_completed_trip) layoutDashboard.setOnSingleClickListener { listener.onDashBoardSelectedListener(item) diff --git a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/DashBoardDecoration.kt b/presentation/src/main/java/com/going/presentation/dashboard/triplist/DashBoardDecoration.kt similarity index 91% rename from presentation/src/main/java/com/going/presentation/tripdashboard/triplist/DashBoardDecoration.kt rename to presentation/src/main/java/com/going/presentation/dashboard/triplist/DashBoardDecoration.kt index 7679064a..a119978a 100644 --- a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/DashBoardDecoration.kt +++ b/presentation/src/main/java/com/going/presentation/dashboard/triplist/DashBoardDecoration.kt @@ -1,4 +1,4 @@ -package com.going.presentation.tripdashboard.triplist +package com.going.presentation.dashboard.triplist import android.content.Context import android.graphics.Rect diff --git a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/OngoingAdapter.kt b/presentation/src/main/java/com/going/presentation/dashboard/triplist/OngoingAdapter.kt similarity index 75% rename from presentation/src/main/java/com/going/presentation/tripdashboard/triplist/OngoingAdapter.kt rename to presentation/src/main/java/com/going/presentation/dashboard/triplist/OngoingAdapter.kt index f08cb98d..91f58972 100644 --- a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/OngoingAdapter.kt +++ b/presentation/src/main/java/com/going/presentation/dashboard/triplist/OngoingAdapter.kt @@ -1,18 +1,18 @@ -package com.going.presentation.tripdashboard.triplist +package com.going.presentation.dashboard.triplist import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.ListAdapter -import com.going.domain.entity.response.OngoingListModel +import com.going.domain.entity.response.DashBoardModel.DashBoardTripModel import com.going.presentation.databinding.ItemDashBoardOngoingBinding import com.going.ui.extension.ItemDiffCallback class OngoingAdapter( private val listener: OnDashBoardSelectedListener -) : ListAdapter(diffUtil) { +) : ListAdapter(diffUtil) { interface OnDashBoardSelectedListener { - fun onDashBoardSelectedListener(tripCreate: OngoingListModel) + fun onDashBoardSelectedListener(tripCreate: DashBoardTripModel) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OngoingViewHolder { @@ -30,7 +30,7 @@ class OngoingAdapter( } companion object { - private val diffUtil = ItemDiffCallback( + private val diffUtil = ItemDiffCallback( onItemsTheSame = { old, new -> old.title == new.title }, onContentsTheSame = { old, new -> old == new }, ) diff --git a/presentation/src/main/java/com/going/presentation/dashboard/triplist/OngoingTripFragment.kt b/presentation/src/main/java/com/going/presentation/dashboard/triplist/OngoingTripFragment.kt new file mode 100644 index 00000000..8534a2bc --- /dev/null +++ b/presentation/src/main/java/com/going/presentation/dashboard/triplist/OngoingTripFragment.kt @@ -0,0 +1,87 @@ +package com.going.presentation.dashboard.triplist + +import android.os.Bundle +import android.view.View +import androidx.core.view.isVisible +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope +import com.going.domain.entity.response.DashBoardModel.DashBoardTripModel +import com.going.presentation.R +import com.going.presentation.dashboard.DashBoardViewModel +import com.going.presentation.databinding.FragmentOngoingTripBinding +import com.going.ui.base.BaseFragment +import com.going.ui.extension.UiState +import com.going.ui.extension.toast +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +@AndroidEntryPoint +class OngoingTripFragment : + BaseFragment(R.layout.fragment_ongoing_trip), + OngoingAdapter.OnDashBoardSelectedListener { + + private val viewModel by activityViewModels() + + private var _adapter: OngoingAdapter? = null + private val adapter get() = requireNotNull(_adapter) { getString(R.string.adapter_not_initialized_error_msg) } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + initAdapter() + initItemDecoration() + setTripList() + observeDashBoardListState() + + } + + + private fun initAdapter() { + _adapter = OngoingAdapter(this) + binding.rvDashboardOngoingTrip.adapter = adapter + } + + private fun initItemDecoration() { + val itemDeco = DashBoardDecoration(requireContext()) + binding.rvDashboardOngoingTrip.addItemDecoration(itemDeco) + } + + private fun setTripList() { + val progress = DashBoardViewModel.ONGOING + viewModel.getTripListFromServer(progress) + } + + private fun observeDashBoardListState() { + viewModel.dashBoardOngoingListState.flowWithLifecycle(lifecycle).onEach { state -> + when (state) { + is UiState.Success -> { + setEmptyView(false) + adapter.submitList(state.data.trips) + } + + is UiState.Failure -> toast(getString(R.string.server_error)) + + is UiState.Loading -> return@onEach + + is UiState.Empty -> setEmptyView(true) + } + }.launchIn(lifecycleScope) + } + + private fun setEmptyView(isEmpty: Boolean) { + binding.rvDashboardOngoingTrip.isVisible = !isEmpty + binding.layoutDashboardEmpty.isVisible = isEmpty + } + + override fun onDestroyView() { + super.onDestroyView() + _adapter = null + } + + override fun onDashBoardSelectedListener(tripCreate: DashBoardTripModel) { + + } + +} \ No newline at end of file diff --git a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/OngoingViewHolder.kt b/presentation/src/main/java/com/going/presentation/dashboard/triplist/OngoingViewHolder.kt similarity index 86% rename from presentation/src/main/java/com/going/presentation/tripdashboard/triplist/OngoingViewHolder.kt rename to presentation/src/main/java/com/going/presentation/dashboard/triplist/OngoingViewHolder.kt index c83928dd..66a8d17e 100644 --- a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/OngoingViewHolder.kt +++ b/presentation/src/main/java/com/going/presentation/dashboard/triplist/OngoingViewHolder.kt @@ -1,7 +1,7 @@ -package com.going.presentation.tripdashboard.triplist +package com.going.presentation.dashboard.triplist import androidx.recyclerview.widget.RecyclerView -import com.going.domain.entity.response.OngoingListModel +import com.going.domain.entity.response.DashBoardModel.DashBoardTripModel import com.going.presentation.R import com.going.presentation.databinding.ItemDashBoardOngoingBinding import com.going.ui.extension.setOnSingleClickListener @@ -11,7 +11,7 @@ class OngoingViewHolder( private val listener: OngoingAdapter.OnDashBoardSelectedListener ) : RecyclerView.ViewHolder(binding.root) { - fun onBind(item: OngoingListModel) { + fun onBind(item: DashBoardTripModel) { binding.run { tvDashboardTripTitle.text = item.title tvDashboardDateStart.text = item.startDate diff --git a/presentation/src/main/java/com/going/presentation/setting/SettingActivity.kt b/presentation/src/main/java/com/going/presentation/setting/SettingActivity.kt index 8bd913d7..dd44fa03 100644 --- a/presentation/src/main/java/com/going/presentation/setting/SettingActivity.kt +++ b/presentation/src/main/java/com/going/presentation/setting/SettingActivity.kt @@ -26,27 +26,27 @@ class SettingActivity : BaseActivity(R.layout.activity_s } private fun initProfileClickListener() { - binding.layoutSettingProfile.setOnSingleClickListener { + binding.btnSettingProfile.setOnSingleClickListener { } } private fun initInquireClickListener() { - binding.layoutSettingInquire.setOnSingleClickListener { + binding.btnSettingInquire.setOnSingleClickListener { } } private fun initPolicyClickListener() { - binding.layoutSettingPolicy.setOnSingleClickListener { + binding.btnSettingPolicy.setOnSingleClickListener { } } private fun initAboutDooripClickListener() { - binding.layoutSettingAboutDoorip.setOnSingleClickListener { + binding.btnSettingAboutDoorip.setOnSingleClickListener { } } private fun initLogoutClickListener() { - binding.layoutSettingLogout.setOnSingleClickListener { + binding.btnSettingLogout.setOnSingleClickListener { showLogoutAlertDialog() } } diff --git a/presentation/src/main/java/com/going/presentation/tripdashboard/TripDashBoardViewModel.kt b/presentation/src/main/java/com/going/presentation/tripdashboard/TripDashBoardViewModel.kt deleted file mode 100644 index 996c1103..00000000 --- a/presentation/src/main/java/com/going/presentation/tripdashboard/TripDashBoardViewModel.kt +++ /dev/null @@ -1,94 +0,0 @@ -package com.going.presentation.tripdashboard - -import androidx.lifecycle.ViewModel -import com.going.domain.entity.response.CompletedListModel -import com.going.domain.entity.response.OngoingListModel - -class TripDashBoardViewModel : ViewModel() { - - val mockOngoingList: List = listOf( - OngoingListModel( - title = "굉굉이랑 합숙", - startDate = "2024.01.01", - endDate = "2024.01.21", - day = 16 - ), - OngoingListModel( - title = "여행 제목 자리", - startDate = "2002.09.22", - endDate = "2005.03.31", - day = -10 - ), - OngoingListModel( - title = "상호랑 제주도 여행", - startDate = "2025.03.24", - endDate = "2025.03.31", - day = 100 - ), - OngoingListModel( - title = "동민이랑 서울 구경", - startDate = "2026.03.24", - endDate = "2026.03.31", - day = 200 - ), - OngoingListModel( - title = "유빈이랑 부산 여행", - startDate = "2027.03.24", - endDate = "2027.03.31", - day = 300 - ), - OngoingListModel( - title = "세연이랑 바다 구경", - startDate = "2028.03.24", - endDate = "2028.03.31", - day = 400 - ), - OngoingListModel( - title = "솝트랑 MT", - startDate = "2021.03.24", - endDate = "2021.03.31", - day = 0 - ), - OngoingListModel( - title = "굉굉 신년회", - startDate = "2024.01.02", - endDate = "2024.01.32", - day = 0 - ), - OngoingListModel( - title = "안드 단체 여행", - startDate = "2020.03.24", - endDate = "2021.03.31", - day = 100 - ), - OngoingListModel( - title = "두릅", - startDate = "2003.03.24", - endDate = "2004.03.31", - day = 1000 - ) - ) - - val mockCompletedList: List = listOf( - CompletedListModel( - title = "유빈이 생일 파티", - startDate = "2022.09.22", - endDate = "2022.09.23" - ), - CompletedListModel( - title = "굉굉이랑 만화 카페", - startDate = "2024.01.13", - endDate = "2024.01.23", - ), - CompletedListModel( - title = "굉굉이랑 파스타 먹기", - startDate = "2024.01.09", - endDate = "2024.01.09", - ), - CompletedListModel( - title = "굉굉이랑 고기 구워 먹기", - startDate = "2020.04.10", - endDate = "2020.04.22", - ) - ) -} \ No newline at end of file diff --git a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/CompletedTripFragment.kt b/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/CompletedTripFragment.kt deleted file mode 100644 index aa068dc0..00000000 --- a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/CompletedTripFragment.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.going.presentation.tripdashboard.triplist - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.activityViewModels -import com.going.domain.entity.response.CompletedListModel -import com.going.presentation.R -import com.going.presentation.databinding.FragmentCompletedTripBinding -import com.going.presentation.tripdashboard.TripDashBoardViewModel -import com.going.ui.base.BaseFragment - -class CompletedTripFragment : - BaseFragment(R.layout.fragment_completed_trip), - CompletedAdapter.OnDashBoardSelectedListener { - - private val viewModel by activityViewModels() - - private var _adapter: CompletedAdapter? = null - private val adapter get() = requireNotNull(_adapter) { getString(R.string.adapter_not_initialized_error_msg) } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - setRecyclerView() - initItemDecoration() - - } - - override fun onDashBoardSelectedListener(tripCreate: CompletedListModel) { - // 여행 생성 레이아웃 클릭 시 처리 - } - - private fun setRecyclerView() { - _adapter = CompletedAdapter(this) - binding.rvDashboardCompletedTrip.adapter = adapter - adapter.submitList(viewModel.mockCompletedList) - } - - private fun initItemDecoration() { - val itemDeco = DashBoardDecoration(requireContext()) - binding.rvDashboardCompletedTrip.addItemDecoration(itemDeco) - } - - override fun onDestroyView() { - super.onDestroyView() - _adapter = null - } - -} \ No newline at end of file diff --git a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/OngoingTripFragment.kt b/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/OngoingTripFragment.kt deleted file mode 100644 index 053bc6d5..00000000 --- a/presentation/src/main/java/com/going/presentation/tripdashboard/triplist/OngoingTripFragment.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.going.presentation.tripdashboard.triplist - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.activityViewModels -import com.going.domain.entity.response.OngoingListModel -import com.going.presentation.R -import com.going.presentation.databinding.FragmentOngoingTripBinding -import com.going.presentation.tripdashboard.TripDashBoardViewModel -import com.going.ui.base.BaseFragment - -class OngoingTripFragment : - BaseFragment(R.layout.fragment_ongoing_trip), - OngoingAdapter.OnDashBoardSelectedListener { - - private val viewModel by activityViewModels() - - private var _adapter: OngoingAdapter? = null - private val adapter get() = requireNotNull(_adapter) { getString(R.string.adapter_not_initialized_error_msg) } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - setRecyclerView() - initItemDecoration() - - } - - override fun onDashBoardSelectedListener(tripCreate: OngoingListModel) { - // 여행 생성 레이아웃 클릭 시 처리 - } - - private fun setRecyclerView() { - _adapter = OngoingAdapter(this) - binding.rvDashboardOngoingTrip.adapter = adapter - adapter.submitList(viewModel.mockOngoingList) - } - - private fun initItemDecoration() { - val itemDeco = DashBoardDecoration(requireContext()) - binding.rvDashboardOngoingTrip.addItemDecoration(itemDeco) - } - - override fun onDestroyView() { - super.onDestroyView() - _adapter = null - } - -} \ No newline at end of file diff --git a/presentation/src/main/res/drawable/ic_empty_dashboard_doorip.xml b/presentation/src/main/res/drawable/ic_empty_dashboard_doorip.xml new file mode 100644 index 00000000..efe2f074 --- /dev/null +++ b/presentation/src/main/res/drawable/ic_empty_dashboard_doorip.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/presentation/src/main/res/layout/activity_setting.xml b/presentation/src/main/res/layout/activity_setting.xml index 52ce8825..92edda12 100644 --- a/presentation/src/main/res/layout/activity_setting.xml +++ b/presentation/src/main/res/layout/activity_setting.xml @@ -47,7 +47,7 @@ + app:layout_constraintTop_toBottomOf="@id/btn_setting_profile"> + app:layout_constraintTop_toBottomOf="@id/btn_setting_inquire"> + app:layout_constraintTop_toBottomOf="@id/btn_setting_service_version"> + app:layout_constraintTop_toBottomOf="@id/btn_setting_policy"> + app:layout_constraintTop_toBottomOf="@id/btn_setting_about_doorip"> + tools:context=".dashboard.DashBoardActivity"> + + + + + + + + + diff --git a/presentation/src/main/res/layout/fragment_ongoing_trip.xml b/presentation/src/main/res/layout/fragment_ongoing_trip.xml index e94898a9..55966c5f 100644 --- a/presentation/src/main/res/layout/fragment_ongoing_trip.xml +++ b/presentation/src/main/res/layout/fragment_ongoing_trip.xml @@ -18,12 +18,48 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:orientation="vertical" + android:visibility="visible" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:listitem="@layout/item_dash_board_ongoing" /> + + + + + + + + diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 9075c0f5..63c7f952 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -97,7 +97,7 @@ %s님의 여행 - 생성된 여행이 없어요. + 새로운 여행을 시작해 보세요 여행 생성하기 여행종료 -