Skip to content

Commit 5b1d55d

Browse files
committed
categories and tags relations
1 parent 656a530 commit 5b1d55d

File tree

49 files changed

+794
-62
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+794
-62
lines changed

app/src/androidTest/java/com/example/util/simpletimetracker/CategoriesTest.kt

Lines changed: 182 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package com.example.util.simpletimetracker
22

3+
import androidx.test.espresso.Espresso.onView
4+
import androidx.test.espresso.Espresso.pressBack
5+
import androidx.test.espresso.assertion.PositionAssertions.isCompletelyBelow
36
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
47
import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
58
import androidx.test.espresso.matcher.ViewMatchers.withId
69
import androidx.test.espresso.matcher.ViewMatchers.withText
710
import androidx.test.ext.junit.runners.AndroidJUnit4
11+
import com.example.util.simpletimetracker.SuggestionsTestUtils.suggestionMatcher
812
import com.example.util.simpletimetracker.utils.BaseUiTest
913
import com.example.util.simpletimetracker.utils.NavUtils
1014
import com.example.util.simpletimetracker.utils.checkViewDoesNotExist
@@ -13,14 +17,16 @@ import com.example.util.simpletimetracker.utils.checkViewIsNotDisplayed
1317
import com.example.util.simpletimetracker.utils.clickOnViewWithId
1418
import com.example.util.simpletimetracker.utils.clickOnViewWithText
1519
import com.example.util.simpletimetracker.utils.longClickOnViewWithId
20+
import com.example.util.simpletimetracker.utils.scrollRecyclerToView
1621
import com.example.util.simpletimetracker.utils.tryAction
1722
import com.example.util.simpletimetracker.utils.typeTextIntoView
1823
import dagger.hilt.android.testing.HiltAndroidTest
24+
import kotlinx.coroutines.runBlocking
1925
import org.hamcrest.CoreMatchers.allOf
2026
import org.junit.Test
2127
import org.junit.runner.RunWith
22-
import com.example.util.simpletimetracker.feature_dialogs.R as dialogsR
2328
import com.example.util.simpletimetracker.feature_categories.R as categoriesR
29+
import com.example.util.simpletimetracker.feature_dialogs.R as dialogsR
2430

2531
@HiltAndroidTest
2632
@RunWith(AndroidJUnit4::class)
@@ -170,8 +176,139 @@ class CategoriesTest : BaseUiTest() {
170176
}
171177
}
172178

