diff --git a/app/build.gradle b/app/build.gradle
index c66fa01d4..361c2453d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -88,7 +88,6 @@ dependencies {
implementation projects.feature.home
implementation projects.feature.detail
implementation projects.feature.search
- implementation projects.feature.theater
implementation projects.feature.settings
implementation projects.feature.theme.api
runtimeOnly projects.feature.theme.impl
diff --git a/core/designsystem/src/main/java/soup/movie/core/designsystem/icon/MovieIcons.kt b/core/designsystem/src/main/java/soup/movie/core/designsystem/icon/MovieIcons.kt
index 94a8ebbea..4b6388a61 100644
--- a/core/designsystem/src/main/java/soup/movie/core/designsystem/icon/MovieIcons.kt
+++ b/core/designsystem/src/main/java/soup/movie/core/designsystem/icon/MovieIcons.kt
@@ -19,11 +19,8 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.automirrored.rounded.Subject
import androidx.compose.material.icons.outlined.PrivacyTip
-import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.Check
import androidx.compose.material.icons.rounded.Close
-import androidx.compose.material.icons.rounded.DragHandle
-import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.FilterList
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material.icons.rounded.Palette
@@ -34,12 +31,9 @@ import androidx.compose.material.icons.rounded.ViewModule
import soup.movie.core.designsystem.R
object MovieIcons {
- val Add = Icons.Rounded.Add
val ArrowBack = Icons.AutoMirrored.Rounded.ArrowBack
val Check = Icons.Rounded.Check
val Close = Icons.Rounded.Close
- val DragHandle = Icons.Rounded.DragHandle
- val Edit = Icons.Rounded.Edit
val FilterList = Icons.Rounded.FilterList
val Info = Icons.Rounded.Info
val Palette = Icons.Rounded.Palette
@@ -58,7 +52,6 @@ object MovieIcons {
val LoadingLogo = R.drawable.ic_loading_logo
val YouTube = R.drawable.ic_logo_youtube
val Metacritic = R.drawable.ic_metacritic
- val NoTheaters = R.drawable.ic_round_no_theaters
val RottenTomatoes = R.drawable.ic_rt
val RottenTomatoesFresh = R.drawable.ic_rt_fresh
val RottenTomatoesRotten = R.drawable.ic_rt_rotten
diff --git a/core/designsystem/src/main/res/drawable/ic_round_no_theaters.xml b/core/designsystem/src/main/res/drawable/ic_round_no_theaters.xml
deleted file mode 100644
index 1048b5421..000000000
--- a/core/designsystem/src/main/res/drawable/ic_round_no_theaters.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/core/resources/src/main/res/values-ko/strings.xml b/core/resources/src/main/res/values-ko/strings.xml
index 75c6db290..ae44beb23 100644
--- a/core/resources/src/main/res/values-ko/strings.xml
+++ b/core/resources/src/main/res/values-ko/strings.xml
@@ -36,31 +36,14 @@
설정
- 자주가는 극장
- 선택된 극장이 없습니다
테마
- 극장 순서 설정
-
- 선호하는 극장 편집
-
- %d개까지 선택할 수 있습니다.\n더 추가하려면 선택된 항목을 지워주세요.
-
- 극장 선택
- 선호하는 극장을 선택해주세요
- 완료
- 취소
-
- 선택된 극장이 없습니다
-
테마 선택
어둡게
밝게
기본 (시스템 설정)
기본 (절전모드 시 어둡게)
- 지도
-
청소년관람불가
15세관람가
12세관람가
diff --git a/core/resources/src/main/res/values/strings.xml b/core/resources/src/main/res/values/strings.xml
index b4c960eb3..bff0e296f 100644
--- a/core/resources/src/main/res/values/strings.xml
+++ b/core/resources/src/main/res/values/strings.xml
@@ -36,31 +36,14 @@
Settings
- Favorite Theaters
- There are no favorite theaters
Theme
- Theater Order Setting
-
- Edit Favorite Theaters
-
- The favorite theaters\'s count is limited to %d.\nIf wants to add more, remove seleted items.
-
- Select theater
- Please select the favorite theaters
- Confirm
- Cancel
-
- There are no favorite theaters
-
Select theme
Dark
Light
Default (Set system setting)
Default (Set by battery saver)
- Map
-
PG 18
PG 15
PG 12
diff --git a/data/database/api/src/main/java/soup/movie/data/database/LocalDataSource.kt b/data/database/api/src/main/java/soup/movie/data/database/LocalDataSource.kt
index a57f694f6..299fa237b 100644
--- a/data/database/api/src/main/java/soup/movie/data/database/LocalDataSource.kt
+++ b/data/database/api/src/main/java/soup/movie/data/database/LocalDataSource.kt
@@ -19,7 +19,6 @@ import kotlinx.coroutines.flow.Flow
import soup.movie.model.MovieListModel
import soup.movie.model.MovieModel
import soup.movie.model.OpenDateAlarmModel
-import soup.movie.model.TheaterAreaGroupModel
interface LocalDataSource {
@@ -32,9 +31,6 @@ interface LocalDataSource {
suspend fun getAllMovieList(): List
suspend fun getNowMovieList(): List
- fun saveCodeList(response: TheaterAreaGroupModel)
- fun getCodeList(): TheaterAreaGroupModel?
-
suspend fun addFavoriteMovie(movie: MovieModel)
suspend fun removeFavoriteMovie(movieId: String)
fun getFavoriteMovieList(): Flow>
diff --git a/data/database/impl/src/main/java/soup/movie/data/database/impl/LocalDataSourceImpl.kt b/data/database/impl/src/main/java/soup/movie/data/database/impl/LocalDataSourceImpl.kt
index 1bbd5e594..17f71b109 100644
--- a/data/database/impl/src/main/java/soup/movie/data/database/impl/LocalDataSourceImpl.kt
+++ b/data/database/impl/src/main/java/soup/movie/data/database/impl/LocalDataSourceImpl.kt
@@ -35,7 +35,6 @@ import soup.movie.log.Logger
import soup.movie.model.MovieListModel
import soup.movie.model.MovieModel
import soup.movie.model.OpenDateAlarmModel
-import soup.movie.model.TheaterAreaGroupModel
import javax.inject.Inject
class LocalDataSourceImpl @Inject constructor(
@@ -44,8 +43,6 @@ class LocalDataSourceImpl @Inject constructor(
private val cacheDao: MovieCacheDao,
) : LocalDataSource {
- private var codeResponse: TheaterAreaGroupModel? = null
-
override suspend fun saveNowMovieList(movieList: MovieListModel) {
saveMovieListAs(TYPE_NOW, movieList)
favoriteMovieDao.updateAll(movieList.list.map { it.toFavoriteMovieEntity() })
@@ -111,14 +108,6 @@ class LocalDataSourceImpl @Inject constructor(
}
}
- override fun saveCodeList(response: TheaterAreaGroupModel) {
- codeResponse = response
- }
-
- override fun getCodeList(): TheaterAreaGroupModel? {
- return codeResponse
- }
-
override suspend fun addFavoriteMovie(movie: MovieModel) {
favoriteMovieDao.insertFavoriteMovie(movie.toFavoriteMovieEntity())
}
diff --git a/data/model/src/main/java/soup/movie/model/AreaModel.kt b/data/model/src/main/java/soup/movie/model/AreaModel.kt
deleted file mode 100644
index 7c2c464d1..000000000
--- a/data/model/src/main/java/soup/movie/model/AreaModel.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.model
-
-data class AreaModel(
- val code: String,
- val name: String,
-)
diff --git a/data/model/src/main/java/soup/movie/model/TheaterAreaGroupModel.kt b/data/model/src/main/java/soup/movie/model/TheaterAreaGroupModel.kt
deleted file mode 100644
index 705bce527..000000000
--- a/data/model/src/main/java/soup/movie/model/TheaterAreaGroupModel.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.model
-
-data class TheaterAreaGroupModel(
- val cgv: List,
- val lotte: List,
- val megabox: List,
-)
diff --git a/data/model/src/main/java/soup/movie/model/TheaterAreaModel.kt b/data/model/src/main/java/soup/movie/model/TheaterAreaModel.kt
deleted file mode 100644
index 61f74c4d6..000000000
--- a/data/model/src/main/java/soup/movie/model/TheaterAreaModel.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.model
-
-data class TheaterAreaModel(
- val area: AreaModel,
- val theaterList: List,
-)
diff --git a/data/model/src/main/java/soup/movie/model/TheaterModel.kt b/data/model/src/main/java/soup/movie/model/TheaterModel.kt
deleted file mode 100644
index 9a11c4550..000000000
--- a/data/model/src/main/java/soup/movie/model/TheaterModel.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.model
-
-data class TheaterModel(
- val id: String,
- val type: TheaterTypeModel,
- val code: String,
- val name: String,
- val lng: Double,
- val lat: Double,
-)
diff --git a/data/model/src/main/java/soup/movie/model/TheaterTypeModel.kt b/data/model/src/main/java/soup/movie/model/TheaterTypeModel.kt
deleted file mode 100644
index 3ce26188f..000000000
--- a/data/model/src/main/java/soup/movie/model/TheaterTypeModel.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2022 SOUP
- *
- * 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
- *
- * https://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 soup.movie.model
-
-enum class TheaterTypeModel {
- CGV,
- LOTTE,
- MEGABOX,
-}
diff --git a/data/network/api/src/main/java/soup/movie/data/network/RemoteDataSource.kt b/data/network/api/src/main/java/soup/movie/data/network/RemoteDataSource.kt
index b6199541e..f25d7a74a 100644
--- a/data/network/api/src/main/java/soup/movie/data/network/RemoteDataSource.kt
+++ b/data/network/api/src/main/java/soup/movie/data/network/RemoteDataSource.kt
@@ -17,7 +17,6 @@ package soup.movie.data.network
import soup.movie.data.network.response.MovieDetailResponse
import soup.movie.data.network.response.MovieListResponse
-import soup.movie.data.network.response.TheaterAreaGroupResponse
interface RemoteDataSource {
@@ -31,7 +30,4 @@ interface RemoteDataSource {
// 영화 상세정보
suspend fun getMovieDetail(movieId: String): MovieDetailResponse
-
- // 공통코드
- suspend fun getCodeList(): TheaterAreaGroupResponse
}
diff --git a/data/network/api/src/main/java/soup/movie/data/network/response/AreaResponse.kt b/data/network/api/src/main/java/soup/movie/data/network/response/AreaResponse.kt
deleted file mode 100644
index eacc72eba..000000000
--- a/data/network/api/src/main/java/soup/movie/data/network/response/AreaResponse.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.data.network.response
-
-import kotlinx.serialization.Serializable
-import soup.movie.model.AreaModel
-
-@Serializable
-class AreaResponse(
- val code: String,
- val name: String,
-)
-
-fun AreaResponse.asModel(): AreaModel {
- return AreaModel(
- code = code,
- name = name,
- )
-}
diff --git a/data/network/api/src/main/java/soup/movie/data/network/response/TheaterAreaGroupResponse.kt b/data/network/api/src/main/java/soup/movie/data/network/response/TheaterAreaGroupResponse.kt
deleted file mode 100644
index c10eaad54..000000000
--- a/data/network/api/src/main/java/soup/movie/data/network/response/TheaterAreaGroupResponse.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.data.network.response
-
-import kotlinx.serialization.Serializable
-import soup.movie.model.TheaterAreaGroupModel
-
-@Serializable
-class TheaterAreaGroupResponse(
- val lastUpdateTime: Long,
- val cgv: List = emptyList(),
- val lotte: List = emptyList(),
- val megabox: List = emptyList(),
-)
-
-fun TheaterAreaGroupResponse.asModel(): TheaterAreaGroupModel {
- return TheaterAreaGroupModel(
- cgv = cgv.map { it.asModel() },
- lotte = lotte.map { it.asModel() },
- megabox = megabox.map { it.asModel() },
- )
-}
diff --git a/data/network/api/src/main/java/soup/movie/data/network/response/TheaterAreaResponse.kt b/data/network/api/src/main/java/soup/movie/data/network/response/TheaterAreaResponse.kt
deleted file mode 100644
index 75c9e5d9c..000000000
--- a/data/network/api/src/main/java/soup/movie/data/network/response/TheaterAreaResponse.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.data.network.response
-
-import kotlinx.serialization.Serializable
-import soup.movie.model.TheaterAreaModel
-
-@Serializable
-class TheaterAreaResponse(
- val area: AreaResponse,
- val theaterList: List = emptyList(),
-)
-
-fun TheaterAreaResponse.asModel(): TheaterAreaModel {
- return TheaterAreaModel(
- area = area.asModel(),
- theaterList = theaterList.map { it.asModel() },
- )
-}
diff --git a/data/network/api/src/main/java/soup/movie/data/network/response/TheaterResponse.kt b/data/network/api/src/main/java/soup/movie/data/network/response/TheaterResponse.kt
deleted file mode 100644
index b0d0274d5..000000000
--- a/data/network/api/src/main/java/soup/movie/data/network/response/TheaterResponse.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.data.network.response
-
-import kotlinx.serialization.Serializable
-import soup.movie.model.TheaterModel
-import soup.movie.model.TheaterTypeModel
-
-@Serializable
-class TheaterResponse(
- val type: String,
- val code: String,
- val name: String,
- val lng: Double,
- val lat: Double,
-)
-
-fun TheaterResponse.asModel(): TheaterModel {
- return TheaterModel(
- id = "$type:$code",
- type = TheaterTypeParser.parse(type),
- code = code,
- name = name,
- lng = lng,
- lat = lat,
- )
-}
-
-private object TheaterTypeParser {
-
- fun parse(type: String): TheaterTypeModel {
- return when (type) {
- "C" -> TheaterTypeModel.CGV
- "L" -> TheaterTypeModel.LOTTE
- "M" -> TheaterTypeModel.MEGABOX
- else -> throw IllegalArgumentException("$type is not valid type.")
- }
- }
-}
diff --git a/data/network/impl/src/main/java/soup/movie/data/network/impl/MovieApiService.kt b/data/network/impl/src/main/java/soup/movie/data/network/impl/MovieApiService.kt
index 0cc15e7b1..dc0bed9d0 100644
--- a/data/network/impl/src/main/java/soup/movie/data/network/impl/MovieApiService.kt
+++ b/data/network/impl/src/main/java/soup/movie/data/network/impl/MovieApiService.kt
@@ -21,7 +21,6 @@ import retrofit2.http.Path
import soup.movie.data.network.impl.OkHttpInterceptors.HEADER_USE_CACHE
import soup.movie.data.network.response.MovieDetailResponse
import soup.movie.data.network.response.MovieListResponse
-import soup.movie.data.network.response.TheaterAreaGroupResponse
interface MovieApiService {
@@ -47,8 +46,4 @@ interface MovieApiService {
@Headers(HEADER_USE_CACHE)
@GET("detail/{movieId}.json")
suspend fun getMovieDetail(@Path("movieId") movieId: String): MovieDetailResponse
-
- // 공통코드
- @GET("code.json")
- suspend fun getCodeList(): TheaterAreaGroupResponse
}
diff --git a/data/network/impl/src/main/java/soup/movie/data/network/impl/RemoteDataSourceImpl.kt b/data/network/impl/src/main/java/soup/movie/data/network/impl/RemoteDataSourceImpl.kt
index bbbbc5185..b3319a4c8 100644
--- a/data/network/impl/src/main/java/soup/movie/data/network/impl/RemoteDataSourceImpl.kt
+++ b/data/network/impl/src/main/java/soup/movie/data/network/impl/RemoteDataSourceImpl.kt
@@ -18,7 +18,6 @@ package soup.movie.data.network.impl
import soup.movie.data.network.RemoteDataSource
import soup.movie.data.network.response.MovieDetailResponse
import soup.movie.data.network.response.MovieListResponse
-import soup.movie.data.network.response.TheaterAreaGroupResponse
import javax.inject.Inject
class RemoteDataSourceImpl @Inject constructor(
@@ -44,8 +43,4 @@ class RemoteDataSourceImpl @Inject constructor(
override suspend fun getMovieDetail(movieId: String): MovieDetailResponse {
return apiService.getMovieDetail(movieId)
}
-
- override suspend fun getCodeList(): TheaterAreaGroupResponse {
- return apiService.getCodeList()
- }
}
diff --git a/data/repository/api/src/main/java/soup/movie/data/repository/TheaterRepository.kt b/data/repository/api/src/main/java/soup/movie/data/repository/TheaterRepository.kt
deleted file mode 100644
index c0c2c2e18..000000000
--- a/data/repository/api/src/main/java/soup/movie/data/repository/TheaterRepository.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2022 SOUP
- *
- * 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
- *
- * https://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 soup.movie.data.repository
-
-import soup.movie.model.TheaterAreaGroupModel
-
-interface TheaterRepository {
- suspend fun getCodeList(): TheaterAreaGroupModel
-}
diff --git a/data/repository/impl/src/main/java/soup/movie/data/repository/impl/TheaterRepositoryImpl.kt b/data/repository/impl/src/main/java/soup/movie/data/repository/impl/TheaterRepositoryImpl.kt
deleted file mode 100644
index 0490b0b14..000000000
--- a/data/repository/impl/src/main/java/soup/movie/data/repository/impl/TheaterRepositoryImpl.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2022 SOUP
- *
- * 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
- *
- * https://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 soup.movie.data.repository.impl
-
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.withContext
-import soup.movie.common.IoDispatcher
-import soup.movie.data.database.LocalDataSource
-import soup.movie.data.network.RemoteDataSource
-import soup.movie.data.network.response.asModel
-import soup.movie.data.repository.TheaterRepository
-import soup.movie.model.TheaterAreaGroupModel
-import javax.inject.Inject
-
-class TheaterRepositoryImpl @Inject constructor(
- private val local: LocalDataSource,
- private val remote: RemoteDataSource,
- @IoDispatcher private val ioDispatcher: CoroutineDispatcher,
-) : TheaterRepository {
-
- override suspend fun getCodeList(): TheaterAreaGroupModel {
- return withContext(ioDispatcher) {
- local.getCodeList() ?: remote.getCodeList().asModel().also {
- local.saveCodeList(it)
- }
- }
- }
-}
diff --git a/data/repository/impl/src/main/java/soup/movie/data/repository/impl/di/RepositoryModule.kt b/data/repository/impl/src/main/java/soup/movie/data/repository/impl/di/RepositoryModule.kt
index 6f13d4336..ee6741874 100644
--- a/data/repository/impl/src/main/java/soup/movie/data/repository/impl/di/RepositoryModule.kt
+++ b/data/repository/impl/src/main/java/soup/movie/data/repository/impl/di/RepositoryModule.kt
@@ -20,9 +20,7 @@ import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import soup.movie.data.repository.MovieRepository
-import soup.movie.data.repository.TheaterRepository
import soup.movie.data.repository.impl.MovieRepositoryImpl
-import soup.movie.data.repository.impl.TheaterRepositoryImpl
import javax.inject.Singleton
@Module
@@ -34,10 +32,4 @@ interface RepositoryModule {
fun provideMovieRepository(
movieRepositoryImpl: MovieRepositoryImpl,
): MovieRepository
-
- @Binds
- @Singleton
- fun provideTheaterRepository(
- theaterRepositoryImpl: TheaterRepositoryImpl,
- ): TheaterRepository
}
diff --git a/data/settings/api/src/main/java/soup/movie/data/settings/AppSettings.kt b/data/settings/api/src/main/java/soup/movie/data/settings/AppSettings.kt
index 301b54b0a..93f3c702a 100644
--- a/data/settings/api/src/main/java/soup/movie/data/settings/AppSettings.kt
+++ b/data/settings/api/src/main/java/soup/movie/data/settings/AppSettings.kt
@@ -16,7 +16,6 @@
package soup.movie.data.settings
import kotlinx.coroutines.flow.Flow
-import soup.movie.model.TheaterModel
import soup.movie.model.settings.AgeFilter
import soup.movie.model.settings.GenreFilter
import soup.movie.model.settings.TheaterFilter
@@ -35,8 +34,4 @@ interface AppSettings {
suspend fun setThemeOption(themeOption: String)
suspend fun getThemeOption(): String
fun getThemeOptionFlow(): Flow
-
- suspend fun setFavoriteTheaterList(list: List)
- suspend fun getFavoriteTheaterList(): List
- fun getFavoriteTheaterListFlow(): Flow>
}
diff --git a/data/settings/impl/src/main/java/soup/movie/data/settings/impl/AppSettingsImpl.kt b/data/settings/impl/src/main/java/soup/movie/data/settings/impl/AppSettingsImpl.kt
index 1e73f42ad..0a05eebb4 100644
--- a/data/settings/impl/src/main/java/soup/movie/data/settings/impl/AppSettingsImpl.kt
+++ b/data/settings/impl/src/main/java/soup/movie/data/settings/impl/AppSettingsImpl.kt
@@ -23,25 +23,28 @@ import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
+import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.encodeToString
-import kotlinx.serialization.json.Json
+import soup.movie.common.ApplicationScope
+import soup.movie.common.IoDispatcher
import soup.movie.data.settings.AppSettings
-import soup.movie.model.TheaterModel
-import soup.movie.model.TheaterTypeModel
import soup.movie.model.settings.AgeFilter
import soup.movie.model.settings.GenreFilter
import soup.movie.model.settings.TheaterFilter
-
-class AppSettingsImpl(
- private val context: Context,
- private val ioDispatcher: CoroutineDispatcher,
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class AppSettingsImpl @Inject constructor(
+ @ApplicationContext private val context: Context,
+ @IoDispatcher private val ioDispatcher: CoroutineDispatcher,
+ @ApplicationScope private val coroutineScope: CoroutineScope,
) : AppSettings {
private val Context.preferencesName: String
@@ -56,6 +59,12 @@ class AppSettingsImpl(
private val theaterFilterKey = intPreferencesKey("theater_filter")
+ init {
+ coroutineScope.launch {
+ clearFavoriteTheaterList()
+ }
+ }
+
override suspend fun setTheaterFilter(theaterFilter: TheaterFilter) {
context.dataStore.edit { settings ->
settings[theaterFilterKey] = theaterFilter.toFlags()
@@ -125,27 +134,10 @@ class AppSettingsImpl(
private val favoriteTheaterListKey = stringPreferencesKey("favorite_theaters")
- override suspend fun setFavoriteTheaterList(list: List) {
+ private suspend fun clearFavoriteTheaterList() {
withContext(ioDispatcher) {
context.dataStore.edit { settings ->
- val rawList = list.map { it.toRaw() }
- settings[favoriteTheaterListKey] = Json.encodeToString(rawList)
- }
- }
- }
-
- override suspend fun getFavoriteTheaterList(): List {
- return getFavoriteTheaterListFlow().first()
- }
-
- override fun getFavoriteTheaterListFlow(): Flow> {
- return context.dataStore.data.map { preferences ->
- val string = preferences[favoriteTheaterListKey]
- if (string != null) {
- val rawList: List = Json.decodeFromString(string)
- rawList.map { it.toModel() }
- } else {
- emptyList()
+ settings.remove(favoriteTheaterListKey)
}
}
}
@@ -155,31 +147,3 @@ class AppSettingsImpl(
private const val SEPARATOR = "|"
}
}
-
-@Serializable
-private data class RawTheater(
- val id: String,
- val type: String,
- val code: String,
- val name: String,
- val lng: Double,
- val lat: Double,
-) {
- fun toModel() = TheaterModel(
- id = id,
- type = TheaterTypeModel.valueOf(type),
- code = code,
- name = name,
- lng = lng,
- lat = lat,
- )
-}
-
-private fun TheaterModel.toRaw() = RawTheater(
- id = id,
- type = type.name,
- code = code,
- name = name,
- lng = lng,
- lat = lat,
-)
diff --git a/data/settings/impl/src/main/java/soup/movie/data/settings/impl/di/DataSettingsModule.kt b/data/settings/impl/src/main/java/soup/movie/data/settings/impl/di/DataSettingsModule.kt
index a3e3a41e0..a64030685 100644
--- a/data/settings/impl/src/main/java/soup/movie/data/settings/impl/di/DataSettingsModule.kt
+++ b/data/settings/impl/src/main/java/soup/movie/data/settings/impl/di/DataSettingsModule.kt
@@ -15,28 +15,19 @@
*/
package soup.movie.data.settings.impl.di
-import android.content.Context
+import dagger.Binds
import dagger.Module
-import dagger.Provides
import dagger.hilt.InstallIn
-import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
-import kotlinx.coroutines.CoroutineDispatcher
-import soup.movie.common.IoDispatcher
import soup.movie.data.settings.AppSettings
import soup.movie.data.settings.impl.AppSettingsImpl
-import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
-class DataSettingsModule {
+interface DataSettingsModule {
- @Singleton
- @Provides
- fun provideAppSettings(
- @ApplicationContext context: Context,
- @IoDispatcher ioDispatcher: CoroutineDispatcher,
- ): AppSettings {
- return AppSettingsImpl(context, ioDispatcher)
- }
+ @Binds
+ fun bindAppSettings(
+ impl: AppSettingsImpl,
+ ): AppSettings
}
diff --git a/feature/settings/build.gradle b/feature/settings/build.gradle
index f6f818612..31b5b59fe 100644
--- a/feature/settings/build.gradle
+++ b/feature/settings/build.gradle
@@ -15,7 +15,6 @@ dependencies {
implementation projects.core.resources
implementation projects.data.settings.api
implementation projects.data.model
- implementation projects.feature.theater
implementation projects.feature.theme.api
implementation libs.kotlin.stdlib
diff --git a/feature/settings/src/main/java/soup/movie/feature/settings/SettingsNavGraph.kt b/feature/settings/src/main/java/soup/movie/feature/settings/SettingsNavGraph.kt
index 085aa41f2..a4a68c5a4 100644
--- a/feature/settings/src/main/java/soup/movie/feature/settings/SettingsNavGraph.kt
+++ b/feature/settings/src/main/java/soup/movie/feature/settings/SettingsNavGraph.kt
@@ -22,18 +22,12 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import soup.compose.material.motion.animation.materialSharedAxisZIn
import soup.compose.material.motion.animation.materialSharedAxisZOut
-import soup.movie.feature.theater.edit.TheaterEditScreen
-import soup.movie.feature.theater.edit.TheaterEditViewModel
-import soup.movie.feature.theater.sort.TheaterSortScreen
-import soup.movie.feature.theater.sort.TheaterSortViewModel
import soup.movie.feature.theme.ThemeEntry
import soup.movie.feature.theme.rememberThemeEntry
private enum class Screen(val route: String) {
Settings("SettingsScreen"),
ThemeOption("ThemeEditScreen"),
- TheaterSort("TheaterSortScreen"),
- TheaterEdit("TheaterEditScreen"),
}
@Composable
@@ -54,33 +48,11 @@ fun SettingsNavGraph() {
onThemeEditClick = {
navController.navigate(Screen.ThemeOption.route)
},
- onTheaterEditClick = {
- navController.navigate(Screen.TheaterSort.route)
- },
)
}
composable(Screen.ThemeOption.route) {
val entry: ThemeEntry = rememberThemeEntry()
entry.ThemeOptionScreen()
}
- composable(Screen.TheaterSort.route) {
- val viewModel = hiltViewModel()
- TheaterSortScreen(
- viewModel = viewModel,
- upPress = {
- navController.navigateUp()
- },
- onAddItemClick = {
- navController.navigate(Screen.TheaterEdit.route)
- },
- )
- }
- composable(Screen.TheaterEdit.route) {
- val viewModel = hiltViewModel()
- TheaterEditScreen(
- viewModel = viewModel,
- upPress = { navController.navigateUp() },
- )
- }
}
}
diff --git a/feature/settings/src/main/java/soup/movie/feature/settings/SettingsScreen.kt b/feature/settings/src/main/java/soup/movie/feature/settings/SettingsScreen.kt
index 9149a8186..a56ef403d 100644
--- a/feature/settings/src/main/java/soup/movie/feature/settings/SettingsScreen.kt
+++ b/feature/settings/src/main/java/soup/movie/feature/settings/SettingsScreen.kt
@@ -15,12 +15,8 @@
*/
package soup.movie.feature.settings
-import android.content.Context
-import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.ExperimentalLayoutApi
-import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
@@ -43,30 +39,21 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import soup.movie.core.designsystem.UnelevatedButton
import soup.movie.core.designsystem.icon.MovieIcons
import soup.movie.core.designsystem.theme.MovieTheme
import soup.movie.core.designsystem.util.debounce
-import soup.movie.core.external.Cgv
-import soup.movie.core.external.LotteCinema
-import soup.movie.core.external.Megabox
-import soup.movie.feature.theater.TheaterChip
import soup.movie.feature.theme.stringResIdOf
-import soup.movie.model.TheaterModel
-import soup.movie.model.TheaterTypeModel
import soup.movie.resources.R
@Composable
internal fun SettingsScreen(
viewModel: SettingsViewModel,
onThemeEditClick: () -> Unit,
- onTheaterEditClick: () -> Unit,
) {
Scaffold(
modifier = Modifier,
@@ -76,9 +63,7 @@ internal fun SettingsScreen(
)
},
) { paddingValues ->
- val context = LocalContext.current
val theme by viewModel.themeUiModel.collectAsState()
- val theater by viewModel.theaterUiModel.collectAsState()
Column(
modifier = Modifier
.padding(paddingValues)
@@ -87,12 +72,6 @@ internal fun SettingsScreen(
) {
SettingsThemeItem(theme, onClick = onThemeEditClick)
SettingsDivider()
- SettingsTheaterItem(
- theater?.theaterList.orEmpty(),
- onItemClick = { theater -> context.executeWeb(theater) },
- onEditClick = onTheaterEditClick,
- )
- SettingsDivider()
}
}
}
@@ -149,56 +128,6 @@ private fun SettingsThemeItem(
}
}
-@OptIn(ExperimentalLayoutApi::class)
-@Composable
-private fun SettingsTheaterItem(
- theaterList: List,
- onItemClick: (TheaterModel) -> Unit,
- onEditClick: () -> Unit,
-) {
- Column(
- modifier = Modifier.padding(top = 12.dp, bottom = 24.dp),
- ) {
- Row(
- modifier = Modifier.fillMaxWidth(),
- verticalAlignment = Alignment.CenterVertically,
- ) {
- SettingsCategory(
- text = stringResource(R.string.settings_category_theater),
- modifier = Modifier.weight(1f),
- )
- IconButton(
- onClick = { debounce(onEditClick) },
- modifier = Modifier.size(48.dp),
- ) {
- Icon(
- MovieIcons.Edit,
- contentDescription = null,
- tint = MovieTheme.colors.onBackground,
- )
- }
- }
- Spacer(modifier = Modifier.height(12.dp))
- Box {
- if (theaterList.isEmpty()) {
- Text(
- text = stringResource(R.string.settings_theater_empty_description),
- textAlign = TextAlign.Center,
- style = MovieTheme.typography.body2,
- )
- } else {
- FlowRow(
- horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start),
- ) {
- theaterList.forEach { theater ->
- TheaterChip(theater, onItemClick)
- }
- }
- }
- }
- }
-}
-
@Composable
private fun SettingsCategory(
text: String,
@@ -217,11 +146,3 @@ private fun SettingsCategory(
private fun SettingsDivider() {
Divider(color = MovieTheme.colors.divider)
}
-
-private fun Context.executeWeb(theater: TheaterModel) {
- return when (theater.type) {
- TheaterTypeModel.CGV -> Cgv.executeWeb(this, theater.code)
- TheaterTypeModel.LOTTE -> LotteCinema.executeWeb(this, theater.code)
- TheaterTypeModel.MEGABOX -> Megabox.executeWeb(this, theater.code)
- }
-}
diff --git a/feature/settings/src/main/java/soup/movie/feature/settings/SettingsUiModel.kt b/feature/settings/src/main/java/soup/movie/feature/settings/SettingsUiModel.kt
index 8f2f801c6..c7c6d6878 100644
--- a/feature/settings/src/main/java/soup/movie/feature/settings/SettingsUiModel.kt
+++ b/feature/settings/src/main/java/soup/movie/feature/settings/SettingsUiModel.kt
@@ -17,16 +17,10 @@ package soup.movie.feature.settings
import androidx.annotation.Keep
import soup.movie.feature.theme.ThemeOption
-import soup.movie.model.TheaterModel
-sealed class SettingsUiModel
-
-@Keep
-data class TheaterSettingUiModel(
- val theaterList: List,
-) : SettingsUiModel()
+sealed interface SettingsUiModel
@Keep
data class ThemeSettingUiModel(
val themeOption: ThemeOption,
-)
+) : SettingsUiModel
diff --git a/feature/settings/src/main/java/soup/movie/feature/settings/SettingsViewModel.kt b/feature/settings/src/main/java/soup/movie/feature/settings/SettingsViewModel.kt
index 8de7602d4..ba8d8cef1 100644
--- a/feature/settings/src/main/java/soup/movie/feature/settings/SettingsViewModel.kt
+++ b/feature/settings/src/main/java/soup/movie/feature/settings/SettingsViewModel.kt
@@ -43,14 +43,4 @@ class SettingsViewModel @Inject constructor(
initialValue = null,
started = SharingStarted.WhileSubscribed(5_000),
)
-
- val theaterUiModel: StateFlow =
- appSettings.getFavoriteTheaterListFlow()
- .map { TheaterSettingUiModel(it) }
- .distinctUntilChanged()
- .stateIn(
- scope = viewModelScope,
- initialValue = null,
- started = SharingStarted.WhileSubscribed(5_000),
- )
}
diff --git a/feature/theater/.gitignore b/feature/theater/.gitignore
deleted file mode 100644
index 42afabfd2..000000000
--- a/feature/theater/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
\ No newline at end of file
diff --git a/feature/theater/build.gradle b/feature/theater/build.gradle
deleted file mode 100644
index 0d085ac20..000000000
--- a/feature/theater/build.gradle
+++ /dev/null
@@ -1,29 +0,0 @@
-plugins {
- id "moop.android.library"
- id "moop.android.compose"
- id "moop.android.hilt"
-}
-
-android {
- namespace "soup.movie.feature.theater"
-}
-
-dependencies {
- implementation projects.core.kotlin
- implementation projects.core.designsystem
- implementation projects.core.logger
- implementation projects.core.resources
- implementation projects.data.settings.api
- implementation projects.data.repository.api
- implementation projects.data.model
-
- implementation libs.kotlin.stdlib
-
- implementation libs.androidx.activity.compose
- implementation libs.compose.foundation
- implementation libs.compose.material
- implementation libs.compose.ui
-
- testImplementation projects.testing
- androidTestImplementation projects.testing
-}
diff --git a/feature/theater/src/main/AndroidManifest.xml b/feature/theater/src/main/AndroidManifest.xml
deleted file mode 100644
index cc947c567..000000000
--- a/feature/theater/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/DraggableList.kt b/feature/theater/src/main/java/soup/movie/feature/theater/DraggableList.kt
deleted file mode 100644
index 8d99c675f..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/DraggableList.kt
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater
-
-import androidx.compose.foundation.gestures.detectDragGestures
-import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
-import androidx.compose.foundation.lazy.LazyListItemInfo
-import androidx.compose.foundation.lazy.LazyListState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.input.pointer.pointerInput
-
-interface DraggableListState {
- fun onDragStart(offset: Offset)
- fun onDragStart(index: Int)
- fun onDrag(offset: Offset)
- fun onDragEnd()
- fun onDragCancel()
- fun getItemState(index: Int): DraggableItemState
-}
-
-@Stable
-data class DraggableItemState(
- val dragging: Boolean,
- val offset: Offset,
- val zIndex: Float,
-)
-
-@Composable
-fun rememberDraggableListState(
- lazyListState: LazyListState,
- onMove: (fromIndex: Int, toIndex: Int) -> Unit,
-): DraggableListState {
- val onMoveState = rememberUpdatedState(onMove)
- return remember(lazyListState) {
- DefaultDraggableListState(lazyListState = lazyListState, onMove = onMoveState.value)
- }
-}
-
-fun Modifier.draggableList(
- listState: DraggableListState,
-): Modifier = pointerInput(Unit) {
- detectDragGesturesAfterLongPress(
- onDragStart = { offset ->
- listState.onDragStart(offset)
- },
- onDrag = { change, offset ->
- change.consume()
- listState.onDrag(offset)
- },
- onDragEnd = {
- listState.onDragEnd()
- },
- onDragCancel = {
- listState.onDragCancel()
- },
- )
-}
-
-fun Modifier.draggableItem(
- index: Int,
- listState: DraggableListState,
-): Modifier = pointerInput(Unit) {
- detectDragGestures(
- onDragStart = {
- listState.onDragStart(index)
- },
- onDrag = { change, offset ->
- change.consume()
- listState.onDrag(offset)
- },
- onDragEnd = {
- listState.onDragEnd()
- },
- onDragCancel = {
- listState.onDragCancel()
- },
- )
-}
-
-class DefaultDraggableListState(
- private val lazyListState: LazyListState,
- private val onMove: (fromIndex: Int, toIndex: Int) -> Unit,
-) : DraggableListState {
-
- private var draggingDistance by mutableStateOf(0f)
- private var draggingItem by mutableStateOf(null)
- private var currentIndexOfDraggingItem by mutableStateOf(null)
-
- private inline val LazyListItemInfo.offsetEnd: Int
- get() = offset + size
-
- private val visibleItemsInfo: List
- get() = lazyListState.layoutInfo.visibleItemsInfo
-
- override fun onDragStart(offset: Offset) {
- visibleItemsInfo
- .firstOrNull { offset.y.toInt() in it.offset..it.offsetEnd }
- ?.also {
- draggingItem = it
- currentIndexOfDraggingItem = it.index
- }
- }
-
- override fun onDragStart(index: Int) {
- visibleItemsInfo
- .find(absoluteIndex = index)
- ?.also {
- draggingItem = it
- currentIndexOfDraggingItem = it.index
- }
- }
-
- override fun onDrag(offset: Offset) {
- draggingDistance += offset.y
-
- val draggingItem = draggingItem ?: return
- val currentIndex = currentIndexOfDraggingItem ?: return
- val hovered = visibleItemsInfo.find(absoluteIndex = currentIndex) ?: return
- val startOffset = draggingItem.offset + draggingDistance
- val endOffset = draggingItem.offsetEnd + draggingDistance
- visibleItemsInfo
- .filterNot { item -> startOffset > item.offsetEnd || item.offset > endOffset || hovered.index == item.index }
- .firstOrNull { item ->
- if (startOffset <= hovered.offset) {
- startOffset < item.offset
- } else {
- endOffset > item.offsetEnd
- }
- }?.also { item ->
- onMove(currentIndex, item.index)
- currentIndexOfDraggingItem = item.index
- }
- }
-
- override fun onDragEnd() {
- resetDraggingState()
- }
-
- override fun onDragCancel() {
- resetDraggingState()
- }
-
- override fun getItemState(index: Int): DraggableItemState {
- val isDraggingItem = index == currentIndexOfDraggingItem
- val offset = if (isDraggingItem) {
- val hovered = visibleItemsInfo.find(absoluteIndex = index)
- if (hovered != null) {
- val offsetY = (draggingItem?.offset ?: 0) + draggingDistance - hovered.offset
- Offset(x = 0f, y = offsetY)
- } else {
- Offset.Zero
- }
- } else {
- Offset.Zero
- }
- return DraggableItemState(
- dragging = isDraggingItem,
- offset = offset,
- zIndex = if (isDraggingItem) 1f else 0f,
- )
- }
-
- private fun resetDraggingState() {
- draggingDistance = 0f
- draggingItem = null
- currentIndexOfDraggingItem = null
- }
-
- private fun List.find(absoluteIndex: Int): LazyListItemInfo? {
- return find { it.index == absoluteIndex }
- }
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/TheaterChip.kt b/feature/theater/src/main/java/soup/movie/feature/theater/TheaterChip.kt
deleted file mode 100644
index 5262c3998..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/TheaterChip.kt
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater
-
-import androidx.compose.foundation.BorderStroke
-import androidx.compose.material.Chip
-import androidx.compose.material.ChipDefaults
-import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.dp
-import soup.movie.core.designsystem.theme.MovieTheme
-import soup.movie.core.designsystem.util.debounce
-import soup.movie.model.TheaterModel
-import soup.movie.model.TheaterTypeModel
-
-@OptIn(ExperimentalMaterialApi::class)
-@Composable
-fun TheaterChip(
- theater: TheaterModel,
- onTheaterClick: (TheaterModel) -> Unit = {},
-) {
- when (theater.type) {
- TheaterTypeModel.CGV -> CgvChip(
- text = theater.name,
- onClick = { debounce { onTheaterClick(theater) } },
- )
- TheaterTypeModel.LOTTE -> LotteChip(
- text = theater.name,
- onClick = { debounce { onTheaterClick(theater) } },
- )
- TheaterTypeModel.MEGABOX -> MegaboxChip(
- text = theater.name,
- onClick = { debounce { onTheaterClick(theater) } },
- )
- }
-}
-
-@ExperimentalMaterialApi
-@Composable
-private fun CgvChip(
- text: String,
- onClick: () -> Unit = {},
- enabled: Boolean = true,
-) {
- Chip(
- onClick = onClick,
- enabled = enabled,
- border = BorderStroke(width = 1.dp, color = Color(0x229E9E9E)),
- colors = ChipDefaults.chipColors(
- backgroundColor = Color.White,
- contentColor = MovieTheme.colors.onCgv,
- ),
- ) {
- Text(
- text = text,
- fontWeight = FontWeight.Bold,
- )
- }
-}
-
-@OptIn(ExperimentalMaterialApi::class)
-@Composable
-private fun LotteChip(
- text: String,
- onClick: () -> Unit = {},
- enabled: Boolean = true,
-) {
- Chip(
- onClick = onClick,
- enabled = enabled,
- colors = ChipDefaults.chipColors(
- backgroundColor = Color(0xFFED1D24),
- contentColor = Color.White,
- ),
- ) {
- Text(
- text = text,
- fontWeight = FontWeight.Bold,
- )
- }
-}
-
-@OptIn(ExperimentalMaterialApi::class)
-@Composable
-private fun MegaboxChip(
- text: String,
- onClick: () -> Unit = {},
- enabled: Boolean = true,
-) {
- Chip(
- onClick = onClick,
- enabled = enabled,
- colors = ChipDefaults.chipColors(
- backgroundColor = Color(0xFF352263),
- contentColor = Color.White,
- ),
- ) {
- Text(
- text = text,
- fontWeight = FontWeight.Bold,
- )
- }
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/TheaterFilterChip.kt b/feature/theater/src/main/java/soup/movie/feature/theater/TheaterFilterChip.kt
deleted file mode 100644
index e294966d4..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/TheaterFilterChip.kt
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater
-
-import androidx.compose.foundation.BorderStroke
-import androidx.compose.foundation.Image
-import androidx.compose.material.ChipDefaults
-import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.FilterChip
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.dp
-import soup.movie.core.designsystem.icon.MovieIcons
-import soup.movie.core.designsystem.theme.MovieTheme
-import soup.movie.model.TheaterModel
-import soup.movie.model.TheaterTypeModel
-
-@OptIn(ExperimentalMaterialApi::class)
-@Composable
-internal fun TheaterFilterChip(
- theater: TheaterModel,
- checked: Boolean,
- onCheckedChange: (Boolean) -> Unit,
-) {
- when (theater.type) {
- TheaterTypeModel.CGV -> CgvFilterChip(
- text = theater.name,
- checked = checked,
- onCheckedChange = onCheckedChange,
- )
- TheaterTypeModel.LOTTE -> LotteFilterChip(
- text = theater.name,
- checked = checked,
- onCheckedChange = onCheckedChange,
- )
- TheaterTypeModel.MEGABOX -> MegaboxFilterChip(
- text = theater.name,
- checked = checked,
- onCheckedChange = onCheckedChange,
- )
- }
-}
-
-@ExperimentalMaterialApi
-@Composable
-private fun CgvFilterChip(
- text: String,
- checked: Boolean,
- onCheckedChange: (Boolean) -> Unit,
- enabled: Boolean = true,
-) {
- FilterChip(
- selected = checked,
- onClick = { onCheckedChange(!checked) },
- selectedIcon = {
- Image(
- MovieIcons.Check,
- contentDescription = null,
- colorFilter = ColorFilter.tint(MovieTheme.colors.onCgv),
- )
- },
- enabled = enabled,
- border = BorderStroke(width = 1.dp, color = Color(0x229E9E9E)),
- colors = ChipDefaults.filterChipColors(
- selectedBackgroundColor = MovieTheme.colors.cgv,
- selectedContentColor = MovieTheme.colors.onCgv,
- backgroundColor = Color(0x55FFFFFF),
- contentColor = Color(0x66000000),
- ),
- ) {
- Text(
- text = text,
- fontWeight = FontWeight.Bold,
- )
- }
-}
-
-@OptIn(ExperimentalMaterialApi::class)
-@Composable
-private fun LotteFilterChip(
- text: String,
- checked: Boolean,
- onCheckedChange: (Boolean) -> Unit,
- enabled: Boolean = true,
-) {
- FilterChip(
- selected = checked,
- onClick = { onCheckedChange(!checked) },
- selectedIcon = {
- Image(
- MovieIcons.Check,
- contentDescription = null,
- colorFilter = ColorFilter.tint(MovieTheme.colors.onLotte),
- )
- },
- enabled = enabled,
- colors = ChipDefaults.filterChipColors(
- selectedBackgroundColor = Color(0xFFED1D24),
- selectedContentColor = Color.White,
- backgroundColor = Color(0x66ED1D24),
- contentColor = Color(0x77FFFFFF),
- ),
- ) {
- Text(
- text = text,
- fontWeight = FontWeight.Bold,
- )
- }
-}
-
-@OptIn(ExperimentalMaterialApi::class)
-@Composable
-private fun MegaboxFilterChip(
- text: String,
- checked: Boolean,
- onCheckedChange: (Boolean) -> Unit,
- enabled: Boolean = true,
-) {
- FilterChip(
- selected = checked,
- onClick = { onCheckedChange(!checked) },
- selectedIcon = {
- Image(
- MovieIcons.Check,
- contentDescription = null,
- colorFilter = ColorFilter.tint(MovieTheme.colors.onMegabox),
- )
- },
- enabled = enabled,
- colors = ChipDefaults.filterChipColors(
- selectedBackgroundColor = Color(0xFF352263),
- selectedContentColor = Color.White,
- backgroundColor = Color(0x77352263),
- contentColor = Color(0x77FFFFFF),
- ),
- ) {
- Text(
- text = text,
- fontWeight = FontWeight.Bold,
- )
- }
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/di/TheaterEditDomainModule.kt b/feature/theater/src/main/java/soup/movie/feature/theater/di/TheaterEditDomainModule.kt
deleted file mode 100644
index 9eaf168ef..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/di/TheaterEditDomainModule.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater.di
-
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.android.components.ViewModelComponent
-import dagger.hilt.android.scopes.ViewModelScoped
-import soup.movie.data.repository.TheaterRepository
-import soup.movie.data.settings.AppSettings
-import soup.movie.feature.theater.edit.TheaterEditManager
-
-@Module
-@InstallIn(ViewModelComponent::class)
-class TheaterEditDomainModule {
-
- @Provides
- @ViewModelScoped
- fun provideTheaterEditManager(
- repository: TheaterRepository,
- appSettings: AppSettings,
- ): TheaterEditManager {
- return TheaterEditManager(
- repository,
- appSettings,
- )
- }
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/edit/PagerTab.kt b/feature/theater/src/main/java/soup/movie/feature/theater/edit/PagerTab.kt
deleted file mode 100644
index e362af6d2..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/edit/PagerTab.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2024 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater.edit
-
-import androidx.compose.foundation.pager.HorizontalPager
-import androidx.compose.foundation.pager.PagerState
-import androidx.compose.foundation.pager.VerticalPager
-import androidx.compose.material.ScrollableTabRow
-import androidx.compose.material.TabPosition
-import androidx.compose.material.TabRow
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.layout.layout
-import androidx.compose.ui.unit.Constraints
-import androidx.compose.ui.unit.lerp
-
-/**
- * From https://github.com/google/accompanist/tree/main/pager-indicators
- *
- * This indicator syncs up a [TabRow] or [ScrollableTabRow] tab indicator with a
- * [HorizontalPager] or [VerticalPager].
- */
-fun Modifier.pagerTabIndicatorOffset(
- pagerState: PagerState,
- tabPositions: List,
- pageIndexMapping: (Int) -> Int = { it },
-): Modifier {
- val stateBridge = object : PagerStateBridge {
- override val currentPage: Int
- get() = pagerState.currentPage
- override val currentPageOffset: Float
- get() = pagerState.currentPageOffsetFraction
- }
-
- return pagerTabIndicatorOffset(stateBridge, tabPositions, pageIndexMapping)
-}
-
-private fun Modifier.pagerTabIndicatorOffset(
- pagerState: PagerStateBridge,
- tabPositions: List,
- pageIndexMapping: (Int) -> Int = { it },
-): Modifier = layout { measurable, constraints ->
- if (tabPositions.isEmpty()) {
- // If there are no pages, nothing to show
- layout(constraints.maxWidth, 0) {}
- } else {
- val currentPage = minOf(tabPositions.lastIndex, pageIndexMapping(pagerState.currentPage))
- val currentTab = tabPositions[currentPage]
- val previousTab = tabPositions.getOrNull(currentPage - 1)
- val nextTab = tabPositions.getOrNull(currentPage + 1)
- val fraction = pagerState.currentPageOffset
- val indicatorWidth = if (fraction > 0 && nextTab != null) {
- lerp(currentTab.width, nextTab.width, fraction).roundToPx()
- } else if (fraction < 0 && previousTab != null) {
- lerp(currentTab.width, previousTab.width, -fraction).roundToPx()
- } else {
- currentTab.width.roundToPx()
- }
- val indicatorOffset = if (fraction > 0 && nextTab != null) {
- lerp(currentTab.left, nextTab.left, fraction).roundToPx()
- } else if (fraction < 0 && previousTab != null) {
- lerp(currentTab.left, previousTab.left, -fraction).roundToPx()
- } else {
- currentTab.left.roundToPx()
- }
- val placeable = measurable.measure(
- Constraints(
- minWidth = indicatorWidth,
- maxWidth = indicatorWidth,
- minHeight = 0,
- maxHeight = constraints.maxHeight,
- ),
- )
- layout(constraints.maxWidth, maxOf(placeable.height, constraints.minHeight)) {
- placeable.placeRelative(
- indicatorOffset,
- maxOf(constraints.minHeight - placeable.height, 0),
- )
- }
- }
-}
-
-internal interface PagerStateBridge {
- val currentPage: Int
- val currentPageOffset: Float
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditChildScreen.kt b/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditChildScreen.kt
deleted file mode 100644
index 2b0e7784b..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditChildScreen.kt
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater.edit
-
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.ExperimentalLayoutApi
-import androidx.compose.foundation.layout.FlowRow
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.items
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.dp
-import kotlinx.coroutines.launch
-import soup.movie.core.designsystem.showToast
-import soup.movie.core.designsystem.theme.MovieTheme
-import soup.movie.feature.theater.TheaterFilterChip
-import soup.movie.model.TheaterModel
-import soup.movie.resources.R
-
-@Composable
-internal fun CgvScreen(viewModel: TheaterEditViewModel) {
- val uiModel by viewModel.cgvUiModel.collectAsState(TheaterEditChildUiModel(emptyList()))
- TheaterEditChildScreen(
- uiModel = uiModel,
- onAddTheater = { viewModel.add(it) },
- onRemoveTheater = { viewModel.remove(it) },
- )
-}
-
-@Composable
-internal fun LotteScreen(viewModel: TheaterEditViewModel) {
- val uiModel by viewModel.lotteUiModel.collectAsState(TheaterEditChildUiModel(emptyList()))
- TheaterEditChildScreen(
- uiModel = uiModel,
- onAddTheater = { viewModel.add(it) },
- onRemoveTheater = { viewModel.remove(it) },
- )
-}
-
-@Composable
-internal fun MegaboxScreen(viewModel: TheaterEditViewModel) {
- val uiModel by viewModel.megaboxUiModel.collectAsState(TheaterEditChildUiModel(emptyList()))
- TheaterEditChildScreen(
- uiModel = uiModel,
- onAddTheater = { viewModel.add(it) },
- onRemoveTheater = { viewModel.remove(it) },
- )
-}
-
-@Composable
-private fun TheaterEditChildScreen(
- uiModel: TheaterEditChildUiModel,
- onAddTheater: (TheaterModel) -> Boolean,
- onRemoveTheater: (TheaterModel) -> Unit,
-) {
- val context = LocalContext.current
- val coroutineScope = rememberCoroutineScope()
- LazyColumn(
- modifier = Modifier.fillMaxSize(),
- contentPadding = PaddingValues(all = 8.dp),
- ) {
- items(uiModel.areaGroupList) { item ->
- TheaterAreaItem(
- item.title,
- item.theaterList,
- onCheckedChange = { theater, checked ->
- coroutineScope.launch {
- if (checked) {
- if (onAddTheater(theater).not()) {
- context.showToast(
- context.getString(
- R.string.theater_select_limit_description,
- TheaterEditManager.MAX_ITEMS,
- ),
- )
- }
- } else {
- onRemoveTheater(theater)
- }
- }
- },
- )
- }
- }
-}
-
-@OptIn(ExperimentalLayoutApi::class)
-@Composable
-private fun TheaterAreaItem(
- title: String,
- theaterList: List,
- onCheckedChange: (TheaterModel, Boolean) -> Unit,
-) {
- Column(modifier = Modifier.padding(vertical = 8.dp)) {
- Text(
- text = title,
- modifier = Modifier.padding(all = 8.dp),
- fontWeight = FontWeight.Bold,
- color = MovieTheme.colors.onBackground,
- style = MovieTheme.typography.subtitle1,
- )
- FlowRow(
- horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start),
- modifier = Modifier.padding(all = 4.dp),
- ) {
- theaterList.forEach { item ->
- TheaterFilterChip(
- item.theater,
- checked = item.checked,
- onCheckedChange = { checked -> onCheckedChange(item.theater, checked) },
- )
- }
- }
- }
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditManager.kt b/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditManager.kt
deleted file mode 100644
index ed002c499..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditManager.kt
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater.edit
-
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.runBlocking
-import soup.movie.data.repository.TheaterRepository
-import soup.movie.data.settings.AppSettings
-import soup.movie.model.TheaterAreaGroupModel
-import soup.movie.model.TheaterAreaModel
-import soup.movie.model.TheaterModel
-
-class TheaterEditManager(
- private val repository: TheaterRepository,
- private val appSettings: AppSettings,
-) {
-
- private val cgvSubject = MutableStateFlow>(emptyList())
- private val lotteSubject = MutableStateFlow>(emptyList())
- private val megaboxSubject = MutableStateFlow>(emptyList())
- private val selectedTheatersChannel = MutableStateFlow>(emptyList())
-
- private var theaterList: List = emptyList()
- private var selectedItemSet: MutableSet = mutableSetOf()
-
- fun asCgvFlow(): Flow> = cgvSubject
-
- fun asLotteFlow(): Flow> = lotteSubject
-
- fun asMegaboxFlow(): Flow> = megaboxSubject
-
- fun asSelectedTheaterListFlow(): Flow> = selectedTheatersChannel
-
- suspend fun loadAsync(): TheaterAreaGroupModel {
- setupSelectedList()
- return repository.getCodeList().also {
- setupTotalList(it)
- cgvSubject.value = it.cgv
- lotteSubject.value = it.lotte
- megaboxSubject.value = it.megabox
- }
- }
-
- private fun setupTotalList(group: TheaterAreaGroupModel) {
- theaterList = group.run {
- (cgv + lotte + megabox).flatMap(TheaterAreaModel::theaterList)
- }
- }
-
- private fun setupSelectedList() {
- // TODO: Avoid blocking threads on DataStore
- selectedItemSet = runBlocking { appSettings.getFavoriteTheaterList() }.toMutableSet()
- selectedTheatersChannel.value = selectedItemSet.asSequence()
- .sortedBy { it.type }
- .toList()
- }
-
- private fun updateSelectedItemCount() {
- selectedTheatersChannel.value = theaterList.asSequence()
- .filter {
- selectedItemSet.any { selectedItem ->
- selectedItem == it
- }
- }
- .sortedBy { it.type }
- .toList()
- }
-
- fun add(theater: TheaterModel): Boolean {
- val isUnderLimit = selectedItemSet.size < MAX_ITEMS
- if (isUnderLimit) {
- selectedItemSet.add(theater)
- updateSelectedItemCount()
- }
- return isUnderLimit
- }
-
- fun remove(theater: TheaterModel) {
- selectedItemSet.remove(theater)
- updateSelectedItemCount()
- }
-
- fun save() {
- // TODO: Avoid blocking threads on DataStore
- runBlocking {
- appSettings.setFavoriteTheaterList(
- theaterList.asSequence()
- .filter {
- selectedItemSet.any { selectedItem ->
- selectedItem.id == it.id
- }
- }
- .sortedBy { it.type }
- .toList(),
- )
- }
- }
-
- companion object {
-
- const val MAX_ITEMS = 10
- }
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditScreen.kt b/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditScreen.kt
deleted file mode 100644
index e8e15a969..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditScreen.kt
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater.edit
-
-import android.view.MotionEvent
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.ExperimentalLayoutApi
-import androidx.compose.foundation.layout.FlowRow
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.requiredHeight
-import androidx.compose.foundation.layout.requiredSize
-import androidx.compose.foundation.pager.HorizontalPager
-import androidx.compose.foundation.pager.rememberPagerState
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.BottomSheetScaffold
-import androidx.compose.material.BottomSheetState
-import androidx.compose.material.CircularProgressIndicator
-import androidx.compose.material.Divider
-import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.Icon
-import androidx.compose.material.Surface
-import androidx.compose.material.Tab
-import androidx.compose.material.TabRow
-import androidx.compose.material.TabRowDefaults
-import androidx.compose.material.Text
-import androidx.compose.material.rememberBottomSheetScaffoldState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.ExperimentalComposeUiApi
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.shadow
-import androidx.compose.ui.input.pointer.pointerInteropFilter
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import soup.movie.core.designsystem.icon.MovieIcons
-import soup.movie.core.designsystem.theme.MovieTheme
-import soup.movie.core.designsystem.util.debounce
-import soup.movie.feature.theater.TheaterChip
-import soup.movie.model.TheaterModel
-import soup.movie.resources.R
-
-private enum class Page(val title: String) {
- CGV("CGV"),
- Lotte("롯데시네마"),
- Megabox("메가박스"),
- ;
-
- companion object {
- fun of(page: Int): Page {
- return when (page) {
- 0 -> CGV
- 1 -> Lotte
- else -> Megabox
- }
- }
- }
-}
-
-@OptIn(
- ExperimentalComposeUiApi::class,
- ExperimentalMaterialApi::class,
- ExperimentalFoundationApi::class,
-)
-@Composable
-fun TheaterEditScreen(
- viewModel: TheaterEditViewModel,
- upPress: () -> Unit,
-) {
- val pages = Page.values()
- val pagerState = rememberPagerState(pageCount = { pages.size })
- val coroutineScope = rememberCoroutineScope()
- val bottomSheetScaffoldState = rememberBottomSheetScaffoldState()
- FirstLaunchedEffect {
- delay(500)
- bottomSheetScaffoldState.bottomSheetState.expand()
- delay(500)
- bottomSheetScaffoldState.bottomSheetState.collapse()
- }
- BottomSheetScaffold(
- scaffoldState = bottomSheetScaffoldState,
- topBar = {
- TabRow(
- selectedTabIndex = pagerState.currentPage,
- indicator = { tabPositions ->
- TabRowDefaults.Indicator(
- modifier = Modifier.pagerTabIndicatorOffset(pagerState, tabPositions),
- color = MovieTheme.colors.secondary,
- )
- },
- modifier = Modifier.shadow(elevation = 4.dp),
- ) {
- pages.forEachIndexed { index, page ->
- Tab(
- text = { Text(page.title) },
- selected = pagerState.currentPage == index,
- onClick = {
- coroutineScope.launch {
- pagerState.animateScrollToPage(index)
- }
- },
- selectedContentColor = MovieTheme.colors.secondary,
- unselectedContentColor = MovieTheme.colors.onBackground,
- )
- }
- }
- },
- sheetPeekHeight = 60.dp,
- sheetElevation = if (MovieTheme.colors.isLight) 16.dp else 0.dp,
- sheetContent = {
- val uiModel by viewModel.footerUiModel.collectAsState(
- TheaterEditFooterUiModel(emptyList()),
- )
- TheaterEditFooter(
- uiModel = uiModel,
- onClick = {
- coroutineScope.launch {
- bottomSheetScaffoldState.bottomSheetState.toggle()
- }
- },
- onTheaterClick = {
- viewModel.remove(it)
- },
- onConfirmClick = {
- viewModel.onConfirmClick()
- upPress()
- },
- )
- },
- ) { paddingValues ->
- Box(
- modifier = Modifier
- .padding(paddingValues)
- .pointerInteropFilter {
- if (it.action == MotionEvent.ACTION_DOWN) {
- if (bottomSheetScaffoldState.bottomSheetState.isExpanded) {
- coroutineScope.launch {
- bottomSheetScaffoldState.bottomSheetState.collapse()
- }
- return@pointerInteropFilter true
- }
- }
- false
- },
- ) {
- HorizontalPager(state = pagerState) { page ->
- when (Page.of(page)) {
- Page.CGV -> CgvScreen(viewModel)
- Page.Lotte -> LotteScreen(viewModel)
- Page.Megabox -> MegaboxScreen(viewModel)
- }
- }
- val viewState by viewModel.contentUiModel.collectAsState(
- TheaterEditContentUiModel.LoadingState,
- )
- if (viewState is TheaterEditContentUiModel.LoadingState) {
- CircularProgressIndicator(
- color = MovieTheme.colors.secondary,
- modifier = Modifier.align(Alignment.Center),
- )
- }
- }
- }
-}
-
-@Composable
-private fun TheaterEditFooter(
- uiModel: TheaterEditFooterUiModel,
- onClick: () -> Unit,
- onTheaterClick: (TheaterModel) -> Unit,
- onConfirmClick: () -> Unit,
-) {
- Column(
- modifier = Modifier.clickable(
- onClick = { debounce(onClick) },
- interactionSource = remember { MutableInteractionSource() },
- indication = null,
- ),
- ) {
- TheaterEditFooterPeek(
- currentCount = uiModel.theaterList.size,
- isFull = uiModel.isFull(),
- onConfirmClick = onConfirmClick,
- )
- TheaterEditFooterContents(
- theaterList = uiModel.theaterList,
- onTheaterClick = onTheaterClick,
- )
- }
-}
-
-@OptIn(ExperimentalMaterialApi::class)
-@Composable
-private fun TheaterEditFooterPeek(
- currentCount: Int,
- isFull: Boolean,
- onConfirmClick: () -> Unit,
-) {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .requiredHeight(60.dp),
- verticalAlignment = Alignment.CenterVertically,
- ) {
- Text(
- text = "자주가는 극장은 최대 10개까지\n선택할 수 있습니다.",
- modifier = Modifier
- .padding(horizontal = 16.dp)
- .weight(1f),
- fontSize = 14.sp,
- color = MovieTheme.colors.onSurface,
- )
- Surface(
- onClick = { debounce(onConfirmClick) },
- modifier = Modifier
- .padding(end = 8.dp)
- .requiredSize(100.dp, 36.dp),
- shape = RoundedCornerShape(percent = 50),
- color = if (isFull) MovieTheme.colors.error else MovieTheme.colors.secondary,
- ) {
- Row(verticalAlignment = Alignment.CenterVertically) {
- Icon(
- MovieIcons.Check,
- contentDescription = null,
- modifier = Modifier.padding(start = 8.dp),
- )
- // TODO: Ticker Animation
- Text(
- text = currentCount.toString(),
- modifier = Modifier
- .padding(end = 6.dp)
- .weight(1f),
- fontSize = 14.sp,
- fontWeight = FontWeight.Bold,
- textAlign = TextAlign.End,
- )
- Text(
- text = "/ 10",
- modifier = Modifier.padding(end = 16.dp),
- fontSize = 14.sp,
- )
- }
- }
- }
-}
-
-@OptIn(ExperimentalLayoutApi::class)
-@Composable
-private fun TheaterEditFooterContents(
- theaterList: List,
- onTheaterClick: (TheaterModel) -> Unit,
-) {
- Box(
- modifier = Modifier
- .fillMaxWidth()
- .requiredHeight(180.dp),
- ) {
- Divider(color = MovieTheme.colors.divider)
- if (theaterList.isEmpty()) {
- Text(
- text = stringResource(R.string.theater_empty_description),
- modifier = Modifier.align(Alignment.Center),
- textAlign = TextAlign.Center,
- style = MovieTheme.typography.body2,
- )
- } else {
- FlowRow(
- modifier = Modifier.padding(all = 16.dp),
- horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start),
- verticalArrangement = Arrangement.spacedBy(8.dp, Alignment.Top),
- ) {
- theaterList.forEach { theater ->
- TheaterChip(theater, onTheaterClick)
- }
- }
- }
- }
-}
-
-@Composable
-private fun FirstLaunchedEffect(block: suspend CoroutineScope.() -> Unit) {
- var first by rememberSaveable { mutableStateOf(true) }
- LaunchedEffect(Unit) {
- if (first) {
- first = false
- block()
- }
- }
-}
-
-@ExperimentalMaterialApi
-private suspend fun BottomSheetState.toggle() {
- if (isCollapsed) {
- expand()
- } else {
- collapse()
- }
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditUiModel.kt b/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditUiModel.kt
deleted file mode 100644
index d8bb6ae8a..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditUiModel.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater.edit
-
-import androidx.annotation.Keep
-import soup.movie.model.TheaterModel
-
-sealed class TheaterEditContentUiModel {
-
- @Keep
- data object LoadingState : TheaterEditContentUiModel()
-
- @Keep
- data object ErrorState : TheaterEditContentUiModel()
-
- @Keep
- data object DoneState : TheaterEditContentUiModel()
-}
-
-@Keep
-data class TheaterEditChildUiModel(
- val areaGroupList: List,
-)
-
-@Keep
-data class TheaterEditAreaGroupUiModel(
- val title: String,
- val theaterList: List,
-)
-
-@Keep
-data class TheaterEditTheaterUiModel(
- val theater: TheaterModel,
- val checked: Boolean,
-)
-
-@Keep
-data class TheaterEditFooterUiModel(
- val theaterList: List,
-) {
-
- fun isFull(): Boolean = theaterList.size >= TheaterEditManager.MAX_ITEMS
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditViewModel.kt b/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditViewModel.kt
deleted file mode 100644
index f49ab7cec..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/edit/TheaterEditViewModel.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater.edit
-
-import androidx.lifecycle.ViewModel
-import dagger.hilt.android.lifecycle.HiltViewModel
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.withContext
-import soup.movie.common.DefaultDispatcher
-import soup.movie.log.Logger
-import soup.movie.model.TheaterAreaModel
-import soup.movie.model.TheaterModel
-import javax.inject.Inject
-
-@HiltViewModel
-class TheaterEditViewModel @Inject constructor(
- private val manager: TheaterEditManager,
- @DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher,
-) : ViewModel() {
-
- val contentUiModel = flow {
- emit(TheaterEditContentUiModel.LoadingState)
- try {
- manager.loadAsync()
- emit(TheaterEditContentUiModel.DoneState)
- } catch (t: Throwable) {
- Logger.w(t)
- emit(TheaterEditContentUiModel.ErrorState)
- }
- }
-
- val cgvUiModel = combine(
- manager.asCgvFlow(),
- manager.asSelectedTheaterListFlow(),
- ) { cgv, selectedList ->
- cgv.toUiModel(selectedList)
- }
-
- val lotteUiModel = combine(
- manager.asLotteFlow(),
- manager.asSelectedTheaterListFlow(),
- ) { lotte, selectedList ->
- lotte.toUiModel(selectedList)
- }
-
- val megaboxUiModel = combine(
- manager.asMegaboxFlow(),
- manager.asSelectedTheaterListFlow(),
- ) { megabox, selectedList ->
- megabox.toUiModel(selectedList)
- }
-
- val footerUiModel = manager.asSelectedTheaterListFlow()
- .map { TheaterEditFooterUiModel(it) }
-
- fun add(theater: TheaterModel): Boolean {
- return manager.add(theater)
- }
-
- fun remove(theater: TheaterModel) {
- manager.remove(theater)
- }
-
- fun onConfirmClick() {
- manager.save()
- }
-
- private suspend fun List.toUiModel(selectedList: List) =
- withContext(defaultDispatcher) {
- TheaterEditChildUiModel(
- map { theaterArea ->
- TheaterEditAreaGroupUiModel(
- title = theaterArea.area.name,
- theaterList = theaterArea.theaterList.map { theater ->
- TheaterEditTheaterUiModel(
- theater = theater,
- checked = selectedList.any { it.id == theater.id },
- )
- },
- )
- },
- )
- }
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/sort/MutableList.kt b/feature/theater/src/main/java/soup/movie/feature/theater/sort/MutableList.kt
deleted file mode 100644
index 0cd59d9b7..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/sort/MutableList.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater.sort
-
-fun MutableList.swap(i: Int, j: Int) {
- // instead of using a raw type here, it's possible to capture
- // the wildcard but it will require a call to a supplementary
- // private method
- this[i] = set(j, this[i])
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/sort/TheaterSortScreen.kt b/feature/theater/src/main/java/soup/movie/feature/theater/sort/TheaterSortScreen.kt
deleted file mode 100644
index 829ff000e..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/sort/TheaterSortScreen.kt
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater.sort
-
-import androidx.activity.compose.BackHandler
-import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.itemsIndexed
-import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.material.FloatingActionButton
-import androidx.compose.material.Icon
-import androidx.compose.material.Scaffold
-import androidx.compose.material.Text
-import androidx.compose.material.TopAppBar
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.graphicsLayer
-import androidx.compose.ui.layout.ContentScale
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.zIndex
-import kotlinx.coroutines.launch
-import soup.movie.core.designsystem.icon.MovieIcons
-import soup.movie.core.designsystem.theme.MovieTheme
-import soup.movie.core.designsystem.util.debounce
-import soup.movie.feature.theater.TheaterChip
-import soup.movie.feature.theater.draggableItem
-import soup.movie.feature.theater.draggableList
-import soup.movie.feature.theater.rememberDraggableListState
-import soup.movie.model.TheaterModel
-import soup.movie.resources.R
-
-@Composable
-fun TheaterSortScreen(
- viewModel: TheaterSortViewModel,
- upPress: () -> Unit,
- onAddItemClick: () -> Unit,
-) {
- val coroutineScope = rememberCoroutineScope()
- BackHandler {
- coroutineScope.launch {
- viewModel.saveSnapshot()
- upPress()
- }
- }
- Scaffold(
- topBar = {
- TopAppBar(
- title = { Text(text = stringResource(R.string.theater_sort_title)) },
- )
- },
- floatingActionButton = {
- FloatingActionButton(onClick = { debounce(onAddItemClick) }) {
- Icon(
- MovieIcons.Add,
- contentDescription = stringResource(R.string.theater_select_action_confirm),
- )
- }
- },
- ) { paddingValues ->
- val selectedTheaters = viewModel.selectedTheaters
- val modifier = Modifier
- .fillMaxSize()
- .padding(paddingValues)
-
- if (selectedTheaters.isEmpty()) {
- TheaterSortNoItem(modifier)
- } else {
- TheaterSortReorderList(
- selectedTheaters,
- modifier = modifier,
- onMove = { fromPosition, toPosition ->
- viewModel.onItemMove(fromPosition, toPosition)
- },
- )
- }
- }
-}
-
-@Composable
-private fun TheaterSortNoItem(modifier: Modifier = Modifier) {
- Column(
- verticalArrangement = Arrangement.Center,
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier = modifier.fillMaxSize(),
- ) {
- Image(
- painterResource(MovieIcons.NoTheaters),
- contentDescription = null,
- modifier = Modifier
- .width(48.dp)
- .height(68.dp),
- colorFilter = ColorFilter.tint(color = MovieTheme.colors.onBackground),
- )
- Text(
- stringResource(R.string.theater_empty_description),
- color = MovieTheme.colors.onBackground,
- modifier = Modifier.padding(8.dp),
- )
- }
-}
-
-@Composable
-private fun TheaterSortReorderList(
- selectedTheaters: List,
- onMove: (fromIndex: Int, toIndex: Int) -> Unit,
- modifier: Modifier = Modifier,
-) {
- val lazyListState = rememberLazyListState()
- val draggableListState = rememberDraggableListState(lazyListState, onMove = onMove)
- LazyColumn(
- modifier = modifier.draggableList(draggableListState),
- state = lazyListState,
- ) {
- itemsIndexed(selectedTheaters) { index, theater ->
- val itemState = draggableListState.getItemState(index)
- val transY by animateFloatAsState(targetValue = itemState.offset.y)
- Row(
- verticalAlignment = Alignment.CenterVertically,
- modifier = Modifier
- .fillMaxWidth()
- .height(48.dp)
- .padding(horizontal = 12.dp)
- .graphicsLayer { translationY = transY }
- .zIndex(itemState.zIndex),
- ) {
- TheaterChip(theater)
- Spacer(modifier = Modifier.weight(1f))
- Image(
- MovieIcons.DragHandle,
- contentDescription = null,
- contentScale = ContentScale.Inside,
- modifier = Modifier
- .width(48.dp)
- .fillMaxHeight()
- .draggableItem(index, draggableListState),
- colorFilter = ColorFilter.tint(color = MovieTheme.colors.onBackground),
- )
- }
- }
- }
-}
diff --git a/feature/theater/src/main/java/soup/movie/feature/theater/sort/TheaterSortViewModel.kt b/feature/theater/src/main/java/soup/movie/feature/theater/sort/TheaterSortViewModel.kt
deleted file mode 100644
index 49fdb1331..000000000
--- a/feature/theater/src/main/java/soup/movie/feature/theater/sort/TheaterSortViewModel.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2021 SOUP
- *
- * 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
- *
- * https://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 soup.movie.feature.theater.sort
-
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import dagger.hilt.android.lifecycle.HiltViewModel
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import soup.movie.data.settings.AppSettings
-import soup.movie.model.TheaterModel
-import javax.inject.Inject
-
-@HiltViewModel
-class TheaterSortViewModel @Inject constructor(
- private val appSettings: AppSettings,
-) : ViewModel() {
-
- private var listSnapshot = mutableListOf()
-
- var selectedTheaters by mutableStateOf>(emptyList())
- private set
-
- init {
- appSettings.getFavoriteTheaterListFlow()
- .distinctUntilChanged()
- .onEach { updateTheaters(it) }
- .launchIn(viewModelScope)
- }
-
- private fun updateTheaters(it: List) {
- listSnapshot = it.toMutableList()
- selectedTheaters = it
- }
-
- fun onItemMove(fromPosition: Int, toPosition: Int) {
- listSnapshot.swap(fromPosition, toPosition)
- updateTheaters(listSnapshot)
- }
-
- suspend fun saveSnapshot() {
- appSettings.setFavoriteTheaterList(listSnapshot.toList())
- }
-}