diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index dd59fbacc..4439a39af 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -10,6 +10,8 @@
* [Kotlin](#kotlin)
* [Code quality](#code-quality)
* [Adding translations](#adding-translations)
+ * [Updating the instance list](#updating-the-instance-list)
+ * [Generate compose compiler metrics](#generate-compose-compiler-metrics)
@@ -73,3 +75,25 @@ prettier --write "*.md" "*.yml"`
You can find the translations in the `app/src/main/res/values-{locale}/strings.xml` file.
You can open it in android studio, right click and click open translations editor or you can
directly edit the files.
+
+## Updating the instance list
+
+There is a custom gradle task that generates all the lemmy instances that this app directly supports.
+It updates the lemmy instances list in DefaultInstances.kt and the AndroidManifest.
+It uses the fediverse api and filters on the monthly users.
+You can run it by doing
+
+```shell
+ ./gradlew app:updateInstances --no-configuration-cache
+```
+
+## Generate compose compiler metrics
+
+You can generate the compose compiler metrics by executing the following gradle task.
+
+```shell
+./gradlew assembleRelease --rerun-tasks -P com.jerboa.enableComposeCompilerReports=true
+```
+
+Then you will find the metrics in `app/build/compose_metrics` directory.
+See [this link for more information on these metrics](https://github.com/androidx/androidx/blob/androidx-main/compose/compiler/design/compiler-metrics.md)
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 35625b6a1..f3c715c9c 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -7,6 +7,8 @@ plugins {
id("androidx.baselineprofile")
}
+apply(from = "update_instances.gradle.kts")
+
android {
compileSdk = 33
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0b6927abb..d30c7f06d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -59,26 +59,68 @@
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/jerboa/DefaultInstances.kt b/app/src/main/java/com/jerboa/DefaultInstances.kt
new file mode 100644
index 000000000..f20ce474c
--- /dev/null
+++ b/app/src/main/java/com/jerboa/DefaultInstances.kt
@@ -0,0 +1,59 @@
+package com.jerboa
+
+val DEFAULT_LEMMY_INSTANCES = arrayOf(
+ "lemmy.world", // 13911 monthly users
+ "lemmy.ml", // 4217 monthly users
+ "beehaw.org", // 3739 monthly users
+ "feddit.de", // 2300 monthly users
+ "sh.itjust.works", // 2221 monthly users
+ "www.hexbear.net", // 1602 monthly users
+ "lemmy.ca", // 1095 monthly users
+ "lemm.ee", // 994 monthly users
+ "lemmy.one", // 987 monthly users
+ "lemmy.fmhy.ml", // 945 monthly users
+ "lemmy.dbzer0.com", // 784 monthly users
+ "lemmy.blahaj.zone", // 769 monthly users
+ "lemmygrad.ml", // 630 monthly users
+ "programming.dev", // 624 monthly users
+ "discuss.tchncs.de", // 564 monthly users
+ "sopuli.xyz", // 563 monthly users
+ "lemmy.sdf.org", // 476 monthly users
+ "vlemmy.net", // 399 monthly users
+ "midwest.social", // 396 monthly users
+ "aussie.zone", // 373 monthly users
+ "startrek.website", // 317 monthly users
+ "infosec.pub", // 288 monthly users
+ "feddit.uk", // 286 monthly users
+ "dormi.zone", // 269 monthly users
+ "feddit.it", // 260 monthly users
+ "pawb.social", // 243 monthly users
+ "feddit.nl", // 197 monthly users
+ "burggit.moe", // 187 monthly users
+ "slrpnk.net", // 179 monthly users
+ "lemmy.nz", // 167 monthly users
+ "feddit.dk", // 159 monthly users
+ "delraymisfitsboard.com", // 158 monthly users
+ "reddthat.com", // 154 monthly users
+ "mander.xyz", // 152 monthly users
+ "feddit.cl", // 123 monthly users
+ "lemmy.zip", // 118 monthly users
+ "lemmy.pt", // 100 monthly users
+ "dataterm.digital", // 86 monthly users
+ "lemmy.eco.br", // 86 monthly users
+ "szmer.info", // 85 monthly users
+ "latte.isnot.coffee", // 85 monthly users
+ "monyet.cc", // 85 monthly users
+ "exploding-heads.com", // 84 monthly users
+ "waveform.social", // 78 monthly users
+ "lemmy.tedomum.net", // 76 monthly users
+ "enterprise.lemmy.ml", // 72 monthly users
+ "pathofexile-discuss.com", // 71 monthly users
+ "iusearchlinux.fyi", // 65 monthly users
+ "yiffit.net", // 62 monthly users
+ "ttrpg.network", // 61 monthly users
+ "lemmyrs.org", // 59 monthly users
+ "sub.wetshaving.social", // 57 monthly users
+ "monero.town", // 54 monthly users
+ "bakchodi.org", // 53 monthly users
+ "geddit.social", // 50 monthly users
+)
diff --git a/app/src/main/java/com/jerboa/Utils.kt b/app/src/main/java/com/jerboa/Utils.kt
index 1a8f83706..70bafc7f1 100644
--- a/app/src/main/java/com/jerboa/Utils.kt
+++ b/app/src/main/java/com/jerboa/Utils.kt
@@ -83,23 +83,6 @@ val gson = Gson()
const val DEBOUNCE_DELAY = 1000L
const val MAX_POST_TITLE_LENGTH = 200
-val DEFAULT_LEMMY_INSTANCES = listOf(
- "beehaw.org",
- "feddit.de",
- "feddit.it",
- "lemmy.ca",
- "lemmy.ml",
- "lemmy.one",
- "lemmy.world",
- "lemmygrad.ml",
- "midwest.social",
- "mujico.org",
- "sh.itjust.works",
- "slrpnk.net",
- "sopuli.xyz",
- "szmer.info",
-)
-
// convert a data class to a map
fun T.serializeToMap(): Map {
return convert()
@@ -1320,9 +1303,9 @@ fun getLangPreferenceDropdownEntries(ctx: Context): Map {
val localeList = getLocaleListFromXml(ctx)
val map = mutableMapOf()
- for (a in 0 until localeList.size()) {
- localeList[a].let {
- it?.let { it1 -> map.put(it, it.getDisplayName(it)) }
+ for (i in 0 until localeList.size()) {
+ localeList[i]?.let {
+ map.put(it, it.getDisplayName(it))
}
}
return map
diff --git a/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt b/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt
index b8aecbc86..e941f3fd8 100644
--- a/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt
+++ b/app/src/main/java/com/jerboa/ui/components/inbox/InboxActivity.kt
@@ -293,9 +293,9 @@ fun InboxTabs(
items(
replies,
key = { reply -> reply.comment_reply.id },
- ) { crv ->
+ ) { commentReplyView ->
CommentReplyNode(
- commentReplyView = crv,
+ commentReplyView = commentReplyView,
onUpvoteClick = { cr ->
account?.also { acct ->
inboxViewModel.likeReply(
diff --git a/app/update_instances.gradle.kts b/app/update_instances.gradle.kts
new file mode 100644
index 000000000..61930aff6
--- /dev/null
+++ b/app/update_instances.gradle.kts
@@ -0,0 +1,142 @@
+import java.io.OutputStreamWriter
+import java.net.URL
+import java.net.HttpURLConnection
+
+// We can't import libraries here for some reason, so we must use what is provided
+// by gradle, which isn't much. The groovy JSON library is meant for use by groovy code,
+// so we need some creativity to use it in Kotlin.
+import org.apache.groovy.json.internal.LazyMap
+import groovy.json.JsonOutput
+import groovy.json.JsonSlurper
+
+// All lemmy instances with at least this amount of monthly active users will be included.
+val minimumMAU = 50
+
+
+val endpointUrl = "https://api.fediverse.observer/"
+val instancesFilePath = "src/main/java/com/jerboa/DefaultInstances.kt"
+val manifestPath = "src/main/AndroidManifest.xml"
+val START_TAG = ""
+val END_TAG = ""
+val IDENT = 14
+val nsfwList = listOf("lemmynsfw.com")
+
+// Some extension methods to make the JsonSlurper output easier to process
+fun LazyMap.getMap(key: String): LazyMap {
+ return this[key] as LazyMap
+}
+
+fun LazyMap.getArray(key: String): ArrayList<*> {
+ return this[key] as ArrayList<*>
+}
+
+@Suppress("UNCHECKED_CAST")
+fun LazyMap.getAs(key: String): T {
+ return this[key] as T
+}
+
+// Run this as `./gradlew app:updateInstances --no-configuration-cache`
+tasks.register("updateInstances") {
+ description = "Fetches a list of popular Lemmy instances and writes it to the DefaultInstances.kt file"
+
+ doFirst {
+ // Get sorted list of nodes
+ val nodes = getData()
+ .getMap("data")
+ .getArray("nodes")
+ .map {
+ val name = (it as LazyMap)["domain"] as String
+ val users = it["active_users_monthly"] as Int?
+
+ Pair(name, users ?: 0)
+ }
+ .filter {
+ it.second >= minimumMAU && !nsfwList.contains(it.first)
+ }
+ .sortedBy {
+ it.second
+ }
+ .reversed()
+
+ updateInstanceList(nodes)
+ updateManifest(nodes.map { it.first })
+ }
+}
+
+
+fun getData(): LazyMap {
+ val url = URL(endpointUrl)
+ val query = """
+{
+ nodes(softwarename: "lemmy") {
+ domain
+ active_users_monthly
+ }
+}"""
+
+ // Format JSON request body
+ val body = JsonOutput.toJson(mapOf("query" to query))
+
+ // Create POST request
+ val req = url.openConnection() as HttpURLConnection
+ req.requestMethod = "POST"
+ req.doOutput = true
+ req.setRequestProperty("Content-Type", "application/json")
+
+ // Write body to request
+ OutputStreamWriter(req.outputStream, "UTF-8").use {
+ it.write(body)
+ }
+
+ // Get response and JSON parse it
+ return JsonSlurper().parse(req.inputStream.reader()) as LazyMap
+}
+
+fun updateInstanceList(nodes: List>) {
+ // Create output file and write header
+ val outFile = file(instancesFilePath)
+ outFile.writeText(
+ """package com.jerboa
+
+val DEFAULT_LEMMY_INSTANCES = arrayOf(
+"""
+ )
+
+ // Write each node's name, one per line
+ for (n in nodes) {
+ outFile.appendText(" \"${n.first}\", // ${n.second} monthly users\n")
+ }
+
+ outFile.appendText(")\n")
+}
+
+
+fun updateManifest(list: List) {
+ val manifest = file(manifestPath)
+ val lines = manifest.readLines()
+ manifest.writeText("")
+
+ var skip = false
+
+ for (line in lines) {
+ if (line.trim() == START_TAG) {
+ skip = true
+ manifest.appendText(" ".repeat(IDENT) + START_TAG)
+ manifest.appendText(genManifestHosts(list))
+ manifest.appendText(" ".repeat(IDENT) + END_TAG + System.lineSeparator())
+ } else if (line.trim() == END_TAG) {
+ skip = false
+ } else if (!skip) {
+ manifest.appendText(line + System.lineSeparator())
+ }
+ }
+}
+
+fun genManifestHosts(list: List): String {
+ return list.joinToString(
+ separator = System.lineSeparator(),
+ prefix = System.lineSeparator(),
+ postfix = System.lineSeparator(),
+ ) { " ".repeat(IDENT) + "" }
+}
+
diff --git a/build.gradle.kts b/build.gradle.kts
index 32b673cfd..3a6d6ca35 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -45,7 +45,3 @@ subprojects {
}
}
}
-
-tasks.register("clean", Delete::class) {
- delete(rootProject.buildDir)
-}