Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ ij_kotlin_allow_trailing_comma_on_call_site = true
ij_kotlin_name_count_to_use_star_import = 2147483647
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
ij_kotlin_packages_to_use_import_on_demand = unset
ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than = 1
ij_kotlin_line_break_after_multiline_when_entry = false
ktlint_code_style = android_studio
ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than = 1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate of line 17.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from GrapheneOS/app-docs#2. Already fixed here and left a comment there.

Expand Down
45 changes: 45 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -521,10 +521,9 @@
android:theme="@style/BackgroundOnlyTheme"/>

<activity
android:name=".activities.SimImportActivity"
android:name=".ui.simimport.SimImportActivity"
android:label="@string/sim_import_title"
android:theme="@style/PeopleThemeAppCompat.FullScreenDialog.SimImportActivity"/>

android:theme="@style/Theme.Compose"/>

<service
android:name=".vcard.VCardService"
Expand Down
2 changes: 2 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
alias(libs.plugins.detekt)
alias(libs.plugins.hilt)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.ksp)
}

Expand Down Expand Up @@ -91,6 +92,7 @@ dependencies {
implementation(libs.androidx.appcompat)
implementation(libs.androidx.palette)
implementation(libs.androidx.swiperefreshlayout)
implementation(libs.accompanist.drawablepainter)

implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.activity.compose)
Expand Down
144 changes: 144 additions & 0 deletions app/src/test/kotlin/com/android/contacts/sim/SimImportScreenTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.android.contacts.sim

import androidx.compose.ui.test.ComposeUiTest
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.v2.runComposeUiTest
import com.android.contacts.tests.AccountUiModelFactory
import com.android.contacts.tests.SimContactUiModelFactory
import com.android.contacts.ui.common.model.SelectableItem
import com.android.contacts.ui.simimport.screen.SimImportEffectHandler
import com.android.contacts.ui.simimport.screen.SimImportScreen
import com.android.contacts.ui.simimport.screen.SimImportScreenModel
import com.android.contacts.ui.simimport.screen.model.SIM_IMPORT_ACCOUNT_PICKER_MENU_ITEM_TEST_TAG
import com.android.contacts.ui.simimport.screen.model.SIM_IMPORT_ACCOUNT_PICKER_TEST_TAG
import com.android.contacts.ui.simimport.screen.model.SIM_IMPORT_CONTACTS_TO_IMPORT_TITLE_TEST_TAG
import com.android.contacts.ui.simimport.screen.model.SIM_IMPORT_DESELECT_ALL_TEST_TAG
import com.android.contacts.ui.simimport.screen.model.SIM_IMPORT_IMPORT_BUTTON_TEST_TAG
import com.android.contacts.ui.simimport.screen.model.SIM_IMPORT_SELECT_ALL_TEST_TAG
import com.android.contacts.ui.simimport.screen.model.SimImportAction as Action
import com.android.contacts.ui.simimport.screen.model.SimImportUiState as State
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

@OptIn(ExperimentalTestApi::class)
@RunWith(RobolectricTestRunner::class)
class SimImportScreenTest {

private val fakeUiStateFlow = MutableStateFlow<State>(State.Loading)
private lateinit var screenModel: SimImportScreenModel
private lateinit var effectHandler: SimImportEffectHandler

@Before
fun setup() {
screenModel = mockk(relaxed = true)
effectHandler = mockk(relaxed = true)
every { screenModel.uiState } returns fakeUiStateFlow
}

@Test
fun showCurrentAccount() = runComposeUiTest {
val account = AccountUiModelFactory.build()
fakeUiStateFlow.value = State.Ready(
accounts = persistentListOf(account),
currentAccount = account,
)

setScreenContent()

onNodeWithText(account.name!!).assertIsDisplayed()
}

@Test
fun pickAnotherAccount() = runComposeUiTest {
val account1 = AccountUiModelFactory.build(name = "First")
val account2 = AccountUiModelFactory.build(name = "Second")
fakeUiStateFlow.value = State.Ready(
accounts = persistentListOf(account1, account2),
currentAccount = account1,
)

setScreenContent()

onNodeWithText(account1.name!!).assertIsDisplayed()
onNodeWithTag(SIM_IMPORT_ACCOUNT_PICKER_TEST_TAG).performClick()
onNode(
hasText(account2.name!!)
.and(hasTestTag(SIM_IMPORT_ACCOUNT_PICKER_MENU_ITEM_TEST_TAG)),
).performClick()
verify { screenModel.onAction(Action.AccountChanged(account2)) }
}

@Test
fun showContactToImport() = runComposeUiTest {
val account = AccountUiModelFactory.build()
val contact = SimContactUiModelFactory.build()
fakeUiStateFlow.value = State.Ready(
accounts = persistentListOf(account),
currentAccount = account,
contactsToImport = persistentListOf(SelectableItem(contact, false)),
contactsAlreadyImported = persistentListOf(),
)

setScreenContent()

onNodeWithTag(SIM_IMPORT_CONTACTS_TO_IMPORT_TITLE_TEST_TAG).assertIsDisplayed()
onNodeWithText(contact.label).assertIsDisplayed()
}

@Test
fun clickContact() = runComposeUiTest {
val account = AccountUiModelFactory.build()
val contact = SimContactUiModelFactory.build()
fakeUiStateFlow.value = State.Ready(
accounts = persistentListOf(account),
currentAccount = account,
contactsToImport = persistentListOf(SelectableItem(contact, false)),
contactsAlreadyImported = persistentListOf(),
)

setScreenContent()

onNodeWithText(contact.label).performClick()
verify { screenModel.onAction(Action.ContactSelectionChanged(contact, true)) }
}

@Test
fun checkTopBarActionsCanBeDisabled() = runComposeUiTest {
val account = AccountUiModelFactory.build()
fakeUiStateFlow.value = State.Ready(
accounts = persistentListOf(account),
currentAccount = account,
contactsToImport = persistentListOf(),
contactsAlreadyImported = persistentListOf(),
)

setScreenContent()

onNodeWithTag(SIM_IMPORT_IMPORT_BUTTON_TEST_TAG).assertIsNotEnabled()
onNodeWithTag(SIM_IMPORT_SELECT_ALL_TEST_TAG).assertIsNotEnabled()
onNodeWithTag(SIM_IMPORT_DESELECT_ALL_TEST_TAG).assertIsNotEnabled()
}

private fun ComposeUiTest.setScreenContent() {
setContent {
SimImportScreen(
effectHandler = effectHandler,
screenModel = screenModel,
)
}
}
}
Loading