mirror of
https://github.com/wismna/DoNext.git
synced 2026-07-25 20:23:06 -04:00
Compare commits
5 Commits
150058437f
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7704d9280b | |||
| bbf9949e21 | |||
| 4f53d28f5c | |||
| 1db7d4f37f | |||
| 210b509132 |
@@ -33,9 +33,6 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
|
||||
- name: Run unit tests
|
||||
run: ./gradlew :donextv2:testDebugUnitTest
|
||||
|
||||
- name: Decode signing key
|
||||
run: echo "${{ secrets.SIGNING_KEY_BASE64 }}" | base64 --decode > ${{ env.MODULE }}/upload.jks
|
||||
|
||||
|
||||
Generated
-1
@@ -9,7 +9,6 @@
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/donext" />
|
||||
<option value="$PROJECT_DIR$/donextv2" />
|
||||
</set>
|
||||
</option>
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ buildscript {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("com.google.devtools.ksp") version '2.3.2' apply false
|
||||
id("com.google.devtools.ksp") version '2.3.10' apply false
|
||||
id("com.google.dagger.hilt.android") version "2.60.1" apply false
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("org.jetbrains.kotlin.plugin.compose")
|
||||
id("com.google.devtools.ksp")
|
||||
id("com.google.dagger.hilt.android")
|
||||
@@ -36,7 +35,7 @@ android {
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
getByName("debug").assets.srcDirs(files("$projectDir/schemas"))
|
||||
getByName("debug").assets.directories.add("$projectDir/schemas")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -56,11 +55,6 @@ android {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget = JvmTarget.JVM_11
|
||||
}
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
viewBinding = true
|
||||
@@ -78,6 +72,12 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget = JvmTarget.JVM_11
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.11.0")
|
||||
implementation("androidx.activity:activity-compose:1.13.0")
|
||||
@@ -91,6 +91,7 @@ dependencies {
|
||||
implementation("androidx.navigation:navigation-compose:2.9.8")
|
||||
implementation("androidx.hilt:hilt-navigation-compose:1.4.0")
|
||||
implementation("sh.calvin.reorderable:reorderable:3.1.0")
|
||||
implementation("androidx.datastore:datastore-preferences:1.2.1")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
testImplementation("io.mockk:mockk:1.14.11")
|
||||
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.11.0")
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.wismna.geoffroy.donext.data.injection
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
||||
import androidx.datastore.preferences.preferencesDataStoreFile
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object PreferencesModule {
|
||||
private const val SETTINGS_PREFERENCES_NAME = "settings"
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSettingsDataStore(
|
||||
@ApplicationContext context: Context
|
||||
): DataStore<Preferences> =
|
||||
PreferenceDataStoreFactory.create(
|
||||
produceFile = { context.preferencesDataStoreFile(SETTINGS_PREFERENCES_NAME) }
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.wismna.geoffroy.donext.data.injection
|
||||
|
||||
import com.wismna.geoffroy.donext.data.local.preferences.SettingsRepositoryImpl
|
||||
import com.wismna.geoffroy.donext.data.local.repository.TaskListRepositoryImpl
|
||||
import com.wismna.geoffroy.donext.data.local.repository.TaskRepositoryImpl
|
||||
import com.wismna.geoffroy.donext.domain.repository.SettingsRepository
|
||||
import com.wismna.geoffroy.donext.domain.repository.TaskListRepository
|
||||
import com.wismna.geoffroy.donext.domain.repository.TaskRepository
|
||||
import dagger.Binds
|
||||
@@ -22,4 +24,9 @@ abstract class RepositoryModule {
|
||||
abstract fun bindTaskListRepository(
|
||||
impl: TaskListRepositoryImpl
|
||||
): TaskListRepository
|
||||
|
||||
@Binds
|
||||
abstract fun bindSettingsRepository(
|
||||
impl: SettingsRepositoryImpl
|
||||
): SettingsRepository
|
||||
}
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.wismna.geoffroy.donext.data.local.preferences
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.emptyPreferences
|
||||
import androidx.datastore.preferences.core.longPreferencesKey
|
||||
import com.wismna.geoffroy.donext.domain.repository.SettingsRepository
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.first
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
class SettingsRepositoryImpl @Inject constructor(
|
||||
private val dataStore: DataStore<Preferences>
|
||||
) : SettingsRepository {
|
||||
override suspend fun getLastOpenedTaskListId(): Long? =
|
||||
dataStore.data
|
||||
.catch { e -> if (e is IOException) emit(emptyPreferences()) else throw e }
|
||||
.first()[LAST_OPENED_TASK_LIST_ID_KEY]
|
||||
|
||||
override suspend fun setLastOpenedTaskListId(taskListId: Long) {
|
||||
dataStore.edit { prefs -> prefs[LAST_OPENED_TASK_LIST_ID_KEY] = taskListId }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val LAST_OPENED_TASK_LIST_ID_KEY = longPreferencesKey("last_opened_task_list_id")
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package com.wismna.geoffroy.donext.domain.repository
|
||||
|
||||
interface SettingsRepository {
|
||||
suspend fun getLastOpenedTaskListId(): Long?
|
||||
suspend fun setLastOpenedTaskListId(taskListId: Long)
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.wismna.geoffroy.donext.domain.usecase
|
||||
|
||||
import com.wismna.geoffroy.donext.domain.repository.SettingsRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetLastOpenedTaskListIdUseCase @Inject constructor(
|
||||
private val repository: SettingsRepository
|
||||
) {
|
||||
suspend operator fun invoke(): Long? = repository.getLastOpenedTaskListId()
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.wismna.geoffroy.donext.domain.usecase
|
||||
|
||||
import com.wismna.geoffroy.donext.domain.repository.SettingsRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class SaveLastOpenedTaskListUseCase @Inject constructor(
|
||||
private val repository: SettingsRepository
|
||||
) {
|
||||
suspend operator fun invoke(taskListId: Long) = repository.setLastOpenedTaskListId(taskListId)
|
||||
}
|
||||
+22
-7
@@ -7,18 +7,20 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import com.wismna.geoffroy.donext.domain.model.AppDestination
|
||||
import com.wismna.geoffroy.donext.domain.usecase.GetLastOpenedTaskListIdUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.GetTaskListsUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.SaveLastOpenedTaskListUseCase
|
||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEvent
|
||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEventBus
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class MainViewModel @Inject constructor(
|
||||
getTaskListsUseCase: GetTaskListsUseCase,
|
||||
private val getLastOpenedTaskListIdUseCase: GetLastOpenedTaskListIdUseCase,
|
||||
private val saveLastOpenedTaskListUseCase: SaveLastOpenedTaskListUseCase,
|
||||
val uiEventBus: UiEventBus
|
||||
) : ViewModel() {
|
||||
|
||||
@@ -38,8 +40,9 @@ class MainViewModel @Inject constructor(
|
||||
var showAddListSheet by mutableStateOf(false)
|
||||
|
||||
init {
|
||||
getTaskListsUseCase()
|
||||
.onEach { lists ->
|
||||
viewModelScope.launch {
|
||||
val lastOpenedTaskListId = getLastOpenedTaskListIdUseCase()
|
||||
getTaskListsUseCase().collect { lists ->
|
||||
destinations = lists.map { taskList ->
|
||||
AppDestination.TaskList(taskList.id!!, taskList.name)
|
||||
} +
|
||||
@@ -47,11 +50,14 @@ class MainViewModel @Inject constructor(
|
||||
AppDestination.RecycleBin +
|
||||
AppDestination.DueTodayList
|
||||
if (startDestination == AppDestination.ManageLists && destinations.isNotEmpty()) {
|
||||
startDestination = destinations.first()
|
||||
startDestination = destinations
|
||||
.filterIsInstance<AppDestination.TaskList>()
|
||||
.firstOrNull { it.taskListId == lastOpenedTaskListId }
|
||||
?: destinations.first()
|
||||
}
|
||||
isLoading = false
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
}
|
||||
|
||||
fun navigateBack() {
|
||||
@@ -79,12 +85,21 @@ class MainViewModel @Inject constructor(
|
||||
val route = navBackStackEntry?.destination?.route
|
||||
val taskListId = navBackStackEntry?.arguments?.getLong("taskListId")
|
||||
|
||||
currentDestination = destinations.firstOrNull { dest ->
|
||||
val resolved = destinations.firstOrNull { dest ->
|
||||
when (dest) {
|
||||
is AppDestination.TaskList -> taskListId != null && dest.taskListId == taskListId
|
||||
else -> dest.route == route
|
||||
}
|
||||
} ?: startDestination
|
||||
|
||||
if (resolved != currentDestination) {
|
||||
currentDestination = resolved
|
||||
(resolved as? AppDestination.TaskList)?.let { taskList ->
|
||||
viewModelScope.launch {
|
||||
saveLastOpenedTaskListUseCase(taskList.taskListId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun doesListExist(taskListId: Long): Boolean {
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.wismna.geoffroy.donext.data.local.preferences
|
||||
|
||||
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class SettingsRepositoryImplTest {
|
||||
|
||||
@get:Rule
|
||||
val tempFolder = TemporaryFolder()
|
||||
|
||||
private fun createRepository(): SettingsRepositoryImpl {
|
||||
// DataStore's internal actor coroutine runs on this scope. A plain TestScope() uses
|
||||
// StandardTestDispatcher, which queues work that only runs when its own scheduler is
|
||||
// advanced — but nothing here ever advances it, so reads/writes deadlock forever.
|
||||
// UnconfinedTestDispatcher runs dispatched coroutines eagerly instead, so the actor
|
||||
// makes progress without needing to be pumped.
|
||||
val testDataStore = PreferenceDataStoreFactory.create(
|
||||
scope = TestScope(UnconfinedTestDispatcher()),
|
||||
produceFile = { tempFolder.newFile("test.preferences_pb") }
|
||||
)
|
||||
return SettingsRepositoryImpl(testDataStore)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getLastOpenedTaskListId returns null when nothing saved`() = runTest {
|
||||
assertThat(createRepository().getLastOpenedTaskListId()).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setLastOpenedTaskListId then get returns saved value`() = runTest {
|
||||
val repo = createRepository()
|
||||
repo.setLastOpenedTaskListId(42L)
|
||||
assertThat(repo.getLastOpenedTaskListId()).isEqualTo(42L)
|
||||
}
|
||||
}
|
||||
+115
-7
@@ -4,7 +4,9 @@ import androidx.navigation.NavBackStackEntry
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.wismna.geoffroy.donext.domain.model.AppDestination
|
||||
import com.wismna.geoffroy.donext.domain.model.TaskList
|
||||
import com.wismna.geoffroy.donext.domain.usecase.GetLastOpenedTaskListIdUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.GetTaskListsUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.SaveLastOpenedTaskListUseCase
|
||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEvent
|
||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEventBus
|
||||
import io.mockk.*
|
||||
@@ -23,8 +25,17 @@ class MainViewModelTest {
|
||||
private val uiEventBus: UiEventBus = mockk(relaxUnitFun = true)
|
||||
private lateinit var getTaskListsFlow: MutableSharedFlow<List<TaskList>>
|
||||
private lateinit var getTaskListsUseCase: GetTaskListsUseCase
|
||||
private lateinit var getLastOpenedTaskListIdUseCase: GetLastOpenedTaskListIdUseCase
|
||||
private val saveLastOpenedTaskListUseCase: SaveLastOpenedTaskListUseCase = mockk(relaxUnitFun = true)
|
||||
private lateinit var viewModel: MainViewModel
|
||||
|
||||
private fun createViewModel() = MainViewModel(
|
||||
getTaskListsUseCase,
|
||||
getLastOpenedTaskListIdUseCase,
|
||||
saveLastOpenedTaskListUseCase,
|
||||
uiEventBus
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
Dispatchers.setMain(dispatcher)
|
||||
@@ -32,6 +43,9 @@ class MainViewModelTest {
|
||||
getTaskListsUseCase = mockk {
|
||||
every { this@mockk.invoke() } returns getTaskListsFlow
|
||||
}
|
||||
getLastOpenedTaskListIdUseCase = mockk {
|
||||
coEvery { this@mockk.invoke() } returns null
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -41,14 +55,14 @@ class MainViewModelTest {
|
||||
|
||||
@Test
|
||||
fun `initially isLoading is true and destinations are empty`() = runTest {
|
||||
viewModel = MainViewModel(getTaskListsUseCase, uiEventBus)
|
||||
viewModel = createViewModel()
|
||||
assertThat(viewModel.isLoading).isTrue()
|
||||
assertThat(viewModel.destinations).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when task lists are emitted they populate destinations and isLoading becomes false`() = runTest {
|
||||
viewModel = MainViewModel(getTaskListsUseCase, uiEventBus)
|
||||
viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
|
||||
val lists = listOf(
|
||||
@@ -72,9 +86,45 @@ class MainViewModelTest {
|
||||
assertThat(viewModel.isLoading).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `starts on the last opened list when it still exists`() = runTest {
|
||||
getLastOpenedTaskListIdUseCase = mockk {
|
||||
coEvery { this@mockk.invoke() } returns 2L
|
||||
}
|
||||
viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
|
||||
val lists = listOf(
|
||||
TaskList(id = 1L, name = "Work", isDeleted = false, order = 0),
|
||||
TaskList(id = 2L, name = "Personal", isDeleted = false, order = 1)
|
||||
)
|
||||
getTaskListsFlow.emit(lists)
|
||||
advanceUntilIdle()
|
||||
|
||||
assertThat(viewModel.startDestination).isEqualTo(AppDestination.TaskList(2L, "Personal"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `falls back to the first list when the last opened list no longer exists`() = runTest {
|
||||
getLastOpenedTaskListIdUseCase = mockk {
|
||||
coEvery { this@mockk.invoke() } returns 99L
|
||||
}
|
||||
viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
|
||||
val lists = listOf(
|
||||
TaskList(id = 1L, name = "Work", isDeleted = false, order = 0),
|
||||
TaskList(id = 2L, name = "Personal", isDeleted = false, order = 1)
|
||||
)
|
||||
getTaskListsFlow.emit(lists)
|
||||
advanceUntilIdle()
|
||||
|
||||
assertThat(viewModel.startDestination).isEqualTo(AppDestination.TaskList(1L, "Work"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `navigateBack sends UiEvent_NavigateBack`() = runTest {
|
||||
viewModel = MainViewModel(getTaskListsUseCase, uiEventBus)
|
||||
viewModel = createViewModel()
|
||||
|
||||
viewModel.navigateBack()
|
||||
advanceUntilIdle()
|
||||
@@ -84,7 +134,7 @@ class MainViewModelTest {
|
||||
|
||||
@Test
|
||||
fun `onNewTaskButtonClicked sets showTaskSheet true and sends CreateNewTask`() = runTest {
|
||||
viewModel = MainViewModel(getTaskListsUseCase, uiEventBus)
|
||||
viewModel = createViewModel()
|
||||
val taskListId = 42L
|
||||
|
||||
viewModel.onNewTaskButtonClicked(taskListId)
|
||||
@@ -96,7 +146,7 @@ class MainViewModelTest {
|
||||
|
||||
@Test
|
||||
fun `onDismissTaskSheet sets showTaskSheet false and clears sticky`() = runTest {
|
||||
viewModel = MainViewModel(getTaskListsUseCase, uiEventBus)
|
||||
viewModel = createViewModel()
|
||||
|
||||
viewModel.showTaskSheet = true
|
||||
viewModel.onDismissTaskSheet()
|
||||
@@ -110,7 +160,7 @@ class MainViewModelTest {
|
||||
@Test
|
||||
fun `doesListExist returns true when taskListId is present`() = runTest {
|
||||
val lists = listOf(TaskList(id = 1L, name = "Work", isDeleted = false, order = 0))
|
||||
viewModel = MainViewModel(getTaskListsUseCase, uiEventBus)
|
||||
viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
getTaskListsFlow.emit(lists)
|
||||
advanceUntilIdle()
|
||||
@@ -122,7 +172,7 @@ class MainViewModelTest {
|
||||
@Test
|
||||
fun `setCurrentDestination sets currentDestination based on navBackStackEntry`() = runTest {
|
||||
val lists = listOf(TaskList(id = 1L, name = "Work", isDeleted = false, order = 0))
|
||||
viewModel = MainViewModel(getTaskListsUseCase, uiEventBus)
|
||||
viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
getTaskListsFlow.emit(lists)
|
||||
advanceUntilIdle()
|
||||
@@ -135,4 +185,62 @@ class MainViewModelTest {
|
||||
viewModel.setCurrentDestination(entry)
|
||||
assertThat(viewModel.currentDestination).isEqualTo(AppDestination.TaskList(1L, "Work"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setCurrentDestination saves the new list when navigating to a different TaskList`() = runTest {
|
||||
val lists = listOf(
|
||||
TaskList(id = 1L, name = "Work", isDeleted = false, order = 0),
|
||||
TaskList(id = 2L, name = "Personal", isDeleted = false, order = 1)
|
||||
)
|
||||
viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
getTaskListsFlow.emit(lists)
|
||||
advanceUntilIdle()
|
||||
|
||||
val entry = mockk<NavBackStackEntry> {
|
||||
every { destination.route } returns AppDestination.TaskList(2L, "Personal").route
|
||||
every { arguments?.getLong("taskListId") } returns 2L
|
||||
}
|
||||
|
||||
viewModel.setCurrentDestination(entry)
|
||||
advanceUntilIdle()
|
||||
|
||||
coVerify { saveLastOpenedTaskListUseCase(2L) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setCurrentDestination does not save when navigating to a non-list destination`() = runTest {
|
||||
viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
|
||||
val entry = mockk<NavBackStackEntry> {
|
||||
every { destination.route } returns AppDestination.RecycleBin.route
|
||||
every { arguments } returns null
|
||||
}
|
||||
|
||||
viewModel.setCurrentDestination(entry)
|
||||
advanceUntilIdle()
|
||||
|
||||
coVerify(exactly = 0) { saveLastOpenedTaskListUseCase(any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setCurrentDestination only saves once for repeated identical navigation`() = runTest {
|
||||
val lists = listOf(TaskList(id = 1L, name = "Work", isDeleted = false, order = 0))
|
||||
viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
getTaskListsFlow.emit(lists)
|
||||
advanceUntilIdle()
|
||||
|
||||
val entry = mockk<NavBackStackEntry> {
|
||||
every { destination.route } returns AppDestination.TaskList(1L, "Work").route
|
||||
every { arguments?.getLong("taskListId") } returns 1L
|
||||
}
|
||||
|
||||
viewModel.setCurrentDestination(entry)
|
||||
viewModel.setCurrentDestination(entry)
|
||||
advanceUntilIdle()
|
||||
|
||||
coVerify(exactly = 1) { saveLastOpenedTaskListUseCase(any()) }
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ platform :android do
|
||||
UI.user_error!("VersionCode #{gradle_version} should be higher than Play Store version (#{play_version}). Aborting upload.")
|
||||
end
|
||||
|
||||
gradle(task: "testDebugUnitTest")
|
||||
gradle(task: ":#{module_name}:testDebugUnitTest")
|
||||
gradle(task: "clean :#{module_name}:bundleRelease")
|
||||
upload_to_play_store(
|
||||
track: "internal",
|
||||
|
||||
+1
-2
@@ -16,12 +16,11 @@
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
android.builtInKotlin=false
|
||||
android.defaults.buildfeatures.resvalues=true
|
||||
android.dependency.excludeLibraryComponentsFromConstraints=true
|
||||
android.dependency.useConstraints=true
|
||||
android.enableAppCompileTimeRClass=false
|
||||
android.enableJetifier=false
|
||||
android.newDsl=false
|
||||
android.r8.optimizedResourceShrinking=false
|
||||
android.r8.strictFullModeForKeepRules=false
|
||||
android.sdk.defaultTargetSdkToCompileSdkIfUnset=false
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0'
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
|
||||
}
|
||||
include ':donext'
|
||||
//include ':donext'
|
||||
include ':donextv2'
|
||||
|
||||
Reference in New Issue
Block a user