Skip to content

Commit

Permalink
Merge pull request #5359 from jmizv/master
Browse files Browse the repository at this point in the history
Disable restoring hidden quests when there are none to unhide.
  • Loading branch information
westnordost authored Jan 16, 2024
2 parents 0d2d173 + 0ab82c5 commit 58c0215
Show file tree
Hide file tree
Showing 21 changed files with 1,191 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,10 @@ class OsmQuestsHiddenDaoTest : ApplicationDbTestCase() {
assertFalse(dao.contains(keys[0]))
assertFalse(dao.contains(keys[1]))
}

@Test fun countAll() {
assertEquals(0, dao.countAll())
dao.add(OsmQuestKey(ElementType.NODE, 123L, "bla"))
assertEquals(1, dao.countAll())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,10 @@ class NoteQuestsHiddenDaoTest : ApplicationDbTestCase() {
assertFalse(dao.contains(1L))
assertFalse(dao.contains(2L))
}

@Test fun countAll() {
assertEquals(0, dao.countAll())
dao.add(3L)
assertEquals(1, dao.countAll())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import de.westnordost.streetcomplete.data.osm.edits.ElementEdit
import de.westnordost.streetcomplete.data.osm.edits.ElementEditsController
import de.westnordost.streetcomplete.data.osm.edits.ElementEditsSource
import de.westnordost.streetcomplete.data.osm.edits.IsRevertAction
import de.westnordost.streetcomplete.data.osm.osmquests.OsmQuestController
import de.westnordost.streetcomplete.data.osm.osmquests.OsmQuestHidden
import de.westnordost.streetcomplete.data.osm.osmquests.OsmQuestsHiddenController
import de.westnordost.streetcomplete.data.osm.osmquests.OsmQuestsHiddenSource
import de.westnordost.streetcomplete.data.osmnotes.edits.NoteEdit
import de.westnordost.streetcomplete.data.osmnotes.edits.NoteEditsController
import de.westnordost.streetcomplete.data.osmnotes.edits.NoteEditsSource
import de.westnordost.streetcomplete.data.osmnotes.notequests.OsmNoteQuestController
import de.westnordost.streetcomplete.data.osmnotes.notequests.OsmNoteQuestsHiddenController
import de.westnordost.streetcomplete.data.osmnotes.notequests.OsmNoteQuestsHiddenSource
import de.westnordost.streetcomplete.data.osmnotes.notequests.OsmNoteQuestHidden
import de.westnordost.streetcomplete.util.Listeners
import de.westnordost.streetcomplete.util.ktx.nowAsEpochMilliseconds
Expand All @@ -19,8 +21,8 @@ import de.westnordost.streetcomplete.util.ktx.nowAsEpochMilliseconds
class EditHistoryController(
private val elementEditsController: ElementEditsController,
private val noteEditsController: NoteEditsController,
private val noteQuestController: OsmNoteQuestController,
private val osmQuestController: OsmQuestController
private val osmNoteQuestsHiddenController: OsmNoteQuestsHiddenController,
private val osmQuestsHiddenController: OsmQuestsHiddenController
) : EditHistorySource {
private val listeners = Listeners<EditHistorySource.Listener>()

Expand All @@ -42,12 +44,12 @@ class EditHistoryController(
override fun onDeletedEdits(edits: List<NoteEdit>) { onDeleted(edits) }
}

private val osmNoteQuestHiddenListener = object : OsmNoteQuestController.HideOsmNoteQuestListener {
private val osmNoteQuestHiddenListener = object : OsmNoteQuestsHiddenSource.Listener {
override fun onHid(edit: OsmNoteQuestHidden) { onAdded(edit) }
override fun onUnhid(edit: OsmNoteQuestHidden) { onDeleted(listOf(edit)) }
override fun onUnhidAll() { onInvalidated() }
}
private val osmQuestHiddenListener = object : OsmQuestController.HideOsmQuestListener {
private val osmQuestHiddenListener = object : OsmQuestsHiddenSource.Listener {
override fun onHid(edit: OsmQuestHidden) { onAdded(edit) }
override fun onUnhid(edit: OsmQuestHidden) { onDeleted(listOf(edit)) }
override fun onUnhidAll() { onInvalidated() }
Expand All @@ -56,17 +58,17 @@ class EditHistoryController(
init {
elementEditsController.addListener(osmElementEditsListener)
noteEditsController.addListener(osmNoteEditsListener)
noteQuestController.addHideQuestsListener(osmNoteQuestHiddenListener)
osmQuestController.addHideQuestsListener(osmQuestHiddenListener)
osmNoteQuestsHiddenController.addListener(osmNoteQuestHiddenListener)
osmQuestsHiddenController.addListener(osmQuestHiddenListener)
}

fun undo(edit: Edit): Boolean {
if (!edit.isUndoable) return false
return when (edit) {
is ElementEdit -> elementEditsController.undo(edit)
is NoteEdit -> noteEditsController.undo(edit)
is OsmNoteQuestHidden -> noteQuestController.unhide(edit.note.id)
is OsmQuestHidden -> osmQuestController.unhide(edit.questKey)
is OsmNoteQuestHidden -> osmNoteQuestsHiddenController.unhide(edit.note.id)
is OsmQuestHidden -> osmQuestsHiddenController.unhide(edit.questKey)
else -> throw IllegalArgumentException()
}
}
Expand All @@ -78,8 +80,8 @@ class EditHistoryController(
override fun get(key: EditKey): Edit? = when (key) {
is ElementEditKey -> elementEditsController.get(key.id)
is NoteEditKey -> noteEditsController.get(key.id)
is OsmNoteQuestHiddenKey -> noteQuestController.getHidden(key.osmNoteQuestKey.noteId)
is OsmQuestHiddenKey -> osmQuestController.getHidden(key.osmQuestKey)
is OsmNoteQuestHiddenKey -> osmNoteQuestsHiddenController.getHidden(key.osmNoteQuestKey.noteId)
is OsmQuestHiddenKey -> osmQuestsHiddenController.getHidden(key.osmQuestKey)
}

override fun getMostRecentUndoable(): Edit? =
Expand All @@ -93,8 +95,8 @@ class EditHistoryController(
val result = ArrayList<Edit>()
result += elementEditsController.getAll().filter { it.action !is IsRevertAction }
result += noteEditsController.getAll()
result += noteQuestController.getAllHiddenNewerThan(maxAge)
result += osmQuestController.getAllHiddenNewerThan(maxAge)
result += osmNoteQuestsHiddenController.getAllHiddenNewerThan(maxAge)
result += osmQuestsHiddenController.getAllHiddenNewerThan(maxAge)

result.sortByDescending { it.createdTimestamp }
return result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,12 @@ class OsmQuestController internal constructor(
private val notesSource: NotesWithEditsSource,
private val questTypeRegistry: QuestTypeRegistry,
private val countryBoundariesFuture: FutureTask<CountryBoundaries>
) : OsmQuestSource, HideOsmQuestController {
) : OsmQuestSource, OsmQuestsHiddenController, OsmQuestsHiddenSource {

/* Must be a singleton because there is a listener that should respond to a change in the
* database table */

interface HideOsmQuestListener {
fun onHid(edit: OsmQuestHidden)
fun onUnhid(edit: OsmQuestHidden)
fun onUnhidAll()
}
private val hideListeners = Listeners<HideOsmQuestListener>()
private val hideListeners = Listeners<OsmQuestsHiddenSource.Listener>()

private val listeners = Listeners<OsmQuestSource.Listener>()

Expand Down Expand Up @@ -299,7 +294,7 @@ class OsmQuestController internal constructor(
return OsmQuest(questType, entry.elementType, entry.elementId, geometry)
}

/* ----------------------------------- Hiding / Unhiding ----------------------------------- */
/* -------------------------- OsmQuestsHiddenControllerController -------------------------- */

private fun getBlacklistedPositions(bbox: BoundingBox): Set<LatLon> =
notesSource
Expand All @@ -313,7 +308,6 @@ class OsmQuestController internal constructor(
private fun getHiddenQuests(): Set<OsmQuestKey> =
hiddenDB.getAllIds().toSet()

/** Mark the quest as hidden by user interaction */
override fun hide(key: OsmQuestKey) {
synchronized(this) { hiddenDB.add(key) }

Expand All @@ -322,7 +316,7 @@ class OsmQuestController internal constructor(
onUpdated(deletedKeys = listOf(key))
}

fun unhide(key: OsmQuestKey): Boolean {
override fun unhide(key: OsmQuestKey): Boolean {
val hidden = getHidden(key)
synchronized(this) {
if (!hiddenDB.delete(key)) return false
Expand All @@ -333,21 +327,20 @@ class OsmQuestController internal constructor(
return true
}

/** Un-hides all previously hidden quests by user interaction */
fun unhideAll(): Int {
override fun unhideAll(): Int {
val unhidCount = synchronized(this) { hiddenDB.deleteAll() }
onUnhidAll()
onInvalidated()
return unhidCount
}

fun getHidden(key: OsmQuestKey): OsmQuestHidden? {
override fun getHidden(key: OsmQuestKey): OsmQuestHidden? {
val timestamp = hiddenDB.getTimestamp(key) ?: return null
val pos = mapDataSource.getGeometry(key.elementType, key.elementId)?.center
return createOsmQuestHidden(key, pos, timestamp)
}

fun getAllHiddenNewerThan(timestamp: Long): List<OsmQuestHidden> {
override fun getAllHiddenNewerThan(timestamp: Long): List<OsmQuestHidden> {
val questKeysWithTimestamp = hiddenDB.getNewerThan(timestamp)

val elementKeys = questKeysWithTimestamp.mapTo(HashSet()) {
Expand All @@ -362,6 +355,8 @@ class OsmQuestController internal constructor(
}
}

override fun countAll(): Long = hiddenDB.countAll()

private fun createOsmQuestHidden(key: OsmQuestKey, position: LatLon?, timestamp: Long): OsmQuestHidden? {
if (position == null) return null
val questType = questTypeRegistry.getByName(key.questTypeName) as? OsmElementQuestType<*> ?: return null
Expand Down Expand Up @@ -400,10 +395,10 @@ class OsmQuestController internal constructor(

/* ------------------------------------- Hide Listeners ------------------------------------- */

fun addHideQuestsListener(listener: HideOsmQuestListener) {
override fun addListener(listener: OsmQuestsHiddenSource.Listener) {
hideListeners.add(listener)
}
fun removeHideQuestsListener(listener: HideOsmQuestListener) {
override fun removeListener(listener: OsmQuestsHiddenSource.Listener) {
hideListeners.remove(listener)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ val osmQuestModule = module {
factory { OsmQuestsHiddenDao(get()) }

single<OsmQuestSource> { get<OsmQuestController>() }
single<OsmQuestsHiddenSource> { get<OsmQuestController>() }
single<OsmQuestsHiddenController> { get<OsmQuestController>() }

single { OsmQuestController(get(), get(), get(), get(), get(), get(named("CountryBoundariesFuture"))) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package de.westnordost.streetcomplete.data.osm.osmquests

import de.westnordost.streetcomplete.data.quest.OsmQuestKey

/** Controller for managing which osm quests have been hidden by user interaction */
interface OsmQuestsHiddenController : OsmQuestsHiddenSource, HideOsmQuestController {

/** Mark the quest as hidden by user interaction */
override fun hide(key: OsmQuestKey)

/** Un-hide the given quest. Returns whether it was hid before */
fun unhide(key: OsmQuestKey): Boolean

/** Un-hides all previously hidden quests by user interaction */
fun unhideAll(): Int
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class OsmQuestsHiddenDao(private val db: Database) {

fun deleteAll(): Int =
db.delete(NAME)

fun countAll(): Long =
db.queryOne(NAME, columns = arrayOf("COUNT(*)")) { it.getLong("COUNT(*)") } ?: 0L
}

private fun OsmQuestKey.toPairs() = listOf(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package de.westnordost.streetcomplete.data.osm.osmquests

import de.westnordost.streetcomplete.data.quest.OsmQuestKey

interface OsmQuestsHiddenSource {

interface Listener {
fun onHid(edit: OsmQuestHidden)
fun onUnhid(edit: OsmQuestHidden)
fun onUnhidAll()
}

/** Get information about an osm quest hidden by the user or null if it does not exist / has not
* been hidden */
fun getHidden(key: OsmQuestKey): OsmQuestHidden?

/** Get information about all osm quests hidden by the user after the given [timestamp] */
fun getAllHiddenNewerThan(timestamp: Long): List<OsmQuestHidden>

/** Get number of osm quests hidden by the user */
fun countAll(): Long

fun addListener(listener: Listener)
fun removeListener(listener: Listener)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class NoteQuestsHiddenDao(private val db: Database) {

fun deleteAll(): Int =
db.delete(NAME)

fun countAll(): Long =
db.queryOne(NAME, columns = arrayOf("COUNT(*)")) { it.getLong("COUNT(*)")} ?: 0L

Check failure on line 39 in app/src/main/java/de/westnordost/streetcomplete/data/osmnotes/notequests/NoteQuestsHiddenDao.kt

View workflow job for this annotation

GitHub Actions / Kotlin

Missing spacing before "}"
}

private fun CursorPosition.toNoteIdWithTimestamp() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,11 @@ class OsmNoteQuestController(
private val userDataSource: UserDataSource,
private val userLoginStatusSource: UserLoginStatusSource,
private val notesPreferences: NotesPreferences,
) : OsmNoteQuestSource {
) : OsmNoteQuestSource, OsmNoteQuestsHiddenController, OsmNoteQuestsHiddenSource {
/* Must be a singleton because there is a listener that should respond to a change in the
* database table */

interface HideOsmNoteQuestListener {
fun onHid(edit: OsmNoteQuestHidden)
fun onUnhid(edit: OsmNoteQuestHidden)
fun onUnhidAll()
}
private val hideListeners = Listeners<HideOsmNoteQuestListener>()
private val hideListeners = Listeners<OsmNoteQuestsHiddenSource.Listener>()

private val listeners = Listeners<OsmNoteQuestSource.Listener>()

Expand Down Expand Up @@ -100,10 +95,9 @@ class OsmNoteQuestController(
null
}

/* ----------------------------------- Hiding / Unhiding ----------------------------------- */
/* ---------------------------- OsmNoteQuestsHiddenController ------------------------------ */

/** Mark the quest as hidden by user interaction */
fun hide(questId: Long) {
override fun hide(questId: Long) {
val hidden: OsmNoteQuestHidden?
synchronized(this) {
hiddenDB.add(questId)
Expand All @@ -113,8 +107,7 @@ class OsmNoteQuestController(
onUpdated(deletedQuestIds = listOf(questId))
}

/** Un-hides a specific hidden quest by user interaction */
fun unhide(questId: Long): Boolean {
override fun unhide(questId: Long): Boolean {
val hidden = getHidden(questId)
synchronized(this) {
if (!hiddenDB.delete(questId)) return false
Expand All @@ -125,8 +118,7 @@ class OsmNoteQuestController(
return true
}

/** Un-hides all previously hidden quests by user interaction */
fun unhideAll(): Int {
override fun unhideAll(): Int {
val previouslyHiddenNotes = noteSource.getAll(hiddenDB.getAllIds())
val unhidCount = synchronized(this) { hiddenDB.deleteAll() }

Expand All @@ -137,13 +129,13 @@ class OsmNoteQuestController(
return unhidCount
}

fun getHidden(questId: Long): OsmNoteQuestHidden? {
override fun getHidden(questId: Long): OsmNoteQuestHidden? {
val timestamp = hiddenDB.getTimestamp(questId) ?: return null
val note = noteSource.get(questId) ?: return null
return OsmNoteQuestHidden(note, timestamp)
}

fun getAllHiddenNewerThan(timestamp: Long): List<OsmNoteQuestHidden> {
override fun getAllHiddenNewerThan(timestamp: Long): List<OsmNoteQuestHidden> {
val noteIdsWithTimestamp = hiddenDB.getNewerThan(timestamp)
val notesById = noteSource.getAll(noteIdsWithTimestamp.map { it.noteId }).associateBy { it.id }

Expand All @@ -152,6 +144,8 @@ class OsmNoteQuestController(
}
}

override fun countAll(): Long = hiddenDB.countAll()

private fun isHidden(questId: Long): Boolean = hiddenDB.contains(questId)

private fun getHiddenIds(): Set<Long> = hiddenDB.getAllIds().toSet()
Expand Down Expand Up @@ -179,10 +173,10 @@ class OsmNoteQuestController(

/* ------------------------------------- Hide Listeners ------------------------------------- */

fun addHideQuestsListener(listener: HideOsmNoteQuestListener) {
override fun addListener(listener: OsmNoteQuestsHiddenSource.Listener) {
hideListeners.add(listener)
}
fun removeHideQuestsListener(listener: HideOsmNoteQuestListener) {
override fun removeListener(listener: OsmNoteQuestsHiddenSource.Listener) {
hideListeners.remove(listener)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ val osmNoteQuestModule = module {
factory { NoteQuestsHiddenDao(get()) }

single { NotesPreferences(get()) }

single<OsmNoteQuestSource> { get<OsmNoteQuestController>() }
single<OsmNoteQuestsHiddenSource> { get<OsmNoteQuestController>() }
single<OsmNoteQuestsHiddenController> { get<OsmNoteQuestController>() }

single { OsmNoteQuestController(get(), get(), get(), get(), get()) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package de.westnordost.streetcomplete.data.osmnotes.notequests

/** Controller for managing which osm note quests have been hidden by user interaction */
interface OsmNoteQuestsHiddenController : OsmNoteQuestsHiddenSource {

/** Mark the note quest as hidden by user interaction */
fun hide(questId: Long)

/** Un-hides a specific hidden quest by user interaction */
fun unhide(questId: Long): Boolean

/** Un-hides all previously hidden quests by user interaction */
fun unhideAll(): Int
}
Loading

0 comments on commit 58c0215

Please sign in to comment.