Skip to content

Commit

Permalink
Merge branch 'master' into modified
Browse files Browse the repository at this point in the history
  • Loading branch information
Helium314 committed Mar 6, 2024
2 parents fd68a7a + 22b6179 commit b624fd6
Show file tree
Hide file tree
Showing 91 changed files with 1,047 additions and 522 deletions.
3 changes: 0 additions & 3 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ ktlint_standard_backing-property-naming = disabled
ktlint_standard_blank-line-before-declaration = disabled
ktlint_standard_blank-line-between-when-conditions = disabled
ktlint_standard_chain-wrapping = disabled
ktlint_standard_comment-wrapping = disabled
ktlint_standard_function-naming = disabled
ktlint_standard_function-signature = disabled
ktlint_standard_indent = disabled
Expand All @@ -47,8 +46,6 @@ ktlint_standard_statement-wrapping = disabled
ktlint_standard_string-template-indent = disabled
ktlint_standard_trailing-comma-on-call-site = disabled
ktlint_standard_trailing-comma-on-declaration-site = disabled
ktlint_standard_value-argument-comment = disabled
ktlint_standard_value-parameter-comment = disabled
ktlint_standard_wrapping = disabled

# enable some experimental Ktlint rules
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ you map places that are not shops - like hotels, hospitals, schools and so forth

### Other