179+
@Test
180+
fun showRelations() {
181+
val category1 = "category1"
182+
val category2 = "category2"
183+
val category3 = "category3"
184+
val tag1 = "tag1"
185+
val tag2 = "tag2"
186+
val tag3 = "tag3"
187+
val type1 = "type1"
188+
val type2 = "type2"
189+
val type3 = "type3"
190+
val type4 = "type4"
191+
192+
fun getRecordsCount(count: Int): String {
193+
return getString(
194+
R.string.separator_template,
195+
getString(R.string.archive_tagged_records_count),
196+
count,
197+
)
198+
}
199+
200+
// Add data
201+
testUtils.addCategory(category1)
202+
testUtils.addCategory(category2)
203+
testUtils.addCategory(category3)
204+
testUtils.addActivity(type1, categories = listOf(category1))
205+
testUtils.addActivity(type2, categories = listOf(category1))
206+
testUtils.addActivity(type3)
207+
testUtils.addActivity(type4, categories = listOf(category2))
208+
testUtils.addRecordTag(tag1, typeName = type2, defaultTypes = listOf(type3))
209+
testUtils.addRecordTag(tag2, typeName = type4)
210+
testUtils.addRecordTag(tag3)
211+
repeat(2) { testUtils.addRecord(type2, tagNames = listOf(tag1)) }
212+
repeat(4) { testUtils.addRecord(type4, tagNames = listOf(tag2)) }
213+
val categoriesMap = runBlocking { testUtils.categoryInteractor.getAll().associate { it.name to it.id } }
214+
val tagsMap = runBlocking { testUtils.recordTagInteractor.getAll().associate { it.name to it.id } }
215+
216+
// Enable relations
217+
NavUtils.openSettingsScreen()
218+
NavUtils.openCategoriesScreen()
219+
clickOnViewWithId(categoriesR.id.btnCategoriesOptions)
220+
clickOnViewWithText(R.string.categories_show_relations)
221+
Thread.sleep(1000)
222+
223+
// Check
224+
checkTagVisible(category1)
225+
checkRelation(
226+
relationNames = listOf(type1, type2),
227+
parentName = category1,
228+
nameToIdMap = categoriesMap,
229+
)
230+
checkTagVisible(category2)
231+
checkRelation(
232+
relationNames = listOf(type4),
233+
parentName = category2,
234+
nameToIdMap = categoriesMap,
235+
)
236+
checkTagVisible(category3)
237+
checkRelation(
238+
relationNames = listOf(getString(R.string.record_types_empty)),
239+
parentName = category3,
240+
nameToIdMap = categoriesMap,
241+
)
242+
checkTagVisible(tag1)
243+
checkRelation(
244+
relationNames = listOf(type2, getString(R.string.change_record_tag_default_hint), type3, getRecordsCount(2)),
245+
parentName = tag1,
246+
nameToIdMap = tagsMap,
247+
)
248+
checkTagVisible(tag2)
249+
checkRelation(
250+
relationNames = listOf(type4, getRecordsCount(4)),
251+
parentName = tag2,
252+
nameToIdMap = tagsMap,
253+
)
254+
checkTagVisible(tag3)
255+
checkRelation(
256+
relationNames = listOf(getString(R.string.change_record_tag_type_general), getRecordsCount(0)),
257+
parentName = tag3,
258+
nameToIdMap = tagsMap,
259+
)
260+
261+
// Persistence
262+
pressBack()
263+
NavUtils.openRecordsScreen()
264+
NavUtils.openSettingsScreen()
265+
NavUtils.openCategoriesScreen()
266+
checkTagVisible(category1)
267+
checkRelation(
268+
relationNames = listOf(type1, type2),
269+
parentName = category1,
270+
nameToIdMap = categoriesMap,
271+
)
272+
273+
// Search
274+
clickOnViewWithId(categoriesR.id.btnCategoriesOptions)
275+
clickOnViewWithText(R.string.enable_search_hint)
276+
typeTextIntoView(categoriesR.id.etCategoriesSearchField, type3)
277+
tryAction {
278+
checkTagVisible(tag1)
279+
checkTagNotVisible(category1, category2, tag2)
280+
checkRelationVisible(type2, type3)
281+
checkRelationNotVisible(type1, type4)
282+
}
283+
284+
// Filter
285+
typeTextIntoView(categoriesR.id.etCategoriesSearchField, "")
286+
longClickOnViewWithId(categoriesR.id.btnCategoriesOptions)
287+
clickOnViewWithText(type2)
288+
clickOnViewWithText(R.string.change_record_save)
289+
tryAction {
290+
checkTagVisible(category1)
291+
checkRelation(
292+
relationNames = listOf(type1, type2),
293+
parentName = category1,
294+
nameToIdMap = categoriesMap,
295+
)
296+
checkTagVisible(tag1)
297+
checkRelation(
298+
relationNames = listOf(type2, getString(R.string.change_record_tag_default_hint), type3),
299+
parentName = tag1,
300+
nameToIdMap = tagsMap,
301+
)
302+
checkTagNotVisible(category2, tag2)
303+
}
304+
}
305+
173306
private fun checkTagVisible(vararg name: String) {
174307
name.forEach {
308+
scrollRecyclerToView(
309+
R.id.rvCategoriesList,
310+
hasDescendant(withText(it)),
311+
)
175312
checkViewIsDisplayed(
176313
allOf(
177314
withId(dialogsR.id.viewCategoryItem),
@@ -193,4 +330,48 @@ class CategoriesTest : BaseUiTest() {
193330
)
194331
}
195332
}
333+
334+
private fun checkRelation(
335+
relationNames: List<String>,
336+
parentName: String,
337+
nameToIdMap: Map<String, Long>,
338+
) {
339+
val tag = nameToIdMap[parentName]
340+
val parentMatcher = allOf(
341+
withId(R.id.viewCategoryItem),
342+
hasDescendant(withText(parentName)),
343+
)
344+
relationNames.forEach { relationName ->
345+
val matcher = suggestionMatcher(withText(relationName), tag)
346+
scrollRecyclerToView(R.id.rvCategoriesList, matcher)
347+
checkViewIsDisplayed(matcher)
348+
onView(matcher).check(isCompletelyBelow(parentMatcher))
349+
}
350+
}
351+
352+
@Suppress("SameParameterValue")
353+
private fun checkRelationVisible(vararg name: String) {
354+
name.forEach {
355+
checkViewIsDisplayed(
356+
allOf(
357+
withId(R.id.cvActivitySuggestionListItemContent),
358+
hasDescendant(withText(it)),
359+
isCompletelyDisplayed(),
360+
),
361+
)
362+
}
363+
}
364+
365+
@Suppress("SameParameterValue")
366+
private fun checkRelationNotVisible(vararg name: String) {
367+
name.forEach {
368+
checkViewDoesNotExist(
369+
allOf(
370+
withId(R.id.cvActivitySuggestionListItemContent),
371+
hasDescendant(withText(it)),
372+
isCompletelyDisplayed(),
373+
),
374+
)
375+
}
376+
}
196377
}

app/src/androidTest/java/com/example/util/simpletimetracker/ComplexRulesTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,8 @@ class ComplexRulesTest : BaseUiTest() {
600600
clickOnViewWithText(R.string.change_complex_rule_choose_action)
601601
clickOnViewWithText(R.string.change_complex_action_assign_tag)
602602
clickOnViewWithText(tagName)
603+
clickOnViewWithText(R.string.time_now)
604+
Thread.sleep(500)
603605
typeTextIntoView(R.id.etCommentItemField, tagValueText)
604606
closeSoftKeyboard()
605607
clickOnViewWithId(dialogsR.id.btnRecordTagSelectionSave)

app/src/androidTest/java/com/example/util/simpletimetracker/SuggestionsTestUtils.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ object SuggestionsTestUtils {
5353
)
5454
}
5555

56-
private fun suggestionMatcher(
56+
fun suggestionMatcher(
5757
textMatcher: Matcher<View>,
5858
tag: Any?,
5959
): Matcher<View> {

app/src/androidTest/java/com/example/util/simpletimetracker/WidgetUniversal.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ class WidgetUniversal : BaseUiTest() {
164164
clickOnViewWithText(typeName)
165165
checkViewIsDisplayed(withText(tagName))
166166
clickOnViewWithText(tagName)
167-
checkViewIsDisplayed(withText(R.string.change_record_type_value_type_field))
167+
checkViewIsDisplayed(allOf(withId(R.id.tvRecordTagValueSelection), withText(tagName)))
168168
typeTextIntoView(R.id.etCommentItemField, tagValue)
169169
closeSoftKeyboard()
170170
clickOnViewWithText(R.string.duration_dialog_save)

core/src/main/java/com/example/util/simpletimetracker/core/mapper/CategoryViewDataMapper.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,12 @@ class CategoryViewDataMapper @Inject constructor(
232232
)
233233
}
234234

235-
fun mapToCategoryHint(): ViewHolderType = HintViewData(
235+
fun mapToCategoryHint(): HintViewData = HintViewData(
236236
text = R.string.categories_record_type_hint
237237
.let(resourceRepo::getString),
238238
)
239239

240-
fun mapToRecordTagHint(): ViewHolderType = HintViewData(
240+
fun mapToRecordTagHint(): HintViewData = HintViewData(
241241
text = R.string.categories_record_hint
242242
.let(resourceRepo::getString),
243243
)

core/src/main/java/com/example/util/simpletimetracker/core/utils/TestUtils.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ class TestUtils @Inject constructor(
4747
val recordTypeInteractor: RecordTypeInteractor,
4848
val recordInteractor: RecordInteractor,
4949
private val runningRecordInteractor: RunningRecordInteractor,
50-
private val categoryInteractor: CategoryInteractor,
50+
val categoryInteractor: CategoryInteractor,
5151
private val recordTypeCategoryInteractor: RecordTypeCategoryInteractor,
52-
private val recordTagInteractor: RecordTagInteractor,
52+
val recordTagInteractor: RecordTagInteractor,
5353
private val recordTypeToTagInteractor: RecordTypeToTagInteractor,
5454
private val recordTypeToDefaultTagInteractor: RecordTypeToDefaultTagInteractor,
5555
private val activityFilterInteractor: ActivityFilterInteractor,

data_local/src/main/java/com/example/util/simpletimetracker/data_local/backup/BackupPrefsRepo.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Compani
3939
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_INACTIVITY_REMINDER_RECURRENT
4040
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_IS_ACTIVITY_FILTERS_COLLAPSED
4141
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_IS_ARCHIVE_SEARCH_ENABLED
42+
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_IS_CATEGORIES_RELATIONS_ENABLED
4243
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_IS_CATEGORIES_SEARCH_ENABLED
4344
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_IS_NAV_BAR_AT_THE_BOTTOM
4445
import com.example.util.simpletimetracker.data_local.prefs.PrefsRepoImpl.Companion.KEY_KEEP_SCREEN_ON
@@ -242,6 +243,7 @@ class BackupPrefsRepo @Inject constructor(
242243
PrefsProcessor(KEY_DEFAULT_TYPES_HIDDEN, ::defaultTypesHidden),
243244
PrefsProcessor(KEY_IS_NAV_BAR_AT_THE_BOTTOM, ::isNavBarAtTheBottom),
244245
PrefsProcessor(KEY_IS_CATEGORIES_SEARCH_ENABLED, ::isCategoriesSearchEnabled),
246+
PrefsProcessor(KEY_IS_CATEGORIES_RELATIONS_ENABLED, ::isCategoriesRelationsEnabled),
245247
PrefsProcessor(KEY_IS_ARCHIVE_SEARCH_ENABLED, ::isArchiveSearchEnabled),
246248
PrefsProcessor(KEY_HIDDEN_COMMENT_FILTERS, ::hiddenCommentFilters),
247249
PrefsProcessor(KEY_DURATION_SUGGESTIONS_WAS_PREPOPULATED, ::durationSuggestionsWasPrepopulated),

data_local/src/main/java/com/example/util/simpletimetracker/data_local/prefs/PrefsRepoImpl.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,10 @@ class PrefsRepoImpl @Inject constructor(
435435
KEY_IS_CATEGORIES_SEARCH_ENABLED, false,
436436
)
437437

438+
override var isCategoriesRelationsEnabled: Boolean by prefs.delegate(
439+
KEY_IS_CATEGORIES_RELATIONS_ENABLED, false,
440+
)
441+
438442
override var isArchiveSearchEnabled: Boolean by prefs.delegate(
439443
KEY_IS_ARCHIVE_SEARCH_ENABLED, false,
440444
)
@@ -797,6 +801,7 @@ class PrefsRepoImpl @Inject constructor(
797801
const val KEY_DEFAULT_TYPES_HIDDEN = "defaultTypesHidden"
798802
const val KEY_IS_NAV_BAR_AT_THE_BOTTOM = "isNavBarAtTheBottom"
799803
const val KEY_IS_CATEGORIES_SEARCH_ENABLED = "isCategoriesSearchEnabled"
804+
const val KEY_IS_CATEGORIES_RELATIONS_ENABLED = "isCategoriesRelationsEnabled"
800805
const val KEY_IS_ARCHIVE_SEARCH_ENABLED = "isArchiveSearchEnabled"
801806
const val KEY_HIDDEN_COMMENT_FILTERS = "hiddenCommentFilters"
802807
const val KEY_DURATION_SUGGESTIONS_WAS_PREPOPULATED = "durationSuggestionsWasPrepopulated"

domain/src/main/java/com/example/util/simpletimetracker/domain/prefs/interactor/PrefsInteractor.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,14 @@ class PrefsInteractor @Inject constructor(
10121012
prefsRepo.isCategoriesSearchEnabled = value
10131013
}
10141014

1015+
suspend fun getIsCategoriesRelationsEnabled(): Boolean = withContext(Dispatchers.IO) {
1016+
prefsRepo.isCategoriesRelationsEnabled
1017+
}
1018+
1019+
suspend fun setIsCategoriesRelationsEnabled(value: Boolean) = withContext(Dispatchers.IO) {
1020+
prefsRepo.isCategoriesRelationsEnabled = value
1021+
}
1022+
10151023
suspend fun getIsArchiveSearchEnabled(): Boolean = withContext(Dispatchers.IO) {
10161024
prefsRepo.isArchiveSearchEnabled
10171025
}

domain/src/main/java/com/example/util/simpletimetracker/domain/prefs/repo/PrefsRepo.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ interface PrefsRepo {
190190
var isNavBarAtTheBottom: Boolean
191191

192192
var isCategoriesSearchEnabled: Boolean
193+
var isCategoriesRelationsEnabled: Boolean
193194

194195
var isArchiveSearchEnabled: Boolean
195196

0 commit comments

Comments
 (0)