Accessibility
This commit is contained in:
@@ -17,6 +17,8 @@ android {
|
||||
targetSdk = 37
|
||||
versionName project.hasProperty('VERSION_NAME') ? project.property('VERSION_NAME') : "1.4"
|
||||
versionCode project.hasProperty('VERSION_CODE') ? project.property('VERSION_CODE').toInteger() : 1
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
@@ -74,6 +76,18 @@ android {
|
||||
testOptions {
|
||||
unitTests {
|
||||
includeAndroidResources = true
|
||||
all {
|
||||
maxParallelForks = 2
|
||||
forkEvery = 50
|
||||
maxHeapSize = "1024m"
|
||||
// Robolectric loads classes through its own sandbox classloader, which leaves them
|
||||
// without a code-source location. Without this JaCoCo skips them entirely and the
|
||||
// report only sees the handful of plain JVM classes.
|
||||
jacoco {
|
||||
includeNoLocationClasses = true
|
||||
excludes = ["jdk.internal.*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,6 +150,14 @@ dependencies {
|
||||
testImplementation 'org.robolectric:robolectric:4.16.1'
|
||||
testImplementation 'androidx.test:core:1.7.0'
|
||||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.11.0'
|
||||
testImplementation 'androidx.compose.ui:ui-test-junit4'
|
||||
|
||||
androidTestImplementation platform('androidx.compose:compose-bom:2026.08.00')
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
|
||||
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
|
||||
androidTestImplementation 'io.mockk:mockk-android:1.14.11'
|
||||
debugImplementation 'androidx.compose.ui:ui-test-manifest'
|
||||
}
|
||||
|
||||
tasks.register('jacocoTestReport', JacocoReport) {
|
||||
|
||||
@@ -48,7 +48,7 @@ fun AboutScreen(
|
||||
title = { Text(stringResource(R.string.title_about)) },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
|
||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
||||
}
|
||||
},
|
||||
backgroundColor = MaterialTheme.colors.primary,
|
||||
|
||||
@@ -48,7 +48,7 @@ import java.util.Locale
|
||||
|
||||
class AccountActivity : AppCompatActivity() {
|
||||
|
||||
private val viewModel: AccountViewModel by viewModels()
|
||||
internal val viewModel: AccountViewModel by viewModels()
|
||||
|
||||
companion object {
|
||||
private val TAG = AccountActivity::class.java.simpleName
|
||||
|
||||
@@ -34,7 +34,7 @@ import java.util.Calendar
|
||||
|
||||
class EditBillActivity : AppCompatActivity() {
|
||||
|
||||
private val viewModel: EditBillViewModel by viewModels()
|
||||
internal val viewModel: EditBillViewModel by viewModels()
|
||||
private lateinit var db: CowspentSQLiteOpenHelper
|
||||
private lateinit var bill: DBBill
|
||||
private var projectType: ProjectType = ProjectType.LOCAL
|
||||
|
||||
@@ -17,7 +17,7 @@ import net.helcel.cowspent.model.DBBill
|
||||
import net.helcel.cowspent.model.ProjectType
|
||||
|
||||
class LabelBillsActivity : AppCompatActivity() {
|
||||
private val viewModel: LabelBillsViewModel by viewModels()
|
||||
internal val viewModel: LabelBillsViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
enableEdgeToEdge()
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
@@ -223,7 +224,10 @@ fun BillSummaryCard(bill: DBBill, members: List<DBMember>, remainingCount: Int)
|
||||
fun CategoryButton(icon: String, name: String, onClick: () -> Unit) {
|
||||
OutlinedButton(
|
||||
onClick = onClick,
|
||||
modifier = Modifier.fillMaxWidth().height(60.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(60.dp)
|
||||
.testTag("CategoryButton_$name"),
|
||||
contentPadding = PaddingValues(2.dp)
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import net.helcel.cowspent.util.ICallback
|
||||
|
||||
class ManageCurrenciesActivity : AppCompatActivity() {
|
||||
|
||||
private val viewModel: ManageCurrenciesViewModel by viewModels()
|
||||
internal val viewModel: ManageCurrenciesViewModel by viewModels()
|
||||
private var db: CowspentSQLiteOpenHelper? = null
|
||||
private var selectedProjectID: Long = -1
|
||||
|
||||
|
||||
@@ -41,6 +41,8 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
@@ -216,7 +218,7 @@ fun ManageCurrenciesScreen(
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isEditing) Icons.Default.Done else Icons.Default.Add,
|
||||
contentDescription = null,
|
||||
contentDescription = if (isEditing) "Done" else "Add",
|
||||
tint = if (viewModel.isAddEnabled()) {
|
||||
if (isEditing) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||
} else MaterialTheme.colors.onSurface.copy(alpha = 0.2f)
|
||||
@@ -274,7 +276,9 @@ fun CurrencyRow(
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
elevation = if (isEditing) 4.dp else 1.dp,
|
||||
border = if (isEditing) BorderStroke(1.dp, MaterialTheme.colors.secondary.copy(alpha = 0.5f)) else null,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag("CurrencyRow_${currency.name}")
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@@ -320,7 +324,7 @@ fun CurrencyRow(
|
||||
IconButton(onClick = onDelete) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Delete,
|
||||
contentDescription = null,
|
||||
contentDescription = "Delete",
|
||||
tint = MaterialTheme.colors.error.copy(alpha = 0.7f),
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import net.helcel.cowspent.theme.ThemeUtils
|
||||
|
||||
class LabelManagementActivity : AppCompatActivity() {
|
||||
private val viewModel: LabelManagementViewModel by viewModels()
|
||||
internal val viewModel: LabelManagementViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
enableEdgeToEdge()
|
||||
|
||||
@@ -107,7 +107,7 @@ fun LabelManagementScreenContent(
|
||||
showEditDialog = true
|
||||
}
|
||||
}) {
|
||||
Icon(Icons.Default.Add, contentDescription = null)
|
||||
Icon(Icons.Default.Add, contentDescription = "Add Label")
|
||||
}
|
||||
}
|
||||
) { padding ->
|
||||
|
||||
@@ -293,7 +293,7 @@ fun BillsListScreen(
|
||||
isSearchExpanded = false
|
||||
viewModel.searchQuery = ""
|
||||
}) {
|
||||
Icon(Icons.Default.Close, contentDescription = null, tint = MaterialTheme.colors.onPrimary)
|
||||
Icon(Icons.Default.Close, contentDescription = stringResource(R.string.action_clear_search), tint = MaterialTheme.colors.onPrimary)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -322,13 +322,13 @@ fun BillsListScreen(
|
||||
isSearchExpanded = false
|
||||
viewModel.searchQuery = ""
|
||||
}) {
|
||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
|
||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.action_close_search))
|
||||
}
|
||||
} else {
|
||||
IconButton(onClick = {
|
||||
scope.launch { scaffoldState.drawerState.open() }
|
||||
}) {
|
||||
Icon(Icons.Default.Menu, contentDescription = null)
|
||||
Icon(Icons.Default.Menu, contentDescription = stringResource(R.string.action_open_menu))
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -343,7 +343,10 @@ fun BillsListScreen(
|
||||
}
|
||||
}
|
||||
IconButton(onClick = { isSearchExpanded = true }) {
|
||||
Icon(Icons.Default.Search, contentDescription = null)
|
||||
Icon(
|
||||
Icons.Default.Search,
|
||||
contentDescription = stringResource(R.string.action_search)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -63,7 +63,7 @@ class BillsListViewActivity :
|
||||
AppCompatActivity(),
|
||||
IRefreshBillsListCallback {
|
||||
|
||||
private val viewModel: BillsListViewModel by viewModels()
|
||||
internal val viewModel: BillsListViewModel by viewModels()
|
||||
|
||||
companion object {
|
||||
var DEBUG = false
|
||||
|
||||
@@ -31,7 +31,7 @@ import net.helcel.cowspent.android.project.ProjectImportHelper
|
||||
|
||||
class NewProjectActivity : AppCompatActivity() {
|
||||
|
||||
private val viewModel: NewProjectViewModel by viewModels()
|
||||
internal val viewModel: NewProjectViewModel by viewModels()
|
||||
private lateinit var db: CowspentSQLiteOpenHelper
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
@@ -23,7 +23,7 @@ import net.helcel.cowspent.android.main.MainConstants
|
||||
|
||||
class EditProjectActivity : AppCompatActivity() {
|
||||
|
||||
private val viewModel: EditProjectViewModel by viewModels()
|
||||
internal val viewModel: EditProjectViewModel by viewModels()
|
||||
private lateinit var db: CowspentSQLiteOpenHelper
|
||||
private lateinit var project: DBProject
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
@@ -100,6 +101,7 @@ fun MemberEditDialogContent(
|
||||
.fillMaxWidth()
|
||||
.clickable { isActivated = !isActivated }
|
||||
.padding(vertical = 8.dp)
|
||||
.testTag("member_activated_row")
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Block,
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import net.helcel.cowspent.theme.ThemeUtils
|
||||
|
||||
class MemberManagementActivity : AppCompatActivity() {
|
||||
|
||||
private val viewModel: MemberManagementViewModel by viewModels()
|
||||
internal val viewModel: MemberManagementViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
enableEdgeToEdge()
|
||||
|
||||
@@ -134,7 +134,7 @@ fun SettingsScreen(
|
||||
title = { Text(stringResource(R.string.action_settings)) },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
|
||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
||||
}
|
||||
},
|
||||
backgroundColor = MaterialTheme.colors.primary,
|
||||
@@ -401,13 +401,7 @@ fun SettingsListPreference(
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
RadioButton(
|
||||
selected = (key == value),
|
||||
onClick = {
|
||||
onValueChange(key)
|
||||
showDialog = false
|
||||
}
|
||||
)
|
||||
RadioButton(selected = (key == value), onClick = null)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(text = label)
|
||||
}
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ class ProjectStatisticsActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val EXTRA_PROJECT_ID = "extra_project_id"
|
||||
internal const val EXTRA_PROJECT_ID = "extra_project_id"
|
||||
|
||||
fun createIntent(context: Context, projectId: Long): Intent {
|
||||
return Intent(context, ProjectStatisticsActivity::class.java).apply {
|
||||
|
||||
@@ -86,7 +86,7 @@ class NextcloudClient(
|
||||
}
|
||||
|
||||
@Throws(TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||
private fun requestServerWithSSO(
|
||||
internal fun requestServerWithSSO(
|
||||
nextcloudAPI: NextcloudAPI,
|
||||
target: String,
|
||||
method: String,
|
||||
@@ -141,7 +141,7 @@ class NextcloudClient(
|
||||
}
|
||||
|
||||
@Throws(TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||
private fun imageRequestServerWithSSO(
|
||||
internal fun imageRequestServerWithSSO(
|
||||
nextcloudAPI: NextcloudAPI,
|
||||
target: String,
|
||||
method: String,
|
||||
@@ -182,7 +182,7 @@ class NextcloudClient(
|
||||
}
|
||||
|
||||
@Throws(IOException::class, NextcloudHttpRequestFailedException::class)
|
||||
private fun requestServer(
|
||||
internal fun requestServer(
|
||||
target: String,
|
||||
method: String, params: JSONObject?, lastETag: String?, needLogin: Boolean, isOCSRequest: Boolean
|
||||
): VersatileProjectSyncClient.ResponseData {
|
||||
@@ -248,7 +248,7 @@ class NextcloudClient(
|
||||
}
|
||||
|
||||
@Throws(IOException::class, NextcloudHttpRequestFailedException::class)
|
||||
private fun imageRequestServer(
|
||||
internal fun imageRequestServer(
|
||||
target: String,
|
||||
method: String, params: JSONObject?, lastETag: String?, needLogin: Boolean, isOCSRequest: Boolean
|
||||
): VersatileProjectSyncClient.ResponseData {
|
||||
|
||||
@@ -158,10 +158,18 @@ class VersatileProjectSyncClient(
|
||||
paramKeys.add("password")
|
||||
paramValues.add(newPassword)
|
||||
}
|
||||
if (newEmail != null) {
|
||||
paramKeys.add("contact_email")
|
||||
paramValues.add(newEmail)
|
||||
}
|
||||
if (newMainCurrencyName != null) {
|
||||
paramKeys.add("currencyName")
|
||||
paramValues.add(newMainCurrencyName)
|
||||
}
|
||||
if (newArchivedTs != null) {
|
||||
paramKeys.add("archivedTs")
|
||||
paramValues.add(newArchivedTs.toString())
|
||||
}
|
||||
}
|
||||
if (canAccessProjectWithNCLogin(project)) {
|
||||
username = this.username
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
<string name="action_edit">Edit</string>
|
||||
<string name="action_share">Share</string>
|
||||
<string name="action_search">Search</string>
|
||||
<string name="action_open_menu">Open menu</string>
|
||||
<string name="action_close_search">Close search</string>
|
||||
<string name="action_clear_search">Clear search</string>
|
||||
<string name="action_delete">Delete</string>
|
||||
<string name="action_archive">Archive</string>
|
||||
<string name="action_unarchive">Unarchive</string>
|
||||
|
||||
Reference in New Issue
Block a user