- Fix a (shokingly common) crash (#5498)
- Fix a (shockingly common) crash (#5498)
- Fix issues with doing edits while data is being downloaded (#4258)
- Add some interesting links as achievement rewards (#5466)
- Translation to Amharic has been disabled, it was not maintained for over a year
Expand Down
5 changes: 5 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ dependencies {
// scheduling background jobs
implementation("androidx.work:work-runtime-ktx:2.9.0")

// HTTP Client
implementation("io.ktor:ktor-client-core:2.3.8")
implementation("io.ktor:ktor-client-cio:2.3.8")
testImplementation("io.ktor:ktor-client-mock:2.3.8")

// finding in which country we are for country-specific logic
implementation("de.westnordost:countryboundaries:2.1")
// finding a name for a feature without a name tag
Expand Down
4 changes: 3 additions & 1 deletion app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# let's just keep everything
-keep class com.mapzen.tangram.** { *; }
-keep class com.mapzen.tangram.* { *; }

# tangram end --------------------------------------------------------------------------------------

# Lifecycle
Expand Down Expand Up @@ -47,6 +46,9 @@
kotlinx.serialization.KSerializer serializer(...);
}

# ktor client, see https://youtrack.jetbrains.com/issue/KTOR-5528
-dontwarn org.slf4j.impl.StaticLoggerBinder

# Change here com.yourcompany.yourpackage
-keep,includedescriptorclasses class de.westnordost.streetcomplete.**$$serializer { *; }
-keepclassmembers class de.westnordost.streetcomplete.** {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class EditElementsDaoTest : ApplicationDbTestCase() {
))

dao.put(7, listOf(
ElementKey(ElementType.NODE, 0), // referring to same element
ElementKey(ElementType.WAY, 1), // but also another
ElementKey(ElementType.NODE, 0), // referring to same element
ElementKey(ElementType.WAY, 1), // but also another
))

dao.put(3, listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import android.content.res.Resources
import de.westnordost.streetcomplete.util.CrashReportExceptionHandler
import de.westnordost.streetcomplete.util.SoundFx
import de.westnordost.streetcomplete.util.logs.DatabaseLogger
import io.ktor.client.HttpClient
import io.ktor.client.plugins.defaultRequest
import io.ktor.http.userAgent
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module

Expand All @@ -15,4 +18,9 @@ val appModule = module {
single { CrashReportExceptionHandler(androidContext(), get(), get(), "helium@vivaldi.net", "crashreport.txt") }
single { DatabaseLogger(get()) }
single { SoundFx(androidContext()) }
single { HttpClient {
defaultRequest {
userAgent(ApplicationConstants.USER_AGENT)
}
} }
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class StreetCompleteApplication : Application() {
preloader.preload()
}

/* Force logout users who are logged in with OAuth 1.0a, they need to re-authenticate with OAuth 2 */
// Force logout users who are logged in with OAuth 1.0a, they need to re-authenticate with OAuth 2
if (prefs.getStringOrNull(Prefs.OAUTH1_ACCESS_TOKEN) != null) {
userLoginStatusController.logOut()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Cleaner(
noteController.deleteOlderThan(oldDataTimestamp, MAX_DELETE_ELEMENTS)
mapDataController.deleteOlderThan(oldDataTimestamp, MAX_DELETE_ELEMENTS)
downloadedTilesController.deleteOlderThan(oldDataTimestamp)
/* do this after cleaning map data and notes, because some metadata rely on map data */
// do this after cleaning map data and notes, because some metadata rely on map data
questTypeRegistry.forEach { it.deleteMetadataOlderThan(oldDataTimestamp) }

val oldLogTimestamp = nowAsEpochMilliseconds() - ApplicationConstants.DELETE_OLD_LOG_AFTER
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import de.westnordost.streetcomplete.quests.oneway_suspects.data.WayTrafficFlowT

/** Creates the database and upgrades it */
object DatabaseInitializer {
const val DB_VERSION = 15
const val DB_VERSION = 16

fun onCreate(db: Database) {
// OSM notes
Expand Down Expand Up @@ -243,9 +243,22 @@ object DatabaseInitializer {
if (oldVersion <= 14 && newVersion > 14) {
db.renameOverlay("ShopsOverlay", "PlacesOverlay")
}
if (oldVersion <= 15 && newVersion > 15) {
db.deleteQuest("AddCrossingType")
}
}
}

private fun Database.deleteQuest(name: String) {
deleteValue(ElementEditsTable.NAME, ElementEditsTable.Columns.QUEST_TYPE, name)
deleteValue(OsmQuestTable.NAME, OsmQuestTable.Columns.QUEST_TYPE, name)
deleteValue(OsmQuestsHiddenTable.NAME, OsmQuestsHiddenTable.Columns.QUEST_TYPE, name)
deleteValue(VisibleQuestTypeTable.NAME, VisibleQuestTypeTable.Columns.QUEST_TYPE, name)
deleteValue(OpenChangesetsTable.NAME, OpenChangesetsTable.Columns.QUEST_TYPE, name)
deleteValue(QuestTypeOrderTable.NAME, QuestTypeOrderTable.Columns.BEFORE, name)
deleteValue(QuestTypeOrderTable.NAME, QuestTypeOrderTable.Columns.AFTER, name)
}

private fun Database.renameQuest(old: String, new: String) {
renameValue(ElementEditsTable.NAME, ElementEditsTable.Columns.QUEST_TYPE, old, new)
renameValue(OsmQuestTable.NAME, OsmQuestTable.Columns.QUEST_TYPE, old, new)
Expand All @@ -264,3 +277,7 @@ private fun Database.renameOverlay(old: String, new: String) {
private fun Database.renameValue(table: String, column: String, oldValue: String, newValue: String) {
update(table, listOf(column to newValue), "$column = ?", arrayOf(oldValue))
}

private fun Database.deleteValue(table: String, column: String, value: String) {
delete(table, "$column = ?", arrayOf(value))
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class ElementFilterExpression(
internal val elementsTypes: Set<ElementsTypeFilter>,
internal val elementExprRoot: BooleanExpression<ElementFilter, Element>?
) {
/* Performance improvement: Allows to skip early on elements that have no tags at all */
// Performance improvement: Allows to skip early on elements that have no tags at all
val mayEvaluateToTrueWithNoTags = elementExprRoot?.mayEvaluateToTrueWithNoTags ?: true

/** returns whether the given element is found through (=matches) this expression */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ private fun StringWithCursor.parseQuotedWord(quot: Char): String? {
val word = advanceBy(length)
return word
.substring(1, word.length - 1) // remove quotes
.replace("\\$quot", "$quot") // unescape quotes within string
.replace("\\$quot", "$quot") // unescape quotes within string
}

private fun StringWithCursor.parseWord(): String {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package de.westnordost.streetcomplete.data.location

import android.location.Location
import de.westnordost.streetcomplete.util.ktx.elapsedDuration
import de.westnordost.streetcomplete.util.ktx.toLatLon
import de.westnordost.streetcomplete.util.math.flatDistanceTo
import kotlin.math.abs
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds

class RecentLocationStore {
private val recentLocations = ArrayDeque<Location>()
Expand All @@ -17,7 +19,7 @@ class RecentLocationStore {
previousLocation = it
return@filter true
}
if (abs(it.elapsedRealtimeNanos - loc.elapsedRealtimeNanos) > LOCATION_MIN_TIME_DIFFERENCE_NANOS
if ((it.elapsedDuration - loc.elapsedDuration).absoluteValue > LOCATION_MIN_TIME_DIFFERENCE
&& loc.toLatLon().flatDistanceTo(it.toLatLon()) >= MAX_DISTANCE_TO_ELEMENT_FOR_SURVEY / 2
) {
previousLocation = it
Expand All @@ -30,13 +32,15 @@ class RecentLocationStore {

fun add(location: Location) = synchronized(recentLocations) {
while (recentLocations.isNotEmpty()
&& recentLocations.first().elapsedRealtimeNanos <= location.elapsedRealtimeNanos - LOCATION_STORE_TIME_NANOS
&& recentLocations.first().elapsedDuration <= location.elapsedDuration - LOCATION_STORE_TIME
) {
recentLocations.removeFirst()
}
recentLocations.add(location)
}
}

private const val LOCATION_STORE_TIME_NANOS = 600 * 1000 * 1000 * 1000L // 10 min
private const val LOCATION_MIN_TIME_DIFFERENCE_NANOS = 5 * 1000 * 1000 * 1000L // 5 sec
companion object {
private val LOCATION_STORE_TIME = 10.minutes
private val LOCATION_MIN_TIME_DIFFERENCE = 5.seconds
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ class MapDataWithEditsSource internal constructor(
val ids = way.nodeIds.toHashSet()
val nodes = getNodes(ids)

/* If the way is (now) not complete, this is not acceptable */
// If the way is (now) not complete, this is not acceptable
if (nodes.size < ids.size) {
Log.w(TAG, "could not find nodes ${ids - nodes.map { it.id }} for way $way")
return null
Expand Down Expand Up @@ -324,7 +324,7 @@ class MapDataWithEditsSource internal constructor(
private fun getRelationElements(relation: Relation): MutableMapData = synchronized(this) {
val elements = ArrayList<Element>()
for (member in relation.members) {
/* for way members, also get their nodes */
// for way members, also get their nodes
if (member.type == WAY) {
val wayComplete = getWayComplete(member.ref)
if (wayComplete != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,23 @@ package de.westnordost.streetcomplete.data.osmnotes
import de.westnordost.osmapi.user.UserApi
import de.westnordost.streetcomplete.util.ktx.format
import de.westnordost.streetcomplete.util.ktx.nowAsEpochMilliseconds
import de.westnordost.streetcomplete.util.ktx.saveToFile
import de.westnordost.streetcomplete.util.logs.Log
import io.ktor.client.HttpClient
import io.ktor.client.plugins.expectSuccess
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsChannel
import io.ktor.util.cio.writeChannel
import io.ktor.utils.io.copyAndClose
import java.io.File
import java.io.IOException
import java.net.URL

/** Downloads and stores the OSM avatars of users */
class AvatarsDownloader(
private val httpClient: HttpClient,
private val userApi: UserApi,
private val cacheDir: File
) {

fun download(userIds: Collection<Long>) {
suspend fun download(userIds: Collection<Long>) {
if (!ensureCacheDirExists()) {
Log.w(TAG, "Unable to create directories for avatars")
return
Expand All @@ -41,13 +45,16 @@ class AvatarsDownloader(
}

/** download avatar for the given user and a known avatar url */
fun download(userId: Long, avatarUrl: String) {
suspend fun download(userId: Long, avatarUrl: String) {
if (!ensureCacheDirExists()) return
val avatarFile = File(cacheDir, "$userId")
try {
val avatarFile = File(cacheDir, "$userId")
URL(avatarUrl).saveToFile(avatarFile)
val response = httpClient.get(avatarUrl) {
expectSuccess = true
}
response.bodyAsChannel().copyAndClose(avatarFile.writeChannel())
Log.d(TAG, "Downloaded file: ${avatarFile.path}")
} catch (e: IOException) {
} catch (e: Exception) {
Log.w(TAG, "Unable to download avatar for user id $userId")
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package de.westnordost.streetcomplete.data.osmnotes
import kotlinx.coroutines.runBlocking

class AvatarsInNotesUpdater(private val downloader: AvatarsDownloader) :
NoteController.Listener {
Expand All @@ -7,7 +8,7 @@ class AvatarsInNotesUpdater(private val downloader: AvatarsDownloader) :
if (added.isEmpty() && updated.isEmpty()) return

val noteCommentUserIds = (added + updated).flatMap { it.userIds }.toSet()
downloader.download(noteCommentUserIds)
runBlocking { downloader.download(noteCommentUserIds) }
}

override fun onCleared() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import java.io.File

val notesModule = module {
factory(named("AvatarsCacheDirectory")) { File(get<Context>().cacheDir, ApplicationConstants.AVATARS_CACHE_DIRECTORY) }
factory { AvatarsDownloader(get(), get(named("AvatarsCacheDirectory"))) }
factory { AvatarsDownloader(get(), get(), get(named("AvatarsCacheDirectory"))) }
factory { AvatarsInNotesUpdater(get()) }
factory { NoteDao(get()) }
factory { NotesDownloader(get(), get()) }
factory { StreetCompleteImageUploader(ApplicationConstants.SC_PHOTO_SERVICE_URL) }
factory { StreetCompleteImageUploader(get(), ApplicationConstants.SC_PHOTO_SERVICE_URL) }

single {
NoteController(get()).apply {
Expand Down

0 comments on commit b624fd6

Please sign in to comment.