From a6bc40515b41580e79aaa9edae2bd835ba3935eb Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 24 Jun 2024 07:13:06 -0300 Subject: [PATCH 01/49] Move httpclient to another package --- ammolite/.gitignore | 1 + ammolite/build.gradle | 42 ++++++++++++++++ ammolite/consumer-rules.pro | 0 ammolite/proguard-rules.pro | 21 ++++++++ ammolite/src/main/AndroidManifest.xml | 4 ++ .../ammolite}/service/HttpClientManager.kt | 14 ++++-- app/build.gradle | 1 + .../com/vitorpamplona/amethyst/Amethyst.kt | 1 + .../amethyst/LocalPreferences.kt | 2 +- .../vitorpamplona/amethyst/ServiceManager.kt | 20 +++++++- .../amethyst/service/CashuProcessor.kt | 1 + .../service/Nip05NostrAddressVerifier.kt | 1 + .../service/Nip11RelayInfoRetriever.kt | 1 + .../amethyst/service/Nip96MediaServers.kt | 1 + .../amethyst/service/Nip96Uploader.kt | 1 + .../amethyst/service/OnlineCheck.kt | 1 + .../service/lnurl/LightningAddressResolver.kt | 2 +- .../service/notifications/RegisterAccounts.kt | 2 +- .../service/ots/OkHttpBlockstreamExplorer.kt | 2 +- .../amethyst/service/ots/OkHttpCalendar.kt | 2 +- .../service/ots/OkHttpCalendarAsyncSubmit.kt | 2 +- .../service/playback/PlaybackService.kt | 2 +- .../service/previews/UrlPreviewUtils.kt | 2 +- .../amethyst/service/relays/Client.kt | 50 +++++++++++++++++++ .../amethyst/service/relays/Relay.kt | 30 ++++++++++- .../amethyst/service/relays/RelayPool.kt | 35 +++++++++++++ .../vitorpamplona/amethyst/ui/MainActivity.kt | 2 +- .../amethyst/ui/actions/ImageDownloader.kt | 2 +- .../amethyst/ui/actions/ImageSaver.kt | 2 +- .../ui/screen/AccountStateViewModel.kt | 2 +- .../ui/screen/loggedIn/AccountViewModel.kt | 2 +- gradle/libs.versions.toml | 3 ++ settings.gradle | 1 + 33 files changed, 235 insertions(+), 20 deletions(-) create mode 100644 ammolite/.gitignore create mode 100644 ammolite/build.gradle create mode 100644 ammolite/consumer-rules.pro create mode 100644 ammolite/proguard-rules.pro create mode 100644 ammolite/src/main/AndroidManifest.xml rename {app/src/main/java/com/vitorpamplona/amethyst => ammolite/src/main/java/com/vitorpamplona/ammolite}/service/HttpClientManager.kt (91%) diff --git a/ammolite/.gitignore b/ammolite/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/ammolite/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/ammolite/build.gradle b/ammolite/build.gradle new file mode 100644 index 000000000..b81832b59 --- /dev/null +++ b/ammolite/build.gradle @@ -0,0 +1,42 @@ +plugins { + alias(libs.plugins.androidLibrary) + alias(libs.plugins.jetbrainsKotlinAndroid) +} + +android { + namespace 'com.vitorpamplona.ammolite' + compileSdk 34 + + defaultConfig { + minSdk 26 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + + implementation libs.androidx.core.ktx + implementation libs.androidx.appcompat + implementation libs.material + testImplementation libs.junit + androidTestImplementation libs.androidx.junit + androidTestImplementation libs.androidx.espresso.core + + implementation libs.okhttp +} \ No newline at end of file diff --git a/ammolite/consumer-rules.pro b/ammolite/consumer-rules.pro new file mode 100644 index 000000000..e69de29bb diff --git a/ammolite/proguard-rules.pro b/ammolite/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/ammolite/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/ammolite/src/main/AndroidManifest.xml b/ammolite/src/main/AndroidManifest.xml new file mode 100644 index 000000000..a5918e68a --- /dev/null +++ b/ammolite/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClientManager.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/service/HttpClientManager.kt similarity index 91% rename from app/src/main/java/com/vitorpamplona/amethyst/service/HttpClientManager.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/service/HttpClientManager.kt index 0bf677167..56d96feed 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClientManager.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/service/HttpClientManager.kt @@ -18,10 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service +package com.vitorpamplona.ammolite.service import android.util.Log -import com.vitorpamplona.amethyst.BuildConfig import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.Request @@ -40,6 +39,7 @@ object HttpClientManager { private var defaultTimeout = DEFAULT_TIMEOUT_ON_WIFI private var defaultHttpClient: OkHttpClient? = null private var defaultHttpClientWithoutProxy: OkHttpClient? = null + private var internalInterceptor: Interceptor = DefaultContentTypeInterceptor() // fires off every time value of the property changes private var internalProxy: Proxy? by @@ -73,6 +73,12 @@ object HttpClientManager { } } + fun setDefaultInterceptor(interceptor: Interceptor) { + Log.d("HttpClient", "Changing interceptor") + this.internalInterceptor = interceptor + this.defaultHttpClient = buildHttpClient(internalProxy, defaultTimeout) + } + private fun buildHttpClient( proxy: Proxy?, timeout: Duration, @@ -84,7 +90,7 @@ object HttpClientManager { .readTimeout(duration) .connectTimeout(duration) .writeTimeout(duration) - .addInterceptor(DefaultContentTypeInterceptor()) + .addInterceptor(internalInterceptor) .followRedirects(true) .followSslRedirects(true) .build() @@ -97,7 +103,7 @@ object HttpClientManager { val requestWithUserAgent: Request = originalRequest .newBuilder() - .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") + .header("User-Agent", "Amethyst") .build() return chain.proceed(requestWithUserAgent) } diff --git a/app/build.gradle b/app/build.gradle index cb9b24d5d..77b1af158 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -165,6 +165,7 @@ dependencies { implementation project(path: ':quartz') implementation project(path: ':commons') + implementation project(path: ':ammolite') implementation libs.androidx.core.ktx implementation libs.androidx.activity.compose diff --git a/app/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt b/app/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt index f3dde4d65..1199f184b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt @@ -70,6 +70,7 @@ class Amethyst : Application() { override fun onCreate() { super.onCreate() + instance = this OtsEvent.otsInstance = OpenTimestamps(OkHttpBlockstreamExplorer(), OkHttpCalendarBuilder()) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 3b21ef66d..4cb6574e6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -33,9 +33,9 @@ import com.vitorpamplona.amethyst.model.GLOBAL_FOLLOWS import com.vitorpamplona.amethyst.model.KIND3_FOLLOWS import com.vitorpamplona.amethyst.model.RelaySetupInfo import com.vitorpamplona.amethyst.model.Settings -import com.vitorpamplona.amethyst.service.HttpClientManager import com.vitorpamplona.amethyst.service.Nip96MediaServers import com.vitorpamplona.amethyst.service.checkNotInMainThread +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.Nip47WalletConnect diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt index de9a28a1e..6136950c7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt @@ -30,7 +30,6 @@ import coil.decode.SvgDecoder import coil.size.Precision import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache -import com.vitorpamplona.amethyst.service.HttpClientManager import com.vitorpamplona.amethyst.service.NostrAccountDataSource import com.vitorpamplona.amethyst.service.NostrChannelDataSource import com.vitorpamplona.amethyst.service.NostrChatroomDataSource @@ -48,6 +47,7 @@ import com.vitorpamplona.amethyst.service.NostrThreadDataSource import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource import com.vitorpamplona.amethyst.service.NostrVideoDataSource import com.vitorpamplona.amethyst.service.relays.Client +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.encoders.bechToBytes import com.vitorpamplona.quartz.encoders.decodePublicKeyAsHexOrNull import com.vitorpamplona.quartz.encoders.toHexKey @@ -60,6 +60,10 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import okhttp3.Interceptor +import okhttp3.Request +import okhttp3.Response +import java.io.IOException @Stable class ServiceManager { @@ -86,6 +90,7 @@ class ServiceManager { // Resets Proxy Use HttpClientManager.setDefaultProxy(account?.proxy) + HttpClientManager.setDefaultInterceptor(DefaultContentTypeInterceptor()) LocalCache.antiSpam.active = account?.filterSpamFromStrangers ?: true Coil.setImageLoader { Amethyst.instance @@ -249,3 +254,16 @@ class ServiceManager { forceRestart(null, false, true) } } + +class DefaultContentTypeInterceptor : Interceptor { + @Throws(IOException::class) + override fun intercept(chain: Interceptor.Chain): Response { + val originalRequest: Request = chain.request() + val requestWithUserAgent: Request = + originalRequest + .newBuilder() + .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") + .build() + return chain.proceed(requestWithUserAgent) + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt index 50203703b..9d603e50f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt @@ -29,6 +29,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver import com.vitorpamplona.amethyst.ui.components.GenericLoadable import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.events.Event import okhttp3.MediaType.Companion.toMediaType import okhttp3.Request diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt index 184612497..1771e29ec 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.service import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.amethyst.BuildConfig +import com.vitorpamplona.ammolite.service.HttpClientManager import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip11RelayInfoRetriever.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip11RelayInfoRetriever.kt index f5cbf8e68..b0f4134a1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip11RelayInfoRetriever.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip11RelayInfoRetriever.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.service import android.util.Log import android.util.LruCache +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.encoders.Nip11RelayInformation import com.vitorpamplona.quartz.encoders.RelayUrlFormatter import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip96MediaServers.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip96MediaServers.kt index 8b4771a9a..07f7244eb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip96MediaServers.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip96MediaServers.kt @@ -24,6 +24,7 @@ import android.util.Log import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.vitorpamplona.ammolite.service.HttpClientManager import kotlinx.coroutines.CancellationException import okhttp3.Request diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt index 923538ed5..7d069d0f1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt @@ -30,6 +30,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.ammolite.service.HttpClientManager import kotlinx.coroutines.delay import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withTimeoutOrNull diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt index b2eff00bd..72e11ab2e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt @@ -24,6 +24,7 @@ import android.util.Log import android.util.LruCache import androidx.compose.runtime.Immutable import com.vitorpamplona.amethyst.BuildConfig +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.crypto.CryptoUtils import okhttp3.EventListener import okhttp3.Protocol diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt index 85b19ebce..4f142daf0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt @@ -24,9 +24,9 @@ import android.content.Context import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.service.HttpClientManager import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.encoders.LnInvoiceUtil import com.vitorpamplona.quartz.encoders.Lud06 import okhttp3.Request diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt index 2049d817d..6ce76450b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.HttpClientManager +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.events.RelayAuthEvent import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpBlockstreamExplorer.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpBlockstreamExplorer.kt index 9b074670a..eeb092395 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpBlockstreamExplorer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpBlockstreamExplorer.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.service.ots import android.util.Log import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.amethyst.BuildConfig -import com.vitorpamplona.amethyst.service.HttpClientManager +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.ots.BitcoinExplorer import com.vitorpamplona.quartz.ots.BlockHeader import com.vitorpamplona.quartz.ots.exceptions.UrlException diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt index 91db7a2b4..0e16a2320 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.service.ots import com.vitorpamplona.amethyst.BuildConfig -import com.vitorpamplona.amethyst.service.HttpClientManager +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.encoders.Hex import com.vitorpamplona.quartz.ots.ICalendar import com.vitorpamplona.quartz.ots.StreamDeserializationContext diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarAsyncSubmit.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarAsyncSubmit.kt index be082413f..515f9150e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarAsyncSubmit.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarAsyncSubmit.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.service.ots import com.vitorpamplona.amethyst.BuildConfig -import com.vitorpamplona.amethyst.service.HttpClientManager +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.ots.ICalendarAsyncSubmit import com.vitorpamplona.quartz.ots.StreamDeserializationContext import com.vitorpamplona.quartz.ots.Timestamp diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt index 82167f0ad..449055818 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt @@ -33,7 +33,7 @@ import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy import androidx.media3.session.MediaSession import androidx.media3.session.MediaSessionService import com.vitorpamplona.amethyst.Amethyst -import com.vitorpamplona.amethyst.service.HttpClientManager +import com.vitorpamplona.ammolite.service.HttpClientManager /** * HLS LiveStreams cannot use cache. diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt index ea2425fc3..79fb36e32 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt @@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.service.previews import com.vitorpamplona.amethyst.commons.preview.MetaTag import com.vitorpamplona.amethyst.commons.preview.MetaTagsParser -import com.vitorpamplona.amethyst.service.HttpClientManager import com.vitorpamplona.amethyst.service.checkNotInMainThread +import com.vitorpamplona.ammolite.service.HttpClientManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okhttp3.MediaType diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt index 22d449c4c..34c494813 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt @@ -234,6 +234,7 @@ object Client : RelayPool.Listener { GlobalScope.launch(Dispatchers.Default) { listeners.forEach { it.onAuth(relay, challenge) } } } + @OptIn(DelicateCoroutinesApi::class) override fun onNotify( relay: Relay, description: String, @@ -245,6 +246,38 @@ object Client : RelayPool.Listener { } } + @OptIn(DelicateCoroutinesApi::class) + override fun onSend( + relay: Relay, + msg: String, + success: Boolean, + ) { + GlobalScope.launch(Dispatchers.Default) { + listeners.forEach { it.onSend(relay, msg, success) } + } + } + + @OptIn(DelicateCoroutinesApi::class) + override fun onBeforeSend( + relay: Relay, + event: EventInterface, + ) { + GlobalScope.launch(Dispatchers.Default) { + listeners.forEach { it.onBeforeSend(relay, event) } + } + } + + @OptIn(DelicateCoroutinesApi::class) + override fun onError( + error: Error, + subscriptionId: String, + relay: Relay, + ) { + GlobalScope.launch(Dispatchers.Default) { + listeners.forEach { it.onError(error, subscriptionId, relay) } + } + } + fun subscribe(listener: Listener) { listeners = listeners.plus(listener) } @@ -298,5 +331,22 @@ object Client : RelayPool.Listener { relay: Relay, description: String, ) = Unit + + open fun onSend( + relay: Relay, + msg: String, + success: Boolean, + ) = Unit + + open fun onBeforeSend( + relay: Relay, + event: EventInterface, + ) = Unit + + open fun onError( + error: Error, + subscriptionId: String, + relay: Relay, + ) = Unit } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt index ab7108d84..0475ed4c3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt @@ -24,8 +24,8 @@ import android.util.Log import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.model.RelaySetupInfo -import com.vitorpamplona.amethyst.service.HttpClientManager import com.vitorpamplona.amethyst.service.checkNotInMainThread +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.EventInterface @@ -452,6 +452,10 @@ class Relay( fun sendOverride(signedEvent: EventInterface) { checkNotInMainThread() + listeners.forEach { listener -> + listener.onBeforeSend(this@Relay, signedEvent) + } + if (signedEvent is RelayAuthEvent) { sendAuth(signedEvent) } else { @@ -462,6 +466,10 @@ class Relay( fun send(signedEvent: EventInterface) { checkNotInMainThread() + listeners.forEach { listener -> + listener.onBeforeSend(this@Relay, signedEvent) + } + if (signedEvent is RelayAuthEvent) { sendAuth(signedEvent) } else { @@ -496,6 +504,10 @@ class Relay( if (isConnected()) { if (isReady) { writeToSocket("""["EVENT",${signedEvent.toJson()}]""") + } else { + synchronized(sendWhenReady) { + sendWhenReady.add(signedEvent) + } } } else { // sends all filters after connection is successful. @@ -512,7 +524,10 @@ class Relay( socket?.let { checkNotInMainThread() - it.send(str) + val result = it.send(str) + listeners.forEach { listener -> + listener.onSend(this@Relay, str, result) + } RelayStats.addBytesSent(url, str.bytesUsedInMemory()) if (BuildConfig.DEBUG) { @@ -588,5 +603,16 @@ class Relay( relay: Relay, description: String, ) + + fun onSend( + relay: Relay, + msg: String, + success: Boolean, + ) + + fun onBeforeSend( + relay: Relay, + event: EventInterface, + ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt index b7470feca..3a3ffaa74 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt @@ -64,6 +64,8 @@ object RelayPool : Relay.Listener { return relays.filter { it.url == url } } + fun getAll() = relays + fun getOrCreateRelay( url: String, feedTypes: Set? = null, @@ -221,6 +223,23 @@ object RelayPool : Relay.Listener { relay: Relay, description: String, ) + + fun onSend( + relay: Relay, + msg: String, + success: Boolean, + ) + + fun onBeforeSend( + relay: Relay, + event: EventInterface, + ) + + fun onError( + error: Error, + subscriptionId: String, + relay: Relay, + ) } override fun onEvent( @@ -237,6 +256,7 @@ object RelayPool : Relay.Listener { subscriptionId: String, error: Error, ) { + listeners.forEach { it.onError(error, subscriptionId, relay) } updateStatus() } @@ -274,6 +294,21 @@ object RelayPool : Relay.Listener { listeners.forEach { it.onNotify(relay, description) } } + override fun onSend( + relay: Relay, + msg: String, + success: Boolean, + ) { + listeners.forEach { it.onSend(relay, msg, success) } + } + + override fun onBeforeSend( + relay: Relay, + event: EventInterface, + ) { + listeners.forEach { it.onBeforeSend(relay, event) } + } + private fun updateStatus() { val connected = connectedRelays() val available = availableRelays() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index ba1ead032..9a3515bf1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -37,13 +37,13 @@ import androidx.compose.runtime.mutableStateOf import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.LocalCache -import com.vitorpamplona.amethyst.service.HttpClientManager import com.vitorpamplona.amethyst.service.lang.LanguageTranslatorService import com.vitorpamplona.amethyst.service.notifications.PushNotificationUtils import com.vitorpamplona.amethyst.ui.components.DEFAULT_MUTED_SETTING import com.vitorpamplona.amethyst.ui.components.keepPlayingMutex import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.navigation.debugState +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.encoders.Nip19Bech32 import com.vitorpamplona.quartz.encoders.Nip47WalletConnect import com.vitorpamplona.quartz.events.ChannelCreateEvent diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageDownloader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageDownloader.kt index e61c88ccd..466fd0a7f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageDownloader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageDownloader.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.amethyst.ui.actions -import com.vitorpamplona.amethyst.service.HttpClientManager +import com.vitorpamplona.ammolite.service.HttpClientManager import kotlinx.coroutines.CancellationException import kotlinx.coroutines.delay import java.net.HttpURLConnection diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt index b734e01ee..d044d249e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt @@ -32,7 +32,7 @@ import androidx.annotation.RequiresApi import androidx.core.net.toFile import androidx.core.net.toUri import com.vitorpamplona.amethyst.BuildConfig -import com.vitorpamplona.amethyst.service.HttpClientManager +import com.vitorpamplona.ammolite.service.HttpClientManager import kotlinx.coroutines.CancellationException import okhttp3.Call import okhttp3.Callback diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt index 18e4803c2..cffbdf57b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt @@ -28,9 +28,9 @@ import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.HttpClientManager import com.vitorpamplona.amethyst.service.Nip05NostrAddressVerifier import com.vitorpamplona.amethyst.service.relays.Client +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.crypto.CryptoUtils import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.crypto.nip06.Nip06 diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 23371bf3c..c1d0fac33 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -52,7 +52,6 @@ import com.vitorpamplona.amethyst.model.UserState import com.vitorpamplona.amethyst.model.observables.CreatedAtComparator import com.vitorpamplona.amethyst.service.CashuProcessor import com.vitorpamplona.amethyst.service.CashuToken -import com.vitorpamplona.amethyst.service.HttpClientManager import com.vitorpamplona.amethyst.service.Nip05NostrAddressVerifier import com.vitorpamplona.amethyst.service.Nip11CachedRetriever import com.vitorpamplona.amethyst.service.Nip11Retriever @@ -70,6 +69,7 @@ import com.vitorpamplona.amethyst.ui.note.showAmount import com.vitorpamplona.amethyst.ui.screen.CombinedZap import com.vitorpamplona.amethyst.ui.screen.SettingsState import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.Nip11RelayInformation diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 78eae2453..1525c4cd1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -44,6 +44,8 @@ zelory = "3.0.1" zoomable = "1.6.1" zxing = "3.5.3" zxingAndroidEmbedded = "4.3.0" +material = "1.10.0" +materialVersion = "1.10.0" [libraries] abedElazizShe-image-compressor = { group = "com.github.AbedElazizShe", name = "LightCompressor", version.ref = "lightcompressor" } @@ -114,6 +116,7 @@ zelory-video-compressor = { group = "id.zelory", name = "compressor", version.re zoomable = { group = "net.engawapg.lib", name = "zoomable", version.ref = "zoomable" } zxing = { group = "com.google.zxing", name = "core", version.ref = "zxing" } zxing-embedded = { group = "com.journeyapps", name = "zxing-android-embedded", version.ref = "zxingAndroidEmbedded" } +material = { group = "com.google.android.material", name = "material", version.ref = "materialVersion" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } diff --git a/settings.gradle b/settings.gradle index 45a4461c7..5c054bd44 100644 --- a/settings.gradle +++ b/settings.gradle @@ -32,3 +32,4 @@ include ':app' include ':benchmark' include ':quartz' include ':commons' +include ':ammolite' From 6eb0f153fafd34327b455c52522c86f4628de5fc Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 24 Jun 2024 07:36:11 -0300 Subject: [PATCH 02/49] fix build --- ammolite/build.gradle | 19 +++++++++++++++---- benchmark/build.gradle | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ammolite/build.gradle b/ammolite/build.gradle index b81832b59..2d06634ce 100644 --- a/ammolite/build.gradle +++ b/ammolite/build.gradle @@ -9,6 +9,7 @@ android { defaultConfig { minSdk 26 + targetSdk 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -16,16 +17,26 @@ android { buildTypes { release { - minifyEnabled false + minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } + create("benchmark") { + initWith(getByName("release")) + signingConfig signingConfigs.debug + } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = '17' + freeCompilerArgs += "-Xstring-concat=inline" + } + packagingOptions { + resources { + excludes += ['**/libscrypt.dylib'] + } } } diff --git a/benchmark/build.gradle b/benchmark/build.gradle index cf523ff76..b2f754cb2 100644 --- a/benchmark/build.gradle +++ b/benchmark/build.gradle @@ -55,6 +55,7 @@ dependencies { androidTestImplementation libs.androidx.benchmark.junit4 androidTestImplementation project(path: ':quartz') androidTestImplementation project(path: ':commons') + androidTestImplementation project(path: ':ammolite') androidTestImplementation libs.androidx.compose.foundation From f08a41d7a55f254b999b6fe561f5dfd6ec4a1bbe Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 24 Jun 2024 08:33:57 -0300 Subject: [PATCH 03/49] proguard --- ammolite/proguard-rules.pro | 4 +++- app/proguard-rules.pro | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ammolite/proguard-rules.pro b/ammolite/proguard-rules.pro index 481bb4348..5d804ff76 100644 --- a/ammolite/proguard-rules.pro +++ b/ammolite/proguard-rules.pro @@ -18,4 +18,6 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile + +-keep class com.vitorpamplona.ammolite.service.** { *; } \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 5b1f59d16..ce54a2b43 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -63,3 +63,4 @@ -keep class com.vitorpamplona.quartz.events.** { *; } -keep class com.vitorpamplona.amethyst.model.** { *; } -keep class com.vitorpamplona.amethyst.service.** { *; } +-keep class com.vitorpamplona.ammolite.service.** { *; } From b00781ec32ea0f36eec7c344f6188fa005fa9b40 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 24 Jun 2024 09:19:14 -0300 Subject: [PATCH 04/49] check if HttpClientManager appears in the jar --- .../ammolite/HttpClientHelperTest.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 ammolite/src/test/java/com/vitorpamplona/ammolite/HttpClientHelperTest.kt diff --git a/ammolite/src/test/java/com/vitorpamplona/ammolite/HttpClientHelperTest.kt b/ammolite/src/test/java/com/vitorpamplona/ammolite/HttpClientHelperTest.kt new file mode 100644 index 000000000..e13e41ea3 --- /dev/null +++ b/ammolite/src/test/java/com/vitorpamplona/ammolite/HttpClientHelperTest.kt @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.ammolite + +import com.vitorpamplona.ammolite.service.HttpClientManager +import junit.framework.TestCase.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class HttpClientHelperTest { + @Test + fun test() { + val proxy = HttpClientManager.getDefaultProxy() + assertEquals(null, proxy) + } +} From 66e4021d7bed6d467b02ec4fbb9305da75b4cca5 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 24 Jun 2024 10:52:34 -0300 Subject: [PATCH 05/49] Move all relay and datasource to ammolite package --- ammolite/build.gradle | 6 ++ .../ammolite/relays}/BundledUpdate.kt | 4 +- .../vitorpamplona/ammolite}/relays/Client.kt | 13 ++-- .../ammolite}/relays/Constants.kt | 3 +- .../vitorpamplona/ammolite/relays/EOSETime.kt | 27 ++++++++ .../ammolite}/relays/JsonFilter.kt | 2 +- .../ammolite/relays}/NostrDataSource.kt | 25 +++----- .../vitorpamplona/ammolite}/relays/Relay.kt | 10 ++- .../ammolite/relays/RelayBriefInfoCache.kt | 46 ++++++++++++++ .../ammolite}/relays/RelayPool.kt | 5 +- .../ammolite/relays}/RelaySetupInfo.kt | 3 +- .../ammolite}/relays/RelayStats.kt | 2 +- .../ammolite}/relays/Subscription.kt | 2 +- .../ammolite}/relays/TypedFilter.kt | 2 +- .../ammolite/service/HttpClientManager.kt | 18 +++--- .../ammolite/service/MainThreadChecker.kt | 34 ++++++++++ .../amethyst/LocalPreferences.kt | 4 +- .../vitorpamplona/amethyst/ServiceManager.kt | 21 +------ .../vitorpamplona/amethyst/model/Account.kt | 63 +++++++++++++++---- .../amethyst/model/AntiSpamFilter.kt | 6 +- .../vitorpamplona/amethyst/model/Channel.kt | 2 +- .../amethyst/model/LocalCache.kt | 4 +- .../com/vitorpamplona/amethyst/model/Note.kt | 30 ++------- .../com/vitorpamplona/amethyst/model/User.kt | 6 +- .../service/AmethystNostrDataSource.kt | 49 +++++++++++++++ .../service/NostrAccountDataSource.kt | 16 ++--- .../service/NostrChannelDataSource.kt | 8 +-- .../service/NostrChatroomDataSource.kt | 8 +-- .../service/NostrChatroomListDataSource.kt | 10 +-- .../service/NostrCommunityDataSource.kt | 8 +-- .../service/NostrDiscoveryDataSource.kt | 8 +-- .../service/NostrGeohashDataSource.kt | 8 +-- .../service/NostrHashtagDataSource.kt | 8 +-- .../amethyst/service/NostrHomeDataSource.kt | 8 +-- .../NostrLnZapPaymentResponseDataSource.kt | 12 ++-- .../NostrSearchEventOrUserDataSource.kt | 10 +-- .../service/NostrSingleChannelDataSource.kt | 10 +-- .../service/NostrSingleEventDataSource.kt | 10 +-- .../service/NostrSingleUserDataSource.kt | 10 +-- .../amethyst/service/NostrThreadDataSource.kt | 8 +-- .../service/NostrUserProfileDataSource.kt | 8 +-- .../amethyst/service/NostrVideoDataSource.kt | 8 +-- .../amethyst/service/relays/EOSE.kt | 7 +-- .../amethyst/ui/actions/EditPostViewModel.kt | 2 +- .../amethyst/ui/actions/NewMediaModel.kt | 2 +- .../amethyst/ui/actions/NewPostViewModel.kt | 2 +- .../ui/actions/RelaySelectionDialog.kt | 4 +- .../ui/actions/relays/AllRelayListView.kt | 4 +- .../ui/actions/relays/BasicRelaySetupInfo.kt | 6 +- .../relays/BasicRelaySetupInfoDialog.kt | 2 +- .../relays/BasicRelaySetupInfoModel.kt | 2 +- .../ui/actions/relays/Kind3RelayListView.kt | 8 +-- .../actions/relays/Kind3RelayListViewModel.kt | 8 +-- .../actions/relays/Nip65RelayListViewModel.kt | 2 +- .../actions/relays/RelayInformationDialog.kt | 4 +- .../ui/actions/relays/RelayUrlEditField.kt | 2 +- .../amethyst/ui/navigation/AppTopBar.kt | 4 +- .../amethyst/ui/navigation/DrawerContent.kt | 4 +- .../amethyst/ui/note/RelayListRow.kt | 2 +- .../amethyst/ui/note/UserReactionsRow.kt | 2 +- .../amethyst/ui/note/types/RelayList.kt | 2 +- .../ui/screen/AccountStateViewModel.kt | 2 +- .../amethyst/ui/screen/CardFeedViewModel.kt | 4 +- .../amethyst/ui/screen/FeedViewModel.kt | 4 +- .../amethyst/ui/screen/LnZapFeedViewModel.kt | 2 +- .../amethyst/ui/screen/RelayFeedView.kt | 2 +- .../amethyst/ui/screen/StringFeedViewModel.kt | 2 +- .../amethyst/ui/screen/UserFeedViewModel.kt | 2 +- .../ui/screen/loggedIn/AccountViewModel.kt | 2 +- .../ui/screen/loggedIn/SearchScreen.kt | 2 +- 70 files changed, 392 insertions(+), 244 deletions(-) rename {app/src/main/java/com/vitorpamplona/amethyst/ui/components => ammolite/src/main/java/com/vitorpamplona/ammolite/relays}/BundledUpdate.kt (97%) rename {app/src/main/java/com/vitorpamplona/amethyst/service => ammolite/src/main/java/com/vitorpamplona/ammolite}/relays/Client.kt (96%) rename {app/src/main/java/com/vitorpamplona/amethyst/service => ammolite/src/main/java/com/vitorpamplona/ammolite}/relays/Constants.kt (97%) create mode 100644 ammolite/src/main/java/com/vitorpamplona/ammolite/relays/EOSETime.kt rename {app/src/main/java/com/vitorpamplona/amethyst/service => ammolite/src/main/java/com/vitorpamplona/ammolite}/relays/JsonFilter.kt (98%) rename {app/src/main/java/com/vitorpamplona/amethyst/service => ammolite/src/main/java/com/vitorpamplona/ammolite/relays}/NostrDataSource.kt (93%) rename {app/src/main/java/com/vitorpamplona/amethyst/service => ammolite/src/main/java/com/vitorpamplona/ammolite}/relays/Relay.kt (98%) create mode 100644 ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelayBriefInfoCache.kt rename {app/src/main/java/com/vitorpamplona/amethyst/service => ammolite/src/main/java/com/vitorpamplona/ammolite}/relays/RelayPool.kt (98%) rename {app/src/main/java/com/vitorpamplona/amethyst/model => ammolite/src/main/java/com/vitorpamplona/ammolite/relays}/RelaySetupInfo.kt (92%) rename {app/src/main/java/com/vitorpamplona/amethyst/service => ammolite/src/main/java/com/vitorpamplona/ammolite}/relays/RelayStats.kt (98%) rename {app/src/main/java/com/vitorpamplona/amethyst/service => ammolite/src/main/java/com/vitorpamplona/ammolite}/relays/Subscription.kt (98%) rename {app/src/main/java/com/vitorpamplona/amethyst/service => ammolite/src/main/java/com/vitorpamplona/ammolite}/relays/TypedFilter.kt (95%) create mode 100644 ammolite/src/main/java/com/vitorpamplona/ammolite/service/MainThreadChecker.kt create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/service/AmethystNostrDataSource.kt diff --git a/ammolite/build.gradle b/ammolite/build.gradle index 2d06634ce..8a14671f0 100644 --- a/ammolite/build.gradle +++ b/ammolite/build.gradle @@ -15,6 +15,10 @@ android { consumerProguardFiles "consumer-rules.pro" } + buildFeatures { + buildConfig = true + } + buildTypes { release { minifyEnabled true @@ -45,6 +49,8 @@ dependencies { implementation libs.androidx.core.ktx implementation libs.androidx.appcompat implementation libs.material + implementation project(path: ':quartz') + implementation libs.androidx.runtime.runtime testImplementation libs.junit androidTestImplementation libs.androidx.junit androidTestImplementation libs.androidx.espresso.core diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/BundledUpdate.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/BundledUpdate.kt similarity index 97% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/BundledUpdate.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/BundledUpdate.kt index be77cf5f6..0a26b050b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/BundledUpdate.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/BundledUpdate.kt @@ -18,10 +18,10 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.ammolite.relays import androidx.compose.runtime.Stable -import com.vitorpamplona.amethyst.service.checkNotInMainThread +import com.vitorpamplona.ammolite.service.checkNotInMainThread import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Client.kt similarity index 96% rename from app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Client.kt index 34c494813..5fef76836 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Client.kt @@ -18,11 +18,10 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relays +package com.vitorpamplona.ammolite.relays import android.util.Log -import com.vitorpamplona.amethyst.model.RelaySetupInfo -import com.vitorpamplona.amethyst.service.checkNotInMainThread +import com.vitorpamplona.ammolite.service.checkNotInMainThread import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.EventInterface import kotlinx.coroutines.DelicateCoroutinesApi @@ -50,7 +49,7 @@ object Client : RelayPool.Listener { if (onlyIfChanged) { if (!isSameRelaySetConfig(relays)) { - if (this.relays.isNotEmpty()) { + if (Client.relays.isNotEmpty()) { RelayPool.disconnect() RelayPool.unregister(this) RelayPool.unloadRelays() @@ -61,11 +60,11 @@ object Client : RelayPool.Listener { RelayPool.register(this) RelayPool.loadRelays(newRelays) RelayPool.requestAndWatch() - this.relays = newRelays.toTypedArray() + Client.relays = newRelays.toTypedArray() } } } else { - if (this.relays.isNotEmpty()) { + if (Client.relays.isNotEmpty()) { RelayPool.disconnect() RelayPool.unregister(this) RelayPool.unloadRelays() @@ -76,7 +75,7 @@ object Client : RelayPool.Listener { RelayPool.register(this) RelayPool.loadRelays(newRelays) RelayPool.requestAndWatch() - this.relays = newRelays.toTypedArray() + Client.relays = newRelays.toTypedArray() } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Constants.kt similarity index 97% rename from app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Constants.kt index f0d8189b8..8c49189c1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Constants.kt @@ -18,9 +18,8 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relays +package com.vitorpamplona.ammolite.relays -import com.vitorpamplona.amethyst.model.RelaySetupInfo import com.vitorpamplona.quartz.encoders.RelayUrlFormatter object Constants { diff --git a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/EOSETime.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/EOSETime.kt new file mode 100644 index 000000000..4d0ed60e4 --- /dev/null +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/EOSETime.kt @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.ammolite.relays + +class EOSETime(var time: Long) { + override fun toString(): String { + return time.toString() + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/JsonFilter.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/JsonFilter.kt similarity index 98% rename from app/src/main/java/com/vitorpamplona/amethyst/service/relays/JsonFilter.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/JsonFilter.kt index eac7b0f8f..8d36668be 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/JsonFilter.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/JsonFilter.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relays +package com.vitorpamplona.ammolite.relays import com.vitorpamplona.quartz.events.Event diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/NostrDataSource.kt similarity index 93% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/NostrDataSource.kt index 4b6beb515..c27b79fb2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/NostrDataSource.kt @@ -18,15 +18,10 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service +package com.vitorpamplona.ammolite.relays import android.util.Log -import com.vitorpamplona.amethyst.model.LocalCache -import com.vitorpamplona.amethyst.service.relays.Client -import com.vitorpamplona.amethyst.service.relays.Relay -import com.vitorpamplona.amethyst.service.relays.Subscription -import com.vitorpamplona.amethyst.ui.components.BundledUpdate -import com.vitorpamplona.quartz.events.AddressableEvent +import com.vitorpamplona.ammolite.service.checkNotInMainThread import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.CoroutineScope @@ -279,20 +274,20 @@ abstract class NostrDataSource(val debugName: String) { event: Event, relay: Relay, ) { - LocalCache.verifyAndConsume(event, relay) +// LocalCache.verifyAndConsume(event, relay) } open fun markAsSeenOnRelay( eventId: String, relay: Relay, ) { - val note = LocalCache.getNoteIfExists(eventId) - val noteEvent = note?.event - if (noteEvent is AddressableEvent) { - LocalCache.getAddressableNoteIfExists(noteEvent.address().toTag())?.addRelay(relay) - } else { - note?.addRelay(relay) - } +// val note = LocalCache.getNoteIfExists(eventId) +// val noteEvent = note?.event +// if (noteEvent is AddressableEvent) { +// LocalCache.getAddressableNoteIfExists(noteEvent.address().toTag())?.addRelay(relay) +// } else { +// note?.addRelay(relay) +// } } open fun markAsEOSE( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Relay.kt similarity index 98% rename from app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Relay.kt index 0475ed4c3..9c7af4c02 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Relay.kt @@ -18,14 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relays +package com.vitorpamplona.ammolite.relays import android.util.Log -import com.vitorpamplona.amethyst.BuildConfig -import com.vitorpamplona.amethyst.model.RelayBriefInfoCache -import com.vitorpamplona.amethyst.model.RelaySetupInfo -import com.vitorpamplona.amethyst.service.checkNotInMainThread +import com.vitorpamplona.ammolite.BuildConfig import com.vitorpamplona.ammolite.service.HttpClientManager +import com.vitorpamplona.ammolite.service.checkNotInMainThread import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.EventInterface @@ -123,7 +121,7 @@ class Relay( val request = Request .Builder() - .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") + .header("User-Agent", HttpClientManager.getDefaultUserAgentHeader()) .url(url.trim()) .build() diff --git a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelayBriefInfoCache.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelayBriefInfoCache.kt new file mode 100644 index 000000000..51757c1a9 --- /dev/null +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelayBriefInfoCache.kt @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.ammolite.relays + +import android.util.LruCache +import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.encoders.RelayUrlFormatter + +object RelayBriefInfoCache { + val cache = LruCache(50) + + @Immutable + class RelayBriefInfo( + val url: String, + ) { + val displayUrl: String = RelayUrlFormatter.displayUrl(url).intern() + val favIcon: String = "https://$displayUrl/favicon.ico".intern() + } + + fun get(url: String): RelayBriefInfo { + val info = cache[url] + if (info != null) return info + + val newInfo = RelayBriefInfo(url) + cache.put(url, newInfo) + return newInfo + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelayPool.kt similarity index 98% rename from app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelayPool.kt index 3a3ffaa74..0bc96ce90 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelayPool.kt @@ -18,11 +18,10 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relays +package com.vitorpamplona.ammolite.relays import androidx.compose.runtime.Immutable -import com.vitorpamplona.amethyst.model.RelaySetupInfo -import com.vitorpamplona.amethyst.service.checkNotInMainThread +import com.vitorpamplona.ammolite.service.checkNotInMainThread import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.EventInterface import kotlinx.coroutines.DelicateCoroutinesApi diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/RelaySetupInfo.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelaySetupInfo.kt similarity index 92% rename from app/src/main/java/com/vitorpamplona/amethyst/model/RelaySetupInfo.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelaySetupInfo.kt index 6f9094c54..6c18edca8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/RelaySetupInfo.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelaySetupInfo.kt @@ -18,10 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +package com.vitorpamplona.ammolite.relays import androidx.compose.runtime.Immutable -import com.vitorpamplona.amethyst.service.relays.FeedType @Immutable data class RelaySetupInfo( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayStats.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelayStats.kt similarity index 98% rename from app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayStats.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelayStats.kt index 60a05958d..2db9be54f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayStats.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/RelayStats.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relays +package com.vitorpamplona.ammolite.relays import androidx.collection.LruCache import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Subscription.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Subscription.kt similarity index 98% rename from app/src/main/java/com/vitorpamplona/amethyst/service/relays/Subscription.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Subscription.kt index ebd0ce388..9f93b4104 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Subscription.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Subscription.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relays +package com.vitorpamplona.ammolite.relays import java.util.UUID diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/TypedFilter.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/TypedFilter.kt similarity index 95% rename from app/src/main/java/com/vitorpamplona/amethyst/service/relays/TypedFilter.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/TypedFilter.kt index 4817e7b30..84841a3e4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/TypedFilter.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/TypedFilter.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relays +package com.vitorpamplona.ammolite.relays class TypedFilter( val types: Set, diff --git a/ammolite/src/main/java/com/vitorpamplona/ammolite/service/HttpClientManager.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/service/HttpClientManager.kt index 56d96feed..20b14bcae 100644 --- a/ammolite/src/main/java/com/vitorpamplona/ammolite/service/HttpClientManager.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/service/HttpClientManager.kt @@ -39,7 +39,7 @@ object HttpClientManager { private var defaultTimeout = DEFAULT_TIMEOUT_ON_WIFI private var defaultHttpClient: OkHttpClient? = null private var defaultHttpClientWithoutProxy: OkHttpClient? = null - private var internalInterceptor: Interceptor = DefaultContentTypeInterceptor() + private var userAgent: String = "Amethyst" // fires off every time value of the property changes private var internalProxy: Proxy? by @@ -73,12 +73,14 @@ object HttpClientManager { } } - fun setDefaultInterceptor(interceptor: Interceptor) { - Log.d("HttpClient", "Changing interceptor") - this.internalInterceptor = interceptor + fun setDefaultUserAgent(userAgentHeader: String) { + Log.d("HttpClient", "Changing userAgent") + this.userAgent = userAgentHeader this.defaultHttpClient = buildHttpClient(internalProxy, defaultTimeout) } + fun getDefaultUserAgentHeader() = this.userAgent + private fun buildHttpClient( proxy: Proxy?, timeout: Duration, @@ -90,20 +92,22 @@ object HttpClientManager { .readTimeout(duration) .connectTimeout(duration) .writeTimeout(duration) - .addInterceptor(internalInterceptor) + .addInterceptor(DefaultContentTypeInterceptor(userAgent)) .followRedirects(true) .followSslRedirects(true) .build() } - class DefaultContentTypeInterceptor : Interceptor { + class DefaultContentTypeInterceptor( + private val userAgentHeader: String, + ) : Interceptor { @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { val originalRequest: Request = chain.request() val requestWithUserAgent: Request = originalRequest .newBuilder() - .header("User-Agent", "Amethyst") + .header("User-Agent", userAgentHeader) .build() return chain.proceed(requestWithUserAgent) } diff --git a/ammolite/src/main/java/com/vitorpamplona/ammolite/service/MainThreadChecker.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/service/MainThreadChecker.kt new file mode 100644 index 000000000..9b0996073 --- /dev/null +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/service/MainThreadChecker.kt @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.ammolite.service + +import android.os.Looper +import com.vitorpamplona.ammolite.BuildConfig + +fun checkNotInMainThread() { + if (BuildConfig.DEBUG && isMainThread()) { + throw OnMainThreadException("It should not be in the MainThread") + } +} + +fun isMainThread() = Looper.myLooper() == Looper.getMainLooper() + +class OnMainThreadException(str: String) : RuntimeException(str) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 4cb6574e6..22bf19827 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -31,10 +31,10 @@ import com.vitorpamplona.amethyst.model.DefaultReactions import com.vitorpamplona.amethyst.model.DefaultZapAmounts import com.vitorpamplona.amethyst.model.GLOBAL_FOLLOWS import com.vitorpamplona.amethyst.model.KIND3_FOLLOWS -import com.vitorpamplona.amethyst.model.RelaySetupInfo import com.vitorpamplona.amethyst.model.Settings import com.vitorpamplona.amethyst.service.Nip96MediaServers import com.vitorpamplona.amethyst.service.checkNotInMainThread +import com.vitorpamplona.ammolite.relays.RelaySetupInfo import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.HexKey @@ -75,7 +75,7 @@ private object PrefKeys { const val SAVED_ACCOUNTS = "all_saved_accounts" const val NOSTR_PRIVKEY = "nostr_privkey" const val NOSTR_PUBKEY = "nostr_pubkey" - const val RELAYS = "relays" + const val RELAYS = "com/vitorpamplona/ammolite/relays/relays" const val DONT_TRANSLATE_FROM = "dontTranslateFrom" const val LOCAL_RELAY_SERVERS = "localRelayServers" const val LANGUAGE_PREFS = "languagePreferences" diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt index 6136950c7..aec03f645 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt @@ -46,7 +46,7 @@ import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource import com.vitorpamplona.amethyst.service.NostrThreadDataSource import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource import com.vitorpamplona.amethyst.service.NostrVideoDataSource -import com.vitorpamplona.amethyst.service.relays.Client +import com.vitorpamplona.ammolite.relays.Client import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.encoders.bechToBytes import com.vitorpamplona.quartz.encoders.decodePublicKeyAsHexOrNull @@ -60,10 +60,6 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -import okhttp3.Interceptor -import okhttp3.Request -import okhttp3.Response -import java.io.IOException @Stable class ServiceManager { @@ -90,7 +86,7 @@ class ServiceManager { // Resets Proxy Use HttpClientManager.setDefaultProxy(account?.proxy) - HttpClientManager.setDefaultInterceptor(DefaultContentTypeInterceptor()) + HttpClientManager.setDefaultUserAgent("Amethyst/${BuildConfig.VERSION_NAME}") LocalCache.antiSpam.active = account?.filterSpamFromStrangers ?: true Coil.setImageLoader { Amethyst.instance @@ -254,16 +250,3 @@ class ServiceManager { forceRestart(null, false, true) } } - -class DefaultContentTypeInterceptor : Interceptor { - @Throws(IOException::class) - override fun intercept(chain: Interceptor.Chain): Response { - val originalRequest: Request = chain.request() - val requestWithUserAgent: Request = - originalRequest - .newBuilder() - .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") - .build() - return chain.proceed(requestWithUserAgent) - } -} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 81a9f568e..50a4f7d55 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -36,13 +36,14 @@ import com.vitorpamplona.amethyst.service.FileHeader import com.vitorpamplona.amethyst.service.Nip96MediaServers import com.vitorpamplona.amethyst.service.NostrLnZapPaymentResponseDataSource import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.service.relays.Client -import com.vitorpamplona.amethyst.service.relays.Constants -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.Relay -import com.vitorpamplona.amethyst.service.relays.TypedFilter -import com.vitorpamplona.amethyst.ui.components.BundledUpdate +import com.vitorpamplona.ammolite.relays.BundledUpdate +import com.vitorpamplona.ammolite.relays.Client +import com.vitorpamplona.ammolite.relays.Constants +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Relay +import com.vitorpamplona.ammolite.relays.RelaySetupInfo +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.HexKey @@ -265,7 +266,13 @@ class Account( newDMRelaySet.forEach { newUrl -> if (mappedRelaySet.none { it.url == newUrl }) { - mappedRelaySet = mappedRelaySet + RelaySetupInfo(newUrl, true, true, setOf(FeedType.PRIVATE_DMS)) + mappedRelaySet = mappedRelaySet + + RelaySetupInfo( + newUrl, true, true, + setOf( + FeedType.PRIVATE_DMS, + ), + ) } } @@ -284,7 +291,13 @@ class Account( searchRelaySet.forEach { newUrl -> if (mappedRelaySet.none { it.url == newUrl }) { - mappedRelaySet = mappedRelaySet + RelaySetupInfo(newUrl, true, false, setOf(FeedType.SEARCH)) + mappedRelaySet = mappedRelaySet + + RelaySetupInfo( + newUrl, true, false, + setOf( + FeedType.SEARCH, + ), + ) } } @@ -303,7 +316,13 @@ class Account( privateOutboxRelaySet.forEach { newUrl -> if (mappedRelaySet.none { it.url == newUrl }) { - mappedRelaySet = mappedRelaySet + RelaySetupInfo(newUrl, true, true, setOf(FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.GLOBAL, FeedType.PRIVATE_DMS)) + mappedRelaySet = mappedRelaySet + + RelaySetupInfo( + newUrl, true, true, + setOf( + FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.GLOBAL, FeedType.PRIVATE_DMS, + ), + ) } } @@ -322,7 +341,13 @@ class Account( localRelayServers.forEach { newUrl -> if (mappedRelaySet.none { it.url == newUrl }) { - mappedRelaySet = mappedRelaySet + RelaySetupInfo(newUrl, true, true, setOf(FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.GLOBAL, FeedType.PRIVATE_DMS)) + mappedRelaySet = mappedRelaySet + + RelaySetupInfo( + newUrl, true, true, + setOf( + FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.GLOBAL, FeedType.PRIVATE_DMS, + ), + ) } } @@ -336,7 +361,13 @@ class Account( if (nip65setup != null) { val write = nip65setup.type == AdvertisedRelayListEvent.AdvertisedRelayType.BOTH || nip65setup.type == AdvertisedRelayListEvent.AdvertisedRelayType.READ - RelaySetupInfo(relay.url, true, relay.write || write, relay.feedTypes + setOf(FeedType.FOLLOWS, FeedType.GLOBAL, FeedType.PUBLIC_CHATS)) + RelaySetupInfo( + relay.url, true, relay.write || write, + relay.feedTypes + + setOf( + FeedType.FOLLOWS, FeedType.GLOBAL, FeedType.PUBLIC_CHATS, + ), + ) } else { relay } @@ -346,7 +377,13 @@ class Account( if (mappedRelaySet.none { it.url == newNip65Setup.relayUrl }) { val write = newNip65Setup.type == AdvertisedRelayListEvent.AdvertisedRelayType.BOTH || newNip65Setup.type == AdvertisedRelayListEvent.AdvertisedRelayType.READ - mappedRelaySet = mappedRelaySet + RelaySetupInfo(newNip65Setup.relayUrl, true, write, setOf(FeedType.FOLLOWS, FeedType.PUBLIC_CHATS)) + mappedRelaySet = mappedRelaySet + + RelaySetupInfo( + newNip65Setup.relayUrl, true, write, + setOf( + FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, + ), + ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt index b5063e67c..2f0911488 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt @@ -25,9 +25,9 @@ import android.util.LruCache import androidx.compose.runtime.Stable import androidx.lifecycle.LiveData import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.service.relays.Relay -import com.vitorpamplona.amethyst.service.relays.RelayStats -import com.vitorpamplona.amethyst.ui.components.BundledUpdate +import com.vitorpamplona.ammolite.relays.BundledUpdate +import com.vitorpamplona.ammolite.relays.Relay +import com.vitorpamplona.ammolite.relays.RelayStats import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.Nip19Bech32 import com.vitorpamplona.quartz.events.Event diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt index 0c127556e..2c12a5147 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt @@ -25,9 +25,9 @@ import androidx.lifecycle.LiveData import com.vitorpamplona.amethyst.commons.data.LargeCache import com.vitorpamplona.amethyst.service.NostrSingleChannelDataSource import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder import com.vitorpamplona.amethyst.ui.note.toShortenHex +import com.vitorpamplona.ammolite.relays.BundledUpdate import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.Hex import com.vitorpamplona.quartz.encoders.HexKey diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index a88e97566..ccf4d3105 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -29,8 +29,8 @@ import com.vitorpamplona.amethyst.commons.data.LargeCache import com.vitorpamplona.amethyst.model.observables.LatestByKindAndAuthor import com.vitorpamplona.amethyst.model.observables.LatestByKindWithETag import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.service.relays.Relay -import com.vitorpamplona.amethyst.ui.components.BundledInsert +import com.vitorpamplona.ammolite.relays.BundledInsert +import com.vitorpamplona.ammolite.relays.Relay import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.HexValidator diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt index fc05e4e2d..055476c11 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model -import android.util.LruCache import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import androidx.lifecycle.LiveData @@ -29,18 +28,18 @@ import androidx.lifecycle.distinctUntilChanged import com.vitorpamplona.amethyst.service.NostrSingleEventDataSource import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.service.firstFullCharOrEmoji -import com.vitorpamplona.amethyst.service.relays.EOSETime -import com.vitorpamplona.amethyst.service.relays.Relay import com.vitorpamplona.amethyst.ui.actions.relays.updated -import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.note.combineWith import com.vitorpamplona.amethyst.ui.note.toShortenHex +import com.vitorpamplona.ammolite.relays.BundledUpdate +import com.vitorpamplona.ammolite.relays.EOSETime +import com.vitorpamplona.ammolite.relays.Relay +import com.vitorpamplona.ammolite.relays.RelayBriefInfoCache import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.Hex import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.LnInvoiceUtil import com.vitorpamplona.quartz.encoders.Nip19Bech32 -import com.vitorpamplona.quartz.encoders.RelayUrlFormatter import com.vitorpamplona.quartz.encoders.toNote import com.vitorpamplona.quartz.events.AddressableEvent import com.vitorpamplona.quartz.events.BaseTextNoteEvent @@ -1010,24 +1009,3 @@ class NoteLoadingLiveData( @Immutable class NoteState( val note: Note, ) - -object RelayBriefInfoCache { - val cache = LruCache(50) - - @Immutable - class RelayBriefInfo( - val url: String, - ) { - val displayUrl: String = RelayUrlFormatter.displayUrl(url).intern() - val favIcon: String = "https://$displayUrl/favicon.ico".intern() - } - - fun get(url: String): RelayBriefInfo { - val info = cache[url] - if (info != null) return info - - val newInfo = RelayBriefInfo(url) - cache.put(url, newInfo) - return newInfo - } -} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt index 9844ef622..078c53579 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt @@ -27,10 +27,10 @@ import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.distinctUntilChanged import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.service.relays.EOSETime -import com.vitorpamplona.amethyst.service.relays.Relay -import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.note.toShortenHex +import com.vitorpamplona.ammolite.relays.BundledUpdate +import com.vitorpamplona.ammolite.relays.EOSETime +import com.vitorpamplona.ammolite.relays.Relay import com.vitorpamplona.quartz.encoders.Hex import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.Lud06 diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/AmethystNostrDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/AmethystNostrDataSource.kt new file mode 100644 index 000000000..244d60a1f --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/AmethystNostrDataSource.kt @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.service + +import com.vitorpamplona.amethyst.model.LocalCache +import com.vitorpamplona.ammolite.relays.NostrDataSource +import com.vitorpamplona.ammolite.relays.Relay +import com.vitorpamplona.quartz.events.AddressableEvent +import com.vitorpamplona.quartz.events.Event + +abstract class AmethystNostrDataSource(debugName: String) : NostrDataSource(debugName) { + override fun consume( + event: Event, + relay: Relay, + ) { + LocalCache.verifyAndConsume(event, relay) + } + + override fun markAsSeenOnRelay( + eventId: String, + relay: Relay, + ) { + val note = LocalCache.getNoteIfExists(eventId) + val noteEvent = note?.event + if (noteEvent is AddressableEvent) { + LocalCache.getAddressableNoteIfExists(noteEvent.address().toTag())?.addRelay(relay) + } else { + note?.addRelay(relay) + } + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt index 298bcb6b3..d844308a6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt @@ -23,14 +23,14 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.User -import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES -import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.service.relays.EOSEAccount -import com.vitorpamplona.amethyst.service.relays.EOSETime -import com.vitorpamplona.amethyst.service.relays.EVENT_FINDER_TYPES -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.Relay -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES +import com.vitorpamplona.ammolite.relays.Client +import com.vitorpamplona.ammolite.relays.EOSETime +import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Relay +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent import com.vitorpamplona.quartz.events.BadgeAwardEvent @@ -70,7 +70,7 @@ import com.vitorpamplona.quartz.events.TextNoteEvent import com.vitorpamplona.quartz.utils.TimeUtils // TODO: Migrate this to a property of AccountVi -object NostrAccountDataSource : NostrDataSource("AccountData") { +object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { lateinit var account: Account var otherAccounts = listOf() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt index 8b820d284..dee51163a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt @@ -24,13 +24,13 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.Channel import com.vitorpamplona.amethyst.model.LiveActivitiesChannel import com.vitorpamplona.amethyst.model.PublicChatChannel -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.ChannelMessageEvent import com.vitorpamplona.quartz.events.LiveActivitiesChatMessageEvent -object NostrChannelDataSource : NostrDataSource("ChatroomFeed") { +object NostrChannelDataSource : AmethystNostrDataSource("ChatroomFeed") { var account: Account? = null var channel: Channel? = null diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt index ecb0efe56..86858a07b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt @@ -22,13 +22,13 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.relays.EOSEAccount -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.ChatroomKey import com.vitorpamplona.quartz.events.PrivateDmEvent -object NostrChatroomDataSource : NostrDataSource("ChatroomFeed") { +object NostrChatroomDataSource : AmethystNostrDataSource("ChatroomFeed") { lateinit var account: Account private var withRoom: ChatroomKey? = null diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt index e650a9f45..35631e73f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt @@ -22,16 +22,16 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.relays.EOSEAccount -import com.vitorpamplona.amethyst.service.relays.EVENT_FINDER_TYPES -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent import com.vitorpamplona.quartz.events.ChannelMetadataEvent import com.vitorpamplona.quartz.events.PrivateDmEvent -object NostrChatroomListDataSource : NostrDataSource("MailBoxFeed") { +object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") { lateinit var account: Account val latestEOSEs = EOSEAccount() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt index a4e0aacec..f96db2371 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt @@ -21,13 +21,13 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.AddressableNote -import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.CommunityDefinitionEvent import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent -object NostrCommunityDataSource : NostrDataSource("SingleCommunityFeed") { +object NostrCommunityDataSource : AmethystNostrDataSource("SingleCommunityFeed") { private var communityToWatch: AddressableNote? = null private fun createLoadCommunityFilter(): TypedFilter? { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt index 160daee76..62401ba1f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.relays.EOSEAccount -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AppDefinitionEvent import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent @@ -39,7 +39,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch -object NostrDiscoveryDataSource : NostrDataSource("DiscoveryFeed") { +object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { lateinit var account: Account val scope = Amethyst.instance.applicationIOScope diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt index 70e505287..55ba2e658 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt @@ -20,9 +20,9 @@ */ package com.vitorpamplona.amethyst.service -import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AudioHeaderEvent import com.vitorpamplona.quartz.events.AudioTrackEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent @@ -34,7 +34,7 @@ import com.vitorpamplona.quartz.events.PollNoteEvent import com.vitorpamplona.quartz.events.TextNoteEvent import com.vitorpamplona.quartz.events.WikiNoteEvent -object NostrGeohashDataSource : NostrDataSource("SingleGeoHashFeed") { +object NostrGeohashDataSource : AmethystNostrDataSource("SingleGeoHashFeed") { private var geohashToWatch: String? = null fun createLoadHashtagFilter(): TypedFilter? { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt index cea761f7e..d13d6d695 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt @@ -20,9 +20,9 @@ */ package com.vitorpamplona.amethyst.service -import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AudioHeaderEvent import com.vitorpamplona.quartz.events.AudioTrackEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent @@ -34,7 +34,7 @@ import com.vitorpamplona.quartz.events.PollNoteEvent import com.vitorpamplona.quartz.events.TextNoteEvent import com.vitorpamplona.quartz.events.WikiNoteEvent -object NostrHashtagDataSource : NostrDataSource("SingleHashtagFeed") { +object NostrHashtagDataSource : AmethystNostrDataSource("SingleHashtagFeed") { private var hashtagToWatch: String? = null fun createLoadHashtagFilter(): TypedFilter? { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt index be917641c..2417d2f29 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.relays.EOSEAccount -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AudioHeaderEvent import com.vitorpamplona.quartz.events.AudioTrackEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent @@ -45,7 +45,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -object NostrHomeDataSource : NostrDataSource("HomeFeed") { +object NostrHomeDataSource : AmethystNostrDataSource("HomeFeed") { lateinit var account: Account val scope = Amethyst.instance.applicationIOScope diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt index 0cd136ccb..cd5a927db 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.amethyst.service -import com.vitorpamplona.amethyst.service.relays.Client -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.Relay -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.Client +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Relay +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.LnZapPaymentResponseEvent import com.vitorpamplona.quartz.events.RelayAuthEvent import com.vitorpamplona.quartz.signers.NostrSigner @@ -34,7 +34,7 @@ class NostrLnZapPaymentResponseDataSource( private val toUserHex: String, private val replyingToHex: String, private val authSigner: NostrSigner, -) : NostrDataSource("LnZapPaymentResponseFeed") { +) : AmethystNostrDataSource("LnZapPaymentResponseFeed") { val feedTypes = setOf(FeedType.WALLET_CONNECT) private fun createWalletConnectServiceWatcher(): TypedFilter { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt index 429f2117c..432765728 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.amethyst.service -import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.Hex @@ -52,7 +52,7 @@ import com.vitorpamplona.quartz.events.TextNoteEvent import com.vitorpamplona.quartz.events.WikiNoteEvent import kotlin.coroutines.cancellation.CancellationException -object NostrSearchEventOrUserDataSource : NostrDataSource("SearchEventFeed") { +object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFeed") { private var searchString: String? = null private fun createAnythingWithIDFilter(): List? { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt index 73003b297..129e8746c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt @@ -23,14 +23,14 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.Channel import com.vitorpamplona.amethyst.model.LiveActivitiesChannel import com.vitorpamplona.amethyst.model.PublicChatChannel -import com.vitorpamplona.amethyst.service.relays.EVENT_FINDER_TYPES -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelMetadataEvent -object NostrSingleChannelDataSource : NostrDataSource("SingleChannelFeed") { +object NostrSingleChannelDataSource : AmethystNostrDataSource("SingleChannelFeed") { private var channelsToWatch = setOf() private fun createMetadataChangeFilter(): TypedFilter? { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt index ae21fd1bc..cde6acce8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt @@ -23,10 +23,10 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User -import com.vitorpamplona.amethyst.service.relays.EOSETime -import com.vitorpamplona.amethyst.service.relays.EVENT_FINDER_TYPES -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.EOSETime +import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent import com.vitorpamplona.quartz.events.DeletionEvent import com.vitorpamplona.quartz.events.GenericRepostEvent @@ -43,7 +43,7 @@ import com.vitorpamplona.quartz.events.RepostEvent import com.vitorpamplona.quartz.events.TextNoteEvent import com.vitorpamplona.quartz.events.TextNoteModificationEvent -object NostrSingleEventDataSource : NostrDataSource("SingleEventFeed") { +object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") { private var eventsToWatch = setOf() private var addressesToWatch = setOf() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt index e1a768992..7cfb2604a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt @@ -21,16 +21,16 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.User -import com.vitorpamplona.amethyst.service.relays.EOSETime -import com.vitorpamplona.amethyst.service.relays.EVENT_FINDER_TYPES -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.EOSETime +import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent import com.vitorpamplona.quartz.events.MetadataEvent import com.vitorpamplona.quartz.events.ReportEvent import com.vitorpamplona.quartz.events.StatusEvent -object NostrSingleUserDataSource : NostrDataSource("SingleUserFeed") { +object NostrSingleUserDataSource : AmethystNostrDataSource("SingleUserFeed") { private var usersToWatch = setOf() fun createUserMetadataFilter(): List? { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt index 4d6d730a1..3fae129a4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt @@ -21,11 +21,11 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.ThreadAssembler -import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter -object NostrThreadDataSource : NostrDataSource("SingleThreadFeed") { +object NostrThreadDataSource : AmethystNostrDataSource("SingleThreadFeed") { private var eventToWatch: String? = null fun createLoadEventsIfNotLoadedFilter(): TypedFilter? { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt index 58ab69b5b..19e16f2ec 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt @@ -21,9 +21,9 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.User -import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AppRecommendationEvent import com.vitorpamplona.quartz.events.AudioHeaderEvent import com.vitorpamplona.quartz.events.AudioTrackEvent @@ -43,7 +43,7 @@ import com.vitorpamplona.quartz.events.RepostEvent import com.vitorpamplona.quartz.events.TextNoteEvent import com.vitorpamplona.quartz.events.WikiNoteEvent -object NostrUserProfileDataSource : NostrDataSource("UserProfileFeed") { +object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") { var user: User? = null fun loadUserProfile(user: User?) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt index 9cca2cfd2..2dc2c18f2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.relays.EOSEAccount -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.JsonFilter -import com.vitorpamplona.amethyst.service.relays.TypedFilter +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.FileHeaderEvent import com.vitorpamplona.quartz.events.FileStorageHeaderEvent import com.vitorpamplona.quartz.events.VideoHorizontalEvent @@ -37,7 +37,7 @@ import kotlinx.coroutines.launch val SUPPORTED_VIDEO_FEED_MIME_TYPES = listOf("image/jpeg", "image/gif", "image/png", "image/webp", "video/mp4", "video/mpeg", "video/webm", "audio/aac", "audio/mpeg", "audio/webm", "audio/wav", "image/avif") val SUPPORTED_VIDEO_FEED_MIME_TYPES_SET = SUPPORTED_VIDEO_FEED_MIME_TYPES.toSet() -object NostrVideoDataSource : NostrDataSource("VideoFeed") { +object NostrVideoDataSource : AmethystNostrDataSource("VideoFeed") { lateinit var account: Account val scope = Amethyst.instance.applicationIOScope diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt index a99a83878..83f2e9729 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt @@ -21,12 +21,7 @@ package com.vitorpamplona.amethyst.service.relays import com.vitorpamplona.amethyst.model.User - -class EOSETime(var time: Long) { - override fun toString(): String { - return time.toString() - } -} +import com.vitorpamplona.ammolite.relays.EOSETime class EOSERelayList(var relayList: Map = emptyMap()) { fun addOrUpdate( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt index abfc5d22f..a951d4a7a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt @@ -36,13 +36,13 @@ import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.model.RelaySetupInfo import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.FileHeader import com.vitorpamplona.amethyst.service.Nip96Uploader import com.vitorpamplona.amethyst.service.NostrSearchEventOrUserDataSource import com.vitorpamplona.amethyst.ui.components.MediaCompressor import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.ammolite.relays.RelaySetupInfo import com.vitorpamplona.quartz.events.FileHeaderEvent import com.vitorpamplona.quartz.events.FileStorageEvent import com.vitorpamplona.quartz.events.FileStorageHeaderEvent diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt index 91c0bf1c8..c9d3ccf79 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt @@ -31,12 +31,12 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.RelaySetupInfo import com.vitorpamplona.amethyst.service.FileHeader import com.vitorpamplona.amethyst.service.Nip96MediaServers import com.vitorpamplona.amethyst.service.Nip96Uploader import com.vitorpamplona.amethyst.ui.components.MediaCompressor import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.ammolite.relays.RelaySetupInfo import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt index 854d96a96..9a420cb51 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt @@ -40,7 +40,6 @@ import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.model.RelaySetupInfo import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.FileHeader import com.vitorpamplona.amethyst.service.LocationUtil @@ -49,6 +48,7 @@ import com.vitorpamplona.amethyst.service.NostrSearchEventOrUserDataSource import com.vitorpamplona.amethyst.ui.components.MediaCompressor import com.vitorpamplona.amethyst.ui.components.Split import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.ammolite.relays.RelaySetupInfo import com.vitorpamplona.quartz.encoders.Hex import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.toNpub diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt index fceca3760..4d28188f9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt @@ -46,13 +46,13 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.model.RelayBriefInfoCache -import com.vitorpamplona.amethyst.model.RelaySetupInfo import com.vitorpamplona.amethyst.service.Nip11Retriever import com.vitorpamplona.amethyst.ui.actions.relays.RelayInformationDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.FeedPadding +import com.vitorpamplona.ammolite.relays.RelayBriefInfoCache +import com.vitorpamplona.ammolite.relays.RelaySetupInfo import com.vitorpamplona.quartz.encoders.Nip11RelayInformation import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt index 3db105155..a24f599c5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt @@ -47,8 +47,6 @@ import androidx.compose.ui.window.DialogProperties import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.service.relays.Constants -import com.vitorpamplona.amethyst.service.relays.RelayStat import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.SaveButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -58,6 +56,8 @@ import com.vitorpamplona.amethyst.ui.theme.MinHorzSpacer import com.vitorpamplona.amethyst.ui.theme.RowColSpacing import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.grayText +import com.vitorpamplona.ammolite.relays.Constants +import com.vitorpamplona.ammolite.relays.RelayStat @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfo.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfo.kt index be695f995..2d03d4ad7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfo.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfo.kt @@ -21,9 +21,9 @@ package com.vitorpamplona.amethyst.ui.actions.relays import androidx.compose.runtime.Immutable -import com.vitorpamplona.amethyst.model.RelayBriefInfoCache -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.RelayStat +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.RelayBriefInfoCache +import com.vitorpamplona.ammolite.relays.RelayStat @Immutable data class BasicRelaySetupInfo( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt index cc69a83c4..134320ed0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt @@ -28,11 +28,11 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.FeatureSetType -import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.service.Nip11Retriever import com.vitorpamplona.amethyst.ui.actions.RelayInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.ammolite.relays.RelayBriefInfoCache @Composable fun BasicRelaySetupInfoDialog( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt index 69fb9a41a..9eea0faa9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt @@ -24,7 +24,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.Nip11CachedRetriever -import com.vitorpamplona.amethyst.service.relays.RelayStats +import com.vitorpamplona.ammolite.relays.RelayStats import com.vitorpamplona.quartz.encoders.RelayUrlFormatter import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt index 0eba7699e..8741f2cdb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt @@ -67,12 +67,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.FeatureSetType -import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.service.Nip11CachedRetriever import com.vitorpamplona.amethyst.service.Nip11Retriever -import com.vitorpamplona.amethyst.service.relays.Constants -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.RelayStat import com.vitorpamplona.amethyst.ui.actions.RelayInfoDialog import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -91,6 +87,10 @@ import com.vitorpamplona.amethyst.ui.theme.allGoodColor import com.vitorpamplona.amethyst.ui.theme.largeRelayIconModifier import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.warningColor +import com.vitorpamplona.ammolite.relays.Constants +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.RelayBriefInfoCache +import com.vitorpamplona.ammolite.relays.RelayStat import com.vitorpamplona.quartz.encoders.RelayUrlFormatter import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt index bbd00140b..de48cb790 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt @@ -23,11 +23,11 @@ package com.vitorpamplona.amethyst.ui.actions.relays import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.RelaySetupInfo import com.vitorpamplona.amethyst.service.Nip11CachedRetriever -import com.vitorpamplona.amethyst.service.relays.Constants -import com.vitorpamplona.amethyst.service.relays.FeedType -import com.vitorpamplona.amethyst.service.relays.RelayStats +import com.vitorpamplona.ammolite.relays.Constants +import com.vitorpamplona.ammolite.relays.FeedType +import com.vitorpamplona.ammolite.relays.RelaySetupInfo +import com.vitorpamplona.ammolite.relays.RelayStats import com.vitorpamplona.quartz.encoders.RelayUrlFormatter import kotlinx.collections.immutable.toImmutableSet import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt index 615a41e03..c41ce2c1d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt @@ -24,7 +24,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.Nip11CachedRetriever -import com.vitorpamplona.amethyst.service.relays.RelayStats +import com.vitorpamplona.ammolite.relays.RelayStats import com.vitorpamplona.quartz.encoders.RelayUrlFormatter import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt index fa4b5c086..368f5b3ee 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt @@ -49,8 +49,6 @@ import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.FeatureSetType -import com.vitorpamplona.amethyst.model.RelayBriefInfoCache -import com.vitorpamplona.amethyst.service.relays.RelayStats import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.ClickableEmail @@ -67,6 +65,8 @@ import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.largeRelayIconModifier +import com.vitorpamplona.ammolite.relays.RelayBriefInfoCache +import com.vitorpamplona.ammolite.relays.RelayStats import com.vitorpamplona.quartz.encoders.Nip11RelayInformation import com.vitorpamplona.quartz.events.EmptyTagList import kotlinx.collections.immutable.toImmutableList diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt index ded0da398..3cbe0af8a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt @@ -36,11 +36,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.service.relays.RelayStat import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.placeholderText +import com.vitorpamplona.ammolite.relays.RelayStat import com.vitorpamplona.quartz.encoders.RelayUrlFormatter @Composable diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt index f8faac59e..ca2a34b62 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt @@ -97,8 +97,6 @@ import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource import com.vitorpamplona.amethyst.service.NostrThreadDataSource import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource import com.vitorpamplona.amethyst.service.NostrVideoDataSource -import com.vitorpamplona.amethyst.service.relays.Client -import com.vitorpamplona.amethyst.service.relays.RelayPool import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.note.AmethystIcon @@ -138,6 +136,8 @@ import com.vitorpamplona.amethyst.ui.theme.Size22Modifier import com.vitorpamplona.amethyst.ui.theme.Size34dp import com.vitorpamplona.amethyst.ui.theme.Size40dp import com.vitorpamplona.amethyst.ui.theme.placeholderText +import com.vitorpamplona.ammolite.relays.Client +import com.vitorpamplona.ammolite.relays.RelayPool import com.vitorpamplona.quartz.events.ChatroomKey import com.vitorpamplona.quartz.events.ContactListEvent import com.vitorpamplona.quartz.events.MuteListEvent diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index 4202294fc..2b83b0d60 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -85,8 +85,6 @@ import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.User -import com.vitorpamplona.amethyst.service.relays.RelayPool -import com.vitorpamplona.amethyst.service.relays.RelayPoolStatus import com.vitorpamplona.amethyst.ui.actions.relays.AllRelayListView import com.vitorpamplona.amethyst.ui.components.ClickableText import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji @@ -110,6 +108,8 @@ import com.vitorpamplona.amethyst.ui.theme.bannerModifier import com.vitorpamplona.amethyst.ui.theme.drawerSpacing import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.profileContentHeaderModifier +import com.vitorpamplona.ammolite.relays.RelayPool +import com.vitorpamplona.ammolite.relays.RelayPoolStatus import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.events.ImmutableListOfLists diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt index 39a5b3dd6..c9c3bed9a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt @@ -40,7 +40,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.service.Nip11CachedRetriever import com.vitorpamplona.amethyst.service.Nip11Retriever import com.vitorpamplona.amethyst.ui.actions.relays.RelayInformationDialog @@ -54,6 +53,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size17dp import com.vitorpamplona.amethyst.ui.theme.StdStartPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.relayIconModifier +import com.vitorpamplona.ammolite.relays.RelayBriefInfoCache @Composable public fun RelayBadgesHorizontal( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt index 4d07867c4..9b2e8fd5d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt @@ -57,7 +57,6 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.components.BundledInsert import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange @@ -66,6 +65,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.ui.theme.Size24Modifier import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText +import com.vitorpamplona.ammolite.relays.BundledInsert import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.events.BaseTextNoteEvent import com.vitorpamplona.quartz.events.GenericRepostEvent diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt index 5bef0fcdb..59f0a69e3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt @@ -44,13 +44,13 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.ui.actions.relays.AllRelayListView import com.vitorpamplona.amethyst.ui.components.ShowMoreButton import com.vitorpamplona.amethyst.ui.note.AddRelayButton import com.vitorpamplona.amethyst.ui.note.RemoveRelayButton import com.vitorpamplona.amethyst.ui.note.getGradient import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.ammolite.relays.RelayBriefInfoCache import com.vitorpamplona.quartz.events.RelaySetEvent import kotlinx.collections.immutable.toImmutableList diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt index cffbdf57b..e7ba98d21 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt @@ -29,7 +29,7 @@ import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.Nip05NostrAddressVerifier -import com.vitorpamplona.amethyst.service.relays.Client +import com.vitorpamplona.ammolite.relays.Client import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.crypto.CryptoUtils import com.vitorpamplona.quartz.crypto.KeyPair diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt index 26134adc5..d41d24623 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt @@ -32,11 +32,11 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.components.BundledInsert -import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter import com.vitorpamplona.amethyst.ui.dal.FeedFilter import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter +import com.vitorpamplona.ammolite.relays.BundledInsert +import com.vitorpamplona.ammolite.relays.BundledUpdate import com.vitorpamplona.quartz.events.BadgeAwardEvent import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelMetadataEvent diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt index c4ca09313..422bd15a2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt @@ -33,8 +33,6 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.components.BundledInsert -import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter import com.vitorpamplona.amethyst.ui.dal.BookmarkPrivateFeedFilter import com.vitorpamplona.amethyst.ui.dal.BookmarkPublicFeedFilter @@ -62,6 +60,8 @@ import com.vitorpamplona.amethyst.ui.dal.UserProfileConversationsFeedFilter import com.vitorpamplona.amethyst.ui.dal.UserProfileNewThreadFeedFilter import com.vitorpamplona.amethyst.ui.dal.UserProfileReportsFeedFilter import com.vitorpamplona.amethyst.ui.dal.VideoFeedFilter +import com.vitorpamplona.ammolite.relays.BundledInsert +import com.vitorpamplona.ammolite.relays.BundledUpdate import com.vitorpamplona.quartz.events.ChatroomKey import com.vitorpamplona.quartz.events.DeletionEvent import kotlinx.collections.immutable.ImmutableList diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt index 1465d73ea..a0db78fc0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt @@ -29,9 +29,9 @@ import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.dal.FeedFilter import com.vitorpamplona.amethyst.ui.dal.UserProfileZapsFeedFilter +import com.vitorpamplona.ammolite.relays.BundledUpdate import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt index dafa52a53..38b5550b1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt @@ -38,11 +38,11 @@ import com.vitorpamplona.amethyst.model.RelayInfo import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.UserState import com.vitorpamplona.amethyst.ui.actions.relays.AllRelayListView -import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.note.RelayCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding +import com.vitorpamplona.ammolite.relays.BundledUpdate import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedViewModel.kt index 438c5849b..600d8b756 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedViewModel.kt @@ -29,9 +29,9 @@ import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.dal.FeedFilter import com.vitorpamplona.amethyst.ui.dal.HiddenWordsFeedFilter +import com.vitorpamplona.ammolite.relays.BundledUpdate import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt index 58a5b8b4e..252d3fdb0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt @@ -30,12 +30,12 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.dal.FeedFilter import com.vitorpamplona.amethyst.ui.dal.HiddenAccountsFeedFilter import com.vitorpamplona.amethyst.ui.dal.SpammerAccountsFeedFilter import com.vitorpamplona.amethyst.ui.dal.UserProfileFollowersFeedFilter import com.vitorpamplona.amethyst.ui.dal.UserProfileFollowsFeedFilter +import com.vitorpamplona.ammolite.relays.BundledUpdate import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index c1d0fac33..092109738 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -59,7 +59,6 @@ import com.vitorpamplona.amethyst.service.OnlineChecker import com.vitorpamplona.amethyst.service.ZapPaymentHandler import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.actions.Dao -import com.vitorpamplona.amethyst.ui.components.BundledInsert import com.vitorpamplona.amethyst.ui.components.UrlPreviewState import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.navigation.bottomNavigationItems @@ -69,6 +68,7 @@ import com.vitorpamplona.amethyst.ui.note.showAmount import com.vitorpamplona.amethyst.ui.screen.CombinedZap import com.vitorpamplona.amethyst.ui.screen.SettingsState import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.ammolite.relays.BundledInsert import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.HexKey diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt index 04587f108..b2f8e7b60 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt @@ -76,7 +76,6 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.NostrSearchEventOrUserDataSource import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.note.AboutDisplay import com.vitorpamplona.amethyst.ui.note.ChannelName import com.vitorpamplona.amethyst.ui.note.ClearTextIcon @@ -92,6 +91,7 @@ import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.ui.theme.StdTopPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText +import com.vitorpamplona.ammolite.relays.BundledUpdate import com.vitorpamplona.quartz.events.findHashtags import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview From c0ee8e2d61b65afa320ba434ac9e272a48a06113 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 24 Jun 2024 11:10:13 -0300 Subject: [PATCH 06/49] fix proguard rules --- ammolite/proguard-rules.pro | 3 ++- app/proguard-rules.pro | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ammolite/proguard-rules.pro b/ammolite/proguard-rules.pro index 5d804ff76..f2c80152a 100644 --- a/ammolite/proguard-rules.pro +++ b/ammolite/proguard-rules.pro @@ -20,4 +20,5 @@ # hide the original source file name. #-renamesourcefileattribute SourceFile --keep class com.vitorpamplona.ammolite.service.** { *; } \ No newline at end of file +-keep class com.vitorpamplona.ammolite.service.** { *; } +-keep class com.vitorpamplona.ammolite.relays.** { *; } \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index ce54a2b43..fc7d6cf0f 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -64,3 +64,4 @@ -keep class com.vitorpamplona.amethyst.model.** { *; } -keep class com.vitorpamplona.amethyst.service.** { *; } -keep class com.vitorpamplona.ammolite.service.** { *; } +-keep class com.vitorpamplona.ammolite.relays.** { *; } From 21898482dee97823756b27b4e15ddfeaf9d27cbc Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 24 Jun 2024 11:22:41 -0300 Subject: [PATCH 07/49] Fix merge --- .../main/java/com/vitorpamplona/ammolite/relays/Client.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Client.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Client.kt index 054c3a958..12bc0a62f 100644 --- a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Client.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Client.kt @@ -194,7 +194,6 @@ object Client : RelayPool.Listener { } } - @OptIn(DelicateCoroutinesApi::class) override fun onRelayStateChange( type: Relay.StateType, relay: Relay, @@ -207,7 +206,6 @@ object Client : RelayPool.Listener { // } } - @OptIn(DelicateCoroutinesApi::class) override fun onSendResponse( eventId: String, success: Boolean, @@ -221,7 +219,6 @@ object Client : RelayPool.Listener { } } - @OptIn(DelicateCoroutinesApi::class) override fun onAuth( relay: Relay, challenge: String, @@ -231,7 +228,6 @@ object Client : RelayPool.Listener { GlobalScope.launch(Dispatchers.Default) { listeners.forEach { it.onAuth(relay, challenge) } } } - @OptIn(DelicateCoroutinesApi::class) override fun onNotify( relay: Relay, description: String, @@ -243,7 +239,6 @@ object Client : RelayPool.Listener { } } - @OptIn(DelicateCoroutinesApi::class) override fun onSend( relay: Relay, msg: String, @@ -254,7 +249,6 @@ object Client : RelayPool.Listener { } } - @OptIn(DelicateCoroutinesApi::class) override fun onBeforeSend( relay: Relay, event: EventInterface, @@ -264,7 +258,6 @@ object Client : RelayPool.Listener { } } - @OptIn(DelicateCoroutinesApi::class) override fun onError( error: Error, subscriptionId: String, From 266dabdd7a371ba8b253dcccaa0ef44b47e04756 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 24 Jun 2024 11:24:13 -0300 Subject: [PATCH 08/49] fix shared prefs key --- .../main/java/com/vitorpamplona/amethyst/LocalPreferences.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index b127119cf..7a3c1ac78 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -75,7 +75,7 @@ private object PrefKeys { const val SAVED_ACCOUNTS = "all_saved_accounts" const val NOSTR_PRIVKEY = "nostr_privkey" const val NOSTR_PUBKEY = "nostr_pubkey" - const val RELAYS = "com/vitorpamplona/ammolite/relays/relays" + const val RELAYS = "relays" const val DONT_TRANSLATE_FROM = "dontTranslateFrom" const val LOCAL_RELAY_SERVERS = "localRelayServers" const val LANGUAGE_PREFS = "languagePreferences" From 9ee2452430c4d2da6daddbc4ac54ec4978eb039c Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 24 Jun 2024 11:32:03 -0300 Subject: [PATCH 09/49] Fix build --- .../java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt index aaffa85f1..f915355ee 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt @@ -97,6 +97,7 @@ import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource import com.vitorpamplona.amethyst.service.NostrThreadDataSource import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource import com.vitorpamplona.amethyst.service.NostrVideoDataSource +import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.note.AmethystIcon From 8c3e87339aacc7b0ae7b2548a9d81d8387e8fca3 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 24 Jun 2024 14:03:01 -0300 Subject: [PATCH 10/49] remove commented code --- .../ammolite/relays/NostrDataSource.kt | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/NostrDataSource.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/NostrDataSource.kt index c27b79fb2..666b55061 100644 --- a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/NostrDataSource.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/NostrDataSource.kt @@ -25,6 +25,7 @@ import com.vitorpamplona.ammolite.service.checkNotInMainThread import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.SupervisorJob @@ -152,6 +153,7 @@ abstract class NostrDataSource(val debugName: String) { resetFilters() } + @OptIn(DelicateCoroutinesApi::class) open fun stop() { active = false println("DataSource: ${this.javaClass.simpleName} Stop") @@ -202,7 +204,7 @@ abstract class NostrDataSource(val debugName: String) { scope.launch(Dispatchers.IO) { resetFiltersSuspend() } } - fun resetFiltersSuspend() { + private fun resetFiltersSuspend() { println("DataSource: ${this.javaClass.simpleName} resetFiltersSuspend $active") checkNotInMainThread() @@ -273,22 +275,12 @@ abstract class NostrDataSource(val debugName: String) { open fun consume( event: Event, relay: Relay, - ) { -// LocalCache.verifyAndConsume(event, relay) - } + ) = Unit open fun markAsSeenOnRelay( eventId: String, relay: Relay, - ) { -// val note = LocalCache.getNoteIfExists(eventId) -// val noteEvent = note?.event -// if (noteEvent is AddressableEvent) { -// LocalCache.getAddressableNoteIfExists(noteEvent.address().toTag())?.addRelay(relay) -// } else { -// note?.addRelay(relay) -// } - } + ) = Unit open fun markAsEOSE( subscriptionId: String, From 1b57c5636d8bdc822809ee10efa72c6b127c6293 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Mon, 24 Jun 2024 17:36:59 +0000 Subject: [PATCH 11/49] New Crowdin translations by GitHub Action --- app/src/main/res/values-hi-rIN/strings.xml | 2 ++ app/src/main/res/values-pl-rPL/strings.xml | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index b978d5c61..38fd4c515 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -448,6 +448,7 @@ स्थापना विकल्प सर्वदा केवल वै॰फै॰ + मात्रांकन रहित वैफै॰ कभी नहीं सम्पूर्ण सरलीकृत @@ -661,6 +662,7 @@ उद्धृत करें अथवा टीका लिखें इष्ट ज्साप + शीघ्र प्रतिक्रियाओं का परिवर्तन करें %1$s का परिचय चित्र पुनःप्रसारक %1$s पुनःप्रसारक सूची का विस्तारण करें diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index 51949274a..027123bdf 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -86,7 +86,7 @@ "Informacja o grupie.. " Co masz na myśli? Wyślij - Zapisz + OK Utwórz Anuluj Nie udało się przesłać obrazu @@ -385,7 +385,7 @@ Zalecenia: Filtruj spam z nieznajomych Ostrzegaj, gdy posty zostały zgłoszone przez osoby które obserwujesz - Nowy Symbol reakcji + Nowy Symbol Odzewu Brak wstępnie wybranych typów reakcji dla tego użytkownika. Przytrzymaj przycisk serce, aby zmienić Zapraiser Dodaje docelową liczbę satów do podniesienia dla tego wpisu. W zależności od aplikacji może być pokazywany to jako pasek postępu, aby zachęcić do darowizn @@ -448,6 +448,7 @@ Ustawienia Zawsze Tylko WiFi + Nielimitowany Wi-Fi Nigdy Kompletny Uproszczony @@ -585,7 +586,7 @@ Nie można utworzyć faktury przed wysłaniem zapa. Element pr nie został znaleziony w powstałym JSON. Nie można utworzyć faktury od %1$s: Element pr nie został znaleziony w powstałym JSON. \"Tylko do odczytu\" - Nie ustawiono reakcji + Nie ustawiono odzewu Wybierz aplikację UnifiedPush Powiadomienia Z zainstalowanych aplikacji UnifiedPush @@ -655,12 +656,13 @@ Nowy post Nowe Króciaki: zdjęcia lub filmiki Nowy wpis w społeczności - Otwórz wszystkie reakcje na ten post - Zamknij wszystkie reakcje na ten post + Otwórz wszystkie odzewy na ten post + Zamknij wszystkie odzewy na ten post Odpowiedz Zrepostuj lub Zacytuj Lubię Zap + Zmień odzew Zdjęcie profilowe %1$s Transmiter %1$s Rozwiń listę transmiterów From 4609d6e3436d8b414fb5ef68e2ab160d7960fda5 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 24 Jun 2024 14:13:55 -0400 Subject: [PATCH 12/49] changes app directory to amethyst --- .github/workflows/build.yml | 4 +-- .github/workflows/create-release.yml | 32 +++++++++--------- README.md | 2 +- {app => amethyst}/.gitignore | 0 {app => amethyst}/build.gradle | 0 {app => amethyst}/google-services.json | 0 {app => amethyst}/proguard-rules.pro | 0 .../amethyst/ImageUploadTesting.kt | 0 .../vitorpamplona/amethyst/OkHttpOtsTest.kt | 0 .../amethyst/ThreadAssemblerTest.kt | 0 .../amethyst/UrlUserTagTransformationTest.kt | 0 .../src/androidTest/res/values/strings.xml | 0 .../amethyst/TranslationsTest.kt | 0 .../src/fdroid/AndroidManifest.xml | 0 .../service/lang/LanguageTranslatorService.kt | 0 .../notifications/PushDistributorHandler.kt | 0 .../notifications/PushMessageReceiver.kt | 0 .../notifications/PushNotificationUtils.kt | 0 .../components/SelectNotificationProvider.kt | 0 .../components/TranslatableRichTextViewer.kt | 0 .../src/main/AndroidManifest.xml | 0 .../src/main/ic_launcher-playstore.png | Bin .../material3/pullrefresh/PullRefresh.kt | 0 .../pullrefresh/PullRefreshIndicator.kt | 0 .../PullRefreshIndicatorTransform.kt | 0 .../material3/pullrefresh/PullRefreshState.kt | 0 .../com/vitorpamplona/amethyst/Amethyst.kt | 0 .../amethyst/EncryptedStorage.kt | 0 .../amethyst/LocalPreferences.kt | 0 .../vitorpamplona/amethyst/ServiceManager.kt | 0 .../vitorpamplona/amethyst/model/Account.kt | 0 .../amethyst/model/AntiSpamFilter.kt | 0 .../vitorpamplona/amethyst/model/Channel.kt | 0 .../vitorpamplona/amethyst/model/Chatroom.kt | 0 .../amethyst/model/HashtagIcon.kt | 0 .../amethyst/model/LocalCache.kt | 0 .../vitorpamplona/amethyst/model/MiniFhir.kt | 0 .../com/vitorpamplona/amethyst/model/Note.kt | 0 .../amethyst/model/ParticipantListBuilder.kt | 0 .../vitorpamplona/amethyst/model/Settings.kt | 0 .../amethyst/model/ThreadAssembler.kt | 0 .../amethyst/model/ThreadLevelCalculator.kt | 0 .../amethyst/model/UrlCachedPreviewer.kt | 0 .../com/vitorpamplona/amethyst/model/User.kt | 0 .../model/observables/CreatedAtComparator.kt | 0 .../observables/LatestByKindAndAuthor.kt | 0 .../model/observables/LatestByKindWithETag.kt | 0 .../service/AmethystNostrDataSource.kt | 0 .../amethyst/service/BlurHashImage.kt | 0 .../amethyst/service/CachedRichTextParser.kt | 0 .../amethyst/service/CashuProcessor.kt | 0 .../amethyst/service/EmojiUtils.kt | 0 .../amethyst/service/FileHeader.kt | 0 .../amethyst/service/LocationUtil.kt | 0 .../amethyst/service/MainThreadChecker.kt | 0 .../service/Nip05NostrAddressVerifier.kt | 0 .../service/Nip11RelayInfoRetriever.kt | 0 .../amethyst/service/Nip96MediaServers.kt | 0 .../amethyst/service/Nip96Uploader.kt | 0 .../service/NostrAccountDataSource.kt | 0 .../service/NostrChannelDataSource.kt | 0 .../service/NostrChatroomDataSource.kt | 0 .../service/NostrChatroomListDataSource.kt | 0 .../service/NostrCommunityDataSource.kt | 0 .../service/NostrDiscoveryDataSource.kt | 0 .../service/NostrGeohashDataSource.kt | 0 .../service/NostrHashtagDataSource.kt | 0 .../amethyst/service/NostrHomeDataSource.kt | 0 .../NostrLnZapPaymentResponseDataSource.kt | 0 .../NostrSearchEventOrUserDataSource.kt | 0 .../service/NostrSingleChannelDataSource.kt | 0 .../service/NostrSingleEventDataSource.kt | 0 .../service/NostrSingleUserDataSource.kt | 0 .../amethyst/service/NostrThreadDataSource.kt | 0 .../service/NostrUserProfileDataSource.kt | 0 .../amethyst/service/NostrVideoDataSource.kt | 0 .../amethyst/service/OnlineCheck.kt | 0 .../amethyst/service/PackageUtils.kt | 0 .../amethyst/service/ZapPaymentHandler.kt | 0 .../amethyst/service/lnurl/CachedLnInvoice.kt | 0 .../service/lnurl/LightningAddressResolver.kt | 0 .../amethyst/service/model/zaps/UserZaps.kt | 0 .../EventNotificationConsumer.kt | 0 .../notifications/NotificationUtils.kt | 0 .../service/notifications/RegisterAccounts.kt | 0 .../service/ots/OkHttpBlockstreamExplorer.kt | 0 .../amethyst/service/ots/OkHttpCalendar.kt | 0 .../service/ots/OkHttpCalendarAsyncSubmit.kt | 0 .../service/ots/OkHttpCalendarBuilder.kt | 0 .../playback/MultiPlayerPlaybackManager.kt | 0 .../playback/PlaybackClientController.kt | 0 .../service/playback/PlaybackService.kt | 0 .../amethyst/service/playback/VideoCache.kt | 0 .../playback/VideoViewedPositionCache.kt | 0 .../playback/WssDataStreamCollector.kt | 0 .../service/playback/WssStreamDataSource.kt | 0 .../service/previews/BahaUrlPreview.kt | 0 .../service/previews/IUrlPreviewCallback.kt | 0 .../amethyst/service/previews/UrlInfoItem.kt | 0 .../service/previews/UrlPreviewUtils.kt | 0 .../amethyst/service/relays/EOSE.kt | 0 .../service/tts/TextToSpeechEngine.kt | 0 .../service/tts/TextToSpeechHelper.kt | 0 .../vitorpamplona/amethyst/ui/AppScreen.kt | 0 .../vitorpamplona/amethyst/ui/MainActivity.kt | 0 .../amethyst/ui/StringResourceCache.kt | 0 .../amethyst/ui/actions/CrossfadeIfEnabled.kt | 0 .../amethyst/ui/actions/EditPostView.kt | 0 .../amethyst/ui/actions/EditPostViewModel.kt | 0 .../amethyst/ui/actions/ImageDownloader.kt | 0 .../amethyst/ui/actions/ImageSaver.kt | 0 .../amethyst/ui/actions/InformationDialog.kt | 0 .../ui/actions/JoinUserOrChannelView.kt | 0 .../amethyst/ui/actions/NewChannelView.kt | 0 .../ui/actions/NewChannelViewModel.kt | 0 .../amethyst/ui/actions/NewMediaModel.kt | 0 .../amethyst/ui/actions/NewMediaView.kt | 0 .../amethyst/ui/actions/NewMessageTagger.kt | 0 .../amethyst/ui/actions/NewPollClosing.kt | 0 .../ui/actions/NewPollConsensusThreshold.kt | 0 .../amethyst/ui/actions/NewPollOption.kt | 0 .../ui/actions/NewPollPrimaryDescription.kt | 0 .../ui/actions/NewPollRecipientsField.kt | 0 .../ui/actions/NewPollVoteValueRange.kt | 0 .../amethyst/ui/actions/NewPostView.kt | 0 .../amethyst/ui/actions/NewPostViewModel.kt | 0 .../ui/actions/NewUserMetadataView.kt | 0 .../ui/actions/NewUserMetadataViewModel.kt | 0 .../ui/actions/NotifyRequestDialog.kt | 0 .../ui/actions/RelaySelectionDialog.kt | 0 .../amethyst/ui/actions/SaveToGallery.kt | 0 .../amethyst/ui/actions/UploadFromGallery.kt | 0 .../ui/actions/UrlUserTagTransformation.kt | 0 .../ui/actions/relays/AddDMRelayListDialog.kt | 0 .../relays/AddSearchRelayListDialog.kt | 0 .../ui/actions/relays/AllRelayListView.kt | 0 .../ui/actions/relays/BasicRelaySetupInfo.kt | 0 .../relays/BasicRelaySetupInfoClickableRow.kt | 0 .../relays/BasicRelaySetupInfoDialog.kt | 0 .../relays/BasicRelaySetupInfoModel.kt | 0 .../ui/actions/relays/ByteFormatter.kt | 0 .../ui/actions/relays/DMRelayListView.kt | 0 .../ui/actions/relays/DMRelayListViewModel.kt | 0 .../ui/actions/relays/Kind3RelayListView.kt | 0 .../actions/relays/Kind3RelayListViewModel.kt | 0 .../ui/actions/relays/LocalRelayListView.kt | 0 .../actions/relays/LocalRelayListViewModel.kt | 0 .../ui/actions/relays/Nip65RelayListView.kt | 0 .../actions/relays/Nip65RelayListViewModel.kt | 0 .../relays/PrivateOutboxRelayListView.kt | 0 .../relays/PrivateOutboxRelayListViewModel.kt | 0 .../actions/relays/RelayInformationDialog.kt | 0 .../relays/RelayNameAndRemoveButton.kt | 0 .../ui/actions/relays/RelayStatusRow.kt | 0 .../ui/actions/relays/RelayUrlEditField.kt | 0 .../ui/actions/relays/SearchRelayListView.kt | 0 .../relays/SearchRelayListViewModel.kt | 0 .../amethyst/ui/buttons/ChannelFabColumn.kt | 0 .../amethyst/ui/buttons/NewChannelButton.kt | 0 .../ui/buttons/NewCommunityNoteButton.kt | 0 .../amethyst/ui/buttons/NewImageButton.kt | 0 .../amethyst/ui/buttons/NewNoteButton.kt | 0 .../ui/components/AudioWaveformReadOnly.kt | 0 .../amethyst/ui/components/CashuRedeem.kt | 0 .../amethyst/ui/components/ClickableBox.kt | 0 .../amethyst/ui/components/ClickableEmail.kt | 0 .../ui/components/ClickableNoteTag.kt | 0 .../amethyst/ui/components/ClickablePhone.kt | 0 .../amethyst/ui/components/ClickableRoute.kt | 0 .../amethyst/ui/components/ClickableUrl.kt | 0 .../ui/components/ClickableUserTag.kt | 0 .../ui/components/ClickableWithdrawal.kt | 0 .../ui/components/ExpandableRichTextViewer.kt | 0 .../ui/components/ForwardingPainter.kt | 0 .../amethyst/ui/components/GenericLoadable.kt | 0 .../amethyst/ui/components/InvoicePreview.kt | 0 .../amethyst/ui/components/InvoiceRequest.kt | 0 .../amethyst/ui/components/LoadUrlPreview.kt | 0 .../amethyst/ui/components/MediaCompressor.kt | 0 .../amethyst/ui/components/RichTextViewer.kt | 0 .../ui/components/RobohashAsyncImage.kt | 0 .../ui/components/SelectTextDialog.kt | 0 .../ui/components/SensitivityWarning.kt | 0 .../amethyst/ui/components/SlidingCarousel.kt | 0 .../amethyst/ui/components/SplitItem.kt | 0 .../amethyst/ui/components/TextSpinner.kt | 0 .../ui/components/TranslationConfig.kt | 0 .../amethyst/ui/components/UrlPreviewCard.kt | 0 .../amethyst/ui/components/UrlPreviewState.kt | 0 .../amethyst/ui/components/VideoView.kt | 0 .../ui/components/ZapRaiserRequest.kt | 0 .../ui/components/ZoomableContentDialog.kt | 0 .../ui/components/ZoomableContentView.kt | 0 .../markdown/MarkdownMediaRenderer.kt | 0 .../markdown/RenderContentAsMarkdown.kt | 0 .../ui/dal/BookmarkPrivateFeedFilter.kt | 0 .../ui/dal/BookmarkPublicFeedFilter.kt | 0 .../amethyst/ui/dal/ChannelFeedFilter.kt | 0 .../amethyst/ui/dal/ChatroomFeedFilter.kt | 0 .../ui/dal/ChatroomListKnownFeedFilter.kt | 0 .../ui/dal/ChatroomListNewFeedFilter.kt | 0 .../amethyst/ui/dal/CommunityFeedFilter.kt | 0 .../amethyst/ui/dal/DefaultFeedOrder.kt | 0 .../amethyst/ui/dal/DiscoverChatFeedFilter.kt | 0 .../ui/dal/DiscoverCommunityFeedFilter.kt | 0 .../amethyst/ui/dal/DiscoverLiveFeedFilter.kt | 0 .../ui/dal/DiscoverMarketplaceFeedFilter.kt | 0 .../ui/dal/DiscoverNIP89FeedFilter.kt | 0 .../amethyst/ui/dal/DraftEventsFeedFilter.kt | 0 .../amethyst/ui/dal/FeedFilter.kt | 0 .../amethyst/ui/dal/FilterByListParams.kt | 0 .../amethyst/ui/dal/GeoHashFeedFilter.kt | 0 .../amethyst/ui/dal/HashtagFeedFilter.kt | 0 .../ui/dal/HiddenAccountsFeedFilter.kt | 0 .../ui/dal/HomeConversationsFeedFilter.kt | 0 .../ui/dal/HomeNewThreadFeedFilter.kt | 0 .../NIP90ContentDiscoveryResponseFilter.kt | 0 .../amethyst/ui/dal/NotificationFeedFilter.kt | 0 .../amethyst/ui/dal/ThreadFeedFilter.kt | 0 ...UserProfileAppRecommendationsFeedFilter.kt | 0 .../ui/dal/UserProfileBookmarksFeedFilter.kt | 0 .../dal/UserProfileConversationsFeedFilter.kt | 0 .../ui/dal/UserProfileFollowersFeedFilter.kt | 0 .../ui/dal/UserProfileFollowsFeedFilter.kt | 0 .../ui/dal/UserProfileNewThreadFeedFilter.kt | 0 .../ui/dal/UserProfileReportsFeedFilter.kt | 0 .../ui/dal/UserProfileZapsFeedFilter.kt | 0 .../amethyst/ui/dal/VideoFeedFilter.kt | 0 .../amethyst/ui/layouts/ChatHeaderLayout.kt | 0 .../amethyst/ui/layouts/LeftPictureLayout.kt | 0 .../amethyst/ui/layouts/RepostLayout.kt | 0 .../ui/navigation/AccountSwitchBottomSheet.kt | 0 .../amethyst/ui/navigation/AppBottomBar.kt | 0 .../amethyst/ui/navigation/AppNavigation.kt | 0 .../amethyst/ui/navigation/AppTopBar.kt | 0 .../amethyst/ui/navigation/DrawerContent.kt | 0 .../amethyst/ui/navigation/RouteMaker.kt | 0 .../amethyst/ui/navigation/Routes.kt | 0 .../amethyst/ui/note/BadgeCompose.kt | 0 .../amethyst/ui/note/BlankNote.kt | 0 .../amethyst/ui/note/BlockReportChecker.kt | 0 .../amethyst/ui/note/ChannelCardCompose.kt | 0 .../amethyst/ui/note/ChatroomHeaderCompose.kt | 0 .../ui/note/ChatroomMessageCompose.kt | 0 .../vitorpamplona/amethyst/ui/note/Icons.kt | 0 .../vitorpamplona/amethyst/ui/note/Loaders.kt | 0 .../amethyst/ui/note/MessageSetCompose.kt | 0 .../amethyst/ui/note/MultiSetCompose.kt | 0 .../ui/note/NIP05VerificationDisplay.kt | 0 .../amethyst/ui/note/NoteCompose.kt | 0 .../amethyst/ui/note/NoteQuickActionMenu.kt | 0 .../amethyst/ui/note/PollNote.kt | 0 .../amethyst/ui/note/PollNoteViewModel.kt | 0 .../amethyst/ui/note/PubKeyFormatter.kt | 0 .../amethyst/ui/note/ReactionsRow.kt | 0 .../amethyst/ui/note/RelayCompose.kt | 0 .../amethyst/ui/note/RelayListBox.kt | 0 .../amethyst/ui/note/RelayListRow.kt | 0 .../amethyst/ui/note/ReplyInformation.kt | 0 .../amethyst/ui/note/TimeAgoFormatter.kt | 0 .../ui/note/UpdateReactionTypeDialog.kt | 0 .../amethyst/ui/note/UpdateZapAmountDialog.kt | 0 .../amethyst/ui/note/UserCompose.kt | 0 .../amethyst/ui/note/UserProfilePicture.kt | 0 .../amethyst/ui/note/UserReactionsRow.kt | 0 .../amethyst/ui/note/UsernameDisplay.kt | 0 .../amethyst/ui/note/WatchNoteEvent.kt | 0 .../amethyst/ui/note/ZapCustomDialog.kt | 0 .../amethyst/ui/note/ZapFormatter.kt | 0 .../amethyst/ui/note/ZapNoteCompose.kt | 0 .../amethyst/ui/note/ZapUserSetCompose.kt | 0 .../note/elements/AddInboxRelayForDMCard.kt | 0 .../elements/AddInboxRelayForSearchCard.kt | 0 .../ui/note/elements/AddRemoveButtons.kt | 0 .../amethyst/ui/note/elements/BoostedMark.kt | 0 .../ui/note/elements/DefaultImageHeader.kt | 0 .../ui/note/elements/DisplayCommunity.kt | 0 .../ui/note/elements/DisplayEditStatus.kt | 0 .../ui/note/elements/DisplayHashtags.kt | 0 .../ui/note/elements/DisplayLocation.kt | 0 .../amethyst/ui/note/elements/DisplayOts.kt | 0 .../amethyst/ui/note/elements/DisplayPoW.kt | 0 .../ui/note/elements/DisplayReward.kt | 0 .../note/elements/DisplayUncitedHashtags.kt | 0 .../ui/note/elements/DisplayZapSplits.kt | 0 .../amethyst/ui/note/elements/DropDownMenu.kt | 0 .../amethyst/ui/note/elements/ForkInfo.kt | 0 .../amethyst/ui/note/elements/TimeAgo.kt | 0 .../ui/note/elements/ZapTheDevsCard.kt | 0 .../amethyst/ui/note/types/AppDefinition.kt | 0 .../amethyst/ui/note/types/AudioTrack.kt | 0 .../amethyst/ui/note/types/Badge.kt | 0 .../amethyst/ui/note/types/ChannelMessage.kt | 0 .../amethyst/ui/note/types/ChatMessage.kt | 0 .../amethyst/ui/note/types/Classifieds.kt | 0 .../amethyst/ui/note/types/CommunityHeader.kt | 0 .../amethyst/ui/note/types/Emoji.kt | 0 .../amethyst/ui/note/types/FileHeader.kt | 0 .../amethyst/ui/note/types/FileStorage.kt | 0 .../amethyst/ui/note/types/Git.kt | 0 .../amethyst/ui/note/types/Highlight.kt | 0 .../amethyst/ui/note/types/LiveActivity.kt | 0 .../ui/note/types/LiveActivityChatMessage.kt | 0 .../amethyst/ui/note/types/LongForm.kt | 0 .../amethyst/ui/note/types/MedicalData.kt | 0 .../types/NIP90ContentDiscoveryResponse.kt | 0 .../amethyst/ui/note/types/NIP90Status.kt | 0 .../amethyst/ui/note/types/PeopleList.kt | 0 .../amethyst/ui/note/types/PinList.kt | 0 .../amethyst/ui/note/types/Poll.kt | 0 .../amethyst/ui/note/types/PrivateMessage.kt | 0 .../amethyst/ui/note/types/Reaction.kt | 0 .../amethyst/ui/note/types/RelayList.kt | 0 .../ui/note/types/RenderPostApproval.kt | 0 .../amethyst/ui/note/types/Report.kt | 0 .../amethyst/ui/note/types/Text.kt | 0 .../ui/note/types/TextModification.kt | 0 .../amethyst/ui/note/types/Video.kt | 0 .../amethyst/ui/note/types/VideoDisplay.kt | 0 .../amethyst/ui/note/types/Wiki.kt | 0 .../amethyst/ui/qrcode/QrCodeDrawer.kt | 0 .../amethyst/ui/qrcode/QrCodeScanner.kt | 0 .../amethyst/ui/qrcode/ShowQRDialog.kt | 0 .../amethyst/ui/screen/AccountScreen.kt | 0 .../amethyst/ui/screen/AccountState.kt | 0 .../ui/screen/AccountStateViewModel.kt | 0 .../amethyst/ui/screen/CardFeedState.kt | 0 .../amethyst/ui/screen/CardFeedView.kt | 0 .../amethyst/ui/screen/CardFeedViewModel.kt | 0 .../amethyst/ui/screen/ChatroomFeedView.kt | 0 .../ui/screen/ChatroomListFeedView.kt | 0 .../amethyst/ui/screen/FeedState.kt | 0 .../amethyst/ui/screen/FeedView.kt | 0 .../amethyst/ui/screen/FeedViewModel.kt | 0 .../amethyst/ui/screen/LnZapFeedState.kt | 0 .../amethyst/ui/screen/LnZapFeedView.kt | 0 .../amethyst/ui/screen/LnZapFeedViewModel.kt | 0 .../amethyst/ui/screen/RelayFeedView.kt | 0 .../ui/screen/RememberForeverStates.kt | 0 .../ui/screen/SharedPreferencesViewModel.kt | 0 .../amethyst/ui/screen/StringFeedState.kt | 0 .../amethyst/ui/screen/StringFeedView.kt | 0 .../amethyst/ui/screen/StringFeedViewModel.kt | 0 .../amethyst/ui/screen/ThreadFeedView.kt | 0 .../amethyst/ui/screen/UserFeedState.kt | 0 .../amethyst/ui/screen/UserFeedView.kt | 0 .../amethyst/ui/screen/UserFeedViewModel.kt | 0 .../ui/screen/loggedIn/AccountBackupDialog.kt | 0 .../ui/screen/loggedIn/AccountViewModel.kt | 2 ++ .../ui/screen/loggedIn/BookmarkListScreen.kt | 0 .../ui/screen/loggedIn/ChannelScreen.kt | 0 .../ui/screen/loggedIn/ChatroomListScreen.kt | 0 .../ui/screen/loggedIn/ChatroomScreen.kt | 0 .../ui/screen/loggedIn/CommunityScreen.kt | 0 .../ui/screen/loggedIn/ConnectOrbotDialog.kt | 0 .../ui/screen/loggedIn/DiscoverScreen.kt | 0 .../ui/screen/loggedIn/DraftListScreen.kt | 0 .../ui/screen/loggedIn/GeoHashScreen.kt | 0 .../ui/screen/loggedIn/HashtagScreen.kt | 0 .../ui/screen/loggedIn/HiddenUsersScreen.kt | 0 .../amethyst/ui/screen/loggedIn/HomeScreen.kt | 0 .../ui/screen/loggedIn/LoadRedirectScreen.kt | 0 .../amethyst/ui/screen/loggedIn/MainScreen.kt | 0 .../loggedIn/NIP90ContentDiscoveryScreen.kt | 0 .../ui/screen/loggedIn/NotificationScreen.kt | 0 .../ui/screen/loggedIn/ProfileScreen.kt | 0 .../ui/screen/loggedIn/ReportNoteDialog.kt | 0 .../ui/screen/loggedIn/SearchScreen.kt | 0 .../ui/screen/loggedIn/SettingsScreen.kt | 0 .../ui/screen/loggedIn/ThreadScreen.kt | 0 .../ui/screen/loggedIn/VideoScreen.kt | 0 .../screen/loggedOff/LoginOrSignupScreen.kt | 0 .../ui/screen/loggedOff/LoginScreen.kt | 0 .../ui/screen/loggedOff/SignUpScreen.kt | 0 .../vitorpamplona/amethyst/ui/theme/Color.kt | 0 .../vitorpamplona/amethyst/ui/theme/Shape.kt | 0 .../vitorpamplona/amethyst/ui/theme/Theme.kt | 0 .../vitorpamplona/amethyst/ui/theme/Type.kt | 0 .../main/res/drawable-anydpi/ic_add_photo.xml | 0 .../src/main/res/drawable-anydpi/ic_close.xml | 0 .../src/main/res/drawable-anydpi/ic_key.xml | 0 .../main/res/drawable-anydpi/ic_logout.xml | 0 .../main/res/drawable-anydpi/ic_security.xml | 0 .../main/res/drawable-hdpi/ic_bookmarks.png | Bin .../src/main/res/drawable-hdpi/ic_compose.png | Bin .../src/main/res/drawable-hdpi/ic_dm.png | Bin .../src/main/res/drawable-hdpi/ic_globe.png | Bin .../src/main/res/drawable-hdpi/ic_home.png | Bin .../src/main/res/drawable-hdpi/ic_key.png | Bin .../src/main/res/drawable-hdpi/ic_lists.png | Bin .../src/main/res/drawable-hdpi/ic_logout.png | Bin .../src/main/res/drawable-hdpi/ic_moments.png | Bin .../res/drawable-hdpi/ic_notifications.png | Bin .../src/main/res/drawable-hdpi/ic_poll.png | Bin .../src/main/res/drawable-hdpi/ic_profile.png | Bin .../src/main/res/drawable-hdpi/ic_qrcode.png | Bin .../main/res/drawable-hdpi/ic_security.png | Bin .../src/main/res/drawable-hdpi/ic_theme.png | Bin .../src/main/res/drawable-hdpi/ic_topics.png | Bin .../src/main/res/drawable-hdpi/ic_trends.png | Bin .../main/res/drawable-hdpi/ic_verified.png | Bin .../drawable-hdpi/ic_verified_transparent.png | Bin .../main/res/drawable-mdpi/ic_bookmarks.png | Bin .../src/main/res/drawable-mdpi/ic_compose.png | Bin .../src/main/res/drawable-mdpi/ic_dm.png | Bin .../src/main/res/drawable-mdpi/ic_globe.png | Bin .../src/main/res/drawable-mdpi/ic_home.png | Bin .../src/main/res/drawable-mdpi/ic_key.png | Bin .../src/main/res/drawable-mdpi/ic_lists.png | Bin .../src/main/res/drawable-mdpi/ic_logout.png | Bin .../src/main/res/drawable-mdpi/ic_moments.png | Bin .../res/drawable-mdpi/ic_notifications.png | Bin .../src/main/res/drawable-mdpi/ic_poll.png | Bin .../src/main/res/drawable-mdpi/ic_profile.png | Bin .../src/main/res/drawable-mdpi/ic_qrcode.png | Bin .../main/res/drawable-mdpi/ic_security.png | Bin .../src/main/res/drawable-mdpi/ic_theme.png | Bin .../src/main/res/drawable-mdpi/ic_topics.png | Bin .../src/main/res/drawable-mdpi/ic_trends.png | Bin .../main/res/drawable-mdpi/ic_verified.png | Bin .../drawable-mdpi/ic_verified_transparent.png | Bin .../res/drawable-night-hdpi/ic_verified.png | Bin .../res/drawable-night-mdpi/ic_verified.png | Bin .../res/drawable-night-xhdpi/ic_verified.png | Bin .../res/drawable-night-xxhdpi/ic_verified.png | Bin .../drawable-night-xxxhdpi/ic_verified.png | Bin .../src/main/res/drawable-night/nip_05.xml | 0 .../main/res/drawable-xhdpi/ic_bookmarks.png | Bin .../main/res/drawable-xhdpi/ic_compose.png | Bin .../src/main/res/drawable-xhdpi/ic_dm.png | Bin .../src/main/res/drawable-xhdpi/ic_globe.png | Bin .../src/main/res/drawable-xhdpi/ic_home.png | Bin .../src/main/res/drawable-xhdpi/ic_key.png | Bin .../src/main/res/drawable-xhdpi/ic_lists.png | Bin .../src/main/res/drawable-xhdpi/ic_logout.png | Bin .../main/res/drawable-xhdpi/ic_moments.png | Bin .../res/drawable-xhdpi/ic_notifications.png | Bin .../src/main/res/drawable-xhdpi/ic_poll.png | Bin .../main/res/drawable-xhdpi/ic_profile.png | Bin .../src/main/res/drawable-xhdpi/ic_qrcode.png | Bin .../main/res/drawable-xhdpi/ic_security.png | Bin .../src/main/res/drawable-xhdpi/ic_theme.png | Bin .../src/main/res/drawable-xhdpi/ic_topics.png | Bin .../src/main/res/drawable-xhdpi/ic_trends.png | Bin .../main/res/drawable-xhdpi/ic_verified.png | Bin .../ic_verified_transparent.png | Bin .../main/res/drawable-xxhdpi/ic_bookmarks.png | Bin .../main/res/drawable-xxhdpi/ic_compose.png | Bin .../src/main/res/drawable-xxhdpi/ic_dm.png | Bin .../src/main/res/drawable-xxhdpi/ic_globe.png | Bin .../src/main/res/drawable-xxhdpi/ic_home.png | Bin .../src/main/res/drawable-xxhdpi/ic_key.png | Bin .../src/main/res/drawable-xxhdpi/ic_lists.png | Bin .../main/res/drawable-xxhdpi/ic_logout.png | Bin .../main/res/drawable-xxhdpi/ic_moments.png | Bin .../res/drawable-xxhdpi/ic_notifications.png | Bin .../src/main/res/drawable-xxhdpi/ic_poll.png | Bin .../main/res/drawable-xxhdpi/ic_profile.png | Bin .../main/res/drawable-xxhdpi/ic_qrcode.png | Bin .../main/res/drawable-xxhdpi/ic_security.png | Bin .../src/main/res/drawable-xxhdpi/ic_theme.png | Bin .../main/res/drawable-xxhdpi/ic_topics.png | Bin .../main/res/drawable-xxhdpi/ic_trends.png | Bin .../main/res/drawable-xxhdpi/ic_verified.png | Bin .../ic_verified_transparent.png | Bin .../res/drawable-xxxhdpi/ic_bookmarks.png | Bin .../main/res/drawable-xxxhdpi/ic_compose.png | Bin .../src/main/res/drawable-xxxhdpi/ic_dm.png | Bin .../main/res/drawable-xxxhdpi/ic_globe.png | Bin .../src/main/res/drawable-xxxhdpi/ic_home.png | Bin .../main/res/drawable-xxxhdpi/ic_lists.png | Bin .../main/res/drawable-xxxhdpi/ic_moments.png | Bin .../res/drawable-xxxhdpi/ic_notifications.png | Bin .../src/main/res/drawable-xxxhdpi/ic_poll.png | Bin .../main/res/drawable-xxxhdpi/ic_profile.png | Bin .../main/res/drawable-xxxhdpi/ic_qrcode.png | Bin .../main/res/drawable-xxxhdpi/ic_theme.png | Bin .../main/res/drawable-xxxhdpi/ic_topics.png | Bin .../main/res/drawable-xxxhdpi/ic_trends.png | Bin .../main/res/drawable-xxxhdpi/ic_verified.png | Bin .../ic_verified_transparent.png | Bin .../res/drawable-xxxhdpi/profile_banner.jpeg | Bin .../src/main/res/drawable/alby.xml | 0 .../src/main/res/drawable/amethyst.xml | 0 .../main/res/drawable/amethyst_monochrome.xml | 0 .../src/main/res/drawable/following.xml | 0 .../src/main/res/drawable/github.xml | 0 .../res/drawable/ic_launcher_foreground.xml | 0 .../src/main/res/drawable/ic_sensors.xml | 0 .../src/main/res/drawable/ic_settings.xml | 0 .../src/main/res/drawable/ic_tor.xml | 0 .../src/main/res/drawable/ic_video.xml | 0 .../src/main/res/drawable/incognito.xml | 0 .../src/main/res/drawable/incognito_off.xml | 0 .../src/main/res/drawable/lyrics_off.xml | 0 .../src/main/res/drawable/lyrics_on.xml | 0 .../src/main/res/drawable/manage_accounts.xml | 0 .../src/main/res/drawable/mastodon.xml | 0 .../src/main/res/drawable/nip_05.xml | 0 .../src/main/res/drawable/nip_05_full.xml | 0 .../src/main/res/drawable/original.xml | 0 .../src/main/res/drawable/relays.xml | 0 .../src/main/res/drawable/telegram.xml | 0 .../text_select_move_forward_character.xml | 0 .../src/main/res/drawable/twitter.xml | 0 .../res/mipmap-anydpi-v26/ic_launcher.xml | 0 .../mipmap-anydpi-v26/ic_launcher_round.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../mipmap-hdpi/ic_launcher_foreground.png | Bin .../res/mipmap-hdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-hdpi/mutiny.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../mipmap-mdpi/ic_launcher_foreground.png | Bin .../res/mipmap-mdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-mdpi/mutiny.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../mipmap-xhdpi/ic_launcher_foreground.png | Bin .../res/mipmap-xhdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-xhdpi/mutiny.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-xxhdpi/mutiny.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-xxxhdpi/mutiny.png | Bin .../src/main/res/values-ar/strings.xml | 0 .../src/main/res/values-bn-rBD/strings.xml | 0 .../src/main/res/values-cs/strings.xml | 0 .../src/main/res/values-cy-rGB/strings.xml | 0 .../src/main/res/values-da-rDK/strings.xml | 0 .../src/main/res/values-de/strings.xml | 0 .../src/main/res/values-el-rGR/strings.xml | 0 .../src/main/res/values-en-rGB/strings.xml | 0 .../src/main/res/values-eo/strings.xml | 0 .../src/main/res/values-es-rES/strings.xml | 0 .../src/main/res/values-es-rMX/strings.xml | 0 .../src/main/res/values-es-rUS/strings.xml | 0 .../src/main/res/values-es/strings.xml | 0 .../src/main/res/values-et-rEE/strings.xml | 0 .../src/main/res/values-fa/strings.xml | 0 .../src/main/res/values-fi-rFI/strings.xml | 0 .../src/main/res/values-fo-rFO/strings.xml | 0 .../src/main/res/values-fr-rCA/strings.xml | 0 .../src/main/res/values-fr/strings.xml | 0 .../src/main/res/values-gu-rIN/strings.xml | 0 .../src/main/res/values-hi-rIN/strings.xml | 0 .../src/main/res/values-hr-rHR/strings.xml | 0 .../src/main/res/values-hu/strings.xml | 0 .../src/main/res/values-in-rID/strings.xml | 0 .../src/main/res/values-in/strings.xml | 0 .../src/main/res/values-it-rIT/strings.xml | 0 .../src/main/res/values-iw-rIL/strings.xml | 0 .../src/main/res/values-ja/strings.xml | 0 .../src/main/res/values-kk-rKZ/strings.xml | 0 .../src/main/res/values-ko-rKR/strings.xml | 0 .../src/main/res/values-ks-rIN/strings.xml | 0 .../src/main/res/values-ku-rTR/strings.xml | 0 .../src/main/res/values-lt-rLT/strings.xml | 0 .../src/main/res/values-ne-rNP/strings.xml | 0 .../src/main/res/values-night/themes.xml | 0 .../src/main/res/values-nl-rBE/strings.xml | 0 .../src/main/res/values-nl/strings.xml | 0 .../src/main/res/values-pcm-rNG/strings.xml | 0 .../src/main/res/values-pl-rPL/strings.xml | 0 .../src/main/res/values-pt-rBR/strings.xml | 0 .../src/main/res/values-pt-rPT/strings.xml | 0 .../src/main/res/values-ru-rUA/strings.xml | 0 .../src/main/res/values-ru/strings.xml | 0 .../src/main/res/values-sa-rIN/strings.xml | 0 .../src/main/res/values-sl-rSI/strings.xml | 0 .../src/main/res/values-so-rSO/strings.xml | 0 .../src/main/res/values-sr-rSP/strings.xml | 0 .../src/main/res/values-ss-rZA/strings.xml | 0 .../src/main/res/values-sv-rSE/strings.xml | 0 .../src/main/res/values-sw-rKE/strings.xml | 0 .../src/main/res/values-sw-rTZ/strings.xml | 0 .../src/main/res/values-ta/strings.xml | 0 .../src/main/res/values-th/strings.xml | 0 .../src/main/res/values-tr/strings.xml | 0 .../src/main/res/values-uk/strings.xml | 0 .../src/main/res/values-ur-rIN/strings.xml | 0 .../src/main/res/values-uz-rUZ/strings.xml | 0 .../src/main/res/values-vi-rVN/strings.xml | 0 .../src/main/res/values-zh-rCN/strings.xml | 0 .../src/main/res/values-zh-rHK/strings.xml | 0 .../src/main/res/values-zh-rSG/strings.xml | 0 .../src/main/res/values-zh-rTW/strings.xml | 0 .../src/main/res/values-zh/strings.xml | 0 .../src/main/res/values/colors.xml | 0 .../res/values/ic_launcher_background.xml | 0 .../src/main/res/values/strings.xml | 0 .../src/main/res/values/themes.xml | 0 .../src/main/res/xml/backup_rules.xml | 0 .../main/res/xml/data_extraction_rules.xml | 0 .../src/main/res/xml/locales_config.xml | 0 .../src/play/AndroidManifest.xml | 0 .../service/lang/LanguageTranslatorService.kt | 0 .../PushNotificationReceiverService.kt | 0 .../notifications/PushNotificationUtils.kt | 0 .../components/SelectNotificationProvider.kt | 0 .../components/TranslatableRichTextViewer.kt | 0 .../src/test/java/android/util/Log.java | 0 .../com/vitorpamplona/amethyst/CharsetTest.kt | 0 .../amethyst/NewMessageTaggerKeyParseTest.kt | 0 .../vitorpamplona/amethyst/SplitterTest.kt | 0 .../service/Nip05NostrAddressVerifierTest.kt | 0 .../amethyst/service/Nip96Test.kt | 0 .../amethyst/service/zaps/UserZapsTest.kt | 0 build.gradle | 2 +- crowdin.yml | 4 +-- settings.gradle | 2 +- 613 files changed, 25 insertions(+), 23 deletions(-) rename {app => amethyst}/.gitignore (100%) rename {app => amethyst}/build.gradle (100%) rename {app => amethyst}/google-services.json (100%) rename {app => amethyst}/proguard-rules.pro (100%) rename {app => amethyst}/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt (100%) rename {app => amethyst}/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt (100%) rename {app => amethyst}/src/androidTest/java/com/vitorpamplona/amethyst/ThreadAssemblerTest.kt (100%) rename {app => amethyst}/src/androidTest/java/com/vitorpamplona/amethyst/UrlUserTagTransformationTest.kt (100%) rename {app => amethyst}/src/androidTest/res/values/strings.xml (100%) rename {app => amethyst}/src/androidTestPlay/java/com/vitorpamplona/amethyst/TranslationsTest.kt (100%) rename {app => amethyst}/src/fdroid/AndroidManifest.xml (100%) rename {app => amethyst}/src/fdroid/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt (100%) rename {app => amethyst}/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt (100%) rename {app => amethyst}/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt (100%) rename {app => amethyst}/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt (100%) rename {app => amethyst}/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt (100%) rename {app => amethyst}/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt (100%) rename {app => amethyst}/src/main/AndroidManifest.xml (100%) rename {app => amethyst}/src/main/ic_launcher-playstore.png (100%) rename {app => amethyst}/src/main/java/androidx/compose/material3/pullrefresh/PullRefresh.kt (100%) rename {app => amethyst}/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshIndicator.kt (100%) rename {app => amethyst}/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshIndicatorTransform.kt (100%) rename {app => amethyst}/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshState.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/Account.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/Chatroom.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/HashtagIcon.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/MiniFhir.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/Note.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/ParticipantListBuilder.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/ThreadAssembler.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/ThreadLevelCalculator.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/UrlCachedPreviewer.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/User.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/observables/CreatedAtComparator.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindAndAuthor.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindWithETag.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/AmethystNostrDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/BlurHashImage.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/EmojiUtils.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/FileHeader.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/LocationUtil.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/MainThreadChecker.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/Nip11RelayInfoRetriever.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/Nip96MediaServers.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/PackageUtils.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/lnurl/CachedLnInvoice.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/model/zaps/UserZaps.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpBlockstreamExplorer.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarAsyncSubmit.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarBuilder.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/playback/MultiPlayerPlaybackManager.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackClientController.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/playback/VideoCache.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/playback/VideoViewedPositionCache.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/playback/WssDataStreamCollector.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/playback/WssStreamDataSource.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/previews/BahaUrlPreview.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/previews/IUrlPreviewCallback.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlInfoItem.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechEngine.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechHelper.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/AppScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageDownloader.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMessageTagger.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollClosing.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollConsensusThreshold.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollOption.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollPrimaryDescription.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollRecipientsField.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollVoteValueRange.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/UrlUserTagTransformation.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddDMRelayListDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddSearchRelayListDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfo.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoClickableRow.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/ByteFormatter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayNameAndRemoveButton.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayStatusRow.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/buttons/ChannelFabColumn.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewChannelButton.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewCommunityNoteButton.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewImageButton.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewNoteButton.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/AudioWaveformReadOnly.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableEmail.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableNoteTag.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickablePhone.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUrl.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUserTag.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ForwardingPainter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/GenericLoadable.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/MediaCompressor.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/SelectTextDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/SlidingCarousel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/SplitItem.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/TextSpinner.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/TranslationConfig.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewState.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ZapRaiserRequest.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPublicFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChannelFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListNewFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/CommunityFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/DefaultFeedOrder.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverChatFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverCommunityFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverLiveFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverMarketplaceFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverNIP89FeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/DraftEventsFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/FeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/FilterByListParams.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/GeoHashFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/HashtagFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/HiddenAccountsFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/HomeConversationsFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/HomeNewThreadFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/NIP90ContentDiscoveryResponseFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/ThreadFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileAppRecommendationsFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileBookmarksFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileConversationsFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileFollowersFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileFollowsFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileNewThreadFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileReportsFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileZapsFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/dal/VideoFeedFilter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/layouts/RepostLayout.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/navigation/RouteMaker.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNoteViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/PubKeyFormatter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapFormatter.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForSearchCard.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddRemoveButtons.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/BoostedMark.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayHashtags.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayLocation.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayPoW.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayZapSplits.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/TimeAgo.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChatMessage.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileHeader.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MedicalData.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90Status.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VideoDisplay.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeDrawer.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedState.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomFeedView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedState.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedState.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/RememberForeverStates.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedState.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedState.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountBackupDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt (99%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CommunityScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginOrSignupScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt (100%) rename {app => amethyst}/src/main/java/com/vitorpamplona/amethyst/ui/theme/Type.kt (100%) rename {app => amethyst}/src/main/res/drawable-anydpi/ic_add_photo.xml (100%) rename {app => amethyst}/src/main/res/drawable-anydpi/ic_close.xml (100%) rename {app => amethyst}/src/main/res/drawable-anydpi/ic_key.xml (100%) rename {app => amethyst}/src/main/res/drawable-anydpi/ic_logout.xml (100%) rename {app => amethyst}/src/main/res/drawable-anydpi/ic_security.xml (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_bookmarks.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_compose.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_dm.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_globe.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_home.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_key.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_lists.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_logout.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_moments.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_notifications.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_poll.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_profile.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_qrcode.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_security.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_theme.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_topics.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_trends.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_verified.png (100%) rename {app => amethyst}/src/main/res/drawable-hdpi/ic_verified_transparent.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_bookmarks.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_compose.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_dm.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_globe.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_home.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_key.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_lists.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_logout.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_moments.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_notifications.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_poll.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_profile.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_qrcode.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_security.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_theme.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_topics.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_trends.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_verified.png (100%) rename {app => amethyst}/src/main/res/drawable-mdpi/ic_verified_transparent.png (100%) rename {app => amethyst}/src/main/res/drawable-night-hdpi/ic_verified.png (100%) rename {app => amethyst}/src/main/res/drawable-night-mdpi/ic_verified.png (100%) rename {app => amethyst}/src/main/res/drawable-night-xhdpi/ic_verified.png (100%) rename {app => amethyst}/src/main/res/drawable-night-xxhdpi/ic_verified.png (100%) rename {app => amethyst}/src/main/res/drawable-night-xxxhdpi/ic_verified.png (100%) rename {app => amethyst}/src/main/res/drawable-night/nip_05.xml (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_bookmarks.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_compose.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_dm.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_globe.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_home.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_key.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_lists.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_logout.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_moments.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_notifications.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_poll.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_profile.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_qrcode.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_security.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_theme.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_topics.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_trends.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_verified.png (100%) rename {app => amethyst}/src/main/res/drawable-xhdpi/ic_verified_transparent.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_bookmarks.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_compose.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_dm.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_globe.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_home.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_key.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_lists.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_logout.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_moments.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_notifications.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_poll.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_profile.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_qrcode.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_security.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_theme.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_topics.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_trends.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_verified.png (100%) rename {app => amethyst}/src/main/res/drawable-xxhdpi/ic_verified_transparent.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_bookmarks.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_compose.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_dm.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_globe.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_home.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_lists.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_moments.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_notifications.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_poll.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_profile.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_qrcode.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_theme.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_topics.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_trends.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_verified.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/ic_verified_transparent.png (100%) rename {app => amethyst}/src/main/res/drawable-xxxhdpi/profile_banner.jpeg (100%) rename {app => amethyst}/src/main/res/drawable/alby.xml (100%) rename {app => amethyst}/src/main/res/drawable/amethyst.xml (100%) rename {app => amethyst}/src/main/res/drawable/amethyst_monochrome.xml (100%) rename {app => amethyst}/src/main/res/drawable/following.xml (100%) rename {app => amethyst}/src/main/res/drawable/github.xml (100%) rename {app => amethyst}/src/main/res/drawable/ic_launcher_foreground.xml (100%) rename {app => amethyst}/src/main/res/drawable/ic_sensors.xml (100%) rename {app => amethyst}/src/main/res/drawable/ic_settings.xml (100%) rename {app => amethyst}/src/main/res/drawable/ic_tor.xml (100%) rename {app => amethyst}/src/main/res/drawable/ic_video.xml (100%) rename {app => amethyst}/src/main/res/drawable/incognito.xml (100%) rename {app => amethyst}/src/main/res/drawable/incognito_off.xml (100%) rename {app => amethyst}/src/main/res/drawable/lyrics_off.xml (100%) rename {app => amethyst}/src/main/res/drawable/lyrics_on.xml (100%) rename {app => amethyst}/src/main/res/drawable/manage_accounts.xml (100%) rename {app => amethyst}/src/main/res/drawable/mastodon.xml (100%) rename {app => amethyst}/src/main/res/drawable/nip_05.xml (100%) rename {app => amethyst}/src/main/res/drawable/nip_05_full.xml (100%) rename {app => amethyst}/src/main/res/drawable/original.xml (100%) rename {app => amethyst}/src/main/res/drawable/relays.xml (100%) rename {app => amethyst}/src/main/res/drawable/telegram.xml (100%) rename {app => amethyst}/src/main/res/drawable/text_select_move_forward_character.xml (100%) rename {app => amethyst}/src/main/res/drawable/twitter.xml (100%) rename {app => amethyst}/src/main/res/mipmap-anydpi-v26/ic_launcher.xml (100%) rename {app => amethyst}/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml (100%) rename {app => amethyst}/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename {app => amethyst}/src/main/res/mipmap-hdpi/ic_launcher_foreground.png (100%) rename {app => amethyst}/src/main/res/mipmap-hdpi/ic_launcher_round.png (100%) rename {app => amethyst}/src/main/res/mipmap-hdpi/mutiny.png (100%) rename {app => amethyst}/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename {app => amethyst}/src/main/res/mipmap-mdpi/ic_launcher_foreground.png (100%) rename {app => amethyst}/src/main/res/mipmap-mdpi/ic_launcher_round.png (100%) rename {app => amethyst}/src/main/res/mipmap-mdpi/mutiny.png (100%) rename {app => amethyst}/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename {app => amethyst}/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png (100%) rename {app => amethyst}/src/main/res/mipmap-xhdpi/ic_launcher_round.png (100%) rename {app => amethyst}/src/main/res/mipmap-xhdpi/mutiny.png (100%) rename {app => amethyst}/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename {app => amethyst}/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png (100%) rename {app => amethyst}/src/main/res/mipmap-xxhdpi/ic_launcher_round.png (100%) rename {app => amethyst}/src/main/res/mipmap-xxhdpi/mutiny.png (100%) rename {app => amethyst}/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename {app => amethyst}/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png (100%) rename {app => amethyst}/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png (100%) rename {app => amethyst}/src/main/res/mipmap-xxxhdpi/mutiny.png (100%) rename {app => amethyst}/src/main/res/values-ar/strings.xml (100%) rename {app => amethyst}/src/main/res/values-bn-rBD/strings.xml (100%) rename {app => amethyst}/src/main/res/values-cs/strings.xml (100%) rename {app => amethyst}/src/main/res/values-cy-rGB/strings.xml (100%) rename {app => amethyst}/src/main/res/values-da-rDK/strings.xml (100%) rename {app => amethyst}/src/main/res/values-de/strings.xml (100%) rename {app => amethyst}/src/main/res/values-el-rGR/strings.xml (100%) rename {app => amethyst}/src/main/res/values-en-rGB/strings.xml (100%) rename {app => amethyst}/src/main/res/values-eo/strings.xml (100%) rename {app => amethyst}/src/main/res/values-es-rES/strings.xml (100%) rename {app => amethyst}/src/main/res/values-es-rMX/strings.xml (100%) rename {app => amethyst}/src/main/res/values-es-rUS/strings.xml (100%) rename {app => amethyst}/src/main/res/values-es/strings.xml (100%) rename {app => amethyst}/src/main/res/values-et-rEE/strings.xml (100%) rename {app => amethyst}/src/main/res/values-fa/strings.xml (100%) rename {app => amethyst}/src/main/res/values-fi-rFI/strings.xml (100%) rename {app => amethyst}/src/main/res/values-fo-rFO/strings.xml (100%) rename {app => amethyst}/src/main/res/values-fr-rCA/strings.xml (100%) rename {app => amethyst}/src/main/res/values-fr/strings.xml (100%) rename {app => amethyst}/src/main/res/values-gu-rIN/strings.xml (100%) rename {app => amethyst}/src/main/res/values-hi-rIN/strings.xml (100%) rename {app => amethyst}/src/main/res/values-hr-rHR/strings.xml (100%) rename {app => amethyst}/src/main/res/values-hu/strings.xml (100%) rename {app => amethyst}/src/main/res/values-in-rID/strings.xml (100%) rename {app => amethyst}/src/main/res/values-in/strings.xml (100%) rename {app => amethyst}/src/main/res/values-it-rIT/strings.xml (100%) rename {app => amethyst}/src/main/res/values-iw-rIL/strings.xml (100%) rename {app => amethyst}/src/main/res/values-ja/strings.xml (100%) rename {app => amethyst}/src/main/res/values-kk-rKZ/strings.xml (100%) rename {app => amethyst}/src/main/res/values-ko-rKR/strings.xml (100%) rename {app => amethyst}/src/main/res/values-ks-rIN/strings.xml (100%) rename {app => amethyst}/src/main/res/values-ku-rTR/strings.xml (100%) rename {app => amethyst}/src/main/res/values-lt-rLT/strings.xml (100%) rename {app => amethyst}/src/main/res/values-ne-rNP/strings.xml (100%) rename {app => amethyst}/src/main/res/values-night/themes.xml (100%) rename {app => amethyst}/src/main/res/values-nl-rBE/strings.xml (100%) rename {app => amethyst}/src/main/res/values-nl/strings.xml (100%) rename {app => amethyst}/src/main/res/values-pcm-rNG/strings.xml (100%) rename {app => amethyst}/src/main/res/values-pl-rPL/strings.xml (100%) rename {app => amethyst}/src/main/res/values-pt-rBR/strings.xml (100%) rename {app => amethyst}/src/main/res/values-pt-rPT/strings.xml (100%) rename {app => amethyst}/src/main/res/values-ru-rUA/strings.xml (100%) rename {app => amethyst}/src/main/res/values-ru/strings.xml (100%) rename {app => amethyst}/src/main/res/values-sa-rIN/strings.xml (100%) rename {app => amethyst}/src/main/res/values-sl-rSI/strings.xml (100%) rename {app => amethyst}/src/main/res/values-so-rSO/strings.xml (100%) rename {app => amethyst}/src/main/res/values-sr-rSP/strings.xml (100%) rename {app => amethyst}/src/main/res/values-ss-rZA/strings.xml (100%) rename {app => amethyst}/src/main/res/values-sv-rSE/strings.xml (100%) rename {app => amethyst}/src/main/res/values-sw-rKE/strings.xml (100%) rename {app => amethyst}/src/main/res/values-sw-rTZ/strings.xml (100%) rename {app => amethyst}/src/main/res/values-ta/strings.xml (100%) rename {app => amethyst}/src/main/res/values-th/strings.xml (100%) rename {app => amethyst}/src/main/res/values-tr/strings.xml (100%) rename {app => amethyst}/src/main/res/values-uk/strings.xml (100%) rename {app => amethyst}/src/main/res/values-ur-rIN/strings.xml (100%) rename {app => amethyst}/src/main/res/values-uz-rUZ/strings.xml (100%) rename {app => amethyst}/src/main/res/values-vi-rVN/strings.xml (100%) rename {app => amethyst}/src/main/res/values-zh-rCN/strings.xml (100%) rename {app => amethyst}/src/main/res/values-zh-rHK/strings.xml (100%) rename {app => amethyst}/src/main/res/values-zh-rSG/strings.xml (100%) rename {app => amethyst}/src/main/res/values-zh-rTW/strings.xml (100%) rename {app => amethyst}/src/main/res/values-zh/strings.xml (100%) rename {app => amethyst}/src/main/res/values/colors.xml (100%) rename {app => amethyst}/src/main/res/values/ic_launcher_background.xml (100%) rename {app => amethyst}/src/main/res/values/strings.xml (100%) rename {app => amethyst}/src/main/res/values/themes.xml (100%) rename {app => amethyst}/src/main/res/xml/backup_rules.xml (100%) rename {app => amethyst}/src/main/res/xml/data_extraction_rules.xml (100%) rename {app => amethyst}/src/main/res/xml/locales_config.xml (100%) rename {app => amethyst}/src/play/AndroidManifest.xml (100%) rename {app => amethyst}/src/play/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt (100%) rename {app => amethyst}/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt (100%) rename {app => amethyst}/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt (100%) rename {app => amethyst}/src/play/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt (100%) rename {app => amethyst}/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt (100%) rename {app => amethyst}/src/test/java/android/util/Log.java (100%) rename {app => amethyst}/src/test/java/com/vitorpamplona/amethyst/CharsetTest.kt (100%) rename {app => amethyst}/src/test/java/com/vitorpamplona/amethyst/NewMessageTaggerKeyParseTest.kt (100%) rename {app => amethyst}/src/test/java/com/vitorpamplona/amethyst/SplitterTest.kt (100%) rename {app => amethyst}/src/test/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifierTest.kt (100%) rename {app => amethyst}/src/test/java/com/vitorpamplona/amethyst/service/Nip96Test.kt (100%) rename {app => amethyst}/src/test/java/com/vitorpamplona/amethyst/service/zaps/UserZapsTest.kt (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b07d18ed5..20f98529b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,11 +46,11 @@ jobs: uses: actions/upload-artifact@v2 with: name: Debug APK - path: app/build/outputs/apk/debug/app-debug.apk + path: amethyst/build/outputs/apk/debug/app-debug.apk - name: Upload Test Results uses: actions/upload-artifact@v2 with: name: Build Reports - path: app/build/reports + path: amethyst/build/reports diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 77c10ab3f..24e124faf 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -32,7 +32,7 @@ jobs: - name: Sign AAB (Google Play) uses: r0adkll/sign-android-release@v1 with: - releaseDirectory: app/build/outputs/bundle/playRelease + releaseDirectory: amethyst/build/outputs/bundle/playRelease signingKeyBase64: ${{ secrets.SIGNING_KEY }} alias: ${{ secrets.KEY_ALIAS }} keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} @@ -44,7 +44,7 @@ jobs: - name: Sign AAB (F-Droid) uses: r0adkll/sign-android-release@v1 with: - releaseDirectory: app/build/outputs/bundle/fdroidRelease + releaseDirectory: amethyst/build/outputs/bundle/fdroidRelease signingKeyBase64: ${{ secrets.SIGNING_KEY }} alias: ${{ secrets.KEY_ALIAS }} keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} @@ -59,7 +59,7 @@ jobs: - name: Sign APK (Google Play) uses: r0adkll/sign-android-release@v1 with: - releaseDirectory: app/build/outputs/apk/play/release + releaseDirectory: amethyst/build/outputs/apk/play/release signingKeyBase64: ${{ secrets.SIGNING_KEY }} alias: ${{ secrets.KEY_ALIAS }} keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} @@ -71,7 +71,7 @@ jobs: - name: Sign APK (F-Droid) uses: r0adkll/sign-android-release@v1 with: - releaseDirectory: app/build/outputs/apk/fdroid/release + releaseDirectory: amethyst/build/outputs/apk/fdroid/release signingKeyBase64: ${{ secrets.SIGNING_KEY }} alias: ${{ secrets.KEY_ALIAS }} keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} @@ -99,7 +99,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/apk/play/release/app-play-universal-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/play/release/app-play-universal-release-unsigned-signed.apk asset_name: amethyst-googleplay-universal-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -110,7 +110,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/apk/play/release/app-play-x86-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/play/release/app-play-x86-release-unsigned-signed.apk asset_name: amethyst-googleplay-x86-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -121,7 +121,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/apk/play/release/app-play-x86_64-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/play/release/app-play-x86_64-release-unsigned-signed.apk asset_name: amethyst-googleplay-x86_64-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -132,7 +132,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/apk/play/release/app-play-arm64-v8a-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/play/release/app-play-arm64-v8a-release-unsigned-signed.apk asset_name: amethyst-googleplay-arm64-v8a-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -143,7 +143,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/apk/play/release/app-play-armeabi-v7a-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/play/release/app-play-armeabi-v7a-release-unsigned-signed.apk asset_name: amethyst-googleplay-armeabi-v7a-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -155,7 +155,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/apk/fdroid/release/app-fdroid-universal-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/fdroid/release/app-fdroid-universal-release-unsigned-signed.apk asset_name: amethyst-fdroid-universal-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -166,7 +166,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/apk/fdroid/release/app-fdroid-x86-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/fdroid/release/app-fdroid-x86-release-unsigned-signed.apk asset_name: amethyst-fdroid-x86-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -177,7 +177,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/apk/fdroid/release/app-fdroid-x86_64-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/fdroid/release/app-fdroid-x86_64-release-unsigned-signed.apk asset_name: amethyst-fdroid-x86_64-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -188,7 +188,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/apk/fdroid/release/app-fdroid-arm64-v8a-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/fdroid/release/app-fdroid-arm64-v8a-release-unsigned-signed.apk asset_name: amethyst-fdroid-arm64-v8a-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -199,7 +199,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/apk/fdroid/release/app-fdroid-armeabi-v7a-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/fdroid/release/app-fdroid-armeabi-v7a-release-unsigned-signed.apk asset_name: amethyst-fdroid-armeabi-v7a-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -213,7 +213,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/bundle/playRelease/app-play-release.aab + asset_path: amethyst/build/outputs/bundle/playRelease/app-play-release.aab asset_name: amethyst-googleplay-${{ github.ref_name }}.aab asset_content_type: application/zip @@ -225,6 +225,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: app/build/outputs/bundle/fdroidRelease/app-fdroid-release.aab + asset_path: amethyst/build/outputs/bundle/fdroidRelease/app-fdroid-release.aab asset_name: amethyst-fdroid-${{ github.ref_name }}.aab asset_content_type: application/zip diff --git a/README.md b/README.md index a472ef445..74b6aa011 100644 --- a/README.md +++ b/README.md @@ -226,7 +226,7 @@ openssl base64 < | tr -d '\n' | tee some_signing_key.j - `KEY_PASSWORD` <- `` - `KEY_STORE_PASSWORD` <- `` - `SIGNING_KEY` <- the data from `` -3. Change the `versionCode` and `versionName` on `app/build.gradle` +3. Change the `versionCode` and `versionName` on `amethyst/build.gradle` 4. Commit and push. 5. Tag the commit with `v{x.x.x}` 6. Let the [Create Release GitHub Action](https://github.com/vitorpamplona/amethyst/actions/workflows/create-release.yml) build a new `aab` file. diff --git a/app/.gitignore b/amethyst/.gitignore similarity index 100% rename from app/.gitignore rename to amethyst/.gitignore diff --git a/app/build.gradle b/amethyst/build.gradle similarity index 100% rename from app/build.gradle rename to amethyst/build.gradle diff --git a/app/google-services.json b/amethyst/google-services.json similarity index 100% rename from app/google-services.json rename to amethyst/google-services.json diff --git a/app/proguard-rules.pro b/amethyst/proguard-rules.pro similarity index 100% rename from app/proguard-rules.pro rename to amethyst/proguard-rules.pro diff --git a/app/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt similarity index 100% rename from app/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt rename to amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt diff --git a/app/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt similarity index 100% rename from app/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt rename to amethyst/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt diff --git a/app/src/androidTest/java/com/vitorpamplona/amethyst/ThreadAssemblerTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ThreadAssemblerTest.kt similarity index 100% rename from app/src/androidTest/java/com/vitorpamplona/amethyst/ThreadAssemblerTest.kt rename to amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ThreadAssemblerTest.kt diff --git a/app/src/androidTest/java/com/vitorpamplona/amethyst/UrlUserTagTransformationTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/UrlUserTagTransformationTest.kt similarity index 100% rename from app/src/androidTest/java/com/vitorpamplona/amethyst/UrlUserTagTransformationTest.kt rename to amethyst/src/androidTest/java/com/vitorpamplona/amethyst/UrlUserTagTransformationTest.kt diff --git a/app/src/androidTest/res/values/strings.xml b/amethyst/src/androidTest/res/values/strings.xml similarity index 100% rename from app/src/androidTest/res/values/strings.xml rename to amethyst/src/androidTest/res/values/strings.xml diff --git a/app/src/androidTestPlay/java/com/vitorpamplona/amethyst/TranslationsTest.kt b/amethyst/src/androidTestPlay/java/com/vitorpamplona/amethyst/TranslationsTest.kt similarity index 100% rename from app/src/androidTestPlay/java/com/vitorpamplona/amethyst/TranslationsTest.kt rename to amethyst/src/androidTestPlay/java/com/vitorpamplona/amethyst/TranslationsTest.kt diff --git a/app/src/fdroid/AndroidManifest.xml b/amethyst/src/fdroid/AndroidManifest.xml similarity index 100% rename from app/src/fdroid/AndroidManifest.xml rename to amethyst/src/fdroid/AndroidManifest.xml diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt similarity index 100% rename from app/src/fdroid/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt rename to amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt similarity index 100% rename from app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt rename to amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt similarity index 100% rename from app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt rename to amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt similarity index 100% rename from app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt rename to amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt similarity index 100% rename from app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt rename to amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt similarity index 100% rename from app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt rename to amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt diff --git a/app/src/main/AndroidManifest.xml b/amethyst/src/main/AndroidManifest.xml similarity index 100% rename from app/src/main/AndroidManifest.xml rename to amethyst/src/main/AndroidManifest.xml diff --git a/app/src/main/ic_launcher-playstore.png b/amethyst/src/main/ic_launcher-playstore.png similarity index 100% rename from app/src/main/ic_launcher-playstore.png rename to amethyst/src/main/ic_launcher-playstore.png diff --git a/app/src/main/java/androidx/compose/material3/pullrefresh/PullRefresh.kt b/amethyst/src/main/java/androidx/compose/material3/pullrefresh/PullRefresh.kt similarity index 100% rename from app/src/main/java/androidx/compose/material3/pullrefresh/PullRefresh.kt rename to amethyst/src/main/java/androidx/compose/material3/pullrefresh/PullRefresh.kt diff --git a/app/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshIndicator.kt b/amethyst/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshIndicator.kt similarity index 100% rename from app/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshIndicator.kt rename to amethyst/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshIndicator.kt diff --git a/app/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshIndicatorTransform.kt b/amethyst/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshIndicatorTransform.kt similarity index 100% rename from app/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshIndicatorTransform.kt rename to amethyst/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshIndicatorTransform.kt diff --git a/app/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshState.kt b/amethyst/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshState.kt similarity index 100% rename from app/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshState.kt rename to amethyst/src/main/java/androidx/compose/material3/pullrefresh/PullRefreshState.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Chatroom.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Chatroom.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/Chatroom.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/Chatroom.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/HashtagIcon.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/HashtagIcon.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/HashtagIcon.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/HashtagIcon.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/MiniFhir.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/MiniFhir.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/MiniFhir.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/MiniFhir.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Note.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/Note.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/ParticipantListBuilder.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/ParticipantListBuilder.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/ParticipantListBuilder.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/ParticipantListBuilder.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/ThreadAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/ThreadAssembler.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/ThreadAssembler.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/ThreadAssembler.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/ThreadLevelCalculator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/ThreadLevelCalculator.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/ThreadLevelCalculator.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/ThreadLevelCalculator.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/UrlCachedPreviewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UrlCachedPreviewer.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/UrlCachedPreviewer.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/UrlCachedPreviewer.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/User.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/User.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/User.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/observables/CreatedAtComparator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/observables/CreatedAtComparator.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/observables/CreatedAtComparator.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/observables/CreatedAtComparator.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindAndAuthor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindAndAuthor.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindAndAuthor.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindAndAuthor.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindWithETag.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindWithETag.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindWithETag.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindWithETag.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/AmethystNostrDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/AmethystNostrDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/AmethystNostrDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/AmethystNostrDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/BlurHashImage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/BlurHashImage.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/BlurHashImage.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/BlurHashImage.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/EmojiUtils.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/EmojiUtils.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/EmojiUtils.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/EmojiUtils.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/FileHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/FileHeader.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/FileHeader.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/FileHeader.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/LocationUtil.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/LocationUtil.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/LocationUtil.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/LocationUtil.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/MainThreadChecker.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/MainThreadChecker.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/MainThreadChecker.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/MainThreadChecker.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip11RelayInfoRetriever.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip11RelayInfoRetriever.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/Nip11RelayInfoRetriever.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip11RelayInfoRetriever.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip96MediaServers.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip96MediaServers.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/Nip96MediaServers.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip96MediaServers.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/PackageUtils.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/PackageUtils.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/PackageUtils.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/PackageUtils.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/CachedLnInvoice.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/CachedLnInvoice.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/CachedLnInvoice.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/CachedLnInvoice.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/model/zaps/UserZaps.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/model/zaps/UserZaps.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/model/zaps/UserZaps.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/model/zaps/UserZaps.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpBlockstreamExplorer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpBlockstreamExplorer.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpBlockstreamExplorer.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpBlockstreamExplorer.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarAsyncSubmit.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarAsyncSubmit.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarAsyncSubmit.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarAsyncSubmit.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarBuilder.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarBuilder.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarBuilder.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendarBuilder.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/playback/MultiPlayerPlaybackManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/MultiPlayerPlaybackManager.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/playback/MultiPlayerPlaybackManager.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/MultiPlayerPlaybackManager.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackClientController.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackClientController.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackClientController.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackClientController.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/playback/VideoCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/VideoCache.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/playback/VideoCache.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/VideoCache.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/playback/VideoViewedPositionCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/VideoViewedPositionCache.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/playback/VideoViewedPositionCache.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/VideoViewedPositionCache.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/playback/WssDataStreamCollector.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/WssDataStreamCollector.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/playback/WssDataStreamCollector.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/WssDataStreamCollector.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/playback/WssStreamDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/WssStreamDataSource.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/playback/WssStreamDataSource.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/WssStreamDataSource.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/BahaUrlPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/previews/BahaUrlPreview.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/previews/BahaUrlPreview.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/previews/BahaUrlPreview.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/IUrlPreviewCallback.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/previews/IUrlPreviewCallback.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/previews/IUrlPreviewCallback.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/previews/IUrlPreviewCallback.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlInfoItem.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlInfoItem.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlInfoItem.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlInfoItem.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechEngine.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechEngine.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechEngine.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechEngine.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechHelper.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechHelper.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechHelper.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechHelper.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/AppScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/AppScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/AppScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/AppScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageDownloader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageDownloader.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageDownloader.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageDownloader.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMessageTagger.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMessageTagger.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMessageTagger.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMessageTagger.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollClosing.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollClosing.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollClosing.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollClosing.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollConsensusThreshold.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollConsensusThreshold.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollConsensusThreshold.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollConsensusThreshold.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollOption.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollOption.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollOption.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollOption.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollPrimaryDescription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollPrimaryDescription.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollPrimaryDescription.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollPrimaryDescription.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollRecipientsField.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollRecipientsField.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollRecipientsField.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollRecipientsField.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollVoteValueRange.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollVoteValueRange.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollVoteValueRange.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollVoteValueRange.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UrlUserTagTransformation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/UrlUserTagTransformation.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UrlUserTagTransformation.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/UrlUserTagTransformation.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddDMRelayListDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddDMRelayListDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddDMRelayListDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddDMRelayListDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddSearchRelayListDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddSearchRelayListDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddSearchRelayListDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddSearchRelayListDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfo.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfo.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfo.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoClickableRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoClickableRow.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoClickableRow.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoClickableRow.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/ByteFormatter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/ByteFormatter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/ByteFormatter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/ByteFormatter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayNameAndRemoveButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayNameAndRemoveButton.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayNameAndRemoveButton.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayNameAndRemoveButton.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayStatusRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayStatusRow.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayStatusRow.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayStatusRow.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/ChannelFabColumn.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/buttons/ChannelFabColumn.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/ChannelFabColumn.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/buttons/ChannelFabColumn.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewChannelButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewChannelButton.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewChannelButton.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewChannelButton.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewCommunityNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewCommunityNoteButton.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewCommunityNoteButton.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewCommunityNoteButton.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewImageButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewImageButton.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewImageButton.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewImageButton.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewNoteButton.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewNoteButton.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewNoteButton.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/AudioWaveformReadOnly.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AudioWaveformReadOnly.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/AudioWaveformReadOnly.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AudioWaveformReadOnly.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableEmail.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableEmail.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableEmail.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableEmail.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableNoteTag.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableNoteTag.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableNoteTag.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableNoteTag.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickablePhone.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickablePhone.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickablePhone.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickablePhone.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUrl.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUrl.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUrl.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUrl.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUserTag.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUserTag.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUserTag.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUserTag.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ForwardingPainter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ForwardingPainter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ForwardingPainter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ForwardingPainter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/GenericLoadable.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/GenericLoadable.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/GenericLoadable.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/GenericLoadable.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/MediaCompressor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MediaCompressor.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/MediaCompressor.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MediaCompressor.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SelectTextDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SelectTextDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/SelectTextDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SelectTextDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SlidingCarousel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SlidingCarousel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/SlidingCarousel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SlidingCarousel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SplitItem.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SplitItem.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/SplitItem.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SplitItem.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/TextSpinner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/TextSpinner.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/TextSpinner.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/TextSpinner.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/TranslationConfig.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/TranslationConfig.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/TranslationConfig.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/TranslationConfig.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewState.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewState.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewState.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZapRaiserRequest.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZapRaiserRequest.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZapRaiserRequest.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZapRaiserRequest.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPublicFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPublicFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPublicFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPublicFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChannelFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChannelFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChannelFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChannelFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListNewFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListNewFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListNewFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListNewFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/CommunityFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/CommunityFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/CommunityFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/CommunityFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DefaultFeedOrder.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DefaultFeedOrder.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DefaultFeedOrder.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DefaultFeedOrder.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverChatFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverChatFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverChatFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverChatFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverCommunityFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverCommunityFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverCommunityFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverCommunityFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverLiveFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverLiveFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverLiveFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverLiveFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverMarketplaceFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverMarketplaceFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverMarketplaceFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverMarketplaceFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverNIP89FeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverNIP89FeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverNIP89FeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverNIP89FeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DraftEventsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DraftEventsFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DraftEventsFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DraftEventsFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/FeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/FeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/FeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/FeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/FilterByListParams.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/FilterByListParams.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/FilterByListParams.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/FilterByListParams.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/GeoHashFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/GeoHashFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/GeoHashFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/GeoHashFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/HashtagFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/HashtagFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/HashtagFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/HashtagFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/HiddenAccountsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/HiddenAccountsFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/HiddenAccountsFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/HiddenAccountsFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/HomeConversationsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/HomeConversationsFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/HomeConversationsFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/HomeConversationsFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/HomeNewThreadFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/HomeNewThreadFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/HomeNewThreadFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/HomeNewThreadFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NIP90ContentDiscoveryResponseFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/NIP90ContentDiscoveryResponseFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NIP90ContentDiscoveryResponseFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/NIP90ContentDiscoveryResponseFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ThreadFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ThreadFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ThreadFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ThreadFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileAppRecommendationsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileAppRecommendationsFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileAppRecommendationsFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileAppRecommendationsFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileBookmarksFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileBookmarksFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileBookmarksFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileBookmarksFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileConversationsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileConversationsFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileConversationsFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileConversationsFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileFollowersFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileFollowersFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileFollowersFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileFollowersFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileFollowsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileFollowsFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileFollowsFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileFollowsFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileNewThreadFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileNewThreadFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileNewThreadFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileNewThreadFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileReportsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileReportsFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileReportsFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileReportsFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileZapsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileZapsFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileZapsFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileZapsFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/VideoFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/VideoFeedFilter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/dal/VideoFeedFilter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/VideoFeedFilter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/RepostLayout.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/RepostLayout.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/RepostLayout.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/RepostLayout.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/RouteMaker.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/RouteMaker.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/RouteMaker.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/RouteMaker.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNoteViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNoteViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNoteViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNoteViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PubKeyFormatter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/PubKeyFormatter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/PubKeyFormatter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/PubKeyFormatter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapFormatter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapFormatter.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapFormatter.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapFormatter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForSearchCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForSearchCard.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForSearchCard.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForSearchCard.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddRemoveButtons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddRemoveButtons.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddRemoveButtons.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddRemoveButtons.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/BoostedMark.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/BoostedMark.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/BoostedMark.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/BoostedMark.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayHashtags.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayHashtags.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayHashtags.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayHashtags.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayLocation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayLocation.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayLocation.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayLocation.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayPoW.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayPoW.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayPoW.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayPoW.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayZapSplits.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayZapSplits.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayZapSplits.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayZapSplits.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/TimeAgo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/TimeAgo.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/TimeAgo.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/TimeAgo.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChatMessage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChatMessage.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChatMessage.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChatMessage.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileHeader.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileHeader.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileHeader.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MedicalData.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MedicalData.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MedicalData.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MedicalData.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90Status.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90Status.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90Status.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90Status.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VideoDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VideoDisplay.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VideoDisplay.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VideoDisplay.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeDrawer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeDrawer.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeDrawer.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeDrawer.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedState.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedState.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedState.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomFeedView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomFeedView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomFeedView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedState.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedState.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedState.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedState.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedState.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedState.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RememberForeverStates.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/RememberForeverStates.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RememberForeverStates.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/RememberForeverStates.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedState.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedState.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedState.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedState.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedState.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedState.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountBackupDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountBackupDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountBackupDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountBackupDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt similarity index 99% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index df62b338a..b1e5c4eef 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -924,6 +924,8 @@ class AccountViewModel( userMetadata.nip05LastVerificationTime = 0 userMetadata.nip05Verified = false + Log.d("NIP05 Error", it) + onResult(userMetadata.nip05Verified) }, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CommunityScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CommunityScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CommunityScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CommunityScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginOrSignupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginOrSignupScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginOrSignupScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginOrSignupScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Type.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Type.kt similarity index 100% rename from app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Type.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Type.kt diff --git a/app/src/main/res/drawable-anydpi/ic_add_photo.xml b/amethyst/src/main/res/drawable-anydpi/ic_add_photo.xml similarity index 100% rename from app/src/main/res/drawable-anydpi/ic_add_photo.xml rename to amethyst/src/main/res/drawable-anydpi/ic_add_photo.xml diff --git a/app/src/main/res/drawable-anydpi/ic_close.xml b/amethyst/src/main/res/drawable-anydpi/ic_close.xml similarity index 100% rename from app/src/main/res/drawable-anydpi/ic_close.xml rename to amethyst/src/main/res/drawable-anydpi/ic_close.xml diff --git a/app/src/main/res/drawable-anydpi/ic_key.xml b/amethyst/src/main/res/drawable-anydpi/ic_key.xml similarity index 100% rename from app/src/main/res/drawable-anydpi/ic_key.xml rename to amethyst/src/main/res/drawable-anydpi/ic_key.xml diff --git a/app/src/main/res/drawable-anydpi/ic_logout.xml b/amethyst/src/main/res/drawable-anydpi/ic_logout.xml similarity index 100% rename from app/src/main/res/drawable-anydpi/ic_logout.xml rename to amethyst/src/main/res/drawable-anydpi/ic_logout.xml diff --git a/app/src/main/res/drawable-anydpi/ic_security.xml b/amethyst/src/main/res/drawable-anydpi/ic_security.xml similarity index 100% rename from app/src/main/res/drawable-anydpi/ic_security.xml rename to amethyst/src/main/res/drawable-anydpi/ic_security.xml diff --git a/app/src/main/res/drawable-hdpi/ic_bookmarks.png b/amethyst/src/main/res/drawable-hdpi/ic_bookmarks.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_bookmarks.png rename to amethyst/src/main/res/drawable-hdpi/ic_bookmarks.png diff --git a/app/src/main/res/drawable-hdpi/ic_compose.png b/amethyst/src/main/res/drawable-hdpi/ic_compose.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_compose.png rename to amethyst/src/main/res/drawable-hdpi/ic_compose.png diff --git a/app/src/main/res/drawable-hdpi/ic_dm.png b/amethyst/src/main/res/drawable-hdpi/ic_dm.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_dm.png rename to amethyst/src/main/res/drawable-hdpi/ic_dm.png diff --git a/app/src/main/res/drawable-hdpi/ic_globe.png b/amethyst/src/main/res/drawable-hdpi/ic_globe.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_globe.png rename to amethyst/src/main/res/drawable-hdpi/ic_globe.png diff --git a/app/src/main/res/drawable-hdpi/ic_home.png b/amethyst/src/main/res/drawable-hdpi/ic_home.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_home.png rename to amethyst/src/main/res/drawable-hdpi/ic_home.png diff --git a/app/src/main/res/drawable-hdpi/ic_key.png b/amethyst/src/main/res/drawable-hdpi/ic_key.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_key.png rename to amethyst/src/main/res/drawable-hdpi/ic_key.png diff --git a/app/src/main/res/drawable-hdpi/ic_lists.png b/amethyst/src/main/res/drawable-hdpi/ic_lists.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_lists.png rename to amethyst/src/main/res/drawable-hdpi/ic_lists.png diff --git a/app/src/main/res/drawable-hdpi/ic_logout.png b/amethyst/src/main/res/drawable-hdpi/ic_logout.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_logout.png rename to amethyst/src/main/res/drawable-hdpi/ic_logout.png diff --git a/app/src/main/res/drawable-hdpi/ic_moments.png b/amethyst/src/main/res/drawable-hdpi/ic_moments.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_moments.png rename to amethyst/src/main/res/drawable-hdpi/ic_moments.png diff --git a/app/src/main/res/drawable-hdpi/ic_notifications.png b/amethyst/src/main/res/drawable-hdpi/ic_notifications.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_notifications.png rename to amethyst/src/main/res/drawable-hdpi/ic_notifications.png diff --git a/app/src/main/res/drawable-hdpi/ic_poll.png b/amethyst/src/main/res/drawable-hdpi/ic_poll.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_poll.png rename to amethyst/src/main/res/drawable-hdpi/ic_poll.png diff --git a/app/src/main/res/drawable-hdpi/ic_profile.png b/amethyst/src/main/res/drawable-hdpi/ic_profile.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_profile.png rename to amethyst/src/main/res/drawable-hdpi/ic_profile.png diff --git a/app/src/main/res/drawable-hdpi/ic_qrcode.png b/amethyst/src/main/res/drawable-hdpi/ic_qrcode.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_qrcode.png rename to amethyst/src/main/res/drawable-hdpi/ic_qrcode.png diff --git a/app/src/main/res/drawable-hdpi/ic_security.png b/amethyst/src/main/res/drawable-hdpi/ic_security.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_security.png rename to amethyst/src/main/res/drawable-hdpi/ic_security.png diff --git a/app/src/main/res/drawable-hdpi/ic_theme.png b/amethyst/src/main/res/drawable-hdpi/ic_theme.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_theme.png rename to amethyst/src/main/res/drawable-hdpi/ic_theme.png diff --git a/app/src/main/res/drawable-hdpi/ic_topics.png b/amethyst/src/main/res/drawable-hdpi/ic_topics.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_topics.png rename to amethyst/src/main/res/drawable-hdpi/ic_topics.png diff --git a/app/src/main/res/drawable-hdpi/ic_trends.png b/amethyst/src/main/res/drawable-hdpi/ic_trends.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_trends.png rename to amethyst/src/main/res/drawable-hdpi/ic_trends.png diff --git a/app/src/main/res/drawable-hdpi/ic_verified.png b/amethyst/src/main/res/drawable-hdpi/ic_verified.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_verified.png rename to amethyst/src/main/res/drawable-hdpi/ic_verified.png diff --git a/app/src/main/res/drawable-hdpi/ic_verified_transparent.png b/amethyst/src/main/res/drawable-hdpi/ic_verified_transparent.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_verified_transparent.png rename to amethyst/src/main/res/drawable-hdpi/ic_verified_transparent.png diff --git a/app/src/main/res/drawable-mdpi/ic_bookmarks.png b/amethyst/src/main/res/drawable-mdpi/ic_bookmarks.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_bookmarks.png rename to amethyst/src/main/res/drawable-mdpi/ic_bookmarks.png diff --git a/app/src/main/res/drawable-mdpi/ic_compose.png b/amethyst/src/main/res/drawable-mdpi/ic_compose.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_compose.png rename to amethyst/src/main/res/drawable-mdpi/ic_compose.png diff --git a/app/src/main/res/drawable-mdpi/ic_dm.png b/amethyst/src/main/res/drawable-mdpi/ic_dm.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_dm.png rename to amethyst/src/main/res/drawable-mdpi/ic_dm.png diff --git a/app/src/main/res/drawable-mdpi/ic_globe.png b/amethyst/src/main/res/drawable-mdpi/ic_globe.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_globe.png rename to amethyst/src/main/res/drawable-mdpi/ic_globe.png diff --git a/app/src/main/res/drawable-mdpi/ic_home.png b/amethyst/src/main/res/drawable-mdpi/ic_home.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_home.png rename to amethyst/src/main/res/drawable-mdpi/ic_home.png diff --git a/app/src/main/res/drawable-mdpi/ic_key.png b/amethyst/src/main/res/drawable-mdpi/ic_key.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_key.png rename to amethyst/src/main/res/drawable-mdpi/ic_key.png diff --git a/app/src/main/res/drawable-mdpi/ic_lists.png b/amethyst/src/main/res/drawable-mdpi/ic_lists.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_lists.png rename to amethyst/src/main/res/drawable-mdpi/ic_lists.png diff --git a/app/src/main/res/drawable-mdpi/ic_logout.png b/amethyst/src/main/res/drawable-mdpi/ic_logout.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_logout.png rename to amethyst/src/main/res/drawable-mdpi/ic_logout.png diff --git a/app/src/main/res/drawable-mdpi/ic_moments.png b/amethyst/src/main/res/drawable-mdpi/ic_moments.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_moments.png rename to amethyst/src/main/res/drawable-mdpi/ic_moments.png diff --git a/app/src/main/res/drawable-mdpi/ic_notifications.png b/amethyst/src/main/res/drawable-mdpi/ic_notifications.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_notifications.png rename to amethyst/src/main/res/drawable-mdpi/ic_notifications.png diff --git a/app/src/main/res/drawable-mdpi/ic_poll.png b/amethyst/src/main/res/drawable-mdpi/ic_poll.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_poll.png rename to amethyst/src/main/res/drawable-mdpi/ic_poll.png diff --git a/app/src/main/res/drawable-mdpi/ic_profile.png b/amethyst/src/main/res/drawable-mdpi/ic_profile.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_profile.png rename to amethyst/src/main/res/drawable-mdpi/ic_profile.png diff --git a/app/src/main/res/drawable-mdpi/ic_qrcode.png b/amethyst/src/main/res/drawable-mdpi/ic_qrcode.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_qrcode.png rename to amethyst/src/main/res/drawable-mdpi/ic_qrcode.png diff --git a/app/src/main/res/drawable-mdpi/ic_security.png b/amethyst/src/main/res/drawable-mdpi/ic_security.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_security.png rename to amethyst/src/main/res/drawable-mdpi/ic_security.png diff --git a/app/src/main/res/drawable-mdpi/ic_theme.png b/amethyst/src/main/res/drawable-mdpi/ic_theme.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_theme.png rename to amethyst/src/main/res/drawable-mdpi/ic_theme.png diff --git a/app/src/main/res/drawable-mdpi/ic_topics.png b/amethyst/src/main/res/drawable-mdpi/ic_topics.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_topics.png rename to amethyst/src/main/res/drawable-mdpi/ic_topics.png diff --git a/app/src/main/res/drawable-mdpi/ic_trends.png b/amethyst/src/main/res/drawable-mdpi/ic_trends.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_trends.png rename to amethyst/src/main/res/drawable-mdpi/ic_trends.png diff --git a/app/src/main/res/drawable-mdpi/ic_verified.png b/amethyst/src/main/res/drawable-mdpi/ic_verified.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_verified.png rename to amethyst/src/main/res/drawable-mdpi/ic_verified.png diff --git a/app/src/main/res/drawable-mdpi/ic_verified_transparent.png b/amethyst/src/main/res/drawable-mdpi/ic_verified_transparent.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_verified_transparent.png rename to amethyst/src/main/res/drawable-mdpi/ic_verified_transparent.png diff --git a/app/src/main/res/drawable-night-hdpi/ic_verified.png b/amethyst/src/main/res/drawable-night-hdpi/ic_verified.png similarity index 100% rename from app/src/main/res/drawable-night-hdpi/ic_verified.png rename to amethyst/src/main/res/drawable-night-hdpi/ic_verified.png diff --git a/app/src/main/res/drawable-night-mdpi/ic_verified.png b/amethyst/src/main/res/drawable-night-mdpi/ic_verified.png similarity index 100% rename from app/src/main/res/drawable-night-mdpi/ic_verified.png rename to amethyst/src/main/res/drawable-night-mdpi/ic_verified.png diff --git a/app/src/main/res/drawable-night-xhdpi/ic_verified.png b/amethyst/src/main/res/drawable-night-xhdpi/ic_verified.png similarity index 100% rename from app/src/main/res/drawable-night-xhdpi/ic_verified.png rename to amethyst/src/main/res/drawable-night-xhdpi/ic_verified.png diff --git a/app/src/main/res/drawable-night-xxhdpi/ic_verified.png b/amethyst/src/main/res/drawable-night-xxhdpi/ic_verified.png similarity index 100% rename from app/src/main/res/drawable-night-xxhdpi/ic_verified.png rename to amethyst/src/main/res/drawable-night-xxhdpi/ic_verified.png diff --git a/app/src/main/res/drawable-night-xxxhdpi/ic_verified.png b/amethyst/src/main/res/drawable-night-xxxhdpi/ic_verified.png similarity index 100% rename from app/src/main/res/drawable-night-xxxhdpi/ic_verified.png rename to amethyst/src/main/res/drawable-night-xxxhdpi/ic_verified.png diff --git a/app/src/main/res/drawable-night/nip_05.xml b/amethyst/src/main/res/drawable-night/nip_05.xml similarity index 100% rename from app/src/main/res/drawable-night/nip_05.xml rename to amethyst/src/main/res/drawable-night/nip_05.xml diff --git a/app/src/main/res/drawable-xhdpi/ic_bookmarks.png b/amethyst/src/main/res/drawable-xhdpi/ic_bookmarks.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_bookmarks.png rename to amethyst/src/main/res/drawable-xhdpi/ic_bookmarks.png diff --git a/app/src/main/res/drawable-xhdpi/ic_compose.png b/amethyst/src/main/res/drawable-xhdpi/ic_compose.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_compose.png rename to amethyst/src/main/res/drawable-xhdpi/ic_compose.png diff --git a/app/src/main/res/drawable-xhdpi/ic_dm.png b/amethyst/src/main/res/drawable-xhdpi/ic_dm.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_dm.png rename to amethyst/src/main/res/drawable-xhdpi/ic_dm.png diff --git a/app/src/main/res/drawable-xhdpi/ic_globe.png b/amethyst/src/main/res/drawable-xhdpi/ic_globe.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_globe.png rename to amethyst/src/main/res/drawable-xhdpi/ic_globe.png diff --git a/app/src/main/res/drawable-xhdpi/ic_home.png b/amethyst/src/main/res/drawable-xhdpi/ic_home.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_home.png rename to amethyst/src/main/res/drawable-xhdpi/ic_home.png diff --git a/app/src/main/res/drawable-xhdpi/ic_key.png b/amethyst/src/main/res/drawable-xhdpi/ic_key.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_key.png rename to amethyst/src/main/res/drawable-xhdpi/ic_key.png diff --git a/app/src/main/res/drawable-xhdpi/ic_lists.png b/amethyst/src/main/res/drawable-xhdpi/ic_lists.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_lists.png rename to amethyst/src/main/res/drawable-xhdpi/ic_lists.png diff --git a/app/src/main/res/drawable-xhdpi/ic_logout.png b/amethyst/src/main/res/drawable-xhdpi/ic_logout.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_logout.png rename to amethyst/src/main/res/drawable-xhdpi/ic_logout.png diff --git a/app/src/main/res/drawable-xhdpi/ic_moments.png b/amethyst/src/main/res/drawable-xhdpi/ic_moments.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_moments.png rename to amethyst/src/main/res/drawable-xhdpi/ic_moments.png diff --git a/app/src/main/res/drawable-xhdpi/ic_notifications.png b/amethyst/src/main/res/drawable-xhdpi/ic_notifications.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_notifications.png rename to amethyst/src/main/res/drawable-xhdpi/ic_notifications.png diff --git a/app/src/main/res/drawable-xhdpi/ic_poll.png b/amethyst/src/main/res/drawable-xhdpi/ic_poll.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_poll.png rename to amethyst/src/main/res/drawable-xhdpi/ic_poll.png diff --git a/app/src/main/res/drawable-xhdpi/ic_profile.png b/amethyst/src/main/res/drawable-xhdpi/ic_profile.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_profile.png rename to amethyst/src/main/res/drawable-xhdpi/ic_profile.png diff --git a/app/src/main/res/drawable-xhdpi/ic_qrcode.png b/amethyst/src/main/res/drawable-xhdpi/ic_qrcode.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_qrcode.png rename to amethyst/src/main/res/drawable-xhdpi/ic_qrcode.png diff --git a/app/src/main/res/drawable-xhdpi/ic_security.png b/amethyst/src/main/res/drawable-xhdpi/ic_security.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_security.png rename to amethyst/src/main/res/drawable-xhdpi/ic_security.png diff --git a/app/src/main/res/drawable-xhdpi/ic_theme.png b/amethyst/src/main/res/drawable-xhdpi/ic_theme.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_theme.png rename to amethyst/src/main/res/drawable-xhdpi/ic_theme.png diff --git a/app/src/main/res/drawable-xhdpi/ic_topics.png b/amethyst/src/main/res/drawable-xhdpi/ic_topics.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_topics.png rename to amethyst/src/main/res/drawable-xhdpi/ic_topics.png diff --git a/app/src/main/res/drawable-xhdpi/ic_trends.png b/amethyst/src/main/res/drawable-xhdpi/ic_trends.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_trends.png rename to amethyst/src/main/res/drawable-xhdpi/ic_trends.png diff --git a/app/src/main/res/drawable-xhdpi/ic_verified.png b/amethyst/src/main/res/drawable-xhdpi/ic_verified.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_verified.png rename to amethyst/src/main/res/drawable-xhdpi/ic_verified.png diff --git a/app/src/main/res/drawable-xhdpi/ic_verified_transparent.png b/amethyst/src/main/res/drawable-xhdpi/ic_verified_transparent.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_verified_transparent.png rename to amethyst/src/main/res/drawable-xhdpi/ic_verified_transparent.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_bookmarks.png b/amethyst/src/main/res/drawable-xxhdpi/ic_bookmarks.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_bookmarks.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_bookmarks.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_compose.png b/amethyst/src/main/res/drawable-xxhdpi/ic_compose.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_compose.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_compose.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_dm.png b/amethyst/src/main/res/drawable-xxhdpi/ic_dm.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_dm.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_dm.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_globe.png b/amethyst/src/main/res/drawable-xxhdpi/ic_globe.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_globe.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_globe.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_home.png b/amethyst/src/main/res/drawable-xxhdpi/ic_home.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_home.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_home.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_key.png b/amethyst/src/main/res/drawable-xxhdpi/ic_key.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_key.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_key.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_lists.png b/amethyst/src/main/res/drawable-xxhdpi/ic_lists.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_lists.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_lists.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_logout.png b/amethyst/src/main/res/drawable-xxhdpi/ic_logout.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_logout.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_logout.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_moments.png b/amethyst/src/main/res/drawable-xxhdpi/ic_moments.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_moments.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_moments.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_notifications.png b/amethyst/src/main/res/drawable-xxhdpi/ic_notifications.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_notifications.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_notifications.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_poll.png b/amethyst/src/main/res/drawable-xxhdpi/ic_poll.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_poll.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_poll.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_profile.png b/amethyst/src/main/res/drawable-xxhdpi/ic_profile.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_profile.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_profile.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_qrcode.png b/amethyst/src/main/res/drawable-xxhdpi/ic_qrcode.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_qrcode.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_qrcode.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_security.png b/amethyst/src/main/res/drawable-xxhdpi/ic_security.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_security.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_security.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_theme.png b/amethyst/src/main/res/drawable-xxhdpi/ic_theme.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_theme.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_theme.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_topics.png b/amethyst/src/main/res/drawable-xxhdpi/ic_topics.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_topics.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_topics.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_trends.png b/amethyst/src/main/res/drawable-xxhdpi/ic_trends.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_trends.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_trends.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_verified.png b/amethyst/src/main/res/drawable-xxhdpi/ic_verified.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_verified.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_verified.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_verified_transparent.png b/amethyst/src/main/res/drawable-xxhdpi/ic_verified_transparent.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_verified_transparent.png rename to amethyst/src/main/res/drawable-xxhdpi/ic_verified_transparent.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_bookmarks.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_bookmarks.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_bookmarks.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_bookmarks.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_compose.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_compose.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_compose.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_compose.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_dm.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_dm.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_dm.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_dm.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_globe.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_globe.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_globe.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_globe.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_home.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_home.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_home.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_home.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_lists.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_lists.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_lists.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_lists.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_moments.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_moments.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_moments.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_moments.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_notifications.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_notifications.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_notifications.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_notifications.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_poll.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_poll.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_poll.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_poll.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_profile.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_profile.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_profile.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_profile.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_qrcode.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_qrcode.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_qrcode.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_qrcode.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_theme.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_theme.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_theme.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_theme.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_topics.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_topics.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_topics.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_topics.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_trends.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_trends.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_trends.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_trends.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_verified.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_verified.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_verified.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_verified.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_verified_transparent.png b/amethyst/src/main/res/drawable-xxxhdpi/ic_verified_transparent.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_verified_transparent.png rename to amethyst/src/main/res/drawable-xxxhdpi/ic_verified_transparent.png diff --git a/app/src/main/res/drawable-xxxhdpi/profile_banner.jpeg b/amethyst/src/main/res/drawable-xxxhdpi/profile_banner.jpeg similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/profile_banner.jpeg rename to amethyst/src/main/res/drawable-xxxhdpi/profile_banner.jpeg diff --git a/app/src/main/res/drawable/alby.xml b/amethyst/src/main/res/drawable/alby.xml similarity index 100% rename from app/src/main/res/drawable/alby.xml rename to amethyst/src/main/res/drawable/alby.xml diff --git a/app/src/main/res/drawable/amethyst.xml b/amethyst/src/main/res/drawable/amethyst.xml similarity index 100% rename from app/src/main/res/drawable/amethyst.xml rename to amethyst/src/main/res/drawable/amethyst.xml diff --git a/app/src/main/res/drawable/amethyst_monochrome.xml b/amethyst/src/main/res/drawable/amethyst_monochrome.xml similarity index 100% rename from app/src/main/res/drawable/amethyst_monochrome.xml rename to amethyst/src/main/res/drawable/amethyst_monochrome.xml diff --git a/app/src/main/res/drawable/following.xml b/amethyst/src/main/res/drawable/following.xml similarity index 100% rename from app/src/main/res/drawable/following.xml rename to amethyst/src/main/res/drawable/following.xml diff --git a/app/src/main/res/drawable/github.xml b/amethyst/src/main/res/drawable/github.xml similarity index 100% rename from app/src/main/res/drawable/github.xml rename to amethyst/src/main/res/drawable/github.xml diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/amethyst/src/main/res/drawable/ic_launcher_foreground.xml similarity index 100% rename from app/src/main/res/drawable/ic_launcher_foreground.xml rename to amethyst/src/main/res/drawable/ic_launcher_foreground.xml diff --git a/app/src/main/res/drawable/ic_sensors.xml b/amethyst/src/main/res/drawable/ic_sensors.xml similarity index 100% rename from app/src/main/res/drawable/ic_sensors.xml rename to amethyst/src/main/res/drawable/ic_sensors.xml diff --git a/app/src/main/res/drawable/ic_settings.xml b/amethyst/src/main/res/drawable/ic_settings.xml similarity index 100% rename from app/src/main/res/drawable/ic_settings.xml rename to amethyst/src/main/res/drawable/ic_settings.xml diff --git a/app/src/main/res/drawable/ic_tor.xml b/amethyst/src/main/res/drawable/ic_tor.xml similarity index 100% rename from app/src/main/res/drawable/ic_tor.xml rename to amethyst/src/main/res/drawable/ic_tor.xml diff --git a/app/src/main/res/drawable/ic_video.xml b/amethyst/src/main/res/drawable/ic_video.xml similarity index 100% rename from app/src/main/res/drawable/ic_video.xml rename to amethyst/src/main/res/drawable/ic_video.xml diff --git a/app/src/main/res/drawable/incognito.xml b/amethyst/src/main/res/drawable/incognito.xml similarity index 100% rename from app/src/main/res/drawable/incognito.xml rename to amethyst/src/main/res/drawable/incognito.xml diff --git a/app/src/main/res/drawable/incognito_off.xml b/amethyst/src/main/res/drawable/incognito_off.xml similarity index 100% rename from app/src/main/res/drawable/incognito_off.xml rename to amethyst/src/main/res/drawable/incognito_off.xml diff --git a/app/src/main/res/drawable/lyrics_off.xml b/amethyst/src/main/res/drawable/lyrics_off.xml similarity index 100% rename from app/src/main/res/drawable/lyrics_off.xml rename to amethyst/src/main/res/drawable/lyrics_off.xml diff --git a/app/src/main/res/drawable/lyrics_on.xml b/amethyst/src/main/res/drawable/lyrics_on.xml similarity index 100% rename from app/src/main/res/drawable/lyrics_on.xml rename to amethyst/src/main/res/drawable/lyrics_on.xml diff --git a/app/src/main/res/drawable/manage_accounts.xml b/amethyst/src/main/res/drawable/manage_accounts.xml similarity index 100% rename from app/src/main/res/drawable/manage_accounts.xml rename to amethyst/src/main/res/drawable/manage_accounts.xml diff --git a/app/src/main/res/drawable/mastodon.xml b/amethyst/src/main/res/drawable/mastodon.xml similarity index 100% rename from app/src/main/res/drawable/mastodon.xml rename to amethyst/src/main/res/drawable/mastodon.xml diff --git a/app/src/main/res/drawable/nip_05.xml b/amethyst/src/main/res/drawable/nip_05.xml similarity index 100% rename from app/src/main/res/drawable/nip_05.xml rename to amethyst/src/main/res/drawable/nip_05.xml diff --git a/app/src/main/res/drawable/nip_05_full.xml b/amethyst/src/main/res/drawable/nip_05_full.xml similarity index 100% rename from app/src/main/res/drawable/nip_05_full.xml rename to amethyst/src/main/res/drawable/nip_05_full.xml diff --git a/app/src/main/res/drawable/original.xml b/amethyst/src/main/res/drawable/original.xml similarity index 100% rename from app/src/main/res/drawable/original.xml rename to amethyst/src/main/res/drawable/original.xml diff --git a/app/src/main/res/drawable/relays.xml b/amethyst/src/main/res/drawable/relays.xml similarity index 100% rename from app/src/main/res/drawable/relays.xml rename to amethyst/src/main/res/drawable/relays.xml diff --git a/app/src/main/res/drawable/telegram.xml b/amethyst/src/main/res/drawable/telegram.xml similarity index 100% rename from app/src/main/res/drawable/telegram.xml rename to amethyst/src/main/res/drawable/telegram.xml diff --git a/app/src/main/res/drawable/text_select_move_forward_character.xml b/amethyst/src/main/res/drawable/text_select_move_forward_character.xml similarity index 100% rename from app/src/main/res/drawable/text_select_move_forward_character.xml rename to amethyst/src/main/res/drawable/text_select_move_forward_character.xml diff --git a/app/src/main/res/drawable/twitter.xml b/amethyst/src/main/res/drawable/twitter.xml similarity index 100% rename from app/src/main/res/drawable/twitter.xml rename to amethyst/src/main/res/drawable/twitter.xml diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/amethyst/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to amethyst/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/amethyst/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to amethyst/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/amethyst/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher.png rename to amethyst/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/amethyst/src/main/res/mipmap-hdpi/ic_launcher_foreground.png similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png rename to amethyst/src/main/res/mipmap-hdpi/ic_launcher_foreground.png diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/amethyst/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to amethyst/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-hdpi/mutiny.png b/amethyst/src/main/res/mipmap-hdpi/mutiny.png similarity index 100% rename from app/src/main/res/mipmap-hdpi/mutiny.png rename to amethyst/src/main/res/mipmap-hdpi/mutiny.png diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/amethyst/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher.png rename to amethyst/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/amethyst/src/main/res/mipmap-mdpi/ic_launcher_foreground.png similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png rename to amethyst/src/main/res/mipmap-mdpi/ic_launcher_foreground.png diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/amethyst/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to amethyst/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-mdpi/mutiny.png b/amethyst/src/main/res/mipmap-mdpi/mutiny.png similarity index 100% rename from app/src/main/res/mipmap-mdpi/mutiny.png rename to amethyst/src/main/res/mipmap-mdpi/mutiny.png diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/amethyst/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to amethyst/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/amethyst/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png rename to amethyst/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/amethyst/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to amethyst/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-xhdpi/mutiny.png b/amethyst/src/main/res/mipmap-xhdpi/mutiny.png similarity index 100% rename from app/src/main/res/mipmap-xhdpi/mutiny.png rename to amethyst/src/main/res/mipmap-xhdpi/mutiny.png diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/amethyst/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to amethyst/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/amethyst/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png rename to amethyst/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/amethyst/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to amethyst/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-xxhdpi/mutiny.png b/amethyst/src/main/res/mipmap-xxhdpi/mutiny.png similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/mutiny.png rename to amethyst/src/main/res/mipmap-xxhdpi/mutiny.png diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/amethyst/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to amethyst/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/amethyst/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png rename to amethyst/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/amethyst/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to amethyst/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-xxxhdpi/mutiny.png b/amethyst/src/main/res/mipmap-xxxhdpi/mutiny.png similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/mutiny.png rename to amethyst/src/main/res/mipmap-xxxhdpi/mutiny.png diff --git a/app/src/main/res/values-ar/strings.xml b/amethyst/src/main/res/values-ar/strings.xml similarity index 100% rename from app/src/main/res/values-ar/strings.xml rename to amethyst/src/main/res/values-ar/strings.xml diff --git a/app/src/main/res/values-bn-rBD/strings.xml b/amethyst/src/main/res/values-bn-rBD/strings.xml similarity index 100% rename from app/src/main/res/values-bn-rBD/strings.xml rename to amethyst/src/main/res/values-bn-rBD/strings.xml diff --git a/app/src/main/res/values-cs/strings.xml b/amethyst/src/main/res/values-cs/strings.xml similarity index 100% rename from app/src/main/res/values-cs/strings.xml rename to amethyst/src/main/res/values-cs/strings.xml diff --git a/app/src/main/res/values-cy-rGB/strings.xml b/amethyst/src/main/res/values-cy-rGB/strings.xml similarity index 100% rename from app/src/main/res/values-cy-rGB/strings.xml rename to amethyst/src/main/res/values-cy-rGB/strings.xml diff --git a/app/src/main/res/values-da-rDK/strings.xml b/amethyst/src/main/res/values-da-rDK/strings.xml similarity index 100% rename from app/src/main/res/values-da-rDK/strings.xml rename to amethyst/src/main/res/values-da-rDK/strings.xml diff --git a/app/src/main/res/values-de/strings.xml b/amethyst/src/main/res/values-de/strings.xml similarity index 100% rename from app/src/main/res/values-de/strings.xml rename to amethyst/src/main/res/values-de/strings.xml diff --git a/app/src/main/res/values-el-rGR/strings.xml b/amethyst/src/main/res/values-el-rGR/strings.xml similarity index 100% rename from app/src/main/res/values-el-rGR/strings.xml rename to amethyst/src/main/res/values-el-rGR/strings.xml diff --git a/app/src/main/res/values-en-rGB/strings.xml b/amethyst/src/main/res/values-en-rGB/strings.xml similarity index 100% rename from app/src/main/res/values-en-rGB/strings.xml rename to amethyst/src/main/res/values-en-rGB/strings.xml diff --git a/app/src/main/res/values-eo/strings.xml b/amethyst/src/main/res/values-eo/strings.xml similarity index 100% rename from app/src/main/res/values-eo/strings.xml rename to amethyst/src/main/res/values-eo/strings.xml diff --git a/app/src/main/res/values-es-rES/strings.xml b/amethyst/src/main/res/values-es-rES/strings.xml similarity index 100% rename from app/src/main/res/values-es-rES/strings.xml rename to amethyst/src/main/res/values-es-rES/strings.xml diff --git a/app/src/main/res/values-es-rMX/strings.xml b/amethyst/src/main/res/values-es-rMX/strings.xml similarity index 100% rename from app/src/main/res/values-es-rMX/strings.xml rename to amethyst/src/main/res/values-es-rMX/strings.xml diff --git a/app/src/main/res/values-es-rUS/strings.xml b/amethyst/src/main/res/values-es-rUS/strings.xml similarity index 100% rename from app/src/main/res/values-es-rUS/strings.xml rename to amethyst/src/main/res/values-es-rUS/strings.xml diff --git a/app/src/main/res/values-es/strings.xml b/amethyst/src/main/res/values-es/strings.xml similarity index 100% rename from app/src/main/res/values-es/strings.xml rename to amethyst/src/main/res/values-es/strings.xml diff --git a/app/src/main/res/values-et-rEE/strings.xml b/amethyst/src/main/res/values-et-rEE/strings.xml similarity index 100% rename from app/src/main/res/values-et-rEE/strings.xml rename to amethyst/src/main/res/values-et-rEE/strings.xml diff --git a/app/src/main/res/values-fa/strings.xml b/amethyst/src/main/res/values-fa/strings.xml similarity index 100% rename from app/src/main/res/values-fa/strings.xml rename to amethyst/src/main/res/values-fa/strings.xml diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/amethyst/src/main/res/values-fi-rFI/strings.xml similarity index 100% rename from app/src/main/res/values-fi-rFI/strings.xml rename to amethyst/src/main/res/values-fi-rFI/strings.xml diff --git a/app/src/main/res/values-fo-rFO/strings.xml b/amethyst/src/main/res/values-fo-rFO/strings.xml similarity index 100% rename from app/src/main/res/values-fo-rFO/strings.xml rename to amethyst/src/main/res/values-fo-rFO/strings.xml diff --git a/app/src/main/res/values-fr-rCA/strings.xml b/amethyst/src/main/res/values-fr-rCA/strings.xml similarity index 100% rename from app/src/main/res/values-fr-rCA/strings.xml rename to amethyst/src/main/res/values-fr-rCA/strings.xml diff --git a/app/src/main/res/values-fr/strings.xml b/amethyst/src/main/res/values-fr/strings.xml similarity index 100% rename from app/src/main/res/values-fr/strings.xml rename to amethyst/src/main/res/values-fr/strings.xml diff --git a/app/src/main/res/values-gu-rIN/strings.xml b/amethyst/src/main/res/values-gu-rIN/strings.xml similarity index 100% rename from app/src/main/res/values-gu-rIN/strings.xml rename to amethyst/src/main/res/values-gu-rIN/strings.xml diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/amethyst/src/main/res/values-hi-rIN/strings.xml similarity index 100% rename from app/src/main/res/values-hi-rIN/strings.xml rename to amethyst/src/main/res/values-hi-rIN/strings.xml diff --git a/app/src/main/res/values-hr-rHR/strings.xml b/amethyst/src/main/res/values-hr-rHR/strings.xml similarity index 100% rename from app/src/main/res/values-hr-rHR/strings.xml rename to amethyst/src/main/res/values-hr-rHR/strings.xml diff --git a/app/src/main/res/values-hu/strings.xml b/amethyst/src/main/res/values-hu/strings.xml similarity index 100% rename from app/src/main/res/values-hu/strings.xml rename to amethyst/src/main/res/values-hu/strings.xml diff --git a/app/src/main/res/values-in-rID/strings.xml b/amethyst/src/main/res/values-in-rID/strings.xml similarity index 100% rename from app/src/main/res/values-in-rID/strings.xml rename to amethyst/src/main/res/values-in-rID/strings.xml diff --git a/app/src/main/res/values-in/strings.xml b/amethyst/src/main/res/values-in/strings.xml similarity index 100% rename from app/src/main/res/values-in/strings.xml rename to amethyst/src/main/res/values-in/strings.xml diff --git a/app/src/main/res/values-it-rIT/strings.xml b/amethyst/src/main/res/values-it-rIT/strings.xml similarity index 100% rename from app/src/main/res/values-it-rIT/strings.xml rename to amethyst/src/main/res/values-it-rIT/strings.xml diff --git a/app/src/main/res/values-iw-rIL/strings.xml b/amethyst/src/main/res/values-iw-rIL/strings.xml similarity index 100% rename from app/src/main/res/values-iw-rIL/strings.xml rename to amethyst/src/main/res/values-iw-rIL/strings.xml diff --git a/app/src/main/res/values-ja/strings.xml b/amethyst/src/main/res/values-ja/strings.xml similarity index 100% rename from app/src/main/res/values-ja/strings.xml rename to amethyst/src/main/res/values-ja/strings.xml diff --git a/app/src/main/res/values-kk-rKZ/strings.xml b/amethyst/src/main/res/values-kk-rKZ/strings.xml similarity index 100% rename from app/src/main/res/values-kk-rKZ/strings.xml rename to amethyst/src/main/res/values-kk-rKZ/strings.xml diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/amethyst/src/main/res/values-ko-rKR/strings.xml similarity index 100% rename from app/src/main/res/values-ko-rKR/strings.xml rename to amethyst/src/main/res/values-ko-rKR/strings.xml diff --git a/app/src/main/res/values-ks-rIN/strings.xml b/amethyst/src/main/res/values-ks-rIN/strings.xml similarity index 100% rename from app/src/main/res/values-ks-rIN/strings.xml rename to amethyst/src/main/res/values-ks-rIN/strings.xml diff --git a/app/src/main/res/values-ku-rTR/strings.xml b/amethyst/src/main/res/values-ku-rTR/strings.xml similarity index 100% rename from app/src/main/res/values-ku-rTR/strings.xml rename to amethyst/src/main/res/values-ku-rTR/strings.xml diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/amethyst/src/main/res/values-lt-rLT/strings.xml similarity index 100% rename from app/src/main/res/values-lt-rLT/strings.xml rename to amethyst/src/main/res/values-lt-rLT/strings.xml diff --git a/app/src/main/res/values-ne-rNP/strings.xml b/amethyst/src/main/res/values-ne-rNP/strings.xml similarity index 100% rename from app/src/main/res/values-ne-rNP/strings.xml rename to amethyst/src/main/res/values-ne-rNP/strings.xml diff --git a/app/src/main/res/values-night/themes.xml b/amethyst/src/main/res/values-night/themes.xml similarity index 100% rename from app/src/main/res/values-night/themes.xml rename to amethyst/src/main/res/values-night/themes.xml diff --git a/app/src/main/res/values-nl-rBE/strings.xml b/amethyst/src/main/res/values-nl-rBE/strings.xml similarity index 100% rename from app/src/main/res/values-nl-rBE/strings.xml rename to amethyst/src/main/res/values-nl-rBE/strings.xml diff --git a/app/src/main/res/values-nl/strings.xml b/amethyst/src/main/res/values-nl/strings.xml similarity index 100% rename from app/src/main/res/values-nl/strings.xml rename to amethyst/src/main/res/values-nl/strings.xml diff --git a/app/src/main/res/values-pcm-rNG/strings.xml b/amethyst/src/main/res/values-pcm-rNG/strings.xml similarity index 100% rename from app/src/main/res/values-pcm-rNG/strings.xml rename to amethyst/src/main/res/values-pcm-rNG/strings.xml diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/amethyst/src/main/res/values-pl-rPL/strings.xml similarity index 100% rename from app/src/main/res/values-pl-rPL/strings.xml rename to amethyst/src/main/res/values-pl-rPL/strings.xml diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/amethyst/src/main/res/values-pt-rBR/strings.xml similarity index 100% rename from app/src/main/res/values-pt-rBR/strings.xml rename to amethyst/src/main/res/values-pt-rBR/strings.xml diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/amethyst/src/main/res/values-pt-rPT/strings.xml similarity index 100% rename from app/src/main/res/values-pt-rPT/strings.xml rename to amethyst/src/main/res/values-pt-rPT/strings.xml diff --git a/app/src/main/res/values-ru-rUA/strings.xml b/amethyst/src/main/res/values-ru-rUA/strings.xml similarity index 100% rename from app/src/main/res/values-ru-rUA/strings.xml rename to amethyst/src/main/res/values-ru-rUA/strings.xml diff --git a/app/src/main/res/values-ru/strings.xml b/amethyst/src/main/res/values-ru/strings.xml similarity index 100% rename from app/src/main/res/values-ru/strings.xml rename to amethyst/src/main/res/values-ru/strings.xml diff --git a/app/src/main/res/values-sa-rIN/strings.xml b/amethyst/src/main/res/values-sa-rIN/strings.xml similarity index 100% rename from app/src/main/res/values-sa-rIN/strings.xml rename to amethyst/src/main/res/values-sa-rIN/strings.xml diff --git a/app/src/main/res/values-sl-rSI/strings.xml b/amethyst/src/main/res/values-sl-rSI/strings.xml similarity index 100% rename from app/src/main/res/values-sl-rSI/strings.xml rename to amethyst/src/main/res/values-sl-rSI/strings.xml diff --git a/app/src/main/res/values-so-rSO/strings.xml b/amethyst/src/main/res/values-so-rSO/strings.xml similarity index 100% rename from app/src/main/res/values-so-rSO/strings.xml rename to amethyst/src/main/res/values-so-rSO/strings.xml diff --git a/app/src/main/res/values-sr-rSP/strings.xml b/amethyst/src/main/res/values-sr-rSP/strings.xml similarity index 100% rename from app/src/main/res/values-sr-rSP/strings.xml rename to amethyst/src/main/res/values-sr-rSP/strings.xml diff --git a/app/src/main/res/values-ss-rZA/strings.xml b/amethyst/src/main/res/values-ss-rZA/strings.xml similarity index 100% rename from app/src/main/res/values-ss-rZA/strings.xml rename to amethyst/src/main/res/values-ss-rZA/strings.xml diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/amethyst/src/main/res/values-sv-rSE/strings.xml similarity index 100% rename from app/src/main/res/values-sv-rSE/strings.xml rename to amethyst/src/main/res/values-sv-rSE/strings.xml diff --git a/app/src/main/res/values-sw-rKE/strings.xml b/amethyst/src/main/res/values-sw-rKE/strings.xml similarity index 100% rename from app/src/main/res/values-sw-rKE/strings.xml rename to amethyst/src/main/res/values-sw-rKE/strings.xml diff --git a/app/src/main/res/values-sw-rTZ/strings.xml b/amethyst/src/main/res/values-sw-rTZ/strings.xml similarity index 100% rename from app/src/main/res/values-sw-rTZ/strings.xml rename to amethyst/src/main/res/values-sw-rTZ/strings.xml diff --git a/app/src/main/res/values-ta/strings.xml b/amethyst/src/main/res/values-ta/strings.xml similarity index 100% rename from app/src/main/res/values-ta/strings.xml rename to amethyst/src/main/res/values-ta/strings.xml diff --git a/app/src/main/res/values-th/strings.xml b/amethyst/src/main/res/values-th/strings.xml similarity index 100% rename from app/src/main/res/values-th/strings.xml rename to amethyst/src/main/res/values-th/strings.xml diff --git a/app/src/main/res/values-tr/strings.xml b/amethyst/src/main/res/values-tr/strings.xml similarity index 100% rename from app/src/main/res/values-tr/strings.xml rename to amethyst/src/main/res/values-tr/strings.xml diff --git a/app/src/main/res/values-uk/strings.xml b/amethyst/src/main/res/values-uk/strings.xml similarity index 100% rename from app/src/main/res/values-uk/strings.xml rename to amethyst/src/main/res/values-uk/strings.xml diff --git a/app/src/main/res/values-ur-rIN/strings.xml b/amethyst/src/main/res/values-ur-rIN/strings.xml similarity index 100% rename from app/src/main/res/values-ur-rIN/strings.xml rename to amethyst/src/main/res/values-ur-rIN/strings.xml diff --git a/app/src/main/res/values-uz-rUZ/strings.xml b/amethyst/src/main/res/values-uz-rUZ/strings.xml similarity index 100% rename from app/src/main/res/values-uz-rUZ/strings.xml rename to amethyst/src/main/res/values-uz-rUZ/strings.xml diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/amethyst/src/main/res/values-vi-rVN/strings.xml similarity index 100% rename from app/src/main/res/values-vi-rVN/strings.xml rename to amethyst/src/main/res/values-vi-rVN/strings.xml diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/amethyst/src/main/res/values-zh-rCN/strings.xml similarity index 100% rename from app/src/main/res/values-zh-rCN/strings.xml rename to amethyst/src/main/res/values-zh-rCN/strings.xml diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/amethyst/src/main/res/values-zh-rHK/strings.xml similarity index 100% rename from app/src/main/res/values-zh-rHK/strings.xml rename to amethyst/src/main/res/values-zh-rHK/strings.xml diff --git a/app/src/main/res/values-zh-rSG/strings.xml b/amethyst/src/main/res/values-zh-rSG/strings.xml similarity index 100% rename from app/src/main/res/values-zh-rSG/strings.xml rename to amethyst/src/main/res/values-zh-rSG/strings.xml diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/amethyst/src/main/res/values-zh-rTW/strings.xml similarity index 100% rename from app/src/main/res/values-zh-rTW/strings.xml rename to amethyst/src/main/res/values-zh-rTW/strings.xml diff --git a/app/src/main/res/values-zh/strings.xml b/amethyst/src/main/res/values-zh/strings.xml similarity index 100% rename from app/src/main/res/values-zh/strings.xml rename to amethyst/src/main/res/values-zh/strings.xml diff --git a/app/src/main/res/values/colors.xml b/amethyst/src/main/res/values/colors.xml similarity index 100% rename from app/src/main/res/values/colors.xml rename to amethyst/src/main/res/values/colors.xml diff --git a/app/src/main/res/values/ic_launcher_background.xml b/amethyst/src/main/res/values/ic_launcher_background.xml similarity index 100% rename from app/src/main/res/values/ic_launcher_background.xml rename to amethyst/src/main/res/values/ic_launcher_background.xml diff --git a/app/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml similarity index 100% rename from app/src/main/res/values/strings.xml rename to amethyst/src/main/res/values/strings.xml diff --git a/app/src/main/res/values/themes.xml b/amethyst/src/main/res/values/themes.xml similarity index 100% rename from app/src/main/res/values/themes.xml rename to amethyst/src/main/res/values/themes.xml diff --git a/app/src/main/res/xml/backup_rules.xml b/amethyst/src/main/res/xml/backup_rules.xml similarity index 100% rename from app/src/main/res/xml/backup_rules.xml rename to amethyst/src/main/res/xml/backup_rules.xml diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/amethyst/src/main/res/xml/data_extraction_rules.xml similarity index 100% rename from app/src/main/res/xml/data_extraction_rules.xml rename to amethyst/src/main/res/xml/data_extraction_rules.xml diff --git a/app/src/main/res/xml/locales_config.xml b/amethyst/src/main/res/xml/locales_config.xml similarity index 100% rename from app/src/main/res/xml/locales_config.xml rename to amethyst/src/main/res/xml/locales_config.xml diff --git a/app/src/play/AndroidManifest.xml b/amethyst/src/play/AndroidManifest.xml similarity index 100% rename from app/src/play/AndroidManifest.xml rename to amethyst/src/play/AndroidManifest.xml diff --git a/app/src/play/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt similarity index 100% rename from app/src/play/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt rename to amethyst/src/play/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt diff --git a/app/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt similarity index 100% rename from app/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt rename to amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt diff --git a/app/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt similarity index 100% rename from app/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt rename to amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt diff --git a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt similarity index 100% rename from app/src/play/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt rename to amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt diff --git a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt similarity index 100% rename from app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt rename to amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt diff --git a/app/src/test/java/android/util/Log.java b/amethyst/src/test/java/android/util/Log.java similarity index 100% rename from app/src/test/java/android/util/Log.java rename to amethyst/src/test/java/android/util/Log.java diff --git a/app/src/test/java/com/vitorpamplona/amethyst/CharsetTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/CharsetTest.kt similarity index 100% rename from app/src/test/java/com/vitorpamplona/amethyst/CharsetTest.kt rename to amethyst/src/test/java/com/vitorpamplona/amethyst/CharsetTest.kt diff --git a/app/src/test/java/com/vitorpamplona/amethyst/NewMessageTaggerKeyParseTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/NewMessageTaggerKeyParseTest.kt similarity index 100% rename from app/src/test/java/com/vitorpamplona/amethyst/NewMessageTaggerKeyParseTest.kt rename to amethyst/src/test/java/com/vitorpamplona/amethyst/NewMessageTaggerKeyParseTest.kt diff --git a/app/src/test/java/com/vitorpamplona/amethyst/SplitterTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/SplitterTest.kt similarity index 100% rename from app/src/test/java/com/vitorpamplona/amethyst/SplitterTest.kt rename to amethyst/src/test/java/com/vitorpamplona/amethyst/SplitterTest.kt diff --git a/app/src/test/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifierTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifierTest.kt similarity index 100% rename from app/src/test/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifierTest.kt rename to amethyst/src/test/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifierTest.kt diff --git a/app/src/test/java/com/vitorpamplona/amethyst/service/Nip96Test.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/Nip96Test.kt similarity index 100% rename from app/src/test/java/com/vitorpamplona/amethyst/service/Nip96Test.kt rename to amethyst/src/test/java/com/vitorpamplona/amethyst/service/Nip96Test.kt diff --git a/app/src/test/java/com/vitorpamplona/amethyst/service/zaps/UserZapsTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/zaps/UserZapsTest.kt similarity index 100% rename from app/src/test/java/com/vitorpamplona/amethyst/service/zaps/UserZapsTest.kt rename to amethyst/src/test/java/com/vitorpamplona/amethyst/service/zaps/UserZapsTest.kt diff --git a/build.gradle b/build.gradle index 121417ec7..e59be5f63 100644 --- a/build.gradle +++ b/build.gradle @@ -60,4 +60,4 @@ tasks.register('installGitHook', Copy) { into { new File(rootProject.rootDir, '.git/hooks') } fileMode 0777 } -tasks.getByPath(':app:preBuild').dependsOn installGitHook \ No newline at end of file +tasks.getByPath(':amethyst:preBuild').dependsOn installGitHook \ No newline at end of file diff --git a/crowdin.yml b/crowdin.yml index c822c312a..0ac256fc3 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -5,8 +5,8 @@ "preserve_hierarchy": true files: - - source: app/src/main/res/values/strings.xml - translation: app/src/main/res/values-%android_code%/%original_file_name% + - source: amethyst/src/main/res/values/strings.xml + translation: amethyst/src/main/res/values-%android_code%/%original_file_name% type: android skip_untranslated_strings: true languages_mapping: diff --git a/settings.gradle b/settings.gradle index 5c054bd44..03c0ea0b2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -28,7 +28,7 @@ dependencyResolutionManagement { } rootProject.name = "Amethyst" -include ':app' +include ':amethyst' include ':benchmark' include ':quartz' include ':commons' From 8cef7bcb755dba07ec189e1ca8279122b13ef4ea Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 24 Jun 2024 17:55:31 -0400 Subject: [PATCH 13/49] Logging as a Relay error message when the relay does not accept an event. --- .../src/main/java/com/vitorpamplona/ammolite/relays/Relay.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Relay.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Relay.kt index 9c7af4c02..b403af399 100644 --- a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Relay.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Relay.kt @@ -316,6 +316,11 @@ class Relay( } Log.w("Relay", "Relay on OK $url, $eventId, $success, $message") + + if (!success) { + RelayStats.newNotice(url, "Failed to receive $eventId: $message") + } + it.onSendResponse(this@Relay, eventId, success, message) } "AUTH" -> From 839cadea3576b7dfe418f9601ccad7ff3b2aba13 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 24 Jun 2024 17:56:24 -0400 Subject: [PATCH 14/49] Saves a copy of the NIP65 and NIP17 relay lists locally --- .../amethyst/LocalPreferences.kt | 83 ++++++++++++-- .../vitorpamplona/amethyst/model/Account.kt | 104 +++++++++++++++--- 2 files changed, 167 insertions(+), 20 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 7a3c1ac78..39d36c3d0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -42,6 +42,8 @@ import com.vitorpamplona.quartz.encoders.Nip47WalletConnect import com.vitorpamplona.quartz.encoders.hexToByteArray import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.encoders.toNpub +import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent +import com.vitorpamplona.quartz.events.ChatMessageRelayListEvent import com.vitorpamplona.quartz.events.ContactListEvent import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.LnZapEvent @@ -90,6 +92,8 @@ private object PrefKeys { const val DEFAULT_DISCOVERY_FOLLOW_LIST = "defaultDiscoveryFollowList" const val ZAP_PAYMENT_REQUEST_SERVER = "zapPaymentServer" const val LATEST_CONTACT_LIST = "latestContactList" + const val LATEST_DM_RELAY_LIST = "latestDMRelayList" + const val LATEST_NIP65_RELAY_LIST = "latestNIP65RelayList" const val HIDE_DELETE_REQUEST_DIALOG = "hide_delete_request_dialog" const val HIDE_BLOCK_ALERT_DIALOG = "hide_block_alert_dialog" const val HIDE_NIP_17_WARNING_DIALOG = "hide_nip24_warning_dialog" // delete later @@ -311,10 +315,33 @@ object LocalPreferences { PrefKeys.ZAP_PAYMENT_REQUEST_SERVER, Event.mapper.writeValueAsString(account.zapPaymentRequest), ) - putString( - PrefKeys.LATEST_CONTACT_LIST, - Event.mapper.writeValueAsString(account.backupContactList), - ) + if (account.backupContactList != null) { + putString( + PrefKeys.LATEST_CONTACT_LIST, + Event.mapper.writeValueAsString(account.backupContactList), + ) + } else { + remove(PrefKeys.LATEST_CONTACT_LIST) + } + + if (account.backupDMRelayList != null) { + putString( + PrefKeys.LATEST_DM_RELAY_LIST, + Event.mapper.writeValueAsString(account.backupDMRelayList), + ) + } else { + remove(PrefKeys.LATEST_DM_RELAY_LIST) + } + + if (account.backupNIP65RelayList != null) { + putString( + PrefKeys.LATEST_NIP65_RELAY_LIST, + Event.mapper.writeValueAsString(account.backupNIP65RelayList), + ) + } else { + remove(PrefKeys.LATEST_NIP65_RELAY_LIST) + } + putBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, account.hideDeleteRequestDialog) putBoolean(PrefKeys.HIDE_NIP_17_WARNING_DIALOG, account.hideNIP17WarningDialog) putBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, account.hideBlockAlertDialog) @@ -471,8 +498,8 @@ object LocalPreferences { val latestContactList = try { getString(PrefKeys.LATEST_CONTACT_LIST, null)?.let { - println("Decoding Contact List: " + it) - if (it != null) { + if (it != "null") { + println("Decoding Contact List: $it") Event.fromJson(it) as ContactListEvent? } else { null @@ -488,6 +515,46 @@ object LocalPreferences { null } + val latestDmRelayList = + try { + getString(PrefKeys.LATEST_DM_RELAY_LIST, null)?.let { + if (it != "null") { + println("Decoding DM Relay List: $it") + Event.fromJson(it) as ChatMessageRelayListEvent? + } else { + null + } + } + } catch (e: Throwable) { + if (e is CancellationException) throw e + Log.w( + "LocalPreferences", + "Error Decoding DM Relay List ${getString(PrefKeys.LATEST_DM_RELAY_LIST, null)}", + e, + ) + null + } + + val latestNip65RelayList = + try { + getString(PrefKeys.LATEST_NIP65_RELAY_LIST, null)?.let { + if (it != "null") { + println("Decoding NIP65 Relay List: $it") + Event.fromJson(it) as AdvertisedRelayListEvent? + } else { + null + } + } + } catch (e: Throwable) { + if (e is CancellationException) throw e + Log.w( + "LocalPreferences", + "Error Decoding NIP65 Relay List ${getString(PrefKeys.LATEST_NIP65_RELAY_LIST, null)}", + e, + ) + null + } + val pendingAttestations = try { getString(PrefKeys.PENDING_ATTESTATIONS, null)?.let { @@ -502,7 +569,7 @@ object LocalPreferences { if (e is CancellationException) throw e Log.w( "LocalPreferences", - "Error Decoding Contact List ${getString(PrefKeys.LATEST_CONTACT_LIST, null)}", + "Error Decoding Contact List ${getString(PrefKeys.PENDING_ATTESTATIONS, null)}", e, ) null @@ -595,6 +662,8 @@ object LocalPreferences { hideBlockAlertDialog = hideBlockAlertDialog, hideNIP17WarningDialog = hideNIP17WarningDialog, backupContactList = latestContactList, + backupNIP65RelayList = latestNip65RelayList, + backupDMRelayList = latestDmRelayList, proxy = proxy, proxyPort = proxyPort, showSensitiveContent = MutableStateFlow(showSensitiveContent), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 1e3ff69ff..2fd531131 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -116,6 +116,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flattenMerge @@ -192,6 +193,8 @@ class Account( var hideBlockAlertDialog: Boolean = false, var hideNIP17WarningDialog: Boolean = false, var backupContactList: ContactListEvent? = null, + var backupDMRelayList: ChatMessageRelayListEvent? = null, + var backupNIP65RelayList: AdvertisedRelayListEvent? = null, var proxy: Proxy? = null, var proxyPort: Int = 9050, var showSensitiveContent: MutableStateFlow = MutableStateFlow(null), @@ -269,7 +272,9 @@ class Account( if (mappedRelaySet.none { it.url == newUrl }) { mappedRelaySet = mappedRelaySet + RelaySetupInfo( - newUrl, true, true, + newUrl, + true, + true, setOf( FeedType.PRIVATE_DMS, ), @@ -294,7 +299,9 @@ class Account( if (mappedRelaySet.none { it.url == newUrl }) { mappedRelaySet = mappedRelaySet + RelaySetupInfo( - newUrl, true, false, + newUrl, + true, + false, setOf( FeedType.SEARCH, ), @@ -319,9 +326,14 @@ class Account( if (mappedRelaySet.none { it.url == newUrl }) { mappedRelaySet = mappedRelaySet + RelaySetupInfo( - newUrl, true, true, + newUrl, + true, + true, setOf( - FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.GLOBAL, FeedType.PRIVATE_DMS, + FeedType.FOLLOWS, + FeedType.PUBLIC_CHATS, + FeedType.GLOBAL, + FeedType.PRIVATE_DMS, ), ) } @@ -344,9 +356,14 @@ class Account( if (mappedRelaySet.none { it.url == newUrl }) { mappedRelaySet = mappedRelaySet + RelaySetupInfo( - newUrl, true, true, + newUrl, + true, + true, setOf( - FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.GLOBAL, FeedType.PRIVATE_DMS, + FeedType.FOLLOWS, + FeedType.PUBLIC_CHATS, + FeedType.GLOBAL, + FeedType.PRIVATE_DMS, ), ) } @@ -363,10 +380,14 @@ class Account( val write = nip65setup.type == AdvertisedRelayListEvent.AdvertisedRelayType.BOTH || nip65setup.type == AdvertisedRelayListEvent.AdvertisedRelayType.READ RelaySetupInfo( - relay.url, true, relay.write || write, + relay.url, + true, + relay.write || write, relay.feedTypes + setOf( - FeedType.FOLLOWS, FeedType.GLOBAL, FeedType.PUBLIC_CHATS, + FeedType.FOLLOWS, + FeedType.GLOBAL, + FeedType.PUBLIC_CHATS, ), ) } else { @@ -380,9 +401,12 @@ class Account( mappedRelaySet = mappedRelaySet + RelaySetupInfo( - newNip65Setup.relayUrl, true, write, + newNip65Setup.relayUrl, + true, + write, setOf( - FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, + FeedType.FOLLOWS, + FeedType.PUBLIC_CHATS, ), ) } @@ -2635,6 +2659,26 @@ class Account( } } + private fun updateDMRelayList(newDMRelayList: ChatMessageRelayListEvent?) { + if (newDMRelayList == null || newDMRelayList.tags.isEmpty()) return + + // Events might be different objects, we have to compare their ids. + if (backupDMRelayList?.id != newDMRelayList.id) { + backupDMRelayList = newDMRelayList + saveable.invalidateData() + } + } + + private fun updateNIP65RelayList(newNIP65RelayList: AdvertisedRelayListEvent?) { + if (newNIP65RelayList == null || newNIP65RelayList.tags.isEmpty()) return + + // Events might be different objects, we have to compare their ids. + if (backupNIP65RelayList?.id != newNIP65RelayList.id) { + backupNIP65RelayList = newNIP65RelayList + saveable.invalidateData() + } + } + // Takes a User's relay list and adds the types of feeds they are active for. fun activeRelays(): Array? { val usersRelayList = @@ -2968,8 +3012,32 @@ class Account( suspend fun registerObservers() = withContext(Dispatchers.Main) { // saves contact list for the next time. - userProfile().live().follows.observeForever { - GlobalScope.launch(Dispatchers.IO) { updateContactListTo(userProfile().latestContactList) } + scope.launch { + Log.d("AccountRegisterObservers", "Kind 3 Collector Start") + userProfile().flow().follows.stateFlow.collect { + Log.d("AccountRegisterObservers", "Updating Kind 3 ${userProfile().toBestDisplayName()}") + updateContactListTo(userProfile().latestContactList) + } + } + + scope.launch { + Log.d("AccountRegisterObservers", "NIP-17 Relay List Collector Start") + getDMRelayListFlow().collect { + Log.d("AccountRegisterObservers", "Updating DM Relay List for ${userProfile().toBestDisplayName()}") + (it.note.event as? ChatMessageRelayListEvent)?.let { + updateDMRelayList(it) + } + } + } + + scope.launch { + Log.d("AccountRegisterObservers", "NIP-65 Relay List Collector Start") + getNIP65RelayListFlow().collect { + Log.d("AccountRegisterObservers", "Updating NIP-65 List for ${userProfile().toBestDisplayName()}") + (it.note.event as? AdvertisedRelayListEvent)?.let { + updateNIP65RelayList(it) + } + } } // imports transient blocks due to spam. @@ -2990,7 +3058,7 @@ class Account( } init { - Log.d("Init", "Account") + Log.d("Account", "Init") backupContactList?.let { println("Loading saved contacts ${it.toJson()}") @@ -2998,6 +3066,16 @@ class Account( GlobalScope.launch(Dispatchers.IO) { LocalCache.consume(it) } } } + + backupDMRelayList?.let { + println("Loading DM Relay List ${it.toJson()}") + GlobalScope.launch(Dispatchers.IO) { LocalCache.verifyAndConsume(it, null) } + } + + backupNIP65RelayList?.let { + println("Loading saved contacts ${it.toJson()}") + GlobalScope.launch(Dispatchers.IO) { LocalCache.verifyAndConsume(it, null) } + } } } From 0f066d08170ab0a10a338a1c128e64941db7bb85 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 24 Jun 2024 17:56:24 -0400 Subject: [PATCH 15/49] Saves a copy of the NIP65 and NIP17 relay lists locally --- .../amethyst/LocalPreferences.kt | 83 ++++++++++++-- .../vitorpamplona/amethyst/model/Account.kt | 104 ++++++++++++++--- .../service/notifications/RegisterAccounts.kt | 106 +++++++++++++----- 3 files changed, 247 insertions(+), 46 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 7a3c1ac78..39d36c3d0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -42,6 +42,8 @@ import com.vitorpamplona.quartz.encoders.Nip47WalletConnect import com.vitorpamplona.quartz.encoders.hexToByteArray import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.encoders.toNpub +import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent +import com.vitorpamplona.quartz.events.ChatMessageRelayListEvent import com.vitorpamplona.quartz.events.ContactListEvent import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.LnZapEvent @@ -90,6 +92,8 @@ private object PrefKeys { const val DEFAULT_DISCOVERY_FOLLOW_LIST = "defaultDiscoveryFollowList" const val ZAP_PAYMENT_REQUEST_SERVER = "zapPaymentServer" const val LATEST_CONTACT_LIST = "latestContactList" + const val LATEST_DM_RELAY_LIST = "latestDMRelayList" + const val LATEST_NIP65_RELAY_LIST = "latestNIP65RelayList" const val HIDE_DELETE_REQUEST_DIALOG = "hide_delete_request_dialog" const val HIDE_BLOCK_ALERT_DIALOG = "hide_block_alert_dialog" const val HIDE_NIP_17_WARNING_DIALOG = "hide_nip24_warning_dialog" // delete later @@ -311,10 +315,33 @@ object LocalPreferences { PrefKeys.ZAP_PAYMENT_REQUEST_SERVER, Event.mapper.writeValueAsString(account.zapPaymentRequest), ) - putString( - PrefKeys.LATEST_CONTACT_LIST, - Event.mapper.writeValueAsString(account.backupContactList), - ) + if (account.backupContactList != null) { + putString( + PrefKeys.LATEST_CONTACT_LIST, + Event.mapper.writeValueAsString(account.backupContactList), + ) + } else { + remove(PrefKeys.LATEST_CONTACT_LIST) + } + + if (account.backupDMRelayList != null) { + putString( + PrefKeys.LATEST_DM_RELAY_LIST, + Event.mapper.writeValueAsString(account.backupDMRelayList), + ) + } else { + remove(PrefKeys.LATEST_DM_RELAY_LIST) + } + + if (account.backupNIP65RelayList != null) { + putString( + PrefKeys.LATEST_NIP65_RELAY_LIST, + Event.mapper.writeValueAsString(account.backupNIP65RelayList), + ) + } else { + remove(PrefKeys.LATEST_NIP65_RELAY_LIST) + } + putBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, account.hideDeleteRequestDialog) putBoolean(PrefKeys.HIDE_NIP_17_WARNING_DIALOG, account.hideNIP17WarningDialog) putBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, account.hideBlockAlertDialog) @@ -471,8 +498,8 @@ object LocalPreferences { val latestContactList = try { getString(PrefKeys.LATEST_CONTACT_LIST, null)?.let { - println("Decoding Contact List: " + it) - if (it != null) { + if (it != "null") { + println("Decoding Contact List: $it") Event.fromJson(it) as ContactListEvent? } else { null @@ -488,6 +515,46 @@ object LocalPreferences { null } + val latestDmRelayList = + try { + getString(PrefKeys.LATEST_DM_RELAY_LIST, null)?.let { + if (it != "null") { + println("Decoding DM Relay List: $it") + Event.fromJson(it) as ChatMessageRelayListEvent? + } else { + null + } + } + } catch (e: Throwable) { + if (e is CancellationException) throw e + Log.w( + "LocalPreferences", + "Error Decoding DM Relay List ${getString(PrefKeys.LATEST_DM_RELAY_LIST, null)}", + e, + ) + null + } + + val latestNip65RelayList = + try { + getString(PrefKeys.LATEST_NIP65_RELAY_LIST, null)?.let { + if (it != "null") { + println("Decoding NIP65 Relay List: $it") + Event.fromJson(it) as AdvertisedRelayListEvent? + } else { + null + } + } + } catch (e: Throwable) { + if (e is CancellationException) throw e + Log.w( + "LocalPreferences", + "Error Decoding NIP65 Relay List ${getString(PrefKeys.LATEST_NIP65_RELAY_LIST, null)}", + e, + ) + null + } + val pendingAttestations = try { getString(PrefKeys.PENDING_ATTESTATIONS, null)?.let { @@ -502,7 +569,7 @@ object LocalPreferences { if (e is CancellationException) throw e Log.w( "LocalPreferences", - "Error Decoding Contact List ${getString(PrefKeys.LATEST_CONTACT_LIST, null)}", + "Error Decoding Contact List ${getString(PrefKeys.PENDING_ATTESTATIONS, null)}", e, ) null @@ -595,6 +662,8 @@ object LocalPreferences { hideBlockAlertDialog = hideBlockAlertDialog, hideNIP17WarningDialog = hideNIP17WarningDialog, backupContactList = latestContactList, + backupNIP65RelayList = latestNip65RelayList, + backupDMRelayList = latestDmRelayList, proxy = proxy, proxyPort = proxyPort, showSensitiveContent = MutableStateFlow(showSensitiveContent), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 1e3ff69ff..2fd531131 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -116,6 +116,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flattenMerge @@ -192,6 +193,8 @@ class Account( var hideBlockAlertDialog: Boolean = false, var hideNIP17WarningDialog: Boolean = false, var backupContactList: ContactListEvent? = null, + var backupDMRelayList: ChatMessageRelayListEvent? = null, + var backupNIP65RelayList: AdvertisedRelayListEvent? = null, var proxy: Proxy? = null, var proxyPort: Int = 9050, var showSensitiveContent: MutableStateFlow = MutableStateFlow(null), @@ -269,7 +272,9 @@ class Account( if (mappedRelaySet.none { it.url == newUrl }) { mappedRelaySet = mappedRelaySet + RelaySetupInfo( - newUrl, true, true, + newUrl, + true, + true, setOf( FeedType.PRIVATE_DMS, ), @@ -294,7 +299,9 @@ class Account( if (mappedRelaySet.none { it.url == newUrl }) { mappedRelaySet = mappedRelaySet + RelaySetupInfo( - newUrl, true, false, + newUrl, + true, + false, setOf( FeedType.SEARCH, ), @@ -319,9 +326,14 @@ class Account( if (mappedRelaySet.none { it.url == newUrl }) { mappedRelaySet = mappedRelaySet + RelaySetupInfo( - newUrl, true, true, + newUrl, + true, + true, setOf( - FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.GLOBAL, FeedType.PRIVATE_DMS, + FeedType.FOLLOWS, + FeedType.PUBLIC_CHATS, + FeedType.GLOBAL, + FeedType.PRIVATE_DMS, ), ) } @@ -344,9 +356,14 @@ class Account( if (mappedRelaySet.none { it.url == newUrl }) { mappedRelaySet = mappedRelaySet + RelaySetupInfo( - newUrl, true, true, + newUrl, + true, + true, setOf( - FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.GLOBAL, FeedType.PRIVATE_DMS, + FeedType.FOLLOWS, + FeedType.PUBLIC_CHATS, + FeedType.GLOBAL, + FeedType.PRIVATE_DMS, ), ) } @@ -363,10 +380,14 @@ class Account( val write = nip65setup.type == AdvertisedRelayListEvent.AdvertisedRelayType.BOTH || nip65setup.type == AdvertisedRelayListEvent.AdvertisedRelayType.READ RelaySetupInfo( - relay.url, true, relay.write || write, + relay.url, + true, + relay.write || write, relay.feedTypes + setOf( - FeedType.FOLLOWS, FeedType.GLOBAL, FeedType.PUBLIC_CHATS, + FeedType.FOLLOWS, + FeedType.GLOBAL, + FeedType.PUBLIC_CHATS, ), ) } else { @@ -380,9 +401,12 @@ class Account( mappedRelaySet = mappedRelaySet + RelaySetupInfo( - newNip65Setup.relayUrl, true, write, + newNip65Setup.relayUrl, + true, + write, setOf( - FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, + FeedType.FOLLOWS, + FeedType.PUBLIC_CHATS, ), ) } @@ -2635,6 +2659,26 @@ class Account( } } + private fun updateDMRelayList(newDMRelayList: ChatMessageRelayListEvent?) { + if (newDMRelayList == null || newDMRelayList.tags.isEmpty()) return + + // Events might be different objects, we have to compare their ids. + if (backupDMRelayList?.id != newDMRelayList.id) { + backupDMRelayList = newDMRelayList + saveable.invalidateData() + } + } + + private fun updateNIP65RelayList(newNIP65RelayList: AdvertisedRelayListEvent?) { + if (newNIP65RelayList == null || newNIP65RelayList.tags.isEmpty()) return + + // Events might be different objects, we have to compare their ids. + if (backupNIP65RelayList?.id != newNIP65RelayList.id) { + backupNIP65RelayList = newNIP65RelayList + saveable.invalidateData() + } + } + // Takes a User's relay list and adds the types of feeds they are active for. fun activeRelays(): Array? { val usersRelayList = @@ -2968,8 +3012,32 @@ class Account( suspend fun registerObservers() = withContext(Dispatchers.Main) { // saves contact list for the next time. - userProfile().live().follows.observeForever { - GlobalScope.launch(Dispatchers.IO) { updateContactListTo(userProfile().latestContactList) } + scope.launch { + Log.d("AccountRegisterObservers", "Kind 3 Collector Start") + userProfile().flow().follows.stateFlow.collect { + Log.d("AccountRegisterObservers", "Updating Kind 3 ${userProfile().toBestDisplayName()}") + updateContactListTo(userProfile().latestContactList) + } + } + + scope.launch { + Log.d("AccountRegisterObservers", "NIP-17 Relay List Collector Start") + getDMRelayListFlow().collect { + Log.d("AccountRegisterObservers", "Updating DM Relay List for ${userProfile().toBestDisplayName()}") + (it.note.event as? ChatMessageRelayListEvent)?.let { + updateDMRelayList(it) + } + } + } + + scope.launch { + Log.d("AccountRegisterObservers", "NIP-65 Relay List Collector Start") + getNIP65RelayListFlow().collect { + Log.d("AccountRegisterObservers", "Updating NIP-65 List for ${userProfile().toBestDisplayName()}") + (it.note.event as? AdvertisedRelayListEvent)?.let { + updateNIP65RelayList(it) + } + } } // imports transient blocks due to spam. @@ -2990,7 +3058,7 @@ class Account( } init { - Log.d("Init", "Account") + Log.d("Account", "Init") backupContactList?.let { println("Loading saved contacts ${it.toJson()}") @@ -2998,6 +3066,16 @@ class Account( GlobalScope.launch(Dispatchers.IO) { LocalCache.consume(it) } } } + + backupDMRelayList?.let { + println("Loading DM Relay List ${it.toJson()}") + GlobalScope.launch(Dispatchers.IO) { LocalCache.verifyAndConsume(it, null) } + } + + backupNIP65RelayList?.let { + println("Loading saved contacts ${it.toJson()}") + GlobalScope.launch(Dispatchers.IO) { LocalCache.verifyAndConsume(it, null) } + } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt index 6ce76450b..dc6b7b90c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt @@ -25,19 +25,35 @@ import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.ammolite.service.HttpClientManager +import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent +import com.vitorpamplona.quartz.events.ChatMessageRelayListEvent import com.vitorpamplona.quartz.events.RelayAuthEvent import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.joinAll +import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeoutOrNull import okhttp3.MediaType.Companion.toMediaType import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody +import kotlin.coroutines.resume class RegisterAccounts( private val accounts: List, ) { - private fun recursiveAuthCreation( + val tag = + if (BuildConfig.FLAVOR == "play") { + "RegisterAccounts FirebaseMsgService" + } else { + "RegisterAccounts UnifiedPushService" + } + + private suspend fun signAllAuths( notificationToken: String, remainingTos: List>, output: MutableList, @@ -48,12 +64,32 @@ class RegisterAccounts( return } - val next = remainingTos.first() + coroutineScope { + val jobs = + remainingTos.map { accountRelayPair -> + async { + val result = + withTimeoutOrNull(10000) { + suspendCancellableCoroutine { continuation -> + accountRelayPair.first.createAuthEvent(accountRelayPair.second, notificationToken) { result -> + continuation.resume(result) + } + } + } - next.first.createAuthEvent(next.second, notificationToken) { - output.add(it) - recursiveAuthCreation(notificationToken, remainingTos.filter { next != it }, output, onReady) + if (result != null) { + output.add(result) + } + } + } + + // runs in parallel to avoid overcrowding Amber. + withTimeoutOrNull(15000) { + jobs.joinAll() + } } + + onReady(output) } // creates proof that it controls all accounts @@ -63,25 +99,48 @@ class RegisterAccounts( onReady: (List) -> Unit, ) { val readyToSend = - accounts.mapNotNull { - val acc = LocalPreferences.loadCurrentAccountFromEncryptedStorage(it.npub) - if (acc != null && acc.isWriteable()) { - val readRelays = - acc.userProfile().latestContactList?.relays() ?: acc.backupContactList?.relays() + accounts + .map { + Log.d(tag, "Register Account ${it.npub}") - val relayToUse = readRelays?.firstNotNullOfOrNull { if (it.value.read) it.key else null } - if (relayToUse != null) { - Pair(acc, relayToUse) + val acc = LocalPreferences.loadCurrentAccountFromEncryptedStorage(it.npub) + + if (acc != null && acc.isWriteable()) { + val nip65Read = + ( + LocalCache + .getAddressableNoteIfExists( + AdvertisedRelayListEvent.createAddressTag(acc.userProfile().pubkeyHex), + )?.event as? AdvertisedRelayListEvent + )?.readRelays() ?: acc.backupNIP65RelayList?.readRelays() ?: emptyList() + + Log.d(tag, "Register Account ${acc.userProfile().toBestDisplayName()} NIP65 Reads ${nip65Read.joinToString(", ")}") + + val nip17Read = + ( + LocalCache + .getAddressableNoteIfExists( + ChatMessageRelayListEvent.createAddressTag(acc.userProfile().pubkeyHex), + )?.event as? ChatMessageRelayListEvent + )?.relays() ?: acc.backupDMRelayList?.relays() ?: emptyList() + + Log.d(tag, "Register Account ${acc.userProfile().toBestDisplayName()} NIP17 Reads ${nip17Read.joinToString(", ")}") + + val kind3Relays = (acc.userProfile().latestContactList?.relays() ?: acc.backupContactList?.relays()) + val readKind3Relays = kind3Relays?.mapNotNull { if (it.value.read) it.key else null } ?: emptyList() + + Log.d(tag, "Register Account ${acc.userProfile().toBestDisplayName()} Kind3 Reads ${readKind3Relays.joinToString(", ")}") + + (nip65Read + nip17Read + readKind3Relays).map { + Pair(acc, it) + } } else { - null + emptyList>() } - } else { - null - } - } + }.flatten() val listOfAuthEvents = mutableListOf() - recursiveAuthCreation( + signAllAuths( notificationToken, readyToSend, listOfAuthEvents, @@ -101,7 +160,8 @@ class RegisterAccounts( val body = jsonObject.toRequestBody(mediaType) val request = - Request.Builder() + Request + .Builder() .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") .url("https://push.amethyst.social/register") .post(body) @@ -112,12 +172,6 @@ class RegisterAccounts( val isSucess = client.newCall(request).execute().use { it.isSuccessful } } catch (e: java.lang.Exception) { if (e is CancellationException) throw e - val tag = - if (BuildConfig.FLAVOR == "play") { - "FirebaseMsgService" - } else { - "UnifiedPushService" - } Log.e(tag, "Unable to register with push server", e) } } From 1b2f7e21f629d87f1a4e39a4977bac51c32f3633 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 24 Jun 2024 18:52:04 -0400 Subject: [PATCH 16/49] Makes sure to download the updated list of relays when looking at a user. --- .../amethyst/service/NostrSingleUserDataSource.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt index 7cfb2604a..5b6f48b26 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt @@ -26,6 +26,7 @@ import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES import com.vitorpamplona.ammolite.relays.JsonFilter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent +import com.vitorpamplona.quartz.events.ChatMessageRelayListEvent import com.vitorpamplona.quartz.events.MetadataEvent import com.vitorpamplona.quartz.events.ReportEvent import com.vitorpamplona.quartz.events.StatusEvent @@ -68,7 +69,7 @@ object NostrSingleUserDataSource : AmethystNostrDataSource("SingleUserFeed") { types = EVENT_FINDER_TYPES, filter = JsonFilter( - kinds = listOf(MetadataEvent.KIND, StatusEvent.KIND, AdvertisedRelayListEvent.KIND), + kinds = listOf(MetadataEvent.KIND, StatusEvent.KIND, AdvertisedRelayListEvent.KIND, ChatMessageRelayListEvent.KIND), authors = groupIds, since = minEOSEs, ), From 782df3bcb58ab2bc0eaa107603c1274baf22d255 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Mon, 24 Jun 2024 23:12:34 +0000 Subject: [PATCH 17/49] New Crowdin translations by GitHub Action --- amethyst/src/main/res/values-ar/strings.xml | 6 -- .../src/main/res/values-bn-rBD/strings.xml | 7 --- amethyst/src/main/res/values-cs/strings.xml | 18 ------ amethyst/src/main/res/values-de/strings.xml | 30 ---------- .../src/main/res/values-el-rGR/strings.xml | 12 ---- .../src/main/res/values-en-rGB/strings.xml | 17 ------ amethyst/src/main/res/values-eo/strings.xml | 3 - .../src/main/res/values-es-rES/strings.xml | 30 ---------- .../src/main/res/values-es-rMX/strings.xml | 29 ---------- .../src/main/res/values-es-rUS/strings.xml | 29 ---------- amethyst/src/main/res/values-fa/strings.xml | 3 - .../src/main/res/values-fi-rFI/strings.xml | 10 ---- amethyst/src/main/res/values-fr/strings.xml | 38 ------------- amethyst/src/main/res/values-hu/strings.xml | 15 ----- .../src/main/res/values-in-rID/strings.xml | 19 ------- .../src/main/res/values-it-rIT/strings.xml | 22 -------- amethyst/src/main/res/values-nl/strings.xml | 56 ------------------- .../src/main/res/values-pl-rPL/strings.xml | 17 ------ .../src/main/res/values-pt-rBR/strings.xml | 23 -------- amethyst/src/main/res/values-ru/strings.xml | 1 - .../src/main/res/values-sv-rSE/strings.xml | 29 ---------- .../src/main/res/values-sw-rKE/strings.xml | 11 ---- amethyst/src/main/res/values-th/strings.xml | 22 -------- amethyst/src/main/res/values-uk/strings.xml | 3 - .../src/main/res/values-zh-rCN/strings.xml | 7 --- .../src/main/res/values-zh-rTW/strings.xml | 12 ---- 26 files changed, 469 deletions(-) diff --git a/amethyst/src/main/res/values-ar/strings.xml b/amethyst/src/main/res/values-ar/strings.xml index 8060e9ecd..2140ccd9c 100644 --- a/amethyst/src/main/res/values-ar/strings.xml +++ b/amethyst/src/main/res/values-ar/strings.xml @@ -81,7 +81,6 @@ فشل تحميل الصورة عنوان الخادم (Relay Adress) المنشورات - Bytes الأخطاء المنشورات الرئيسية الرسائل الخاصة @@ -282,7 +281,6 @@ الحد الأدنى الحد الاقصى توافق الآراء - (0–100)% إغلاق بعد أيام تعذر التصويت @@ -370,14 +368,11 @@ الحد الأدنى لل PoW المصادقة الدفع - Cashu Token تسخ الtoken نسخ الtoken من المحفظة تسجيل الخروج سوف يؤدي الى جميع المعلومات المحلية الخاصة بك. تأكد من وجود نسخة احتياطية لمفاتحك السرية لتجنب فقدان حسابك. هل تريد الاستمرار؟ العلامات المُتابعة - Relays - Live مجتمع االدردشات المنشورات الموافق عليها @@ -469,7 +464,6 @@ مثل [Nfty](https://ntfy.sh/). بعد تثبيتك التطبيق قم باختياره من الإعدادات العنوان - iPhone 13 الشرط الفئة الموقع الجغرافيّ diff --git a/amethyst/src/main/res/values-bn-rBD/strings.xml b/amethyst/src/main/res/values-bn-rBD/strings.xml index e0398a9f7..50caf7aa5 100644 --- a/amethyst/src/main/res/values-bn-rBD/strings.xml +++ b/amethyst/src/main/res/values-bn-rBD/strings.xml @@ -56,7 +56,6 @@ "চ্যানেলের ভেতর " প্রোফাইলের ব্যানার সফলভাবে মূল্য পরিশোধিত হয়েছে - Error parsing error message " অনুসরণ" " অনুসারী" প্রোফাইল @@ -187,9 +186,6 @@ নস্টার ঠিকানা কখনো না এখন - h - m - d নগ্নতা অশ্লীলতা / বিদ্বেষপূর্ণ বক্তব্য বিদ্বেষপূর্ণ বক্তব্য হিসেবে অভিযোগ জানান @@ -461,7 +457,6 @@ নিয়ম Amber দিয়ে লগইন করুন আপনার স্ট্যাটাস আপডেট করুন - Error parsing error message জ্যাপের পরিমাণ দ্বারা ভোটসংখ্যা গোণা হয়। আপনি স্প্যামার এড়াতে একটি সর্বনিম্ন পরিমাণ এবং একটি বড়ো জ্যাপার দ্বারা পোল দখল এড়াতে সর্বোচ্চ পরিমাণ স্যাট নির্ধারণ করতে পারেন। প্রতিটি ভোটের মূল্য একই পরিমাণে রয়েছে তা নিশ্চিত করতে উভয় ক্ষেত্রেই একই পরিমাণ ব্যবহার করুন। যেকোনো পরিমাণ গ্রহণ করতে এটি খালি ছেড়ে দিন। জ্যাপ পাঠানো যায় নি ব্যবহারকারীকে বার্তা দিন @@ -490,10 +485,8 @@ ওয়ালেট %1$s স্বাক্ষরের অ্যাপ খোলা যাচ্ছে না স্বাক্ষরের অনুরোধ প্রত্যাখ্যান করা হয়েছে - iPhone 13 শর্ত ক্যাটাগরি - 1000 নতুন ভাল ন্যায্য diff --git a/amethyst/src/main/res/values-cs/strings.xml b/amethyst/src/main/res/values-cs/strings.xml index ffc1055b6..c760b9db1 100644 --- a/amethyst/src/main/res/values-cs/strings.xml +++ b/amethyst/src/main/res/values-cs/strings.xml @@ -14,7 +14,6 @@ Nepodařilo se dešifrovat zprávu Obrázek skupiny Explicitní obsah - Spam Počet spamových událostí z tohoto relé Zneužívání identity Nezákonné jednání @@ -103,7 +102,6 @@ Přidat přeposílání Zobrazované jméno Moje zobrazované jméno - Ostrich McAwesome Vítejte Ostrich! Uživatelské jméno Moje uživatelské jméno @@ -199,9 +197,6 @@ Nostr Adresa nikdy nyní - h - m - d Nahota Neslušnost / Nenávistná řeč Nahlásit nenávistnou řeč @@ -302,7 +297,6 @@ Minimální zaps Maximální zaps Konsensus - (0–100)% Uzavřít po dnech Nebylo možné hlasovat @@ -365,7 +359,6 @@ Upozorní vás, když dorazí soukromá zpráva Přijaté zapsy Upozorní vás, když vás někdo zapsne - %1$s sats Od %1$s pro %1$s Upozornit: @@ -417,7 +410,6 @@ Minimální PoW Ověření Platba - Cashu Token Vyměnit Poslat do Zap peněženky Otevřít v Cashu Wallet @@ -425,7 +417,6 @@ Není nastavena žádná Lightning adresa Token zkopírován do schránky ŽIVĚ - OFFLINE UKONČENO PLÁNOVÁNO Živé vysílání je offline @@ -512,7 +503,6 @@ Hlasy jsou váženy podle hodnoty zapu. Můžete nastavit minimální částku, abyste se vyhnuli spammerům, a maximální částku, abyste zabránili velkým zapperům, kteří by mohli ovládnout hlasování. Použijte stejnou částku v obou polích, aby byla hodnota každého hlasu stejná. Nechte prázdné pro přijetí libovolné částky. Nelze odeslat zap Poslat zprávu uživateli - OK Nepodařilo se dosáhnout %1$s: %2$s Nepodařilo se sestavit adresu URL NIP-11 pro %1$s: %2$s Nepodařilo se dosáhnout %1$s: %2$s @@ -534,7 +524,6 @@ Chybí nastavení blesku Uživatel %1$s nemá nastavenou bleskovou adresu pro přijímání satoshi Procenta - 25 Rozdělování Zapů s Přeposílání Zapů na Bleskové peněženky nenalezený @@ -601,11 +590,9 @@ Ahoj, je to stále k dispozici? Prodat předmět Název - iPhone 13 Stav Kategorie Cena (v Sats) - 1000 Místo Město, stát, země Nový @@ -624,7 +611,6 @@ Knihy Domácí zvířata Sportovní - Fitness Umění Vyrobí Domovský @@ -658,7 +644,6 @@ Odpověď Zvýšit nebo citovat Olajkovat - Zap Obrázek profilu %1$s Relé %1$s Rozbalit seznam relací @@ -673,7 +658,6 @@ Zrušit Zap-zběrku Místo Odstranit umístění - Zap splits Zrušit rozdělení Zap Přidat upozornění na obsah Odstranit upozornění na obsah @@ -718,11 +702,9 @@ Maximální limit Omezené zápisy Rozštěpováno od - FORK Git repositář: %1$s Internet: Klon: - OTS: %1$s Důkaz časového razítka Existuje důkaz, že tento příspěvek byl podepsán někdy před %1$s. Důkaz byl označen v Bitcoin blockchainu v tomto datu a čase. Upravit příspěvek diff --git a/amethyst/src/main/res/values-de/strings.xml b/amethyst/src/main/res/values-de/strings.xml index 7a2882293..89ab15132 100644 --- a/amethyst/src/main/res/values-de/strings.xml +++ b/amethyst/src/main/res/values-de/strings.xml @@ -14,7 +14,6 @@ Nachricht konnte nicht entschlüsselt werden Gruppenbild Anstößiger Inhalt - Spam Anzahl der Spam-Ereignisse von diesem Relais Vortäuschung Illegales Verhalten @@ -45,15 +44,11 @@ Sie verwenden einen öffentlichen Schlüssel und öffentliche Schlüssel sind schreibgeschützt. Mit einem privaten Schlüssel anmelden, um nicht mehr zu folgen Sie verwenden einen öffentlichen Schlüssel, und öffentliche Schlüssel sind nur lesbar. Melden Sie sich mit einem privaten Schlüssel an, um ein Wort oder einen Satz auszublenden Sie verwenden einen öffentlichen Schlüssel und öffentliche Schlüssel sind schreibgeschützt. Mit einem privaten Schlüssel anmelden, um ein Wort oder einen Satz anzeigen zu können - Zaps Aufrufe - Boost - boosted bearbeitet Bearbeitung #%1$s Original Zitat - Fork Eine Bearbeitung vorschlagen Neuer Betrag in Sats Hinzufügen @@ -92,7 +87,6 @@ Fehler beim Hochladen des Bildes Relay-Adresse Beiträge - Bytes Fehler Anzahl der Verbindungsfehler in dieser Sitzung Startseite @@ -103,7 +97,6 @@ Relay hinzufügen Anzeigename Mein Anzeigename - Ostrich McAwesome Willkommen Ostrich! Benutzername Mein Benutzername @@ -204,7 +197,6 @@ anz der Bedingungen ist erforderlich nie jetzt s - m t Nacktheit Beleidigungen / Hassrede @@ -308,7 +300,6 @@ anz der Bedingungen ist erforderlich Mindest-Zap-Betrag Maximaler Zap-Betrag Konsens - (0–100)% Schließen nach Tagen Konnte nicht abstimmen @@ -400,7 +391,6 @@ anz der Bedingungen ist erforderlich Die Menge in Bytes, die von diesem Relais empfangen wurde, einschließlich Filter und Ereignisse Ein Fehler ist beim Abrufen von Relay-Informationen von %1$s aufgetreten Inhaber - Version Programme Kontakt Unterstützte NIPs @@ -409,7 +399,6 @@ anz der Bedingungen ist erforderlich Einschränkungen Länder Sprachen - Tags Veröffentlichungsrichtlinie Fehler und Hinweise von diesem Relais Nachrichtenlänge @@ -429,8 +418,6 @@ anz der Bedingungen ist erforderlich Token kopieren Keine Lightning-Adresse festgelegt Token in die Zwischenablage kopiert - LIVE - OFFLINE BEENDET GEPLANT Livestream ist offline @@ -440,9 +427,7 @@ anz der Bedingungen ist erforderlich Relais Notizen Entdeckung Marktplatz - Live Gemeinschaft - Chats Genehmigte Beiträge Diese Gruppe hat keine Beschreibung oder Regeln. Sprechen Sie mit dem Eigentümer, um eine hinzuzufügen. Diese Community hat keine Beschreibung. Sprechen Sie mit dem Eigentümer, um eine hinzuzufügen. @@ -455,7 +440,6 @@ anz der Bedingungen ist erforderlich Fertig Vereinfacht Leistung - System Hell Dunkel Anwendungseinstellungen @@ -517,7 +501,6 @@ anz der Bedingungen ist erforderlich Die Abstimmungen werden nach der Höhe des Zaps gewichtet. Sie können einen Mindestbetrag festlegen, um Spam zu verhindern, und einen Höchstbetrag, um zu verhindern, dass große Zapper die Abstimmung dominieren. Verwenden Sie denselben Betrag in beiden Feldern, um sicherzustellen, dass jeder Stimme der gleiche Wert zukommt. Lassen Sie es leer, um jeden Betrag zu akzeptieren. Zap konnte nicht gesendet werden Mit dem Benutzer kommunizieren - OK Konnte %1$s nicht erreichen: %2$s Fehler beim Zusammenstellen der NIP-11-URL für %1$s: %2$s Konnte %1$s nicht erreichen: %2$s @@ -529,8 +512,6 @@ anz der Bedingungen ist erforderlich Aktiv für: Startseite Nachrichten - Chats - Global Suche Zaps aufteilen und weiterleiten Unterstützende Clients werden Zaps an die hier hinzugefügten Benutzer aufteilen und weiterleiten, anstatt an Sie @@ -539,7 +520,6 @@ anz der Bedingungen ist erforderlich Fehlende Lightning-Konfiguration Benutzer %1$s hat keine Lightning-Adresse eingerichtet, um Sats zu empfangen Prozent - 25 Zaps aufteilen mit Zaps weiterleiten an Lightning-Wallets nicht gefunden @@ -606,11 +586,9 @@ anz der Bedingungen ist erforderlich Hallo, ist das noch verfügbar? Artikel verkaufen Titel - iPhone 13 Zustand Kategorie Preis (in Sats) - 1000 Ort Stadt, Staat, Land Neu @@ -629,7 +607,6 @@ anz der Bedingungen ist erforderlich Bücher Haustiere Sport - Fitness Kunst Handwerk Zuhause @@ -646,13 +623,11 @@ anz der Bedingungen ist erforderlich Lokale Datei konnte nicht zum Hochladen vorbereitet werden: %1$s Entwurf bearbeiten Einloggen mit QR-Code - Route Startseite Suche Entdecken Nachrichten Benachrichtigungen - Global Kurzfilme Sicherheitsfilter Neuer Beitrag @@ -663,7 +638,6 @@ anz der Bedingungen ist erforderlich Antworten Boosten oder Zitieren Gefällt mir - Zap Profilbild von %1$s %1$s weiterleiten Rela-Liste erweitern @@ -718,16 +692,12 @@ anz der Bedingungen ist erforderlich Jetzt spenden wurde Ihnen präsentiert von: Diese Version wurde Ihnen präsentiert von: - Version %1$s Vielen Dank! Maximallimit Eingeschränkte Schriften Geforkt von - FORK - Git Repository: %1$s Internet: Klonen: - OTS: %1$s Zeitstempel Beweis Es gibt einen Beweis, dass dieser Beitrag irgendwann vor %1$s signiert wurde. Der Beweis wurde zu diesem Datum und Uhrzeit in der Bitcoin-Blockchain gestempelt. Beitrag bearbeiten diff --git a/amethyst/src/main/res/values-el-rGR/strings.xml b/amethyst/src/main/res/values-el-rGR/strings.xml index 7da6e93a1..818d27ed9 100644 --- a/amethyst/src/main/res/values-el-rGR/strings.xml +++ b/amethyst/src/main/res/values-el-rGR/strings.xml @@ -38,7 +38,6 @@ Συνδεθείτε με το \"Μυστικό Κλειδί\" σας για να σταματήσετε να ακολουθείτε κάποιον Συνδεθείτε με το \"Μυστικό Κλειδί\" σας ώστε να μπορείτε να αποκλείετε ανεπιθύμητες λέξεις ή φράσεις Συνδεθείτε με το \"Μυστικό Κλειδί\" σας ώστε να μπορείτε να αναζητάτε συγκεκριμένες λέξεις ή φράσεις - Zaps Προβολή μετρήσεων Προώθηση προωθημένο @@ -80,7 +79,6 @@ Αποτυχία μεταφόρτωσης εικόνας Διεύθυνση Διαμοιραστή Δημοσιεύσεις - Bytes Σφάλματα Ροή Αρχικής Σελίδας Ροή Προσωπικών Μηνυμάτων @@ -173,9 +171,6 @@ Διεύθυνση Nostr ποτέ τώρα - h - m - d Γυμνό Ασέβεια / Ρητορική μίσους Αναφορά Ρητορικής μίσους @@ -266,7 +261,6 @@ Ελάχιστο Zap Μέγιστο Zap Συναίνεση - (0–100)% Λήξη μετά από ημέρες Αδυναμία ψηφοφορίας @@ -297,7 +291,6 @@ Μόνο ο αποστολέας και ο παραλήπτης μπορούν να δουν ο ένας τον άλλο και να διαβάσουν το μήνυμα Ανώνυμα Ο παραλήπτης και το κοινό δε γνωρίζουν ποιός έστειλε την πληρωμή - Non-Zap Δεν αφήνει ίχνος στο Nostr, παρά μόνο στο Lightning Εξυπηρετητής Αρχείων LnAddress (διεύθυνση Lightning) ή @Χρήστης @@ -328,7 +321,6 @@ Σας ειδοποιεί όταν φτάνει ένα ιδιωτικό μήνυμα Ληφθέντα Zaps Σας ειδοποιεί όταν κάποιος σας zapάρει - %1$s sats Από %1$s για %1$s Ειδοποίηση: @@ -348,7 +340,6 @@ Προειδοποίηση όταν δημοσιεύσεις έχουν αναφορές από αυτούς που ακολουθείτε Νέο εικονίδιο Αντίδρασης Δεν έχουν επιλεγεί εικονίδια αντίδρασης. Πατήστε παρατεταμένα το κουμπί της καρδιάς για αλλαγή - Zapraiser Θέτει τον στόχο του ποσού σε sats (υποδιαίρεση του Bitcoin, 1 Bitcoin = 100.000.000 sats) που θέλετε να συγκεντρώσετε για αυτή τη δημοσίευση. Οι Nostr clients που υποστηρίζουν τη λειτουργία zapraiser ίσως δείχνουν μια μπάρα προόδου του στόχου σας ώστε να ενισχύσουν πιθανές δωρεές Το ποσό του στόχου σας σε sats Zapraiser στο %1$s. %2$s sats ως την επίτευξη του στόχου @@ -377,7 +368,6 @@ Ελάχιστη Απόδειξη Έργου (PoW - Proof of Work) Πιστοποίηση Πληρωμή - Cashu Token Εξαργύρωση Cashu Δεν έχει οριστεί διεύθυνση Lightning Το token αντιγράφηκε στο πρόχειρο @@ -459,7 +449,6 @@ Η επιλογή με τα περισσότερα zaps (δηλαδή τα περισσότερα sats) είναι η επικρατέστερη. Μπορείτε να ορίσετε ένα ελάχιστο ποσό zap για να αποφύγετε την ψήφο spammers αλλά και ένα μέγιστο ποσό ώστε να αποφύγετε μεγάλους zappers (χρήστες που στέλνουν zaps) που επιθυμούν να χειραγωγήσουν την ψηφοφορία. Χρησιμοποιήστε το ίδιο ποσό και στα δύο πεδία για να βεβαιωθείτε ότι κάθε ψήφος αποτιμάται το ίδιο. Ή αφήστε τα πεδία κενά για να αποδεχτείτε οποιοδήποτε ποσό. Αδυναμία αποστολής zap Μήνυμα στον Χρήστη - OK Αποτυχία εύρεσης %1$s: %2$s Αποτυχία εύρεσης %1$s: %2$s Αποτυχία ανάλυσης αποτελέσματος από %1$s: %2$s @@ -477,7 +466,6 @@ Λείπει η ρύθμιση lightning (LN) Ο Χρήστης %1$s δεν έχει ορίσει διεύθυνση LN (lightning) για να λαμβάνει sats Ποσοστό - 25 Διαχωρισμός zaps με Προώθηση zaps σε Δε βρέθηκαν πορτοφόλια Lightning diff --git a/amethyst/src/main/res/values-en-rGB/strings.xml b/amethyst/src/main/res/values-en-rGB/strings.xml index c6720ddeb..ca94254a9 100644 --- a/amethyst/src/main/res/values-en-rGB/strings.xml +++ b/amethyst/src/main/res/values-en-rGB/strings.xml @@ -1,21 +1,4 @@ - Point to the QR Code - Show QR Profile Image - Your Profile Picture - Scan QR - Show Anyway - This post was hidden because it mentions your hidden users or words - Post was muted or reported by - Event is loading or can\'t be found in your relay list - Channel Image - Referenced event not found - Could not decrypt the message - Group Picture - Explicit Content - Spam - Cancel - Posts - diff --git a/amethyst/src/main/res/values-eo/strings.xml b/amethyst/src/main/res/values-eo/strings.xml index d305e342c..46053234e 100644 --- a/amethyst/src/main/res/values-eo/strings.xml +++ b/amethyst/src/main/res/values-eo/strings.xml @@ -170,8 +170,6 @@ Adreso de Nostr neniam nun - h - m t Nudeco Blasfemo / Malama Parolado @@ -367,7 +365,6 @@ Maksimumaj etikedoj de evento Longo de enhavo Minimuma PoW - Auth Pago Cashu Signo Elpagi diff --git a/amethyst/src/main/res/values-es-rES/strings.xml b/amethyst/src/main/res/values-es-rES/strings.xml index e5b2b3327..cda4a8344 100644 --- a/amethyst/src/main/res/values-es-rES/strings.xml +++ b/amethyst/src/main/res/values-es-rES/strings.xml @@ -14,7 +14,6 @@ No se pudo desencriptar el mensaje Imagen de grupo Contenido explícito - Spam El número de eventos de spam procedentes de este relé Suplantación de identidad Comportamiento ilegal @@ -45,13 +44,11 @@ Estás usando una clave pública, que es solo de lectura. Inicia sesión con una clave privada para poder dejar de seguir a otros usuarios. Estás usando una clave pública, que es solo de lectura. Inicia sesión con una clave privada para poder ocultar una palabra o frase. Estás usando una clave pública, que es solo de lectura. Inicia sesión con una clave privada para poder mostrar una palabra o frase. - Zaps Total de visualizaciones Impulsar Impulsada editada edición #%1$s - original Citar Bifurcar Proponer una edición @@ -92,7 +89,6 @@ No se pudo cargar la imagen Dirección del relé Publicaciones - Bytes Errores El número de errores de conexión en esta sesión Tus noticias @@ -199,9 +195,6 @@ Dirección de Nostr nunca ahora - h - m - d Desnudos Blasfemias / Discurso de odio Denuncia discurso de odio @@ -227,7 +220,6 @@ Autenticación fallida El sistema biométrico no pudo autenticar al propietario de este teléfono El sistema biométrico no pudo autenticar al propietario de este teléfono. Error: %1$s - Error "Credo por %1$s" "Imagen del Badge para %1$s" Has recibido un nuevo Badge @@ -304,7 +296,6 @@ Zap mínimo Zap máximo Consenso - (0–100)% Cerrar después de días No se puede votar @@ -335,7 +326,6 @@ El remitente y el destinatario pueden verse entre sí y leer el mensaje Anónimo El receptor y el público no saben quién envió el pago - Non-Zap No hay rastro en Nostr, solo en Lightning Servidor de archivos Dirección o @usuario de Lightning @@ -346,10 +336,8 @@ ¿Desconectarse de tu Orbot/Tor? Los datos se transferirán de inmediato en la red normal - No Lista de seguidos Todos los seguidos - Global Lista de silenciados ## Conéctate a través de Tor con Orbot \n\n1. Instala [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android). @@ -367,7 +355,6 @@ Te notifica cuando llega un mensaje privado Zaps recibidos Te notifica cuando alguien te zapea - %1$s sats De %1$s por %1$s Notificar: @@ -387,7 +374,6 @@ Avisar cuando las publicaciones tengan reportes de tus seguidos Nuevo símbolo de reacción No hay tipos de reacción preseleccionados para este usuario. Deja presionado el botón de corazón para cambiarlos. - Zapraiser Añade una meta de sats para recaudar por esta publicación. Los clientes compatibles pueden mostrarla como una barra de progreso para incentivar las donaciones. Cantidad objetivo en sats Zapraiser en %1$s. %2$s sats hasta la meta @@ -398,7 +384,6 @@ Se ha producido un error al intentar obtener información sobre el relé de %1$s Propietario Versión - Software Contacto NIP compatibles Tasas de admisión @@ -417,7 +402,6 @@ Etiquetas de evento máximas Longitud del contenido PoW mínima - Auth Pago Token de Cashu Canjear @@ -439,7 +423,6 @@ Mercado En vivo Comunidad - Chats Publicaciones aprobadas Este grupo no tiene descripción ni reglas. Habla con el propietario para agregar una. Esta comunidad no tiene descripción. Habla con el propietario para agregar una. @@ -466,7 +449,6 @@ Modo de interfaz Elegir el estilo de publicación Cargar imagen - Spammers Silenciado. Hacer clic para reactivar el sonido. Sonido activado. Hacer clic para silenciar. Buscar grabaciones locales y remotas @@ -514,7 +496,6 @@ Los votos se calculan según la cantidad de zaps. Puedes establecer una cantidad mínima para evitar spammers y una máxima para que los zappers grandes no puedan dominar la encuesta. Usa la misma cantidad en ambos campos para asegurarte de que cada voto tenga el mismo valor. Déjalos vacíos para aceptar cualquier cantidad. No se pudo enviar el zap Mensaje para el usuario - OK No se pudo llegar a %1$s: %2$s Error al ensamblar la url NIP-11 para %1$s: %2$s No se pudo contactar %1$s: %2$s @@ -526,8 +507,6 @@ Activo para: Inicio Mensajes directos - Chats - Global Búsqueda Dividir y reenviar zaps Los clientes compatibles dividirán y reenviarán los zaps a los usuarios que se agreguen aquí en lugar de enviártelos a ti. @@ -536,7 +515,6 @@ Lightning no está configurado El usuario %1$s no tiene una dirección de Lightning configurada para recibir sats. Porcentaje - 25 Dividir zaps con Reenviar zaps a No se encontraron billeteras de Lightning @@ -589,7 +567,6 @@ Seleccionar una aplicación UnifiedPush Notificación push De aplicaciones UnifiedPush instaladas - Desactiva las notificaciones push Usa la app %1$s Configuración de notificaciones push @@ -603,11 +580,9 @@ Hola, ¿esto todavía está disponible? Vender un artículo Título - iPhone 13 Estado Categoría Precio (en sats) - 1000 Ubicación Ciudad, estado, país. Nuevo @@ -649,7 +624,6 @@ Descubrir Mensajes Notificaciones - Global Cortos Filtros de seguridad Nueva publicación @@ -660,7 +634,6 @@ Responder Impulsar o citar Me gusta - Zap Imagen de perfil de %1$s Relé %1$s Ampliar lista de relés @@ -671,7 +644,6 @@ Factura de Bitcoin Cancelar factura de Bitcoin Cancelar la venta de un artículo - Zapraiser Cancelar zapraiser Ubicación Eliminar ubicación @@ -722,9 +694,7 @@ Bifurcación de BIFURCACIÓN Repositorio Git: %1$s - Web: Clon: - OTS: %1$s Prueba de marca de tiempo Hay prueba de que esta publicación se firmó en algún momento antes de %1$s. La prueba se marcó en la cadena de bloques de Bitcoin en esa fecha y hora. Editar publicación diff --git a/amethyst/src/main/res/values-es-rMX/strings.xml b/amethyst/src/main/res/values-es-rMX/strings.xml index 31b18062b..b5c3aee43 100644 --- a/amethyst/src/main/res/values-es-rMX/strings.xml +++ b/amethyst/src/main/res/values-es-rMX/strings.xml @@ -14,7 +14,6 @@ No se pudo desencriptar el mensaje Foto de grupo Contenido explícito - Spam El número de eventos de spam procedentes de este relé Suplantación de identidad Comportamiento ilegal @@ -45,13 +44,11 @@ Estás usando una clave pública, que es solo de lectura. Inicia sesión con una clave privada para poder dejar de seguir a otros usuarios. Estás usando una clave pública, que es solo de lectura. Inicia sesión con una clave privada para poder ocultar una palabra o frase. Estás usando una clave pública, que es solo de lectura. Inicia sesión con una clave privada para poder mostrar una palabra o frase. - Zaps Total de visualizaciones Impulsar Impulsada editada edición #%1$s - original Cita Bifurcar Proponer una edición @@ -92,7 +89,6 @@ Error al subir la imagen Dirección del relé Publicaciones - Bytes Errores El número de errores de conexión en esta sesión Tus noticias @@ -199,9 +195,6 @@ Dirección de Nostr nunca ahora - h - m - d Desnudez Groserías o lenguaje que incita al odio Reportar lenguaje que incita al odio @@ -227,7 +220,6 @@ Error de autenticación El sistema biométrico no pudo autenticar al propietario de este teléfono El sistema biométrico no pudo autenticar al propietario de este teléfono. Error: %1$s - Error "Creado por %1$s" "Imagen de premio de insignia por %1$s" Recibiste un nuevo premio de insignia @@ -304,7 +296,6 @@ Zap mínimo Zap máximo Consenso - (0–100)% Cerrar después de días No se puede votar @@ -335,7 +326,6 @@ El remitente y el destinatario pueden verse entre sí y leer el mensaje Anónimo El receptor y el público no saben quién envió el pago - Non-Zap No hay rastro en Nostr, solo en Lightning Servidor de archivos Dirección o @usuario de Lightning @@ -346,10 +336,8 @@ ¿Desconectarse de tu Orbot/Tor? Los datos se transferirán de inmediato en la red normal - No Lista de seguidos Todos los seguidos - Global Lista de silenciados ## Conéctate a través de Tor con Orbot \n\n1. Instala [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android). @@ -367,7 +355,6 @@ Te notifica cuando llega un mensaje privado Zaps recibidos Te notifica cuando alguien te zapea - %1$s sats De %1$s por %1$s Notificar: @@ -387,7 +374,6 @@ Avisar cuando las publicaciones tengan reportes de tus seguidos Nuevo símbolo de reacción No hay tipos de reacción preseleccionados para este usuario. Deja presionado el botón de corazón para cambiarlos. - Zapraiser Agrega una meta de sats para recaudar por esta publicación. Los clientes compatibles pueden mostrarla como una barra de progreso para incentivar las donaciones. Cantidad objetivo en sats Zapraiser en %1$s. %2$s sats hasta la meta @@ -398,7 +384,6 @@ Se produjo un error al intentar obtener información sobre el relé de %1$s Propietario Versión - Software Contacto NIP compatibles Tarifas de admisión @@ -417,7 +402,6 @@ Etiquetas de evento máximas Longitud del contenido PoW mínima - Auth Pago Token de Cashu Canjear @@ -439,7 +423,6 @@ Mercado En vivo Comunidad - Chats Publicaciones aprobadas Este grupo no tiene descripción ni reglas. Habla con el propietario para agregar una. Esta comunidad no tiene descripción. Habla con el propietario para agregar una. @@ -466,7 +449,6 @@ Modo de interfaz Elegir el estilo de publicación Cargar imagen - Spammers Silenciado. Hacer clic para reactivar el sonido. Sonido activado. Hacer clic para silenciar. Buscar grabaciones locales y remotas @@ -514,7 +496,6 @@ Los votos se calculan según la cantidad de zaps. Puedes establecer una cantidad mínima para evitar spammers y una máxima para que los zappers grandes no puedan dominar la encuesta. Usa la misma cantidad en ambos campos para asegurarte de que cada voto tenga el mismo valor. Déjalos vacíos para aceptar cualquier cantidad. No se pudo enviar el zap Mensaje para el usuario - OK No se pudo llegar a %1$s: %2$s Error al ensamblar la url NIP-11 para %1$s: %2$s No se pudo contactar %1$s: %2$s @@ -526,8 +507,6 @@ Activo para: Inicio Mensajes directos - Chats - Global Búsqueda Dividir y reenviar zaps Los clientes compatibles dividirán y reenviarán los zaps a los usuarios que se agreguen aquí en lugar de a ti. @@ -536,7 +515,6 @@ Lightning no está configurado El usuario %1$s no tiene una dirección de Lightning configurada para recibir sats. Porcentaje - 25 Dividir zaps con Reenviar zaps a No se encontraron billeteras de Lightning @@ -603,11 +581,9 @@ Hola, ¿esto todavía está disponible? Vender un artículo Título - iPhone 13 Estado Categoría Precio (en sats) - 1000 Ubicación Ciudad, estado, país. Nuevo @@ -649,7 +625,6 @@ Descubrir Mensajes Notificaciones - Global Cortos Filtros de seguridad Nueva publicación @@ -660,7 +635,6 @@ Responder Impulsar o citar Me gusta - Zap Imagen de perfil de %1$s Relé %1$s Ampliar lista de relés @@ -671,7 +645,6 @@ Factura de Bitcoin Cancelar factura de Bitcoin Cancelar la venta de un artículo - Zapraiser Cancelar zapraiser Ubicación Eliminar ubicación @@ -722,9 +695,7 @@ Bifurcación de BIFURCACIÓN Repositorio Git: %1$s - Web: Clon: - OTS: %1$s Prueba de marca de tiempo Hay prueba de que esta publicación se firmó en algún momento antes de %1$s. La prueba se marcó en la cadena de bloques de Bitcoin en esa fecha y hora. Editar publicación diff --git a/amethyst/src/main/res/values-es-rUS/strings.xml b/amethyst/src/main/res/values-es-rUS/strings.xml index a52f9e805..decf118f1 100644 --- a/amethyst/src/main/res/values-es-rUS/strings.xml +++ b/amethyst/src/main/res/values-es-rUS/strings.xml @@ -14,7 +14,6 @@ No se pudo desencriptar el mensaje Imagen del grupo Contenido explícito - Spam El número de eventos de spam procedentes de este relé Suplantación de identidad Comportamiento ilegal @@ -45,13 +44,11 @@ Estás usando una clave pública, que es solo de lectura. Inicia sesión con una clave privada para poder dejar de seguir a otros usuarios. Estás usando una clave pública, que es solo de lectura. Inicia sesión con una clave privada para poder ocultar una palabra o frase. Estás usando una clave pública, que es solo de lectura. Inicia sesión con una clave privada para poder mostrar una palabra o frase. - Zaps Total vistas Impulsar Impulsada editada edición #%1$s - original Cita Bifurcar Proponer una edición @@ -92,7 +89,6 @@ Error al subir la imagen Dirección del relé Publicaciones - Bytes Errores El número de errores de conexión en esta sesión Tus noticias @@ -199,9 +195,6 @@ Dirección de Nostr nunca ahora - h - m - d Desnudez Groserías o lenguaje que incita al odio Reportar lenguaje que incita al odio @@ -227,7 +220,6 @@ Error de autenticación El sistema biométrico no pudo autenticar al propietario de este teléfono El sistema biométrico no pudo autenticar al propietario de este teléfono. Error: %1$s - Error "Creado por %1$s" "Imagen de premio de insignia por %1$s" Recibiste un nuevo premio de insignia @@ -304,7 +296,6 @@ Zap mínimo Zap máximo Consenso - (0–100)% Cerrar después de días No se puede votar @@ -335,7 +326,6 @@ El remitente y el receptor pueden verse entre sí y leer el mensaje Anónimo El receptor y el público no saben quién envió el pago - Non-Zap No hay rastro en Nostr, solo en Lightning Servidor de archivos Dirección o @usuario de Lightning @@ -346,10 +336,8 @@ ¿Desconectarse de tu Orbot/Tor? Los datos se transferirán de inmediato en la red normal - No Lista de seguidos Todos los seguidos - Global Lista de silenciados ## Conéctate a través de Tor con Orbot \n\n1. Instala [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android). @@ -367,7 +355,6 @@ Te notifica cuando llega un mensaje privado Zaps recibidos Te notifica cuando alguien te zapea - %1$s sats De %1$s por %1$s Notificar: @@ -387,7 +374,6 @@ Avisar cuando las publicaciones tengan reportes de tus seguidos Nuevo símbolo de reacción No hay tipos de reacción preseleccionados para este usuario. Deja presionado el botón de corazón para cambiarlos. - Zapraiser Agrega una meta de sats para recaudar por esta publicación. Los clientes compatibles pueden mostrarla como una barra de progreso para incentivar las donaciones. Cantidad objetivo en sats Zapraiser en %1$s. %2$s sats hasta la meta @@ -398,7 +384,6 @@ Se produjo un error al intentar obtener información sobre el relé de %1$s Propietario Versión - Software Contacto NIP compatibles Comisiones de admisión @@ -417,7 +402,6 @@ Etiquetas de evento máximas Longitud del contenido PoW mínima - Auth Pago Token de Cashu Canjear @@ -439,7 +423,6 @@ Mercado En vivo Comunidad - Chats Publicaciones aprobadas Este grupo no tiene descripción ni reglas. Habla con el propietario para agregar una. Esta comunidad no tiene descripción. Habla con el propietario para agregar una. @@ -466,7 +449,6 @@ Modo de interfaz Elegir el estilo de publicación Cargar imagen - Spammers Silenciado. Hacer clic para reactivar el sonido. Sonido activado. Hacer clic para silenciar. Buscar grabaciones locales y remotas @@ -514,7 +496,6 @@ Los votos se calculan según la cantidad de zaps. Puedes establecer una cantidad mínima para evitar spammers y una máxima para que los zappers grandes no puedan dominar la encuesta. Usa la misma cantidad en ambos campos para asegurarte de que cada voto tenga el mismo valor. Déjalos vacíos para aceptar cualquier cantidad. No se pudo enviar el zap Mensaje para el usuario - OK No se pudo llegar a %1$s: %2$s Error al ensamblar la url NIP-11 para %1$s: %2$s No se pudo contactar %1$s: %2$s @@ -526,8 +507,6 @@ Activo para: Inicio Mensajes directos - Chats - Global Búsqueda Dividir y reenviar zaps Los clientes compatibles dividirán y reenviarán los zaps a los usuarios que se agreguen aquí en lugar de a ti. @@ -536,7 +515,6 @@ Lightning no está configurado El usuario %1$s no tiene una dirección de Lightning configurada para recibir sats. Porcentaje - 25 Dividir zaps con Reenviar zaps a No se encontraron billeteras de Lightning @@ -603,11 +581,9 @@ Hola, ¿esto todavía está disponible? Vender un artículo Título - iPhone 13 Estado Categoría Precio (en sats) - 1000 Ubicación Ciudad, estado, país. Nuevo @@ -649,7 +625,6 @@ Descubrir Mensajes Notificaciones - Global Cortos Filtros de seguridad Nueva publicación @@ -660,7 +635,6 @@ Responder Impulsar o citar Me gusta - Zap Imagen de perfil de %1$s Relé %1$s Ampliar lista de relés @@ -671,7 +645,6 @@ Factura de Bitcoin Cancelar factura de Bitcoin Cancelar la venta de un artículo - Zapraiser Cancelar zapraiser Ubicación Eliminar ubicación @@ -722,9 +695,7 @@ Bifurcación de BIFURCACIÓN Repositorio Git: %1$s - Web: Clon: - OTS: %1$s Prueba de marca de tiempo Hay prueba de que esta publicación se firmó en algún momento antes de %1$s. La prueba se marcó en la cadena de bloques de Bitcoin en esa fecha y hora. Editar publicación diff --git a/amethyst/src/main/res/values-fa/strings.xml b/amethyst/src/main/res/values-fa/strings.xml index ad7098991..b03d53427 100644 --- a/amethyst/src/main/res/values-fa/strings.xml +++ b/amethyst/src/main/res/values-fa/strings.xml @@ -275,7 +275,6 @@ حداقل زپ حداکثر زپ توافق نظر - (0–100)% بسته شدن پس از روز نمی توان رای داد @@ -385,7 +384,6 @@ حداکثر تعداد برچسب رویداد طول محتوا حداقل PoW - Auth پرداخت توکن Cashu بازپرداخت @@ -557,7 +555,6 @@ شرایط دسته بندی قیمت (به ساتوشی) - 1000 موقعیت مکانی شهر، استان، کشور جدید diff --git a/amethyst/src/main/res/values-fi-rFI/strings.xml b/amethyst/src/main/res/values-fi-rFI/strings.xml index 75f5bc608..08fbdcbbd 100644 --- a/amethyst/src/main/res/values-fi-rFI/strings.xml +++ b/amethyst/src/main/res/values-fi-rFI/strings.xml @@ -174,7 +174,6 @@ ei koskaan nyt t - m pv Alastomuus Loukkaava kielenkäyttö / vihapuhe @@ -266,7 +265,6 @@ Vähimmäiszap Enimmäiszap Konsensus - (0–100)% Sulje äänestys päivän kuluttua Ei voi äänestää @@ -329,7 +327,6 @@ Ilmoittaa sinulle, kun yksityinen viesti saapuu Saapuneet Zapit Ilmoittaa sinulle, kun joku zappaa sinua - %1$s sats Lähettäjä: %1$s saaja: %1$s Ilmoitus: @@ -385,7 +382,6 @@ Kopioi tunnus Ei Lightning-osoitetta asetettuna Kopioitu tunnus leikepöydälle - LIVE POISSA PÄÄTTYNYT AJOITETTU @@ -395,7 +391,6 @@ Seuratut tagit Releet Markkinapaikka - Live Yhteisö Keskustelut Hyväksytyt viestit @@ -482,7 +477,6 @@ Lightning asetukset puuttuvat Käyttäjällä %1$s ei ole Lightning-osoitetta määritettynä vastaanottamaan satseja Prosenttiosuus - 25 Zappien jakaminen Ohjaa zappit kohteeseen Lightning-lompakkoja ei löytynyt @@ -503,12 +497,10 @@ Ei voitu perua Wallet Connectin asennus epäonnistui Virhe jäsennettäessä NIP-47 yhteyttä. Tarkista, onko tämä oikein lompakon tarjoajallasi: %1$s. Virhe: %2$s - Error parsing NIP-47 connection string. Check if this is correct with your Wallet provider: %1$s. Cashu epäonnistui lunastuksessa Paja (mint) antoi seuraavan virheilmoituksen: %1$s Cashu tunnukset on jo käytetty. Cashu vastaanotettu - %1$s sats were sent to your wallet. (Fees: %2$s sats) Yhteensopivaa Cashu-lompakkoa ei löytynyt järjestelmästä Laskua ei voi noutaa vastaanottimen palvelimilta Lompakkosi yhteyden tarjoaja palautti seuraavan virheen: %1$s @@ -542,11 +534,9 @@ Hei, onko tämä vielä saatavilla? Myy esine Otsikko - iPhone 13 Kunto Kategoria Hinta (satseissa) - 1000 Sijainti Kaupunki, osavaltio, maa Uusi diff --git a/amethyst/src/main/res/values-fr/strings.xml b/amethyst/src/main/res/values-fr/strings.xml index c63292a5e..ca8038690 100644 --- a/amethyst/src/main/res/values-fr/strings.xml +++ b/amethyst/src/main/res/values-fr/strings.xml @@ -14,7 +14,6 @@ Impossible de déchiffrer le message Image de groupe Contenu choquant - Spam Le nombre d\'événements spam provenant de ce relais Falsification d\'identité Comportement illégal @@ -45,15 +44,11 @@ Connectez-vous avec une clé privée pour ne plus Suivre Vous utilisez une clé publique et les clés publiques sont en lecture seule. Connectez-vous avec une clé privée pour pouvoir masquer un mot ou une phrase Vous utilisez une clé publique et les clés publiques sont en lecture seule. Connectez-vous avec une clé privée pour pouvoir afficher un mot ou une phrase - Zaps Nombre de vues - Boost boosté modifié modification #%1$s - original Citation - Fork Proposer une Modification Nouveau montant en Sats Ajouter @@ -82,7 +77,6 @@ Nom de canal Mon groupe spectaculaire Url de l\'image - Description "à propos" Quoi de neuf ? Envoyer @@ -128,8 +122,6 @@ Nouvelles demandes Utilisateurs bloqués Nouveaux sujets - Conversations - Notes Réponses "Suivis" "Signalements" @@ -190,7 +182,6 @@ Chat public messages reçus Retirer - Auto traduit de vers Montre en %1$s en premier @@ -199,9 +190,6 @@ Adresse Nostr jamais maintenant - h - m - d Nudité Blasphème / Discours haineux Signaler Discours haineux @@ -298,13 +286,8 @@ Champs requis: Bénéficiaires du Zap Description du sondage primaire… - Option %s Description de l\'option du Sondage Champs optionnels : - Zap minimum - Zap maximum - Consensus - (0–100)% Clôturer après jours Impossible de voter @@ -329,13 +312,11 @@ Un bateau bleu sur une plage de sable blanc au coucher du soleil Type de Zap Zap Type pour toutes les options - Public Tout le monde peut voir la transaction et le message Privé L\'expéditeur et le receveur peuvent se voir et lire le message Anonyme Le receveur et le public ne savent pas qui a envoyé le paiement - Non-Zap Aucune trace sur Nostr, seulement sur le Lightning Serveur fichier Adresse LN ou @Utilisateur @@ -367,7 +348,6 @@ Vous notifie lorsqu\'un message privé est reçu Zaps reçus Vous notifie lorsque quelqu\'un vous zap - %1$s sats De %1$s pour %1$s Notifier: @@ -397,9 +377,7 @@ Le nombre d\'octets qui ont été reçus depuis ce relais, y compris les filtres et les événements Une erreur s\'est produite en récupérant les informations du relay depuis %1$s Propriétaire - Version Logiciel - Contact NIPs supportés Frais d\'admission URL de payments @@ -451,7 +429,6 @@ Jamais Complet Simplifié - Performance Système Clair Sombre @@ -484,7 +461,6 @@ Nouvelle Fonctionnalité Pour activer ce mode, Amethyst doit envoyer un message NIP-17 (GiftWrapped, Sealed Direct et Group Messages). Le protocole NIP-17 est nouveau et la plupart des clients ne l\'ont pas encore mis en oeuvre. Assurez-vous que le destinataire utilise un client compatible. Activer - Public Nouveau Groupe Public ou Privé Privé À @@ -536,7 +512,6 @@ Configuration lightning manquante L\'utilisateur %1$s n\'a pas configuré d\'adresse Lightning pour recevoir des sats Pourcentage - 25 Diviser les zaps avec Transférer les zaps à Portefeuilles Lightning introuvables @@ -603,11 +578,9 @@ Bonjour, est-ce toujours disponible ? Vendre un Objet Titre - iPhone 13 État Catégorie Prix (en Sats) - 1000 Emplacement Ville, État, Pays Neuf @@ -625,9 +598,6 @@ Articles de collection Livres Animaux de compagnie - Sports - Fitness - Art Artisanat Accueil Bureau @@ -643,14 +613,10 @@ Impossible de préparer le fichier local à téléverser: %1$s Modifier le brouillon Se connecter avec un QR Code - Route Accueil Rechercher Découvrir - Messages - Notifications Général - Shorts Filtres de Sécurité Nouveau Message Nouveaux Shorts : images ou vidéos @@ -660,7 +626,6 @@ Répondre Booster ou Citer J\'aime - Zap Photo de Profil de %1$s Relais %1$s Développer la liste des relais @@ -715,16 +680,13 @@ Faire un don maintenant vous a été apporté par : Cette version vous a été apportée par : - Version %1$s Merci ! Limite maximale Écritures limitées Forké depuis - FORK Dépôt Git : %1$s Web : Clone : - OTS: %1$s Preuve d\'horodatage Il y a une preuve que ce message a été signé avant %1$s. La preuve a été estampillée dans la blockchain Bitcoin à cette date et à cette heure. Modifier le Message diff --git a/amethyst/src/main/res/values-hu/strings.xml b/amethyst/src/main/res/values-hu/strings.xml index 7672545ad..e31933b7e 100644 --- a/amethyst/src/main/res/values-hu/strings.xml +++ b/amethyst/src/main/res/values-hu/strings.xml @@ -14,7 +14,6 @@ Az üzenet dekódolása sikertelen Csoport Kép Szókimondó tartalom - Spam Ebből a csomópontból érkező spam események száma Megszemélyesítés Illegális viselkedés @@ -53,7 +52,6 @@ szerkesztés #%1$s eredeti Idézet - Fork Szerkesztési javaslat Új összeg sats-ban Hozzáad @@ -303,7 +301,6 @@ Minimum Zap Maximum Zap Konszenzus - (0–100)% Szavazás lezárása napok Nem lehet szavazni @@ -366,7 +363,6 @@ Értesítést küld, amikor privát üzeneted érkezik Zap-et kaptál Értesítést küld, amikor valaki neked Zap-et küldött - %1$s sats %1$s -tól %1$s -ért Értesítés: @@ -418,7 +414,6 @@ Minimális PoW Azonosítás Fizetés - Cashu Token Beváltás Küldje a Zap tárcába Nyissa meg a Cashu tárcában @@ -535,7 +530,6 @@ Hiányzó lightning beállítás A %1$s felhasználó a sat fogadáshoz nem rendelkezik LN cím beállítással Százalék - 25 Zap-ek megosztása Zap-ek továbbítása Lightning tárca nem található @@ -602,11 +596,9 @@ Szia, ez még aktuális? Elem eladása Cím - iPhone 13 Állapot Kategória Ár (satoshiban) - 1000 Helyszín Város, állam, ország Új @@ -625,7 +617,6 @@ Könyvek Háziállatok Sport - Fitness Művészet Iparművészet Otthon @@ -658,8 +649,6 @@ Zárja be a bejegyzésre adott összes reakciót Válasz Megosztás vagy Idézés - Like - Zap %1$s profilképe %1$s csomópont Csomópont lista kibontása @@ -716,14 +705,10 @@ Ezt a verziót hozta neked: %1$s verzió Köszönöm! - Max Limit Korlátozott írások Fork-olva innen - FORK Git-tár: %1$s - Web: Klónoz: - OTS: %1$s Időbélyeg igazolás Bizonyíték van arra, hogy ezt a bejegyzést valamikor %1$s előtt írták alá. A bizonyítékot ezen a napon és időpontban a Bitcoin blokkláncába bélyegezték. Bejegyzés szerkesztése diff --git a/amethyst/src/main/res/values-in-rID/strings.xml b/amethyst/src/main/res/values-in-rID/strings.xml index fef2027fa..c59bbc01d 100644 --- a/amethyst/src/main/res/values-in-rID/strings.xml +++ b/amethyst/src/main/res/values-in-rID/strings.xml @@ -12,7 +12,6 @@ Tidak dapat mendekripsi pesan Gambar Grup Konten Eksplisit - Spam Identitas palsu Perilaku Ilegal Tidak dikenal @@ -55,7 +54,6 @@ " Pengikut" Profil Filter keamanan - Logout Perlihatkan lebih banyak Invoice Lightning Bayar @@ -90,7 +88,6 @@ Tambah Relay Nama Tampilan Nama tampilan saya - Username Username saya Tentang saya URL avatar @@ -143,7 +140,6 @@ ketentuan penggunaan Persetujuan aturan penggunaan diperlukan Kunci diperlukan - Login Buat kunci baru Memuat umpan Memuat akun @@ -174,7 +170,6 @@ jangan pernah sekarang j - m h Ketelanjangan Kata-kata kotor / Ujaran kebencian @@ -256,7 +251,6 @@ Tampilkan kunci rahasia Kunci rahasia nsec / hex Jumlah Ikrar dalam Sat - Post Poll Kolom-kolom wajib: Penerima Zap Deskripsi poll utama… @@ -297,9 +291,7 @@ Pengirim dan Penerima bisa melihat satu sama lain dan membaca pesannya Anonim Publik dan Penerima tidak mengetahui siapa yang mengirim pembayaran - Non-Zap Tidak ada jejak di Nostr, hanya di Lightning - File Server LnAddress atau @Pengguna Relay-relay anda (NIP-95) File dihosting oleh relay Anda. NIP Baru: periksa apakah relay mendukung @@ -311,7 +303,6 @@ Tidak Daftar Ikut Semua Pengikut - Global ## Hubung melalui Tor dengan Orbit \n\n1. Install [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android) \n2. Mulai Orbot @@ -328,7 +319,6 @@ Memberi tahu Anda ketika pesan pribadi tiba Zap Diterima Memberi Tahu anda saat seseorang memberi zap - %1$s sats Dari %1$s untuk %1$s Memberitahu: @@ -375,14 +365,11 @@ Tag Event Maksimum Panjang konten PoW Minimum - Auth Pembayaran Token Cashu - Redeem Tidak ada Alamat Lightning yang ditetapkan Token disalin ke papan klip LANGSUNG - OFFLINE BERAKHIR DIJADWALKAN Livestream Offline @@ -390,7 +377,6 @@ Keluar akan menghapus semua informasi yang disimpan secara lokal. Pastikan kunci pribadi Anda telah simpan untuk menghindari kehilangan akun Anda. Apakah Anda ingin melanjutkan? Tags yang Diikuti - Relays Langsung Komunitas Obrolan @@ -424,7 +410,6 @@ Beri tahu kepada pemilik untuk menambahnya Verifikasi alamat Nostr gagal Memeriksa alamat Nostr Pilih/Batal semua - Default Pilih relay untuk melanjutkan Teruskan Zap ke: Klien yang didukung akan mengalihkan zap ke LNAddress atau Profil Pengguna dibawah ini @@ -460,16 +445,13 @@ Beri tahu kepada pemilik untuk menambahnya Suara ditimbang berdasarkan jumlah zap. Anda dapat menetapkan jumlah minimum untuk menghindari spammer dan jumlah maksimum untuk menghindari zappers besar mengambil alih jajak pendapat. Gunakan jumlah yang sama di kedua kolom untuk memastikan setiap suara bernilai sama. Biarkan kosong untuk menerima jumlah berapa pun. Tidak dapat mengirim zap Kirim pesan ke Pengguna - OK Gagal menghubungi %1$s: %2$s Gagal menghubungi %1$s: %2$s Gagal menguraikan hasil dari %1$s: %2$s %1$s gagal dengan kode %2$s Aktif selama: Beranda - DMs Obrolan - Global Cari Pisah dan alihkan Zap Klien yang didukung akan memisah dan mengalihkan zap kepada user yang ditambahkan disini @@ -478,7 +460,6 @@ Beri tahu kepada pemilik untuk menambahnya Lightning tidak tersedia %1$s belum mengatur alamat lightning untuk menerima sat Persentase - 25 Memisahkan Zap dengan Mengalihkan Zap ke Dompet Lightning tidak ditemukan diff --git a/amethyst/src/main/res/values-it-rIT/strings.xml b/amethyst/src/main/res/values-it-rIT/strings.xml index d418dd645..7310c1023 100644 --- a/amethyst/src/main/res/values-it-rIT/strings.xml +++ b/amethyst/src/main/res/values-it-rIT/strings.xml @@ -12,7 +12,6 @@ Impossibile decriptare il messaggio Foto del gruppo Contenuto esplicito - Spam Impersonificazione Comportamento scorretto Sconosciuto @@ -71,16 +70,12 @@ Descrizione "Su di noi... " A cosa stai pensando? - Post Salva Crea Cancella Impossibile caricare l\'immagine Indirizzo Relay - Posts - Bytes Errori - Home Feed Lista Messaggi Privati Lista Chat Pubbliche Feed Globale @@ -88,7 +83,6 @@ Aggiungi un Relay Nome Visualizzato Il mio nome visualizzato - Username Il mio nome utente Su di me Immagine del profilo URL @@ -161,7 +155,6 @@ Chat Pubblica post ricevuti Cancella - Auto tradotto da a Mostra prima in %1$s @@ -170,9 +163,6 @@ Indirizzo Nostr mai adesso - h - m - d Nuditá Volgaritá / Linguaggio forte Segnala linguaggio forte @@ -245,9 +235,7 @@ Rimuovi dai segnalibri pubblici Servizio di Connessione Portafoglio Autorizza un Nostr Secret a pagare gli zaps senza lasciare l\'app. Mantieni il segreto al sicuro e usa un relè privato se possibile - Wallet Connect Pubkey Wallet Connect Relè - Wallet Connect Secret Mostra chiave segreta nsec / chiave privata esadecimale Importo in pegno in sats @@ -261,7 +249,6 @@ Zap minimo Zap massimo Consenso - (0–100)% Chiudi dopo giorni Quantità in zap @@ -289,9 +276,7 @@ Mittente e Destinatario possono vedersi e leggere il messaggio Anonimo Il destinatario e il pubblico non sanno chi ha inviato il pagamento - Non-Zap Nessuna traccia in Nostr, solo in Lightning - File Server Indirizzo LN o @User I tuoi relè (NIP-95) I file sono ospitati dai tuoi relè. Nuovo NIP: controlla se lo supportano @@ -300,7 +285,6 @@ Disconnettere dal tuo Orbot/Tor? I tuoi dati verranno immediatamente trasferiti nella rete regolare - No Segui Lista Tutti i seguiti Globale @@ -320,7 +304,6 @@ Notifica quando arriva un messaggio privato Zaps Ricevuti Notifica quando qualcuno ti invia uno zap - %1$s sats Da %1$s per %1$s Notificare: @@ -340,7 +323,6 @@ Avvisa quando i post hanno segnalazioni da parte di chi segui Nuovo Simbolo Di Reazione Nessun tipo di reazione selezionato. Premi a lungo per cambiare - Zapraiser Aggiunge una quantità di sats da raccogliere per questo post. I client che supportano questa funzione la mostreranno con una barra di avanzamento per incentivare le donazioni Ammontare dell\'obiettivo in sats Zapraiser a %1$s. %2$s sats all\'obiettivo @@ -349,7 +331,6 @@ Si è verificato un errore nel tentativo di ottenere le informazioni del relè da %1$s Proprietario Versione - Software Contatto NIPs Supportati Commissioni di Ammissione @@ -357,7 +338,6 @@ Limitazioni Paesi Lingue - Tags Politica di pubblicazione Lunghezza del messaggio Iscrizioni @@ -367,7 +347,6 @@ Tags massimi dell\'evento Lunghezza del contenuto PoW Minima - Auth Pagamento Token di Cashu Riscatta @@ -404,7 +383,6 @@ Riproduzione video Anteprima URL Carica immagine - Spammers Mutato. Clicca per riattivare l\'audio Audio acceso. Clicca per disattivarlo Cerca registrazioni locali e remote diff --git a/amethyst/src/main/res/values-nl/strings.xml b/amethyst/src/main/res/values-nl/strings.xml index 5cc12cf94..9f56a8b40 100644 --- a/amethyst/src/main/res/values-nl/strings.xml +++ b/amethyst/src/main/res/values-nl/strings.xml @@ -4,7 +4,6 @@ Toon QR Profielfoto Jouw profielfoto - Scan QR Laat toch zien Dit bericht is verborgen omdat het je verborgen gebruikers of woorden noemt Bericht gemarkeerd als ongepast door @@ -14,7 +13,6 @@ Note versleuteld met encryptie Groepafbeelding Expliciete inhoud - Spam Het nummer van spammende gebeurtenissen komende van deze relay Imitatie Illegaal gedrag @@ -45,15 +43,11 @@ Je gebruikt een publieke sleutel en publieke sleutels zijn alleen-lezen. Login met een geheime sleutel om te ontvolgen Je gebruikt een publieke sleutel en publieke sleutels zijn alleen-lezen. Login met een geheime sleutel om woorden en zinnen te verbergen Je gebruikt een publieke sleutel en publieke sleutels zijn alleen-lezen. Login met een geheime sleutel om woorden of zinnen te tonen - Zaps Aantal keer bekeken - Boost - boosted gewijzigd bewerk #%1$s origineel Citaat - Fork Stel een bewerking voor Nieuw bedrag in sats Toevoegen @@ -92,7 +86,6 @@ Uploaden afbeelding mislukt Relay adres Berichten - Bytes Fouten Het nummer van verbindingsfouten in deze sessie Startpagina @@ -109,8 +102,6 @@ Mijn gebruikersnaam Over mij Profielfoto URL - Banner URL - Website URL LN Adress LN URL (verouderd) Opslaan in galerij @@ -129,13 +120,11 @@ Geblokkeerde gebruikers Nieuwe thread Gesprekken - Notes Reacties "Volgend" "Rapporten" Meer opties "Relays" - Website Lightning Adress Kopieert het NSEC ID (uw wachtwoord) naar klembord voor back-up. Geheime sleutel kopiëren naar het klembord @@ -199,9 +188,6 @@ Nostr adres nooit nu - h - m - d Naaktheid Godslastering / haatdragende taal Haatdragende taal rapporteren @@ -238,7 +224,6 @@ Selecteer tekst "<Kan privébericht niet ontsleutelen>\n\nJe werd genoemd in een privégesprek tussen %1$s en %2$s." Nieuw account toevoegen - Accounts Account selecteren Nieuw account toevoegen Account activeren @@ -249,7 +234,6 @@ Deel browserlink Delen Auteur ID - Note ID Kopieer tekst Verwijderen Ontvolgen @@ -286,11 +270,8 @@ Toevoegen aan publieke bladwijzers Verwijderen uit privé bladwijzers Verwijderen uit publieke bladwijzers - Wallet Connect Service Machtigt een Nostr Secret om zaps te betalen zonder de app te verlaten. Houd het geheim veilig en gebruik indien mogelijk een privé relays. Wallet Connect publieke sleutel - Wallet Connect Relay - Wallet Connect Secret Toon secret sleutel nsec / hex geheime sleutel Bedrag in sats @@ -301,9 +282,6 @@ Optie %s Poll optie beschrijvingen Optionele velden: - Zap minimum - Zap maximum - Consensus (0-100)% Sluit na dagen @@ -335,7 +313,6 @@ Verzender en ontvanger kunnen elkaar zien en het bericht lezen Anoniem Ontvanger en het publiek weten niet wie de betaling verzond - Non-Zap Geen spoor binnen Nostr, alleen in Lightning File server LnAddress of @User @@ -367,7 +344,6 @@ Geeft een melding wanneer er een privébericht binnenkomt Zaps ontvangen Geeft een melding als iemand je zapt - %1$s sats Van %1$s voor %1$s Meld: @@ -387,7 +363,6 @@ Waarschuw wanneer berichten meldingen hebben van je volgers Nieuwe reactie symbool Geen reactietypes geselecteerd. Lang indrukken om te wijzigen - Zapraiser Voegt een streefaantal sats toe dat moet worden opgehaald voor deze post. Ondersteunende clients kunnen dit als een voortgangsbalk weergeven om donaties te stimuleren. Streefaantal in sats Zapraiser op %1$s. %2$s sats tot doel @@ -398,20 +373,16 @@ Er is een fout opgetreden bij het ophalen van de relay-informatie van %1$s Eigenaar Versie - Software - Contact Ondersteunde NIPs Toelatingskosten Betaallink Beperkingen Landen Talen - Tags Postbeleid Fouten en meldingen van deze relay Lengte van bericht Abonnementen - Filters Lengte abonnement-id Minimale voorvoegsel Maximale event tags @@ -426,20 +397,14 @@ Token kopiëren Geen Lightning-adres ingesteld Token gekopieerd naar klembord - LIVE - OFFLINE GEËINDIGD INGEPLAND Livestream is offline Livestream is geëindigd Uitloggen verwijdert al je lokale informatie. Zorg ervoor dat je een back-up hebt van je geheime sleutels om te voorkomen dat je je account kwijtraakt. Wilt u doorgaan? Gevolgde tags - Relays Note ontdekking Marktplaats - Live - Community - Chats Goedgekeurde berichten Deze groep heeft geen beschrijving of regels. Praat met de eigenaar om er een toe te voegen Deze community heeft geen beschrijving. Praat met de eigenaar om er een toe te voegen @@ -466,7 +431,6 @@ UI modus Kies de stijl van het bericht Afbeelding laden - Spammers Geen geluid. Klik om voor geluid Geluid. Klik voor geen geluid Lokale en externe records doorzoeken @@ -526,7 +490,6 @@ Actief voor: Startpagina DM\'s - Chats Globaal Zoeken Deel en stuur Zaps door @@ -535,13 +498,10 @@ Gebruikersnaam of weergavenaam Ontbrekende Lightning configuratie Gebruiker %1$s heeft geen Lightning Adress ingesteld om sats te ontvangen - Percentage - 25 Deel zaps met Stuur zaps door naar Lightning wallets niet gevonden Betaald - Wallet %1$s Fout bij openen ondertekenapp De teken-app kan niet worden gevonden. Controleer of de app niet is verwijderd Ondertekenverzoek afgewezen @@ -597,17 +557,14 @@ Na installatie selecteer de app die je wilt gebruiken in de instellingen. Bericht van %1$s - Thread Stuur de verkoper een bericht Hallo %1$s, is dit nog steeds beschikbaar? Hallo daar, is dit nog steeds beschikbaar? Verkoop een artikel Titel - iPhone 13 Staat Categorie Prijs (in sats) - 1000 Locatie Stad, provincie, land Nieuw @@ -626,7 +583,6 @@ Boeken Huisdieren Sport - Fitness Kunst Ambachten Startpagina @@ -643,14 +599,12 @@ Kon lokaal bestand niet voorbereiden voor upload: %1$s Concept bewerken Inloggen met QR-Code - Route Beginscherm Zoeken Ontdekken Berichten Notificaties Globaal - Shorts Beveiligingsfilters Nieuw bericht Nieuwe shorts: afbeeldingen of video\'s @@ -660,22 +614,17 @@ Antwoorden Boost of citaat Vind ik leuk - Zap Profielfoto van %1$s - Relay %1$s Lijst van relays uitvouwen Note opties Relay selectiemenu - Poll Poll uitschakelen Bitcoin invoice Annuleer Bitcoin invoice Verkoop van een item annuleren - Zapraiser Annuleer Zapraiser Locatie Locatie verwijderen - Zap splits Annuleer splitsing Zap Content waarschuwing toevoegen Content waarschuwing verwijderen @@ -683,7 +632,6 @@ Ongeldig adres Amethist ontving een URI om te openen, maar die uri was ongeldig: %1$s DM inbox relays - Relays: %1$s Gebruik normale relays Stel uw Privé Postvak relays in Deze instelling geeft iedereen informatie over de relays die gebruikt worden bij het verzenden van berichten. Zonder hen mis je mogelijk een bericht. @@ -720,11 +668,7 @@ Max. limiet Beperkte schrijfrechten Geforked van - FORK - Git Repository: %1$s - Web: Kopiëren: - OTS: %1$s Bewijs van tijdstempel Er is bewijs dat dit bericht enige tijd voor %1$sis getekend. Het bewijs is op dat tijdstip en op dat moment getypeerd in de Bitcoin-blockchain. Bericht wijzigen diff --git a/amethyst/src/main/res/values-pl-rPL/strings.xml b/amethyst/src/main/res/values-pl-rPL/strings.xml index 027123bdf..95481cddd 100644 --- a/amethyst/src/main/res/values-pl-rPL/strings.xml +++ b/amethyst/src/main/res/values-pl-rPL/strings.xml @@ -14,7 +14,6 @@ Nie można odszyfrować wiadomości Zdjęcie grupy Niedozwolona zawartość - Spam Liczba spamu z tego transmitera Podszywanie się Antyspołeczne zachowanie @@ -200,8 +199,6 @@ nigdy teraz godz. - m - d Nagość Wulgaryzmy / Mowa nienawiści Zgłoś nienawistną mowę @@ -304,7 +301,6 @@ Minimalny Zap Maksymalny Zap Konsensus - (0–100)% Zamknij po dni Nie można głosować @@ -387,7 +383,6 @@ Ostrzegaj, gdy posty zostały zgłoszone przez osoby które obserwujesz Nowy Symbol Odzewu Brak wstępnie wybranych typów reakcji dla tego użytkownika. Przytrzymaj przycisk serce, aby zmienić - Zapraiser Dodaje docelową liczbę satów do podniesienia dla tego wpisu. W zależności od aplikacji może być pokazywany to jako pasek postępu, aby zachęcić do darowizn Docelowa kwota w Satach Zapraiser przy: %1$s. %2$s satach do celu @@ -419,15 +414,12 @@ Minimalny poW Autoryzacja Płatność - Cashu Token Wykup Wyślij do Zap Wallet Otwórz w Portfelu Cashu Skopiuj token Nie ustawiono adresu Lightning Skopiowano token do schowka - LIVE - OFFLINE Zakończony ZAPLANOWANE Transmisja wyłączona @@ -515,7 +507,6 @@ Głosy są oceniane na podstawie ilości zapperów. Możesz ustawić minimalną kwotę, aby uniknąć spamerów i maksymalną kwotę, aby uniknąć przejęcia ankiety przez dużych zapperów. Użyj tej samej kwoty w obu polach, aby upewnić się, że każdy głos ma taką samą wartość. Pozostaw to pole puste, aby zaakceptować dowolną kwotę. Nie można wysłać zapa Wyślij wiadomość użytkownikowi - OK Nieudane połączenie z %1$s: %2$s Nie udało się skompilować adresu URL NIP-11 dla %1$s: %2$s Nieudane połączenie z %1$s: %2$s @@ -526,7 +517,6 @@ %1$s nie powiódł się z kodem %2$s Aktywny dla: Strona główna - DMs Czaty Wszystkie Szukaj @@ -537,7 +527,6 @@ Brakująca konfiguracja LN Użytkownik %1$s nie ma skonfigurowanego adresu LN, aby odbierać saty Procentowo - 25 Podziel zapsy z Przesyłanie zapasów do Nie znaleziono portfeli Lightning @@ -604,11 +593,9 @@ Cześć, czy to jest nadal dostępne? Sprzedaj przedmiot Tytuł - iPhone 13 Stan Kategoria Cena (w Satach) - 1000 Lokalizacja Miasto, Województwo, Kraj Nowość @@ -627,7 +614,6 @@ Książki Zwierzęta domowe Sporty - Fitness Sztuka Rzemiosło AGD @@ -661,7 +647,6 @@ Odpowiedz Zrepostuj lub Zacytuj Lubię - Zap Zmień odzew Zdjęcie profilowe %1$s Transmiter %1$s @@ -673,7 +658,6 @@ Faktura Bitcoin Anuluj fakturę Bitcoin Anuluj sprzedaż przedmiotu - Zapraiser Anuluj Zapraiser Lokalizacja Usuń lokalizację @@ -726,7 +710,6 @@ Repozytorium Git: %1$s Strona internetowa: Klonuj: - OTS: %1$s Potwierdzenie znacznika czasu Istnieje dowód na to, że ten post został podpisany przed %1$s. Dowód został opatrzony pieczęcią w łańcuchu bloków Bitcoin w tym dniu i czasie. Edytuj wpis diff --git a/amethyst/src/main/res/values-pt-rBR/strings.xml b/amethyst/src/main/res/values-pt-rBR/strings.xml index d14bf1616..87d5ee60d 100644 --- a/amethyst/src/main/res/values-pt-rBR/strings.xml +++ b/amethyst/src/main/res/values-pt-rBR/strings.xml @@ -14,7 +14,6 @@ Não foi possível descriptografar a mensagem Imagem do grupo Conteúdo explícito - Spam O número de eventos de spam vindo deste relé Representação Comportamento ilegal @@ -45,13 +44,11 @@ Faça login com uma chave privada para poder remover seguidores Você está usando uma chave pública e as chaves públicas são somente de leitura. Faça login com uma chave privada para poder ocultar uma palavra ou frase. Você está usando uma chave pública e as chaves públicas são somente de leitura. Faça login com uma chave privada para poder mostrar uma palavra ou frase. - Zaps Contagem de visualizações Impulsionar impulsionado editado edição #%1$s - original Citar Garfo Propor uma Edição @@ -92,7 +89,6 @@ Falha ao enviar imagem Endereço do Relay Postagens - Bytes Erros O número de erros de conexão nesta sessão Feed principal @@ -134,7 +130,6 @@ "Seguindo" "Denúncias" Mais opções - " Relays" Site Endereço Lightning Copiar a chave Nsec (sua senha) para backup @@ -199,9 +194,6 @@ Endereço Nostr nunca agora - h - m - d Nudez Palavrões / Discurso de ódio Denunciar discurso de ódio @@ -302,7 +294,6 @@ Zap mínimo Zap máximo Consenso - (0–100)% Fechar depois dias Impossibilitado de votar @@ -347,7 +338,6 @@ Não Lista de seguidores Seguindo - Global Lista Silenciada ## Conecte-se através do Tor com o Orbot \n\n1. Instale o [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android) @@ -365,7 +355,6 @@ Notifica você quando chega uma mensagem privada Zaps Recebidos Notifica quando alguém te manda um zap - %1$s sats De %1$s por %1$s Notificar: @@ -432,7 +421,6 @@ Transmissão ao vivo encerrada Sair exclui todas as suas informações locais. Certifique-se de fazer backup de suas chaves privadas para evitar a perda de sua conta. Você quer continuar? Tags Seguidas - Relays Descoberta de Notas Mercado Ao vivo @@ -464,7 +452,6 @@ Modo de interface Escolha o estilo da publicação Carregar imagem - Spammers Silenciado. Clique para ativar o som Som ligado. Clique para silenciar Pesquise registros locais e remotos @@ -512,7 +499,6 @@ Os votos são ponderados pelo valor do zap. Você pode definir um valor mínimo para evitar spammers e um valor máximo para evitar que grandes zappers assumam o controle da enquete. Use o mesmo valor em ambos os campos para garantir que cada voto tenha o mesmo valor. Deixe em branco para aceitar qualquer valor. Não foi possível enviar o Zap Mensagem ao usuário - OK Falha ao acessar %1$s: %2$s Falha ao montar NIP-11 url para %1$s: %2$s Falha ao acessar %1$s: %2$s @@ -525,7 +511,6 @@ Início Mensagens diretas Bate-papos - Global Pesquisa Dividir e encaminhar Zaps Os clientes que suportam dividirão e encaminharão zaps para os usuários adicionados aqui em vez dos seus @@ -534,7 +519,6 @@ Configuração Lightning ausente O usuário %1$s não possui um endereço lightning configurado para receber sats Percentual - 25 Dividindo zaps com Encaminhando zaps para Carteira Lightning não encontrada @@ -601,11 +585,9 @@ Olá, ainda está disponível? Vender um Item Título - iPhone 13 Condição Categoria Preço (em Sats) - 1000 Localização Cidade, Estado, País Novo @@ -624,7 +606,6 @@ Livros Animais de Estimação Esportes - Fitness Arte Artesanato Casa @@ -647,7 +628,6 @@ Descobrir Mensagens Notificações - Global Vídeos Curtos Filtros de Segurança Novo Post @@ -658,7 +638,6 @@ Responder Impulsionar ou Citar Gostar - Zap Foto de perfil de %1$s Repassar %1$s Expandir lista de repasse @@ -718,11 +697,9 @@ Limite máximo Gravações Restritas Forkado de - FORK Repositório Git: %1$s Site: Clonar: - OTS: %1$s Prova de Carimbo de data/hora Há prova de que esta postagem foi assinada antes de %1$s. A prova foi carimbada no blockchain do Bitcoin naquela data e hora. Editar postagem diff --git a/amethyst/src/main/res/values-ru/strings.xml b/amethyst/src/main/res/values-ru/strings.xml index bdc8e3ab0..a2fbf24df 100644 --- a/amethyst/src/main/res/values-ru/strings.xml +++ b/amethyst/src/main/res/values-ru/strings.xml @@ -264,7 +264,6 @@ Минимальный зап Максимальный зап Консенсус - (0–100)% Закрытие после дней Невозможно проголосовать diff --git a/amethyst/src/main/res/values-sv-rSE/strings.xml b/amethyst/src/main/res/values-sv-rSE/strings.xml index bd0dcf9c9..e44f42010 100644 --- a/amethyst/src/main/res/values-sv-rSE/strings.xml +++ b/amethyst/src/main/res/values-sv-rSE/strings.xml @@ -14,7 +14,6 @@ Kunde inte dekryptera meddelandet Grupp bild Explicit Innehåll - Spam Antal skräpposthändelser från detta relä Imitation Olagligt beteende @@ -45,13 +44,11 @@ Logga in med en privat nyckel för att kunna sluta följa Du använder en offentlig nyckel, och offentliga nycklar är endast läsbara. Logga in med en privat nyckel för att kunna dölja ett ord eller en mening Du använder en offentlig nyckel, och offentliga nycklar är endast läsbara. Logga in med en privat nyckel för att kunna visa ett ord eller en mening - Zaps Antal visningar Boosta boostad redigerat redigering #%1$s - original Citera Förgrening Föreslå en redigering @@ -92,7 +89,6 @@ Det gick inte att ladda upp bilden Relä Adress Inlägg - Bytes Fel Antal anslutningsfel under denna session Hem Flöde @@ -108,8 +104,6 @@ Användarnamn Mitt användarnamn Om mig - Avatar URL - Banner URL Websida URL LN Adress LN URL (Utdaterad) @@ -150,7 +144,6 @@ Sluta blockera Användare "npub, hex, användarnamn " Rensa - App Logo nsec / npub / hex privat nyckel lösenord för att öppna nyckeln Visa lösenord @@ -199,9 +192,6 @@ Nostr-adress aldrig nu - h - m - d Naket Svordomar / Hatiskt tal Anmäl hattal @@ -286,7 +276,6 @@ Ta bort från Publika Bokmärken Wallet Connect Tjänst Tillåter en Nostr Secret att betala zaps utan att lämna appen. Håll hemligheten säker och använd ett privat relä om möjligt - Wallet Connect Pubkey Wallet Connect relä Wallet Connect hemlighet Visa secret key @@ -302,7 +291,6 @@ Minsta Zap Maximal Zap Konsensus - (0–100)% Avsluta efter dagar Kunde inte rösta @@ -347,7 +335,6 @@ Nej Följ lista Alla följare - Global Tyst listan ## Anslut genom Tor med Orbot \n\n1. Installera [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android) @@ -356,7 +343,6 @@ \n4. Ändra vid behov porten i Orbot \n5. Konfigurera Socks-porten på den här skärmen \n6. Tryck på knappen Aktivera för att använda Orbot som proxy - Orbot Socks Port Ogiltigt portnummer Använd Orbot Koppla ifrån Tor/Orbot @@ -364,7 +350,6 @@ Meddelar dig när ett privat meddelande kommer Zaps Mottaget Meddela dig när någon zappar dig - %1$s sats Från %1$s till %1$s Meddela: @@ -394,7 +379,6 @@ Mängden data i byte som mottogs från detta relä, inklusive filter och händelser Ett fel inträffade vid försök att hämta information från Relay %1$s Ägare - Version Programvara Kontakt Stödda NIPs @@ -416,15 +400,12 @@ Minsta PoW Autentisering Betalning - Cashu Token Inlösen Skicka till Zap Plånbok Öppna i Cashu Plånbok Kopiera Token Ingen Lightning-adress angiven Kopierade token till urklipp - LIVE - OFFLINE SLUTADE PLANERAD Direktsändning är offline @@ -434,7 +415,6 @@ Reläer Upptäckt av anteckningar Marknadsplats - Live Gemenskap Chattar Godkända Inlägg @@ -449,7 +429,6 @@ Slutförd Förenklad Prestanda - System Ljus Mörk Applikationsinställningar @@ -533,7 +512,6 @@ Saknad lightning-konfiguration Användaren %1$s har inte ställt in en blixtfakturaadress för att ta emot satoshis Procent - 25 Delar zaps med Vidarebefordrar zaps till Blixtpengar hittades inte @@ -600,11 +578,9 @@ Hallå där, är detta fortfarande tillgängligt? Sälj en artikel Titel - iPhone 13 Skick Kategori Pris (i Sats) - 1000 Plats Stad, Region, Land Ny @@ -657,7 +633,6 @@ Svara Boosta eller citera Gilla - Zap %1$s Profilbild Relä %1$s Expandera relälistan @@ -712,16 +687,12 @@ Donera nu tillhandahölls av: Denna version tillhandahölls av: - Version %1$s Tack! Maximal gräns Begränsade skrivningar Forkad från - FORK - Git Repository: %1$s Webbplats: Klona: - OTS: %1$s Tidsstämpel Bevis Det finns bevis på att detta inlägg signerades någon gång före %1$s. Beviset stämplades i Bitcoin-blockchainen vid det datumet och den tiden. Redigera inlägg diff --git a/amethyst/src/main/res/values-sw-rKE/strings.xml b/amethyst/src/main/res/values-sw-rKE/strings.xml index 3a5f1af7c..079c33fdf 100644 --- a/amethyst/src/main/res/values-sw-rKE/strings.xml +++ b/amethyst/src/main/res/values-sw-rKE/strings.xml @@ -36,7 +36,6 @@ Ingia kwa kutumia ufunguo wa Faragha ili uweze kutuma Zaps Ingia kwa kutumia Ufunguo wa Faragha ili uweze Kufuata Ingia kwa kutumia Ufunguo wa Faragha ili uweze Kuacha Kufuata - Zaps Idadi ya maoni Kuongeza imeimarishwa @@ -114,9 +113,7 @@ Vidokezo Majibu "Anafuata" - "Reports" Chaguo Zaidi - " Relays" Tovuti Anwani ya Umeme Hunakili Kitambulisho cha Nsec (nywila yako) kwenye ubao wa kunakili kwa ajili ya nakala rudufu @@ -161,7 +158,6 @@ Mazungumzo ya Umma machapisho yamepokelewa Ondoa - Auto imetafsiriwa kutoka kwa Onyesha kwa %1$s kwanza @@ -170,9 +166,6 @@ Anwani ya Nostr kamwe sasa - h - m - d Uchi Lugha chafu / Maneno yenye chuki Ripoti Lugha yenye chuki @@ -261,7 +254,6 @@ Kima cha Chini cha Zaps Kima cha Juu cha Zaps Uamuzi - (0–100)% Funga baada ya siku Kiasi cha Zaps @@ -319,7 +311,6 @@ Inakuarifu wakati ujumbe binafsi unapowasili Zaps Zilizopokelewa Inakuarifu wakati mtu anapokuzap - %1$s sats Kutoka kwa %1$s kwa %1$s Taarifa: @@ -368,7 +359,6 @@ PoW ya Chini Uthibitishaji Malipo - Cashu Token Kukomboa Hakuna Anwani ya Lightning Imewekwa Kitufe kimekopwa kwenye ubao wa kunakili @@ -452,7 +442,6 @@ %1$s imeshindwa kwa kutumia msimbo %2$s Inatumika kwa: Nyumbani - DMs Soga Ulimwenguni Tafuta diff --git a/amethyst/src/main/res/values-th/strings.xml b/amethyst/src/main/res/values-th/strings.xml index 21acd622a..70085ba05 100644 --- a/amethyst/src/main/res/values-th/strings.xml +++ b/amethyst/src/main/res/values-th/strings.xml @@ -45,7 +45,6 @@ เข้าสู่ระบบด้วย private key เพื่อเลิกติดตาม เข้าสู่ระบบด้วย private key เพื่อเพิ่มการซ่อนข้อความ เข้าสู่ระบบด้วย private key เพื่อแก้ไขการซ่อนข้อความ - Zaps ยอดเข้าชม แชร์ แชร์ @@ -151,7 +150,6 @@ "npub, ชื่อผู้ใช้, ข้อความ" เคลียร์ โลโก้ - nsec.. or npub.. รหัสสำหรับเปิดใช้ nsec แสดงรหัสผ่าน ซ่อนรหัสผ่าน @@ -287,11 +285,8 @@ ลบออกจากบุ๊คมาร์คสาธรณะ บริการเชื่อมต่อ wallet อนุญาตให้ Nostr Secret จ่าย zaps โดยไม่ต้องออกจากแอป เพื่อรักษาความลับให้ปลอดภัยและใช้รีเลย์ส่วนตัวหากเป็นไปได้ - Wallet Connect Pubkey บริการเชื่อมต่อ wallet - Wallet Connect Secret แสดง secret key - nsec / hex private key จำนวนเงินที่นำเข้าในหน่วย sat สร้างโพลล์ ส่วนที่จำเป็น: @@ -303,7 +298,6 @@ Zap ขั้นต่ำ Zap สูงสุด ฉันทามติ - (0–100)% ปิดหลังจาก วัน ไม่สามารถโหวต @@ -366,7 +360,6 @@ แจ้งเตือนฉันเมื่อข้อความส่วนตัวมาถึง ได้รับ Zaps แจ้งเตือนเมื่อมีคน zaps - %1$s sats จาก %1$s ถึง %1$s การแจ้งเตือน: @@ -449,7 +442,6 @@ Wifi เท่านั้น ไม่ต้องแสดง เสร็จสมบูรณ์ - Simplified ระบบ(ค่าพื้นฐาน) สว่าง มืด @@ -461,7 +453,6 @@ การแสดงตัวอย่าง URL การไถฟีดแบบลื่นไหล ซ่อนแถบเมนูขณะเลื่อนฟีด - UI Mode เลือกรูปแบบการโพสต์ โหลดรูปภาพ แสปม @@ -530,7 +521,6 @@ ไม่พบการตั้งค่า Lightning ผู้ใช้ %1$s ไม่ได้ตั้งค่า lightning address เพื่อรับ sats เปอร์เซ็นต์ - 25 แบ่ง Zaps กับ ส่งต่อ Zaps ไปยัง ไม่พบกระเป๋า Lightning @@ -595,11 +585,9 @@ สวัสดี! สิ่งนี้ยังมีอยู่ไหม? ขายบางอย่าง ชื่อ - iPhone 13 สภาพ หมวดหมู่ ราคา (หน่วย Sats) - 1000 ตำแหน่ง เมือง, รัฐ, ประเทศ ใหม่ @@ -642,7 +630,6 @@ ข้อความ การแจ้งเตือน ทั่วโลก - Shorts ตัวกรองความปลอดภัย โพสต์ใหม่ สร้าง Shorts: รูปภาพ/วิดีโอ @@ -652,7 +639,6 @@ ตอบกลับ แชร์/โควท ไลค์ - Zap รูปโปร์ไฟล์ของ %1$s รีเลย์ %1$s แสดงรายการรีเลย์ @@ -660,14 +646,12 @@ ตัวเลือกรายการรีเลย์ โพลล์ ยกเลิกโพลล์ - Bitcoin Invoice ยกเลิก Bitcoin Invoice ยกเลิกการขายสิ่งนี้ ระดมทุน ยกเลิกการระดมทุน ตำแหน่ง ลบตำแหน่งออก - Zap splits ยกเลิก Zap split เพิ่มคําเตือนเนื้อหา ลบคําเตือนเนื้อหา @@ -709,14 +693,11 @@ เวอร์ชันนี้นำเสนอโดย: เวอร์ชัน %1$s ขอบคุณ! - Max Limit การเขียนที่ถูกจำกัด คัดลอกมาจาก คัดลอก - Git Repository: %1$s เว็บไซน์ สำเนา: - OTS: %1$s Timestamp ถูกยืนยัน มีหลักฐานว่าโพสต์นี้มีการลงนามก่อน %1$s หลักฐานถูกประทับตราใน Bitcoin blockchain ณ วันและเวลาดังกล่าว แก้ไขโพสต์ @@ -725,8 +706,6 @@ แก้ไขด่วน ยอมรับการแนะนำนี้ ดาวน์โหลด - Lyrics on - Lyrics off ปิดผนึกข้อความแล้ว คลิกเพื่อเปิดข้อความ เปิดผนึกข้อความไว้ คลิกเพื่อปิด ส่ง @@ -738,7 +717,6 @@ ไม่สามารถกดรีแอคโน้ตฉบับร่างได้ ไม่สามารถ zap โน้ตฉบับร่างได้ โน๊ตฉบับร่าง - From Msg กำลังค้นหาแอพพลิเคชั่น Dvm ส่งคำขอเรียบร้อย และกำลังรอการตอบกลับ กำลังรองานจาก DVM diff --git a/amethyst/src/main/res/values-uk/strings.xml b/amethyst/src/main/res/values-uk/strings.xml index 57b4e2f4b..b8943d743 100644 --- a/amethyst/src/main/res/values-uk/strings.xml +++ b/amethyst/src/main/res/values-uk/strings.xml @@ -272,7 +272,6 @@ Мінімальний зап Максимальний зап Консенсус - (0–100)% Закриття після днів Неможливо проголосувати @@ -449,13 +448,11 @@ %1$s помилка з кодом %2$s Активно для: Головна - DMs Чати Глобально Пошук Знайти та додати користувача Ім\'я користувача або ім\'я для відображення - 25 Сплачено Гаманець: %1$s Помилка при відкритті додатка для входу diff --git a/amethyst/src/main/res/values-zh-rCN/strings.xml b/amethyst/src/main/res/values-zh-rCN/strings.xml index b0fd146d6..c5961bdd4 100644 --- a/amethyst/src/main/res/values-zh-rCN/strings.xml +++ b/amethyst/src/main/res/values-zh-rCN/strings.xml @@ -103,7 +103,6 @@ 添加中继器 显示名称 我的显示名称 - Ostrich McAwesome 欢迎! 用户名 我的用户名 @@ -304,7 +303,6 @@ 打闪最低金额 打闪最高金额 共识 - (0–100)% 后关闭 无法投票 @@ -387,7 +385,6 @@ 当帖子有你的关注的报告时警告 新回应符号 未选择回应类型。长按可更改 - Zapraiser 为这个帖子添加目标聪金额。支持的客户端可以将此显示为奖励捐赠的进度条 目标聪金额 Zapraiser 位于 %1$s。距离目标%2$s聪 @@ -536,7 +533,6 @@ 打闪设置缺失 用户 %1$s 尚未设置接收聪的闪电地址 百分比 - 25 与此用户拆分打闪 将打闪转发到 找不到闪电钱包 @@ -603,11 +599,9 @@ 你好,这个还能买到吗? 出售物品 标题 - iPhone 13 条件 分类 价格(聪) - 1000 地点 市,省,国家 全新 @@ -671,7 +665,6 @@ 比特币发票 取消比特币发票 取消出售物品 - Zapraiser 取消 Zapraiser 地点 移除地点 diff --git a/amethyst/src/main/res/values-zh-rTW/strings.xml b/amethyst/src/main/res/values-zh-rTW/strings.xml index b91996083..dfe88bccb 100644 --- a/amethyst/src/main/res/values-zh-rTW/strings.xml +++ b/amethyst/src/main/res/values-zh-rTW/strings.xml @@ -53,7 +53,6 @@ 編輯 #%1$s 原版 引用 - Fork 提議編輯 新的聰金額 添加 @@ -103,7 +102,6 @@ 添加中繼器 顯示名稱 我的顯示名稱 - Ostrich McAwesome 歡迎! 用户名 我的用户名 @@ -303,7 +301,6 @@ 打閃最低金額 打閃最高金額 共識 - (0–100)% 後關閉 無法投票 @@ -386,7 +383,6 @@ 當帖子有你的關注的報告時警告 新回應符號 未選擇回應類型。長按可更改 - Zapraiser 為這個帖子添加目標聰金額。支持的客戶端可以將此顯示為獎勵捐贈的進度條 目標聰金額 Zapraiser 位於 %1$s。距離目標%2$s聰 @@ -528,7 +524,6 @@ 閃電設置缺失 用户 %1$s 尚未設置接收聰的閃電地址 百分比 - 25 與此用戶拆分打閃 將打閃轉發到 找不到閃電錢包 @@ -595,11 +590,9 @@ 你好,這個還能買到嗎? 出售物品 標題 - iPhone 13 狀態 類別 價格(聰) - 1000 地點 市,州,國家 全新 @@ -663,7 +656,6 @@ 比特幣發票 取消比特幣發票 取消出售物品 - Zapraiser 取消 Zapraiser 地點 移除地點 @@ -711,11 +703,7 @@ 謝謝! 最大上限 寫入限制 - Forked from - FORK - Git Repository: %1$s 網址 - Clone: OTS:%1$s 時間戳證明 有在 %1$s 之前的某個時間簽署了此帖子的證明。此證明是在那個日期和時間在比特幣區塊鏈中記錄的時間戳。 From 4c3c7e7cba207d2f3418a5af3ff8b7a1f1d84bea Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 24 Jun 2024 19:22:15 -0400 Subject: [PATCH 18/49] Fixes not showing relay icons when sending messages with Amber. --- .../service/NostrAccountDataSource.kt | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt index d844308a6..103dcd6c1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt @@ -316,15 +316,17 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { val noteEvent = note?.event as? GiftWrapEvent if (noteEvent != null) { if (relay.brief !in note.relays) { - LocalCache.justConsume(noteEvent, relay) noteEvent.cachedGift(account.signer) { + LocalCache.justConsume(noteEvent, relay) this.consume(it, relay) } } } else { // new event - event.cachedGift(account.signer) { this.consume(it, relay) } - LocalCache.justConsume(event, relay) + event.cachedGift(account.signer) { + LocalCache.justConsume(event, relay) + this.consume(it, relay) + } } } @@ -335,15 +337,17 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { if (noteEvent != null) { if (relay.brief !in note.relays) { // adds the relay to seal and inner chat - LocalCache.consume(noteEvent, relay) noteEvent.cachedGossip(account.signer) { + LocalCache.consume(noteEvent, relay) LocalCache.justConsume(it, relay) } } } else { // new event - event.cachedGossip(account.signer) { LocalCache.justConsume(it, relay) } - LocalCache.justConsume(event, relay) + event.cachedGossip(account.signer) { + LocalCache.justConsume(event, relay) + LocalCache.justConsume(it, relay) + } } } @@ -377,24 +381,21 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { super.markAsSeenOnRelay(eventId, relay) val note = LocalCache.getNoteIfExists(eventId) ?: return - val privKey = account.keyPair.privKey ?: return - val noteEvent = note.event ?: return - markInnerAsSeenOnRelay(noteEvent, privKey, relay) + markInnerAsSeenOnRelay(noteEvent, relay) } private fun markInnerAsSeenOnRelay( noteEvent: EventInterface, - privKey: ByteArray, relay: Relay, ) { LocalCache.getNoteIfExists(noteEvent.id())?.addRelay(relay) if (noteEvent is GiftWrapEvent) { - noteEvent.cachedGift(account.signer) { gift -> markInnerAsSeenOnRelay(gift, privKey, relay) } + noteEvent.cachedGift(account.signer) { gift -> markInnerAsSeenOnRelay(gift, relay) } } else if (noteEvent is SealedGossipEvent) { noteEvent.cachedGossip(account.signer) { rumor -> - markInnerAsSeenOnRelay(rumor, privKey, relay) + markInnerAsSeenOnRelay(rumor, relay) } } } From 683af698c664f5590224db5419ac3b0a88d7ba1e Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 24 Jun 2024 20:42:22 -0400 Subject: [PATCH 19/49] Adjusts the size of the reply button on chats --- .../vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt index fc41eb022..4210031af 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt @@ -75,7 +75,7 @@ import com.vitorpamplona.amethyst.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.ui.theme.ReactionRowHeightChat import com.vitorpamplona.amethyst.ui.theme.RowColSpacing import com.vitorpamplona.amethyst.ui.theme.RowColSpacing5dp -import com.vitorpamplona.amethyst.ui.theme.Size15Modifier +import com.vitorpamplona.amethyst.ui.theme.Size18Modifier import com.vitorpamplona.amethyst.ui.theme.Size20dp import com.vitorpamplona.amethyst.ui.theme.Size5Modifier import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer @@ -219,7 +219,7 @@ fun NormalChatNote( grayTint = MaterialTheme.colorScheme.placeholderText, accountViewModel = accountViewModel, showCounter = false, - iconSizeModifier = Size15Modifier, + iconSizeModifier = Size18Modifier, ) { onWantsToReply(note) } From c448e75953d0b0f311bc4461e9a0f6724d7a3a21 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 25 Jun 2024 08:44:32 -0400 Subject: [PATCH 20/49] Updates all dependencies --- gradle/libs.versions.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2d232dcf8..df13a1771 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ accompanistAdaptive = "0.34.0" activityCompose = "1.9.0" agp = "8.5.0" androidKotlinGeohash = "1.0" -androidxJunit = "1.2.0-rc01" +androidxJunit = "1.2.0" appcompat = "1.7.0" audiowaveform = "1.1.1" benchmark = "1.2.4" @@ -13,7 +13,7 @@ blurhash = "1.0.0" coil = "2.6.0" composeBom = "2024.06.00" coreKtx = "1.13.1" -espressoCore = "3.5.1" +espressoCore = "3.6.0" firebaseBom = "33.1.1" fragmentKtx = "1.8.0" gms = "4.4.1" @@ -31,7 +31,7 @@ media3 = "1.3.1" mockk = "1.13.11" navigationCompose = "2.7.7" okhttp = "5.0.0-alpha.14" -runner = "1.5.2" +runner = "1.6.0" rfc3986 = "0.1.0" secp256k1KmpJniAndroid = "0.15.0" securityCryptoKtx = "1.1.0-alpha06" @@ -39,13 +39,13 @@ spotless = "6.25.0" translate = "17.0.2" unifiedpush = "2.3.1" urlDetector = "0.1.23" -vico-charts = "1.14.0" +vico-charts = "1.15.0" zelory = "3.0.1" zoomable = "1.6.1" zxing = "3.5.3" zxingAndroidEmbedded = "4.3.0" material = "1.10.0" -materialVersion = "1.10.0" +materialVersion = "1.12.0" [libraries] abedElazizShe-image-compressor = { group = "com.github.AbedElazizShe", name = "LightCompressor", version.ref = "lightcompressor" } From 79ace7f18ca6505a0b48a9bc4d5528ee25f68f28 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 25 Jun 2024 10:06:06 -0400 Subject: [PATCH 21/49] Renames JsonFilter to just Filter and adds a matching function --- .../vitorpamplona/amethyst/model/Account.kt | 5 +- .../service/NostrAccountDataSource.kt | 22 +- .../service/NostrChannelDataSource.kt | 13 +- .../service/NostrChatroomDataSource.kt | 6 +- .../service/NostrChatroomListDataSource.kt | 42 ++-- .../service/NostrCommunityDataSource.kt | 4 +- .../service/NostrDiscoveryDataSource.kt | 100 +++++--- .../service/NostrGeohashDataSource.kt | 4 +- .../service/NostrHashtagDataSource.kt | 4 +- .../amethyst/service/NostrHomeDataSource.kt | 13 +- .../NostrLnZapPaymentResponseDataSource.kt | 4 +- .../NostrSearchEventOrUserDataSource.kt | 14 +- .../service/NostrSingleChannelDataSource.kt | 8 +- .../service/NostrSingleEventDataSource.kt | 228 +++++++++--------- .../service/NostrSingleUserDataSource.kt | 8 +- .../amethyst/service/NostrThreadDataSource.kt | 4 +- .../service/NostrUserProfileDataSource.kt | 18 +- .../amethyst/service/NostrVideoDataSource.kt | 26 +- .../relays/{JsonFilter.kt => Filter.kt} | 18 +- .../ammolite/relays/TypedFilter.kt | 2 +- 20 files changed, 311 insertions(+), 232 deletions(-) rename ammolite/src/main/java/com/vitorpamplona/ammolite/relays/{JsonFilter.kt => Filter.kt} (85%) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 2fd531131..60fe2689f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -39,7 +39,7 @@ import com.vitorpamplona.ammolite.relays.BundledUpdate import com.vitorpamplona.ammolite.relays.Client import com.vitorpamplona.ammolite.relays.Constants import com.vitorpamplona.ammolite.relays.FeedType -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.Relay import com.vitorpamplona.ammolite.relays.RelaySetupInfo import com.vitorpamplona.ammolite.relays.TypedFilter @@ -116,7 +116,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flattenMerge @@ -1060,7 +1059,7 @@ class Account( listOf( TypedFilter( setOf(FeedType.FOLLOWS, FeedType.PRIVATE_DMS, FeedType.GLOBAL), - JsonFilter( + Filter( ids = listOf(it.id), ), ), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt index 103dcd6c1..586332510 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt @@ -28,7 +28,7 @@ import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES import com.vitorpamplona.ammolite.relays.Client import com.vitorpamplona.ammolite.relays.EOSETime import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.Relay import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.encoders.HexKey @@ -81,7 +81,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(ContactListEvent.KIND), authors = listOf(account.userProfile().pubkeyHex), limit = 1, @@ -92,7 +92,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(MetadataEvent.KIND), authors = listOf(account.userProfile().pubkeyHex), limit = 1, @@ -103,7 +103,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(StatusEvent.KIND, AdvertisedRelayListEvent.KIND, ChatMessageRelayListEvent.KIND, SearchRelayListEvent.KIND, PrivateOutboxRelayListEvent.KIND), authors = listOf(account.userProfile().pubkeyHex), limit = 10, @@ -115,7 +115,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { return TypedFilter( types = EVENT_FINDER_TYPES, filter = - JsonFilter( + Filter( kinds = listOf( MetadataEvent.KIND, @@ -138,7 +138,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(BookmarkListEvent.KIND, PeopleListEvent.KIND, MuteListEvent.KIND, BadgeProfilesEvent.KIND, EmojiPackSelectionEvent.KIND), authors = listOf(account.userProfile().pubkeyHex), limit = 100, @@ -149,7 +149,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(DraftEvent.KIND, ReportEvent.KIND), authors = listOf(account.userProfile().pubkeyHex), since = @@ -164,7 +164,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( authors = listOf(account.userProfile().pubkeyHex), limit = 400, ), @@ -181,7 +181,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { return TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf( TextNoteEvent.KIND, @@ -214,7 +214,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { return TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf( GitReplyEvent.KIND, @@ -236,7 +236,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(GiftWrapEvent.KIND), tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)), since = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt index dee51163a..53a67a931 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChannelDataSource.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.Channel import com.vitorpamplona.amethyst.model.LiveActivitiesChannel import com.vitorpamplona.amethyst.model.PublicChatChannel import com.vitorpamplona.ammolite.relays.FeedType -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.ChannelMessageEvent import com.vitorpamplona.quartz.events.LiveActivitiesChatMessageEvent @@ -58,7 +58,7 @@ object NostrChannelDataSource : AmethystNostrDataSource("ChatroomFeed") { return TypedFilter( types = setOf(FeedType.FOLLOWS, FeedType.PRIVATE_DMS, FeedType.GLOBAL, FeedType.SEARCH), filter = - JsonFilter( + Filter( kinds = listOf(ChannelMessageEvent.KIND), authors = listOf(myAccount.userProfile().pubkeyHex), limit = 50, @@ -71,7 +71,7 @@ object NostrChannelDataSource : AmethystNostrDataSource("ChatroomFeed") { return TypedFilter( types = setOf(FeedType.FOLLOWS, FeedType.PRIVATE_DMS, FeedType.GLOBAL, FeedType.SEARCH), filter = - JsonFilter( + Filter( kinds = listOf(LiveActivitiesChatMessageEvent.KIND), authors = listOf(myAccount.userProfile().pubkeyHex), limit = 50, @@ -86,7 +86,7 @@ object NostrChannelDataSource : AmethystNostrDataSource("ChatroomFeed") { return TypedFilter( types = setOf(FeedType.PUBLIC_CHATS), filter = - JsonFilter( + Filter( kinds = listOf(ChannelMessageEvent.KIND), tags = mapOf("e" to listOfNotNull(channel?.idHex)), limit = 200, @@ -96,7 +96,7 @@ object NostrChannelDataSource : AmethystNostrDataSource("ChatroomFeed") { return TypedFilter( types = setOf(FeedType.PUBLIC_CHATS), filter = - JsonFilter( + Filter( kinds = listOf(LiveActivitiesChatMessageEvent.KIND), tags = mapOf("a" to listOfNotNull(channel?.idHex)), limit = 200, @@ -113,7 +113,6 @@ object NostrChannelDataSource : AmethystNostrDataSource("ChatroomFeed") { listOfNotNull( createMessagesToChannelFilter(), createMessagesByMeToChannelFilter(), - ) - .ifEmpty { null } + ).ifEmpty { null } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt index 86858a07b..6298f533b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomDataSource.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.relays.EOSEAccount import com.vitorpamplona.ammolite.relays.FeedType -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.ChatroomKey import com.vitorpamplona.quartz.events.PrivateDmEvent @@ -50,7 +50,7 @@ object NostrChatroomDataSource : AmethystNostrDataSource("ChatroomFeed") { TypedFilter( types = setOf(FeedType.PRIVATE_DMS), filter = - JsonFilter( + Filter( kinds = listOf(PrivateDmEvent.KIND), authors = myPeer.users.toList(), tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)), @@ -73,7 +73,7 @@ object NostrChatroomDataSource : AmethystNostrDataSource("ChatroomFeed") { TypedFilter( types = setOf(FeedType.PRIVATE_DMS), filter = - JsonFilter( + Filter( kinds = listOf(PrivateDmEvent.KIND), authors = listOf(account.userProfile().pubkeyHex), tags = mapOf("p" to myPeer.users.map { it }), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt index 35631e73f..63539453e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt @@ -24,7 +24,7 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.relays.EOSEAccount import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES import com.vitorpamplona.ammolite.relays.FeedType -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent @@ -41,11 +41,14 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") { TypedFilter( types = setOf(FeedType.PRIVATE_DMS), filter = - JsonFilter( + Filter( kinds = listOf(PrivateDmEvent.KIND), tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)), since = - latestEOSEs.users[account.userProfile()]?.followList?.get(chatRoomList)?.relayList, + latestEOSEs.users[account.userProfile()] + ?.followList + ?.get(chatRoomList) + ?.relayList, ), ) @@ -53,11 +56,14 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") { TypedFilter( types = setOf(FeedType.PRIVATE_DMS), filter = - JsonFilter( + Filter( kinds = listOf(PrivateDmEvent.KIND), authors = listOf(account.userProfile().pubkeyHex), since = - latestEOSEs.users[account.userProfile()]?.followList?.get(chatRoomList)?.relayList, + latestEOSEs.users[account.userProfile()] + ?.followList + ?.get(chatRoomList) + ?.relayList, ), ) @@ -65,11 +71,14 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") { TypedFilter( types = setOf(FeedType.PUBLIC_CHATS), filter = - JsonFilter( + Filter( kinds = listOf(ChannelCreateEvent.KIND, ChannelMetadataEvent.KIND), authors = listOf(account.userProfile().pubkeyHex), since = - latestEOSEs.users[account.userProfile()]?.followList?.get(chatRoomList)?.relayList, + latestEOSEs.users[account.userProfile()] + ?.followList + ?.get(chatRoomList) + ?.relayList, ), ) @@ -82,11 +91,14 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") { // Metadata comes from any relay types = EVENT_FINDER_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(ChannelCreateEvent.KIND), ids = followingEvents.toList(), since = - latestEOSEs.users[account.userProfile()]?.followList?.get(chatRoomList)?.relayList, + latestEOSEs.users[account.userProfile()] + ?.followList + ?.get(chatRoomList) + ?.relayList, ), ) } @@ -101,7 +113,7 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") { // Metadata comes from any relay types = EVENT_FINDER_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(ChannelMetadataEvent.KIND), tags = mapOf("e" to listOf(it)), limit = 1, @@ -119,11 +131,14 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") { TypedFilter( types = setOf(FeedType.PUBLIC_CHATS), filter = - JsonFilter( + Filter( kinds = listOf(ChannelMessageEvent.KIND), tags = mapOf("e" to listOf(it)), since = - latestEOSEs.users[account.userProfile()]?.followList?.get(chatRoomList)?.relayList, + latestEOSEs.users[account.userProfile()] + ?.followList + ?.get(chatRoomList) + ?.relayList, // Remember to consider spam that is being removed from the UI limit = 50, ), @@ -149,8 +164,7 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") { list, createLastChannelInfoFilter(), createLastMessageOfEachChannelFilter(), - ) - .flatten() + ).flatten() .ifEmpty { null } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt index f96db2371..0dc2f9944 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrCommunityDataSource.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.CommunityDefinitionEvent import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent @@ -38,7 +38,7 @@ object NostrCommunityDataSource : AmethystNostrDataSource("SingleCommunityFeed") return TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( authors = community .moderators() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt index 62401ba1f..f51302c1a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrDiscoveryDataSource.kt @@ -24,7 +24,7 @@ import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.relays.EOSEAccount import com.vitorpamplona.ammolite.relays.FeedType -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AppDefinitionEvent import com.vitorpamplona.quartz.events.ChannelCreateEvent @@ -66,15 +66,24 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { } fun createMarketplaceFilter(): List { - val follows = account.liveDiscoveryFollowLists.value?.users?.toList() - val hashToLoad = account.liveDiscoveryFollowLists.value?.hashtags?.toList() - val geohashToLoad = account.liveDiscoveryFollowLists.value?.geotags?.toList() + val follows = + account.liveDiscoveryFollowLists.value + ?.users + ?.toList() + val hashToLoad = + account.liveDiscoveryFollowLists.value + ?.hashtags + ?.toList() + val geohashToLoad = + account.liveDiscoveryFollowLists.value + ?.geotags + ?.toList() return listOfNotNull( TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( authors = follows, kinds = listOf(ClassifiedsEvent.KIND), limit = 300, @@ -89,7 +98,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( kinds = listOf(ClassifiedsEvent.KIND), tags = mapOf( @@ -111,7 +120,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( kinds = listOf(ClassifiedsEvent.KIND), tags = mapOf( @@ -132,12 +141,12 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { ) } - fun createNIP89Filter(kTags: List): List { - return listOfNotNull( + fun createNIP89Filter(kTags: List): List = + listOfNotNull( TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( kinds = listOf(AppDefinitionEvent.KIND), limit = 300, tags = mapOf("k" to kTags), @@ -149,16 +158,18 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { ), ), ) - } fun createLiveStreamFilter(): List { - val follows = account.liveDiscoveryFollowLists.value?.users?.toList() + val follows = + account.liveDiscoveryFollowLists.value + ?.users + ?.toList() return listOfNotNull( TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( authors = follows, kinds = listOf(LiveActivitiesChatMessageEvent.KIND, LiveActivitiesEvent.KIND), limit = 300, @@ -173,7 +184,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( tags = mapOf("p" to it), kinds = listOf(LiveActivitiesEvent.KIND), limit = 100, @@ -189,14 +200,17 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { } fun createPublicChatFilter(): List { - val follows = account.liveDiscoveryFollowLists.value?.users?.toList() + val follows = + account.liveDiscoveryFollowLists.value + ?.users + ?.toList() val followChats = account.selectedChatsFollowList().toList() return listOfNotNull( TypedFilter( types = setOf(FeedType.PUBLIC_CHATS), filter = - JsonFilter( + Filter( authors = follows, kinds = listOf(ChannelMessageEvent.KIND), limit = 500, @@ -211,7 +225,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { TypedFilter( types = setOf(FeedType.PUBLIC_CHATS), filter = - JsonFilter( + Filter( ids = followChats, kinds = listOf(ChannelCreateEvent.KIND, ChannelMessageEvent.KIND), limit = 300, @@ -229,12 +243,15 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { } fun createCommunitiesFilter(): TypedFilter { - val follows = account.liveDiscoveryFollowLists.value?.users?.toList() + val follows = + account.liveDiscoveryFollowLists.value + ?.users + ?.toList() return TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( authors = follows, kinds = listOf(CommunityDefinitionEvent.KIND, CommunityPostApprovalEvent.KIND), limit = 300, @@ -248,14 +265,17 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { } fun createLiveStreamTagsFilter(): TypedFilter? { - val hashToLoad = account.liveDiscoveryFollowLists.value?.hashtags?.toList() + val hashToLoad = + account.liveDiscoveryFollowLists.value + ?.hashtags + ?.toList() if (hashToLoad.isNullOrEmpty()) return null return TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( kinds = listOf(LiveActivitiesChatMessageEvent.KIND, LiveActivitiesEvent.KIND), tags = mapOf( @@ -275,14 +295,17 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { } fun createLiveStreamGeohashesFilter(): TypedFilter? { - val hashToLoad = account.liveDiscoveryFollowLists.value?.geotags?.toList() + val hashToLoad = + account.liveDiscoveryFollowLists.value + ?.geotags + ?.toList() if (hashToLoad.isNullOrEmpty()) return null return TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( kinds = listOf(LiveActivitiesChatMessageEvent.KIND, LiveActivitiesEvent.KIND), tags = mapOf( @@ -302,14 +325,17 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { } fun createPublicChatsTagsFilter(): TypedFilter? { - val hashToLoad = account.liveDiscoveryFollowLists.value?.hashtags?.toList() + val hashToLoad = + account.liveDiscoveryFollowLists.value + ?.hashtags + ?.toList() if (hashToLoad.isNullOrEmpty()) return null return TypedFilter( types = setOf(FeedType.PUBLIC_CHATS), filter = - JsonFilter( + Filter( kinds = listOf(ChannelCreateEvent.KIND, ChannelMetadataEvent.KIND, ChannelMessageEvent.KIND), tags = @@ -330,14 +356,17 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { } fun createPublicChatsGeohashesFilter(): TypedFilter? { - val hashToLoad = account.liveDiscoveryFollowLists.value?.geotags?.toList() + val hashToLoad = + account.liveDiscoveryFollowLists.value + ?.geotags + ?.toList() if (hashToLoad.isNullOrEmpty()) return null return TypedFilter( types = setOf(FeedType.PUBLIC_CHATS), filter = - JsonFilter( + Filter( kinds = listOf(ChannelCreateEvent.KIND, ChannelMetadataEvent.KIND, ChannelMessageEvent.KIND), tags = @@ -358,14 +387,17 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { } fun createCommunitiesTagsFilter(): TypedFilter? { - val hashToLoad = account.liveDiscoveryFollowLists.value?.hashtags?.toList() + val hashToLoad = + account.liveDiscoveryFollowLists.value + ?.hashtags + ?.toList() if (hashToLoad.isNullOrEmpty()) return null return TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( kinds = listOf(CommunityDefinitionEvent.KIND, CommunityPostApprovalEvent.KIND), tags = mapOf( @@ -385,14 +417,17 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { } fun createCommunitiesGeohashesFilter(): TypedFilter? { - val hashToLoad = account.liveDiscoveryFollowLists.value?.geotags?.toList() + val hashToLoad = + account.liveDiscoveryFollowLists.value + ?.geotags + ?.toList() if (hashToLoad.isNullOrEmpty()) return null return TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( kinds = listOf(CommunityDefinitionEvent.KIND, CommunityPostApprovalEvent.KIND), tags = mapOf( @@ -437,8 +472,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") { createPublicChatsTagsFilter(), createPublicChatsGeohashesFilter(), ), - ) - .toList() + ).toList() .ifEmpty { null } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt index 55ba2e658..12dc4cefa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrGeohashDataSource.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AudioHeaderEvent import com.vitorpamplona.quartz.events.AudioTrackEvent @@ -43,7 +43,7 @@ object NostrGeohashDataSource : AmethystNostrDataSource("SingleGeoHashFeed") { return TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( tags = mapOf( "g" to diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt index d13d6d695..60372d4ae 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHashtagDataSource.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AudioHeaderEvent import com.vitorpamplona.quartz.events.AudioTrackEvent @@ -43,7 +43,7 @@ object NostrHashtagDataSource : AmethystNostrDataSource("SingleHashtagFeed") { return TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( tags = mapOf( "t" to diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt index 2417d2f29..f9f159450 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt @@ -24,7 +24,7 @@ import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.relays.EOSEAccount import com.vitorpamplona.ammolite.relays.FeedType -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AudioHeaderEvent import com.vitorpamplona.quartz.events.AudioTrackEvent @@ -80,7 +80,7 @@ object NostrHomeDataSource : AmethystNostrDataSource("HomeFeed") { return TypedFilter( types = setOf(if (follows == null) FeedType.GLOBAL else FeedType.FOLLOWS), filter = - JsonFilter( + Filter( kinds = listOf( TextNoteEvent.KIND, @@ -116,7 +116,7 @@ object NostrHomeDataSource : AmethystNostrDataSource("HomeFeed") { return TypedFilter( types = setOf(FeedType.FOLLOWS), filter = - JsonFilter( + Filter( kinds = listOf( TextNoteEvent.KIND, @@ -155,7 +155,7 @@ object NostrHomeDataSource : AmethystNostrDataSource("HomeFeed") { return TypedFilter( types = setOf(FeedType.FOLLOWS), filter = - JsonFilter( + Filter( kinds = listOf( TextNoteEvent.KIND, @@ -194,7 +194,7 @@ object NostrHomeDataSource : AmethystNostrDataSource("HomeFeed") { return TypedFilter( types = setOf(FeedType.FOLLOWS), filter = - JsonFilter( + Filter( kinds = listOf( TextNoteEvent.KIND, @@ -238,7 +238,6 @@ object NostrHomeDataSource : AmethystNostrDataSource("HomeFeed") { createFollowCommunitiesFilter(), createFollowTagsFilter(), createFollowGeohashesFilter(), - ) - .ifEmpty { null } + ).ifEmpty { null } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt index cd5a927db..b0d77af3d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrLnZapPaymentResponseDataSource.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.ammolite.relays.Client import com.vitorpamplona.ammolite.relays.FeedType -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.Relay import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.LnZapPaymentResponseEvent @@ -42,7 +42,7 @@ class NostrLnZapPaymentResponseDataSource( return TypedFilter( types = feedTypes, filter = - JsonFilter( + Filter( kinds = listOf(LnZapPaymentResponseEvent.KIND), authors = listOf(fromServiceHex), tags = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt index 432765728..268951e2d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSearchEventOrUserDataSource.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES import com.vitorpamplona.ammolite.relays.FeedType -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.ATag @@ -95,7 +95,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(MetadataEvent.KIND, aTag.kind), authors = listOfNotNull(aTag.pubKeyHex), // just to be sure @@ -110,7 +110,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( ids = listOfNotNull(hexToWatch), ), ), @@ -118,7 +118,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(MetadataEvent.KIND), authors = listOfNotNull(hexToWatch), // just to be sure @@ -135,7 +135,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe TypedFilter( types = setOf(FeedType.SEARCH), filter = - JsonFilter( + Filter( kinds = listOf(MetadataEvent.KIND), search = mySearchString, limit = 1000, @@ -144,7 +144,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe TypedFilter( types = setOf(FeedType.SEARCH), filter = - JsonFilter( + Filter( kinds = listOf( TextNoteEvent.KIND, @@ -165,7 +165,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe TypedFilter( types = setOf(FeedType.SEARCH), filter = - JsonFilter( + Filter( kinds = listOf( ChannelMetadataEvent.KIND, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt index 129e8746c..1b83ee2c9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleChannelDataSource.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.LiveActivitiesChannel import com.vitorpamplona.amethyst.model.PublicChatChannel import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES import com.vitorpamplona.ammolite.relays.FeedType -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelMetadataEvent @@ -44,7 +44,7 @@ object NostrSingleChannelDataSource : AmethystNostrDataSource("SingleChannelFeed return TypedFilter( types = setOf(FeedType.PUBLIC_CHATS), filter = - JsonFilter( + Filter( kinds = listOf(ChannelMetadataEvent.KIND), tags = mapOf("e" to reactionsToWatch), ), @@ -65,7 +65,7 @@ object NostrSingleChannelDataSource : AmethystNostrDataSource("SingleChannelFeed return TypedFilter( types = EVENT_FINDER_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(ChannelCreateEvent.KIND), ids = interestedEvents.toList(), ), @@ -88,7 +88,7 @@ object NostrSingleChannelDataSource : AmethystNostrDataSource("SingleChannelFeed TypedFilter( types = EVENT_FINDER_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(aTag.kind), tags = mapOf("d" to listOf(aTag.dTag)), authors = listOf(aTag.pubKeyHex), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt index cde6acce8..6087a1ab3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.ammolite.relays.EOSETime import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent import com.vitorpamplona.quartz.events.DeletionEvent @@ -52,53 +52,53 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") { ( eventsToWatch.filter { it.address() != null } + addressesToWatch.filter { it.address() != null } - ) - .toSet() + ).toSet() if (addressesToWatch.isEmpty()) { return null } - return groupByEOSEPresence(addressesToWatch).map { - listOf( - TypedFilter( - types = EVENT_FINDER_TYPES, - filter = - JsonFilter( - kinds = - listOf( - TextNoteEvent.KIND, - ReactionEvent.KIND, - RepostEvent.KIND, - GenericRepostEvent.KIND, - ReportEvent.KIND, - LnZapEvent.KIND, - PollNoteEvent.KIND, - CommunityPostApprovalEvent.KIND, - LiveActivitiesChatMessageEvent.KIND, - ), - tags = mapOf("a" to it.mapNotNull { it.address()?.toTag() }), - since = findMinimumEOSEs(it), - // Max amount of "replies" to download on a specific event. - limit = 1000, - ), - ), - TypedFilter( - types = EVENT_FINDER_TYPES, - filter = - JsonFilter( - kinds = - listOf( - DeletionEvent.KIND, - ), - tags = mapOf("a" to it.mapNotNull { it.address()?.toTag() }), - since = findMinimumEOSEs(it), - // Max amount of "replies" to download on a specific event. - limit = 10, - ), - ), - ) - }.flatten() + return groupByEOSEPresence(addressesToWatch) + .map { + listOf( + TypedFilter( + types = EVENT_FINDER_TYPES, + filter = + Filter( + kinds = + listOf( + TextNoteEvent.KIND, + ReactionEvent.KIND, + RepostEvent.KIND, + GenericRepostEvent.KIND, + ReportEvent.KIND, + LnZapEvent.KIND, + PollNoteEvent.KIND, + CommunityPostApprovalEvent.KIND, + LiveActivitiesChatMessageEvent.KIND, + ), + tags = mapOf("a" to it.mapNotNull { it.address()?.toTag() }), + since = findMinimumEOSEs(it), + // Max amount of "replies" to download on a specific event. + limit = 1000, + ), + ), + TypedFilter( + types = EVENT_FINDER_TYPES, + filter = + Filter( + kinds = + listOf( + DeletionEvent.KIND, + ), + tags = mapOf("a" to it.mapNotNull { it.address()?.toTag() }), + since = findMinimumEOSEs(it), + // Max amount of "replies" to download on a specific event. + limit = 10, + ), + ), + ) + }.flatten() } private fun createAddressFilter(): List? { @@ -114,7 +114,7 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") { TypedFilter( types = EVENT_FINDER_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(aTag.kind), authors = listOf(aTag.pubKeyHex), limit = 5, @@ -124,7 +124,7 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") { TypedFilter( types = EVENT_FINDER_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(aTag.kind), tags = mapOf("d" to listOf(aTag.dTag)), authors = listOf(aTag.pubKeyHex), @@ -141,48 +141,49 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") { return null } - return groupByEOSEPresence(eventsToWatch).map { - listOf( - TypedFilter( - types = EVENT_FINDER_TYPES, - filter = - JsonFilter( - kinds = - listOf( - TextNoteEvent.KIND, - ReactionEvent.KIND, - RepostEvent.KIND, - GenericRepostEvent.KIND, - ReportEvent.KIND, - LnZapEvent.KIND, - PollNoteEvent.KIND, - OtsEvent.KIND, - TextNoteModificationEvent.KIND, - GitReplyEvent.KIND, - ), - tags = mapOf("e" to it.map { it.idHex }), - since = findMinimumEOSEs(it), - // Max amount of "replies" to download on a specific event. - limit = 10000, - ), - ), - TypedFilter( - types = EVENT_FINDER_TYPES, - filter = - JsonFilter( - kinds = - listOf( - DeletionEvent.KIND, - NIP90ContentDiscoveryResponseEvent.KIND, - NIP90StatusEvent.KIND, - ), - tags = mapOf("e" to it.map { it.idHex }), - since = findMinimumEOSEs(it), - limit = 100, - ), - ), - ) - }.flatten() + return groupByEOSEPresence(eventsToWatch) + .map { + listOf( + TypedFilter( + types = EVENT_FINDER_TYPES, + filter = + Filter( + kinds = + listOf( + TextNoteEvent.KIND, + ReactionEvent.KIND, + RepostEvent.KIND, + GenericRepostEvent.KIND, + ReportEvent.KIND, + LnZapEvent.KIND, + PollNoteEvent.KIND, + OtsEvent.KIND, + TextNoteModificationEvent.KIND, + GitReplyEvent.KIND, + ), + tags = mapOf("e" to it.map { it.idHex }), + since = findMinimumEOSEs(it), + // Max amount of "replies" to download on a specific event. + limit = 10000, + ), + ), + TypedFilter( + types = EVENT_FINDER_TYPES, + filter = + Filter( + kinds = + listOf( + DeletionEvent.KIND, + NIP90ContentDiscoveryResponseEvent.KIND, + NIP90StatusEvent.KIND, + ), + tags = mapOf("e" to it.map { it.idHex }), + since = findMinimumEOSEs(it), + limit = 100, + ), + ), + ) + }.flatten() } private fun createQuotesFilter(): List? { @@ -190,21 +191,22 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") { return null } - return groupByEOSEPresence(eventsToWatch).map { - listOf( - TypedFilter( - types = EVENT_FINDER_TYPES, - filter = - JsonFilter( - kinds = listOf(TextNoteEvent.KIND), - tags = mapOf("q" to it.map { it.idHex }), - since = findMinimumEOSEs(it), - // Max amount of "replies" to download on a specific event. - limit = 1000, - ), - ), - ) - }.flatten() + return groupByEOSEPresence(eventsToWatch) + .map { + listOf( + TypedFilter( + types = EVENT_FINDER_TYPES, + filter = + Filter( + kinds = listOf(TextNoteEvent.KIND), + tags = mapOf("q" to it.map { it.idHex }), + since = findMinimumEOSEs(it), + // Max amount of "replies" to download on a specific event. + limit = 1000, + ), + ), + ) + }.flatten() } fun createLoadEventsIfNotLoadedFilter(): List? { @@ -227,7 +229,7 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") { TypedFilter( types = EVENT_FINDER_TYPES, filter = - JsonFilter( + Filter( ids = interestedEvents.toList(), ), ), @@ -304,13 +306,21 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") { } } -fun groupByEOSEPresence(notes: Set): Collection> { - return notes.groupBy { it.lastReactionsDownloadTime.keys.sorted().joinToString(",") }.values -} +fun groupByEOSEPresence(notes: Set): Collection> = + notes + .groupBy { + it.lastReactionsDownloadTime.keys + .sorted() + .joinToString(",") + }.values -fun groupByEOSEPresence(users: Iterable): Collection> { - return users.groupBy { it.latestEOSEs.keys.sorted().joinToString(",") }.values -} +fun groupByEOSEPresence(users: Iterable): Collection> = + users + .groupBy { + it.latestEOSEs.keys + .sorted() + .joinToString(",") + }.values fun findMinimumEOSEs(notes: List): Map { val minLatestEOSEs = mutableMapOf() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt index 5b6f48b26..a163c176d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.ammolite.relays.EOSETime import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent import com.vitorpamplona.quartz.events.ChatMessageRelayListEvent @@ -45,7 +45,7 @@ object NostrSingleUserDataSource : AmethystNostrDataSource("SingleUserFeed") { TypedFilter( types = EVENT_FINDER_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(MetadataEvent.KIND, AdvertisedRelayListEvent.KIND), authors = firstTimers, ), @@ -68,7 +68,7 @@ object NostrSingleUserDataSource : AmethystNostrDataSource("SingleUserFeed") { TypedFilter( types = EVENT_FINDER_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(MetadataEvent.KIND, StatusEvent.KIND, AdvertisedRelayListEvent.KIND, ChatMessageRelayListEvent.KIND), authors = groupIds, since = minEOSEs, @@ -77,7 +77,7 @@ object NostrSingleUserDataSource : AmethystNostrDataSource("SingleUserFeed") { TypedFilter( types = EVENT_FINDER_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(ReportEvent.KIND), tags = mapOf("p" to groupIds), since = minEOSEs, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt index 3fae129a4..a132bc5c7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrThreadDataSource.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.ThreadAssembler import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter object NostrThreadDataSource : AmethystNostrDataSource("SingleThreadFeed") { @@ -45,7 +45,7 @@ object NostrThreadDataSource : AmethystNostrDataSource("SingleThreadFeed") { return TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( ids = eventsToLoad.toList(), ), ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt index 19e16f2ec..f05299d2c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.AppRecommendationEvent import com.vitorpamplona.quartz.events.AudioHeaderEvent @@ -55,7 +55,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(MetadataEvent.KIND), authors = listOf(it.pubkeyHex), limit = 1, @@ -68,7 +68,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf( TextNoteEvent.KIND, @@ -93,7 +93,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(LnZapEvent.KIND), tags = mapOf("p" to listOf(it.pubkeyHex)), limit = 200, @@ -106,7 +106,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(ContactListEvent.KIND), authors = listOf(it.pubkeyHex), limit = 1, @@ -119,7 +119,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(ContactListEvent.KIND), tags = mapOf("p" to listOf(it.pubkeyHex)), ), @@ -131,7 +131,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(BadgeProfilesEvent.KIND), authors = listOf(it.pubkeyHex), limit = 1, @@ -144,7 +144,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(BookmarkListEvent.KIND, PeopleListEvent.KIND, AppRecommendationEvent.KIND), authors = listOf(it.pubkeyHex), @@ -158,7 +158,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") { TypedFilter( types = COMMON_FEED_TYPES, filter = - JsonFilter( + Filter( kinds = listOf(BadgeAwardEvent.KIND), tags = mapOf("p" to listOf(it.pubkeyHex)), limit = 20, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt index 2dc2c18f2..1165313af 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrVideoDataSource.kt @@ -24,7 +24,7 @@ import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.relays.EOSEAccount import com.vitorpamplona.ammolite.relays.FeedType -import com.vitorpamplona.ammolite.relays.JsonFilter +import com.vitorpamplona.ammolite.relays.Filter import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.quartz.events.FileHeaderEvent import com.vitorpamplona.quartz.events.FileStorageHeaderEvent @@ -64,12 +64,15 @@ object NostrVideoDataSource : AmethystNostrDataSource("VideoFeed") { } fun createContextualFilter(): TypedFilter { - val follows = account.liveStoriesFollowLists.value?.users?.toList() + val follows = + account.liveStoriesFollowLists.value + ?.users + ?.toList() return TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( authors = follows, kinds = listOf(FileHeaderEvent.KIND, FileStorageHeaderEvent.KIND, VideoHorizontalEvent.KIND, VideoVerticalEvent.KIND), limit = 200, @@ -84,14 +87,17 @@ object NostrVideoDataSource : AmethystNostrDataSource("VideoFeed") { } fun createFollowTagsFilter(): TypedFilter? { - val hashToLoad = account.liveStoriesFollowLists.value?.hashtags?.toList() ?: return null + val hashToLoad = + account.liveStoriesFollowLists.value + ?.hashtags + ?.toList() ?: return null if (hashToLoad.isEmpty()) return null return TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( kinds = listOf(FileHeaderEvent.KIND, FileStorageHeaderEvent.KIND, VideoHorizontalEvent.KIND, VideoVerticalEvent.KIND), tags = mapOf( @@ -112,14 +118,17 @@ object NostrVideoDataSource : AmethystNostrDataSource("VideoFeed") { } fun createFollowGeohashesFilter(): TypedFilter? { - val hashToLoad = account.liveStoriesFollowLists.value?.geotags?.toList() ?: return null + val hashToLoad = + account.liveStoriesFollowLists.value + ?.geotags + ?.toList() ?: return null if (hashToLoad.isEmpty()) return null return TypedFilter( types = setOf(FeedType.GLOBAL), filter = - JsonFilter( + Filter( kinds = listOf(FileHeaderEvent.KIND, FileStorageHeaderEvent.KIND, VideoHorizontalEvent.KIND, VideoVerticalEvent.KIND), tags = mapOf( @@ -155,7 +164,6 @@ object NostrVideoDataSource : AmethystNostrDataSource("VideoFeed") { createContextualFilter(), createFollowTagsFilter(), createFollowGeohashesFilter(), - ) - .ifEmpty { null } + ).ifEmpty { null } } } diff --git a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/JsonFilter.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Filter.kt similarity index 85% rename from ammolite/src/main/java/com/vitorpamplona/ammolite/relays/JsonFilter.kt rename to ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Filter.kt index 8d36668be..700a59802 100644 --- a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/JsonFilter.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/Filter.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.ammolite.relays import com.vitorpamplona.quartz.events.Event -class JsonFilter( +class Filter( val ids: List? = null, val authors: List? = null, val kinds: List? = null, @@ -84,4 +84,20 @@ class JsonFilter( } return Event.mapper.writeValueAsString(filter) } + + fun match( + event: Event, + forRelay: String? = null, + ): Boolean { + if (ids?.any { event.id == it } == false) return false + if (kinds?.any { event.kind == it } == false) return false + if (authors?.any { event.pubKey == it } == false) return false + tags?.forEach { tag -> + if (!event.tags.any { it.first() == tag.key && it[1] in tag.value }) return false + } + if (event.createdAt !in (since?.get(forRelay)?.time ?: Long.MIN_VALUE)..(until ?: Long.MAX_VALUE)) { + return false + } + return true + } } diff --git a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/TypedFilter.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/TypedFilter.kt index 84841a3e4..ad83c57de 100644 --- a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/TypedFilter.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/TypedFilter.kt @@ -22,5 +22,5 @@ package com.vitorpamplona.ammolite.relays class TypedFilter( val types: Set, - val filter: JsonFilter, + val filter: Filter, ) From a8a2bda9af3902ced33b462b93c4d6cc89489cc3 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 25 Jun 2024 12:13:17 -0400 Subject: [PATCH 22/49] rearranges the crypto package into separate nips and reduces the amount of circular dependencies. --- .../ui/screen/AccountStateViewModel.kt | 5 +- .../quartz/benchmark/CryptoBenchmark.kt | 4 +- .../benchmark/GiftWrapReceivingBenchmark.kt | 8 +- .../quartz/crypto/CryptoUtilsTest.kt | 16 +- .../crypto/nip06/Bip32SeedDerivationTest.kt | 15 +- .../quartz/crypto/nip06/Nip06Test.kt | 13 +- .../quartz/crypto/{ => nip44}/NIP44v2Test.kt | 9 +- .../quartz/crypto/{ => nip49}/NIP49Test.kt | 2 +- .../quartz/{ => encoders}/HexEncodingTest.kt | 20 +- .../{ => encoders}/LnInvoiceUtilTest.kt | 3 +- .../quartz/{ => encoders}/NIP19EmbedTests.kt | 6 +- .../quartz/{ => events}/ChatroomKeyTest.kt | 3 +- .../quartz/{ => events}/CitationTests.kt | 4 +- .../quartz/{ => events}/EventSigCheck.kt | 3 +- .../quartz/{ => events}/GiftWrapEventTest.kt | 55 +--- .../quartz/{ => events}/PrivateZapTests.kt | 5 +- .../vitorpamplona/quartz/{ => ots}/OtsTest.kt | 2 +- .../quartz/crypto/CryptoUtils.kt | 303 +++--------------- .../quartz/crypto/nip01/Nip01.kt | 60 ++++ .../quartz/crypto/{ => nip04}/Nip04.kt | 24 +- .../crypto/nip06/Bip32SeedDerivation.kt | 25 +- .../quartz/crypto/nip06/Bip39Mnemonics.kt | 23 +- .../quartz/crypto/nip06/Nip06.kt | 22 +- .../quartz/crypto/{ => nip44}/Hkdf.kt | 7 +- .../quartz/crypto/nip44/Nip44.kt | 148 +++++++++ .../quartz/crypto/{ => nip44}/Nip44v1.kt | 22 +- .../quartz/crypto/{ => nip44}/Nip44v2.kt | 37 +-- .../quartz/crypto/{ => nip44}/SodiumUtils.kt | 6 +- .../quartz/crypto/{ => nip49}/Nip49.kt | 33 +- .../quartz/crypto/{ => nip49}/PBKDF.java | 2 +- .../quartz/crypto/{ => nip49}/SCrypt.java | 2 +- .../{ => nip49}/SecretKeyOrEmptySpec.java | 2 +- .../quartz/signers/NostrSignerInternal.kt | 33 +- .../{encoders => utils}/TimeUtilsTest.kt | 7 +- 34 files changed, 468 insertions(+), 461 deletions(-) rename quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/{ => nip44}/NIP44v2Test.kt (97%) rename quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/{ => nip49}/NIP49Test.kt (99%) rename quartz/src/androidTest/java/com/vitorpamplona/quartz/{ => encoders}/HexEncodingTest.kt (79%) rename quartz/src/androidTest/java/com/vitorpamplona/quartz/{ => encoders}/LnInvoiceUtilTest.kt (96%) rename quartz/src/androidTest/java/com/vitorpamplona/quartz/{ => encoders}/NIP19EmbedTests.kt (97%) rename quartz/src/androidTest/java/com/vitorpamplona/quartz/{ => events}/ChatroomKeyTest.kt (95%) rename quartz/src/androidTest/java/com/vitorpamplona/quartz/{ => events}/CitationTests.kt (96%) rename quartz/src/androidTest/java/com/vitorpamplona/quartz/{ => events}/EventSigCheck.kt (97%) rename quartz/src/androidTest/java/com/vitorpamplona/quartz/{ => events}/GiftWrapEventTest.kt (96%) rename quartz/src/androidTest/java/com/vitorpamplona/quartz/{ => events}/PrivateZapTests.kt (97%) rename quartz/src/androidTest/java/com/vitorpamplona/quartz/{ => ots}/OtsTest.kt (99%) create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip01/Nip01.kt rename quartz/src/main/java/com/vitorpamplona/quartz/crypto/{ => nip04}/Nip04.kt (93%) rename quartz/src/main/java/com/vitorpamplona/quartz/crypto/{ => nip44}/Hkdf.kt (94%) create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Nip44.kt rename quartz/src/main/java/com/vitorpamplona/quartz/crypto/{ => nip44}/Nip44v1.kt (93%) rename quartz/src/main/java/com/vitorpamplona/quartz/crypto/{ => nip44}/Nip44v2.kt (92%) rename quartz/src/main/java/com/vitorpamplona/quartz/crypto/{ => nip44}/SodiumUtils.kt (95%) rename quartz/src/main/java/com/vitorpamplona/quartz/crypto/{ => nip49}/Nip49.kt (90%) rename quartz/src/main/java/com/vitorpamplona/quartz/crypto/{ => nip49}/PBKDF.java (98%) rename quartz/src/main/java/com/vitorpamplona/quartz/crypto/{ => nip49}/SCrypt.java (99%) rename quartz/src/main/java/com/vitorpamplona/quartz/crypto/{ => nip49}/SecretKeyOrEmptySpec.java (99%) rename quartz/src/test/java/com/vitorpamplona/quartz/{encoders => utils}/TimeUtilsTest.kt (95%) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt index e7ba98d21..0c9c3ec1b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt @@ -33,7 +33,6 @@ import com.vitorpamplona.ammolite.relays.Client import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.crypto.CryptoUtils import com.vitorpamplona.quartz.crypto.KeyPair -import com.vitorpamplona.quartz.crypto.nip06.Nip06 import com.vitorpamplona.quartz.encoders.Hex import com.vitorpamplona.quartz.encoders.Nip19Bech32 import com.vitorpamplona.quartz.encoders.bechToBytes @@ -129,8 +128,8 @@ class AccountStateViewModel : ViewModel() { proxyPort = proxyPort, signer = NostrSignerInternal(keyPair), ) - } else if (key.contains(" ") && Nip06().isValidMnemonic(key)) { - val keyPair = KeyPair(privKey = Nip06().privateKeyFromMnemonic(key)) + } else if (key.contains(" ") && CryptoUtils.isValidMnemonic(key)) { + val keyPair = KeyPair(privKey = CryptoUtils.privateKeyFromMnemonic(key)) Account( keyPair, proxy = proxy, diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/CryptoBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/CryptoBenchmark.kt index 67332f084..111fc6ad5 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/CryptoBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/CryptoBenchmark.kt @@ -50,7 +50,7 @@ class CryptoBenchmark { val keyPair2 = KeyPair() benchmarkRule.measureRepeated { - assertNotNull(CryptoUtils.getSharedSecretNIP44v1(keyPair1.privKey!!, keyPair2.pubKey)) + assertNotNull(CryptoUtils.nip44.v1.getSharedSecret(keyPair1.privKey!!, keyPair2.pubKey)) } } @@ -70,7 +70,7 @@ class CryptoBenchmark { val keyPair2 = KeyPair() benchmarkRule.measureRepeated { - assertNotNull(CryptoUtils.computeSharedSecretNIP44v1(keyPair1.privKey!!, keyPair2.pubKey)) + assertNotNull(CryptoUtils.nip44.v1.computeSharedSecret(keyPair1.privKey!!, keyPair2.pubKey)) } } diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt index f16b43892..21a27914a 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt @@ -165,7 +165,7 @@ class GiftWrapReceivingBenchmark { benchmarkRule.measureRepeated { assertNotNull( - CryptoUtils.decryptNIP44v2( + CryptoUtils.decryptNIP44( wrap.content, receiver.keyPair.privKey!!, wrap.pubKey.hexToByteArray(), @@ -182,7 +182,7 @@ class GiftWrapReceivingBenchmark { val wrap = createWrap(sender, receiver) val innerJson = - CryptoUtils.decryptNIP44v2( + CryptoUtils.decryptNIP44( wrap.content, receiver.keyPair.privKey!!, wrap.pubKey.hexToByteArray(), @@ -200,7 +200,7 @@ class GiftWrapReceivingBenchmark { benchmarkRule.measureRepeated { assertNotNull( - CryptoUtils.decryptNIP44v2( + CryptoUtils.decryptNIP44( seal.content, receiver.keyPair.privKey!!, seal.pubKey.hexToByteArray(), @@ -217,7 +217,7 @@ class GiftWrapReceivingBenchmark { val seal = createSeal(sender, receiver) val innerJson = - CryptoUtils.decryptNIP44v2( + CryptoUtils.decryptNIP44( seal.content, receiver.keyPair.privKey!!, seal.pubKey.hexToByteArray(), diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/CryptoUtilsTest.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/CryptoUtilsTest.kt index ad5bcff7b..840a7068a 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/CryptoUtilsTest.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/CryptoUtilsTest.kt @@ -43,7 +43,7 @@ class CryptoUtilsTest { val publicKey = "765cd7cf91d3ad07423d114d5a39c61d52b2cdbc18ba055ddbbeec71fbe2aa2f" val key = - CryptoUtils.getSharedSecretNIP44v1( + CryptoUtils.nip44.v1.getSharedSecret( privateKey = privateKey.hexToByteArray(), pubKey = publicKey.hexToByteArray(), ) @@ -56,8 +56,8 @@ class CryptoUtilsTest { val sender = KeyPair() val receiver = KeyPair() - val sharedSecret1 = CryptoUtils.getSharedSecretNIP44v1(sender.privKey!!, receiver.pubKey) - val sharedSecret2 = CryptoUtils.getSharedSecretNIP44v1(receiver.privKey!!, sender.pubKey) + val sharedSecret1 = CryptoUtils.nip44.v1.getSharedSecret(sender.privKey!!, receiver.pubKey) + val sharedSecret2 = CryptoUtils.nip44.v1.getSharedSecret(receiver.privKey!!, sender.pubKey) assertEquals(sharedSecret1.toHexKey(), sharedSecret2.toHexKey()) @@ -88,8 +88,8 @@ class CryptoUtilsTest { val privateKey = CryptoUtils.privkeyCreate() val publicKey = CryptoUtils.pubkeyCreate(privateKey) - val encrypted = CryptoUtils.encryptNIP44v1(msg, privateKey, publicKey) - val decrypted = CryptoUtils.decryptNIP44v1(encrypted, privateKey, publicKey) + val encrypted = CryptoUtils.nip44.v1.encrypt(msg, privateKey, publicKey) + val decrypted = CryptoUtils.nip44.v1.decrypt(encrypted, privateKey, publicKey) assertEquals(msg, decrypted) } @@ -113,10 +113,10 @@ class CryptoUtilsTest { val privateKey = CryptoUtils.privkeyCreate() val publicKey = CryptoUtils.pubkeyCreate(privateKey) - val sharedSecret = CryptoUtils.getSharedSecretNIP44v1(privateKey, publicKey) + val sharedSecret = CryptoUtils.nip44.v1.getSharedSecret(privateKey, publicKey) - val encrypted = CryptoUtils.encryptNIP44v1(msg, sharedSecret) - val decrypted = CryptoUtils.decryptNIP44v1(encrypted, sharedSecret) + val encrypted = CryptoUtils.nip44.v1.encrypt(msg, sharedSecret) + val decrypted = CryptoUtils.nip44.v1.decrypt(encrypted, sharedSecret) assertEquals(msg, decrypted) } diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip06/Bip32SeedDerivationTest.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip06/Bip32SeedDerivationTest.kt index 42fd549f1..e3e14f256 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip06/Bip32SeedDerivationTest.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip06/Bip32SeedDerivationTest.kt @@ -22,42 +22,45 @@ package com.vitorpamplona.quartz.crypto.nip06 import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.encoders.toHexKey +import fr.acinq.secp256k1.Secp256k1 import junit.framework.TestCase.assertEquals import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class Bip32SeedDerivationTest { + val seedDerivation = Bip32SeedDerivation(Secp256k1.get()) + val masterBitcoin = - Bip32SeedDerivation.generate( + seedDerivation.generate( Bip39Mnemonics.toSeed("gun please vital unable phone catalog explain raise erosion zoo truly exist", ""), ) val nostrMnemonic0 = - Bip32SeedDerivation.generate( + seedDerivation.generate( Bip39Mnemonics.toSeed("leader monkey parrot ring guide accident before fence cannon height naive bean", ""), ) val nostrMnemonic1 = - Bip32SeedDerivation.generate( + seedDerivation.generate( Bip39Mnemonics.toSeed("what bleak badge arrange retreat wolf trade produce cricket blur garlic valid proud rude strong choose busy staff weather area salt hollow arm fade", ""), ) @Test fun restoreBIP44Wallet() { - val privateKey = Bip32SeedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/44'/1'/0'")) + val privateKey = seedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/44'/1'/0'")) assertEquals("50b3e7905c642309c8a8b73df5a49757a10f2bebb5804571b9db9004cce8a190", privateKey.toHexKey()) } @Test fun restoreBIP49Wallet() { - val privateKey = Bip32SeedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/49'/1'/0'")) + val privateKey = seedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/49'/1'/0'")) assertEquals("154c02c0b66899291a19012207642ba096a2d3ebf51baf153c9495976feb1b30", privateKey.toHexKey()) } @Test fun restoreBIP84Wallet() { - val privateKey = Bip32SeedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/84'/1'/0'")) + val privateKey = seedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/84'/1'/0'")) assertEquals("53e8c09a0e3ddcd8d68821c1e99e823966e99df91fb253e1f453a443ba543cb2", privateKey.toHexKey()) } diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip06/Nip06Test.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip06/Nip06Test.kt index 687fc5bfe..eaa39101e 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip06/Nip06Test.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip06/Nip06Test.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.quartz.crypto.nip06 import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.encoders.toHexKey +import fr.acinq.secp256k1.Secp256k1 import junit.framework.TestCase.assertEquals import org.junit.Ignore import org.junit.Test @@ -29,6 +30,8 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class Nip06Test { + val nip06 = Nip06(Secp256k1.get()) + // private key (hex): 7f7ff03d123792d6ac594bfa67bf6d0c0ab55b6b1fdb6249303fe861f1ccba9a // nsec: nsec10allq0gjx7fddtzef0ax00mdps9t2kmtrldkyjfs8l5xruwvh2dq0lhhkp private val menemonic0 = "leader monkey parrot ring guide accident before fence cannon height naive bean" @@ -43,26 +46,26 @@ class Nip06Test { @Test fun fromSeedNip06TestVector0() { - val privateKeyHex = Nip06().privateKeyFromMnemonic(menemonic0).toHexKey() + val privateKeyHex = nip06.privateKeyFromMnemonic(menemonic0).toHexKey() assertEquals("7f7ff03d123792d6ac594bfa67bf6d0c0ab55b6b1fdb6249303fe861f1ccba9a", privateKeyHex) - val privateKeyHex21 = Nip06().privateKeyFromMnemonic(menemonic0, 21).toHexKey() + val privateKeyHex21 = nip06.privateKeyFromMnemonic(menemonic0, 21).toHexKey() assertEquals("576390ec69951fcfbf159f2aac0965bb2e6d7a07da2334992af3225c57eaefca", privateKeyHex21) } @Test fun fromSeedNip06TestVector1() { - val privateKeyHex = Nip06().privateKeyFromMnemonic(menemonic1).toHexKey() + val privateKeyHex = nip06.privateKeyFromMnemonic(menemonic1).toHexKey() assertEquals("c15d739894c81a2fcfd3a2df85a0d2c0dbc47a280d092799f144d73d7ae78add", privateKeyHex) - val privateKeyHex21 = Nip06().privateKeyFromMnemonic(menemonic1, 42).toHexKey() + val privateKeyHex21 = nip06.privateKeyFromMnemonic(menemonic1, 42).toHexKey() assertEquals("ad993054383da74e955f8b86346365b5ffd6575992e1de3738dda9f94407052b", privateKeyHex21) } @Test @Ignore("Snort is not correctly implemented") fun fromSeedNip06FromSnort() { - val privateKeyNsec = Nip06().privateKeyFromMnemonic(snortTest).toHexKey() + val privateKeyNsec = nip06.privateKeyFromMnemonic(snortTest).toHexKey() assertEquals("nsec1ppw9ltr2x9qwg9a2qnmgv98tfruy2ejnja7me76mwmsreu3s8u2sscj5nt", privateKeyNsec) } } diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/NIP44v2Test.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip44/NIP44v2Test.kt similarity index 97% rename from quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/NIP44v2Test.kt rename to quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip44/NIP44v2Test.kt index bdd53082e..c2bffa2ee 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/NIP44v2Test.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip44/NIP44v2Test.kt @@ -18,12 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz.crypto +package com.vitorpamplona.quartz.crypto.nip44 import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.hexToByteArray import com.vitorpamplona.quartz.encoders.toHexKey import fr.acinq.secp256k1.Secp256k1 @@ -79,8 +80,7 @@ class NIP44v2Test { v.plaintext!!, conversationKey1, v.nonce!!.hexToByteArray(), - ) - .encodePayload() + ).encodePayload() assertEquals(v.payload, ciphertext) @@ -107,8 +107,7 @@ class NIP44v2Test { plaintext, conversationKey, v.nonce!!.hexToByteArray(), - ) - .encodePayload() + ).encodePayload() assertEquals(v.payloadSha256, sha256Hex(ciphertext.toByteArray(Charsets.UTF_8))) diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/NIP49Test.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip49/NIP49Test.kt similarity index 99% rename from quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/NIP49Test.kt rename to quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip49/NIP49Test.kt index ef750ca52..ca6a2700b 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/NIP49Test.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip49/NIP49Test.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz.crypto +package com.vitorpamplona.quartz.crypto.nip49 import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.encoders.toHexKey diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/HexEncodingTest.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/encoders/HexEncodingTest.kt similarity index 79% rename from quartz/src/androidTest/java/com/vitorpamplona/quartz/HexEncodingTest.kt rename to quartz/src/androidTest/java/com/vitorpamplona/quartz/encoders/HexEncodingTest.kt index 2bb95b09a..5d6451b54 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/HexEncodingTest.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/encoders/HexEncodingTest.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz +package com.vitorpamplona.quartz.encoders import com.vitorpamplona.quartz.crypto.CryptoUtils import org.junit.Assert.assertEquals @@ -31,8 +31,8 @@ class HexEncodingTest { fun testHexEncodeDecodeOurs() { assertEquals( testHex, - com.vitorpamplona.quartz.encoders.Hex.encode( - com.vitorpamplona.quartz.encoders.Hex.decode(testHex), + Hex.encode( + Hex.decode(testHex), ), ) } @@ -42,7 +42,8 @@ class HexEncodingTest { assertEquals( testHex, fr.acinq.secp256k1.Hex.encode( - fr.acinq.secp256k1.Hex.decode(testHex), + fr.acinq.secp256k1.Hex + .decode(testHex), ), ) } @@ -51,14 +52,17 @@ class HexEncodingTest { fun testRandoms() { for (i in 0..1000) { val bytes = CryptoUtils.privkeyCreate() - val hex = fr.acinq.secp256k1.Hex.encode(bytes) + val hex = + fr.acinq.secp256k1.Hex + .encode(bytes) assertEquals( - fr.acinq.secp256k1.Hex.encode(bytes), - com.vitorpamplona.quartz.encoders.Hex.encode(bytes), + fr.acinq.secp256k1.Hex + .encode(bytes), + Hex.encode(bytes), ) assertEquals( bytes.toList(), - com.vitorpamplona.quartz.encoders.Hex.decode(hex).toList(), + Hex.decode(hex).toList(), ) } } diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/LnInvoiceUtilTest.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/encoders/LnInvoiceUtilTest.kt similarity index 96% rename from quartz/src/androidTest/java/com/vitorpamplona/quartz/LnInvoiceUtilTest.kt rename to quartz/src/androidTest/java/com/vitorpamplona/quartz/encoders/LnInvoiceUtilTest.kt index 9c570927e..0c3f8e6da 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/LnInvoiceUtilTest.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/encoders/LnInvoiceUtilTest.kt @@ -18,10 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz +package com.vitorpamplona.quartz.encoders import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.vitorpamplona.quartz.encoders.LnInvoiceUtil import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/NIP19EmbedTests.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/encoders/NIP19EmbedTests.kt similarity index 97% rename from quartz/src/androidTest/java/com/vitorpamplona/quartz/NIP19EmbedTests.kt rename to quartz/src/androidTest/java/com/vitorpamplona/quartz/encoders/NIP19EmbedTests.kt index 57a3beb72..aafe64b5b 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/NIP19EmbedTests.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/encoders/NIP19EmbedTests.kt @@ -18,14 +18,10 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz +package com.vitorpamplona.quartz.encoders import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.crypto.KeyPair -import com.vitorpamplona.quartz.encoders.Hex -import com.vitorpamplona.quartz.encoders.Nip19Bech32 -import com.vitorpamplona.quartz.encoders.decodePrivateKeyAsHexOrNull -import com.vitorpamplona.quartz.encoders.hexToByteArray import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.FhirResourceEvent import com.vitorpamplona.quartz.events.TextNoteEvent diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/ChatroomKeyTest.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/events/ChatroomKeyTest.kt similarity index 95% rename from quartz/src/androidTest/java/com/vitorpamplona/quartz/ChatroomKeyTest.kt rename to quartz/src/androidTest/java/com/vitorpamplona/quartz/events/ChatroomKeyTest.kt index 2e3758c28..58f679a98 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/ChatroomKeyTest.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/events/ChatroomKeyTest.kt @@ -18,10 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz +package com.vitorpamplona.quartz.events import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.vitorpamplona.quartz.events.ChatroomKey import kotlinx.collections.immutable.persistentSetOf import org.junit.Assert.assertEquals import org.junit.Test diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/CitationTests.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/events/CitationTests.kt similarity index 96% rename from quartz/src/androidTest/java/com/vitorpamplona/quartz/CitationTests.kt rename to quartz/src/androidTest/java/com/vitorpamplona/quartz/events/CitationTests.kt index 2a080e954..5a5b7bf7c 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/CitationTests.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/events/CitationTests.kt @@ -18,11 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz +package com.vitorpamplona.quartz.events import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.vitorpamplona.quartz.events.Event -import com.vitorpamplona.quartz.events.TextNoteEvent import junit.framework.TestCase.assertEquals import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/EventSigCheck.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/events/EventSigCheck.kt similarity index 97% rename from quartz/src/androidTest/java/com/vitorpamplona/quartz/EventSigCheck.kt rename to quartz/src/androidTest/java/com/vitorpamplona/quartz/events/EventSigCheck.kt index 74dbdfc54..55b733111 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/EventSigCheck.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/events/EventSigCheck.kt @@ -18,10 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz +package com.vitorpamplona.quartz.events import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.vitorpamplona.quartz.events.Event import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/GiftWrapEventTest.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/events/GiftWrapEventTest.kt similarity index 96% rename from quartz/src/androidTest/java/com/vitorpamplona/quartz/GiftWrapEventTest.kt rename to quartz/src/androidTest/java/com/vitorpamplona/quartz/events/GiftWrapEventTest.kt index c2aab0d1a..4fc96e6e2 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/GiftWrapEventTest.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/events/GiftWrapEventTest.kt @@ -18,18 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz +package com.vitorpamplona.quartz.events import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.Hex import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.hexToByteArray -import com.vitorpamplona.quartz.events.ChatMessageEvent -import com.vitorpamplona.quartz.events.Event -import com.vitorpamplona.quartz.events.GiftWrapEvent -import com.vitorpamplona.quartz.events.NIP17Factory -import com.vitorpamplona.quartz.events.SealedGossipEvent import com.vitorpamplona.quartz.signers.NostrSignerInternal import org.junit.Assert.assertEquals import org.junit.Assert.assertNotEquals @@ -276,14 +271,12 @@ class GiftWrapEventTest { assertTrue(unwrappedMsgForReceiverByReceiver is SealedGossipEvent) if (unwrappedMsgForReceiverByReceiver is SealedGossipEvent) { - unwrappedMsgForReceiverByReceiver.cachedGossip(receiver) { - unwrappedGossipToReceiverByReceiver -> + unwrappedMsgForReceiverByReceiver.cachedGossip(receiver) { unwrappedGossipToReceiverByReceiver -> assertEquals("Hi There!", unwrappedGossipToReceiverByReceiver?.content) countDownDecryptLatch.countDown() } - unwrappedMsgForReceiverByReceiver.cachedGossip(sender) { unwrappedGossipToReceiverBySender, - -> + unwrappedMsgForReceiverByReceiver.cachedGossip(sender) { unwrappedGossipToReceiverBySender -> fail( "Should not be able to decrypt msg for the receiver by the receiver but decrypted with the sender", ) @@ -422,13 +415,11 @@ class GiftWrapEventTest { assertEquals(SealedGossipEvent.KIND, unwrappedMsgForSenderBySender.kind) if (unwrappedMsgForSenderBySender is SealedGossipEvent) { - unwrappedMsgForSenderBySender.cachedGossip(receiverA) { unwrappedGossipToSenderByReceiverA, - -> + unwrappedMsgForSenderBySender.cachedGossip(receiverA) { unwrappedGossipToSenderByReceiverA -> fail() } - unwrappedMsgForSenderBySender.cachedGossip(receiverB) { unwrappedGossipToSenderByReceiverB, - -> + unwrappedMsgForSenderBySender.cachedGossip(receiverB) { unwrappedGossipToSenderByReceiverB -> fail() } @@ -459,21 +450,18 @@ class GiftWrapEventTest { assertEquals(SealedGossipEvent.KIND, unwrappedMsgForReceiverAByReceiverA.kind) if (unwrappedMsgForReceiverAByReceiverA is SealedGossipEvent) { - unwrappedMsgForReceiverAByReceiverA.cachedGossip(receiverA) { - unwrappedGossipToReceiverAByReceiverA -> + unwrappedMsgForReceiverAByReceiverA.cachedGossip(receiverA) { unwrappedGossipToReceiverAByReceiverA -> assertEquals( "Who is going to the party tonight?", unwrappedGossipToReceiverAByReceiverA.content, ) } - unwrappedMsgForReceiverAByReceiverA.cachedGossip(sender) { - unwrappedGossipToReceiverABySender -> + unwrappedMsgForReceiverAByReceiverA.cachedGossip(sender) { unwrappedGossipToReceiverABySender -> fail() } - unwrappedMsgForReceiverAByReceiverA.cachedGossip(receiverB) { - unwrappedGossipToReceiverAByReceiverB -> + unwrappedMsgForReceiverAByReceiverA.cachedGossip(receiverB) { unwrappedGossipToReceiverAByReceiverB -> fail() } } @@ -495,13 +483,11 @@ class GiftWrapEventTest { assertEquals(SealedGossipEvent.KIND, unwrappedMsgForReceiverBByReceiverB.kind) if (unwrappedMsgForReceiverBByReceiverB is SealedGossipEvent) { - unwrappedMsgForReceiverBByReceiverB.cachedGossip(receiverA) { - unwrappedGossipToReceiverBByReceiverA -> + unwrappedMsgForReceiverBByReceiverB.cachedGossip(receiverA) { unwrappedGossipToReceiverBByReceiverA -> fail() } - unwrappedMsgForReceiverBByReceiverB.cachedGossip(receiverB) { - unwrappedGossipToReceiverBByReceiverB -> + unwrappedMsgForReceiverBByReceiverB.cachedGossip(receiverB) { unwrappedGossipToReceiverBByReceiverB -> assertEquals( "Who is going to the party tonight?", unwrappedGossipToReceiverBByReceiverB.content, @@ -510,8 +496,7 @@ class GiftWrapEventTest { countDownDecryptLatch.countDown() } - unwrappedMsgForReceiverBByReceiverB.cachedGossip(sender) { - unwrappedGossipToReceiverBBySender -> + unwrappedMsgForReceiverBByReceiverB.cachedGossip(sender) { unwrappedGossipToReceiverBBySender -> fail() } } @@ -538,8 +523,7 @@ class GiftWrapEventTest { ] ] } - """ - .trimIndent() + """.trimIndent() var gossip: Event? = null @@ -573,8 +557,7 @@ class GiftWrapEventTest { ] ] } - """ - .trimIndent() + """.trimIndent() val privateKey = "409ff7654141eaa16cd2161fe5bd127aeaef71f270c67587474b78998a8e3533" @@ -612,8 +595,7 @@ class GiftWrapEventTest { "wss://relay.damus.io/" ] } - """ - .trimIndent() + """.trimIndent() val privateKey = "09e0051fdf5fdd9dd7a54713583006442cbdbf87bdcdab1a402f26e527d56771" var gossip: Event? = null @@ -647,8 +629,7 @@ class GiftWrapEventTest { ] ] } - """ - .trimIndent() + """.trimIndent() val privateKey = "09e0051fdf5fdd9dd7a54713583006442cbdbf87bdcdab1a402f26e527d56771" @@ -687,8 +668,7 @@ class GiftWrapEventTest { "id": "d9fc85ece892ce45ffa737b3ddc0f8b752623181d75363b966191f8c03d2debe", "sig": "1b20416b83f4b5b8eead11e29c185f46b5e76d1960e4505210ddd00f7a6973cc11268f52a8989e3799b774d5f3a55db95bed4d66a1b6e88ab54becec5c771c17" } - """ - .trimIndent() + """.trimIndent() val privateKey = "7dd22cafc512c0bc363a259f6dcda515b13ae3351066d7976fd0bb79cbd0d700" @@ -753,8 +733,7 @@ class GiftWrapEventTest { "id": "ae625fd43612127d63bfd1967ba32ae915100842a205fc2c3b3fc02ab3827f08", "sig": "2807a7ab5728984144676fd34686267cbe6fe38bc2f65a3640ba9243c13e8a1ae5a9a051e8852aa0c997a3623d7fa066cf2073a233c6d7db46fb1a0d4c01e5a3" } - """ - .trimIndent() + """.trimIndent() val wrap = Event.fromJson(msg) as GiftWrapEvent wrap.checkSignature() diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/PrivateZapTests.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/events/PrivateZapTests.kt similarity index 97% rename from quartz/src/androidTest/java/com/vitorpamplona/quartz/PrivateZapTests.kt rename to quartz/src/androidTest/java/com/vitorpamplona/quartz/events/PrivateZapTests.kt index a13c8768d..5b5493850 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/PrivateZapTests.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/events/PrivateZapTests.kt @@ -18,15 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz +package com.vitorpamplona.quartz.events import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.Hex import com.vitorpamplona.quartz.encoders.toHexKey -import com.vitorpamplona.quartz.events.Event -import com.vitorpamplona.quartz.events.LnZapEvent -import com.vitorpamplona.quartz.events.LnZapRequestEvent import com.vitorpamplona.quartz.events.LnZapRequestEvent.Companion.createEncryptionPrivateKey import com.vitorpamplona.quartz.signers.NostrSignerInternal import junit.framework.TestCase.assertNotNull diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/OtsTest.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/ots/OtsTest.kt similarity index 99% rename from quartz/src/androidTest/java/com/vitorpamplona/quartz/OtsTest.kt rename to quartz/src/androidTest/java/com/vitorpamplona/quartz/ots/OtsTest.kt index 838c279ca..6471fa8f7 100644 --- a/quartz/src/androidTest/java/com/vitorpamplona/quartz/OtsTest.kt +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/ots/OtsTest.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz +package com.vitorpamplona.quartz.ots import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.crypto.KeyPair diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/CryptoUtils.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/CryptoUtils.kt index 64d0efd82..da9450d6a 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/CryptoUtils.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/CryptoUtils.kt @@ -20,35 +20,32 @@ */ package com.vitorpamplona.quartz.crypto -import android.util.Log +import com.vitorpamplona.quartz.crypto.nip01.Nip01 +import com.vitorpamplona.quartz.crypto.nip04.Nip04 +import com.vitorpamplona.quartz.crypto.nip06.Nip06 +import com.vitorpamplona.quartz.crypto.nip44.Nip44 +import com.vitorpamplona.quartz.crypto.nip44.Nip44v2 +import com.vitorpamplona.quartz.crypto.nip49.Nip49 import com.vitorpamplona.quartz.encoders.HexKey -import com.vitorpamplona.quartz.events.Event import fr.acinq.secp256k1.Secp256k1 -import java.security.MessageDigest import java.security.SecureRandom -import java.util.Base64 object CryptoUtils { private val secp256k1 = Secp256k1.get() private val random = SecureRandom() - private val nip04 = Nip04(secp256k1, random) - private val nip44v1 = Nip44v1(secp256k1, random) - private val nip44v2 = Nip44v2(secp256k1, random) - private val nip49 = Nip49(secp256k1, random) + public val nip01 = Nip01(secp256k1, random) + public val nip06 = Nip06(secp256k1) + public val nip04 = Nip04(secp256k1, random) + public val nip44 = Nip44(secp256k1, random, nip04) + public val nip49 = Nip49(secp256k1, random) fun clearCache() { nip04.clearCache() - nip44v1.clearCache() - nip44v2.clearCache() + nip44.clearCache() } - fun randomInt(bound: Int): Int { - return random.nextInt(bound) - } - - /** Provides a 32B "private key" aka random number */ - fun privkeyCreate() = random(32) + fun randomInt(bound: Int): Int = random.nextInt(bound) fun random(size: Int): ByteArray { val bytes = ByteArray(size) @@ -56,39 +53,32 @@ object CryptoUtils { return bytes } - fun pubkeyCreateBitcoin(privKey: ByteArray) = secp256k1.pubKeyCompress(secp256k1.pubkeyCreate(privKey)) + /** Provides a 32B "private key" aka random number */ + fun privkeyCreate() = nip01.privkeyCreate() - fun pubkeyCreate(privKey: ByteArray) = secp256k1.pubKeyCompress(secp256k1.pubkeyCreate(privKey)).copyOfRange(1, 33) - - fun isPrivKeyValid(il: ByteArray): Boolean { - return secp256k1.secKeyVerify(il) - } + fun pubkeyCreate(privKey: ByteArray) = nip01.pubkeyCreate(privKey) fun signString( message: String, privKey: ByteArray, auxrand32: ByteArray = random(32), - ): ByteArray { - return sign(sha256(message.toByteArray()), privKey, auxrand32) - } + ): ByteArray = nip01.signString(message, privKey, auxrand32) fun sign( data: ByteArray, privKey: ByteArray, auxrand32: ByteArray? = null, - ): ByteArray = secp256k1.signSchnorr(data, privKey, auxrand32) + ): ByteArray = nip01.sign(data, privKey, auxrand32) fun verifySignature( signature: ByteArray, hash: ByteArray, pubKey: ByteArray, - ): Boolean { - return secp256k1.verifySchnorr(signature, hash, pubKey) - } + ): Boolean = nip01.verify(signature, hash, pubKey) fun sha256(data: ByteArray): ByteArray { // Creates a new buffer every time - return MessageDigest.getInstance("SHA-256").digest(data) + return nip01.sha256(data) } /** NIP 04 Utils */ @@ -96,189 +86,84 @@ object CryptoUtils { msg: String, privateKey: ByteArray, pubKey: ByteArray, - ): String { - return nip04.encrypt(msg, privateKey, pubKey) - } + ): String = nip04.encrypt(msg, privateKey, pubKey) fun encryptNIP04( msg: String, sharedSecret: ByteArray, - ): Nip04.EncryptedInfo { - return nip04.encrypt(msg, sharedSecret) - } + ): Nip04.EncryptedInfo = nip04.encrypt(msg, sharedSecret) fun decryptNIP04( msg: String, privateKey: ByteArray, pubKey: ByteArray, - ): String { - return nip04.decrypt(msg, privateKey, pubKey) - } + ): String = nip04.decrypt(msg, privateKey, pubKey) fun decryptNIP04( encryptedInfo: Nip04.EncryptedInfo, privateKey: ByteArray, pubKey: ByteArray, - ): String { - return nip04.decrypt(encryptedInfo, privateKey, pubKey) - } + ): String = nip04.decrypt(encryptedInfo, privateKey, pubKey) fun decryptNIP04( msg: String, sharedSecret: ByteArray, - ): String { - return nip04.decrypt(msg, sharedSecret) - } + ): String = nip04.decrypt(msg, sharedSecret) private fun decryptNIP04( cipher: String, nonce: String, sharedSecret: ByteArray, - ): String { - return nip04.decrypt(cipher, nonce, sharedSecret) - } + ): String = nip04.decrypt(cipher, nonce, sharedSecret) private fun decryptNIP04( encryptedMsg: ByteArray, iv: ByteArray, sharedSecret: ByteArray, - ): String { - return nip04.decrypt(encryptedMsg, iv, sharedSecret) - } + ): String = nip04.decrypt(encryptedMsg, iv, sharedSecret) fun getSharedSecretNIP04( privateKey: ByteArray, pubKey: ByteArray, - ): ByteArray { - return nip04.getSharedSecret(privateKey, pubKey) - } + ): ByteArray = nip04.getSharedSecret(privateKey, pubKey) fun computeSharedSecretNIP04( privateKey: ByteArray, pubKey: ByteArray, - ): ByteArray { - return nip04.computeSharedSecret(privateKey, pubKey) - } + ): ByteArray = nip04.computeSharedSecret(privateKey, pubKey) - /** NIP 44v1 Utils */ - fun encryptNIP44v1( + /** NIP 06 Utils */ + fun isValidMnemonic(mnemonic: String): Boolean = nip06.isValidMnemonic(mnemonic) + + fun privateKeyFromMnemonic( + mnemonic: String, + account: Long = 0, + ) = nip06.privateKeyFromMnemonic(mnemonic, account) + + /** NIP 44 Utils */ + fun getSharedSecretNIP44( + privateKey: ByteArray, + pubKey: ByteArray, + ): ByteArray = nip44.getSharedSecret(privateKey, pubKey) + + fun computeSharedSecretNIP44( + privateKey: ByteArray, + pubKey: ByteArray, + ): ByteArray = nip44.computeSharedSecret(privateKey, pubKey) + + fun encryptNIP44( msg: String, privateKey: ByteArray, pubKey: ByteArray, - ): Nip44v1.EncryptedInfo { - return nip44v1.encrypt(msg, privateKey, pubKey) - } - - fun encryptNIP44v1( - msg: String, - sharedSecret: ByteArray, - ): Nip44v1.EncryptedInfo { - return nip44v1.encrypt(msg, sharedSecret) - } - - fun decryptNIP44v1( - encryptedInfo: Nip44v1.EncryptedInfo, - privateKey: ByteArray, - pubKey: ByteArray, - ): String? { - return nip44v1.decrypt(encryptedInfo, privateKey, pubKey) - } - - fun decryptNIP44v1( - encryptedInfo: String, - privateKey: ByteArray, - pubKey: ByteArray, - ): String? { - return nip44v1.decrypt(encryptedInfo, privateKey, pubKey) - } - - fun decryptNIP44v1( - encryptedInfo: Nip44v1.EncryptedInfo, - sharedSecret: ByteArray, - ): String? { - return nip44v1.decrypt(encryptedInfo, sharedSecret) - } - - fun getSharedSecretNIP44v1( - privateKey: ByteArray, - pubKey: ByteArray, - ): ByteArray { - return nip44v1.getSharedSecret(privateKey, pubKey) - } - - fun computeSharedSecretNIP44v1( - privateKey: ByteArray, - pubKey: ByteArray, - ): ByteArray { - return nip44v1.computeSharedSecret(privateKey, pubKey) - } - - /** NIP 44v2 Utils */ - fun encryptNIP44v2( - msg: String, - privateKey: ByteArray, - pubKey: ByteArray, - ): Nip44v2.EncryptedInfo { - return nip44v2.encrypt(msg, privateKey, pubKey) - } - - fun encryptNIP44v2( - msg: String, - sharedSecret: ByteArray, - ): Nip44v2.EncryptedInfo { - return nip44v2.encrypt(msg, sharedSecret) - } - - fun decryptNIP44v2( - encryptedInfo: Nip44v2.EncryptedInfo, - privateKey: ByteArray, - pubKey: ByteArray, - ): String? { - return nip44v2.decrypt(encryptedInfo, privateKey, pubKey) - } - - fun decryptNIP44v2( - encryptedInfo: String, - privateKey: ByteArray, - pubKey: ByteArray, - ): String? { - return nip44v2.decrypt(encryptedInfo, privateKey, pubKey) - } - - fun decryptNIP44v2( - encryptedInfo: Nip44v2.EncryptedInfo, - sharedSecret: ByteArray, - ): String? { - return nip44v2.decrypt(encryptedInfo, sharedSecret) - } - - fun getSharedSecretNIP44v2( - privateKey: ByteArray, - pubKey: ByteArray, - ): ByteArray { - return nip44v2.getConversationKey(privateKey, pubKey) - } - - fun computeSharedSecretNIP44v2( - privateKey: ByteArray, - pubKey: ByteArray, - ): ByteArray { - return nip44v2.computeConversationKey(privateKey, pubKey) - } + ): Nip44v2.EncryptedInfo = nip44.encrypt(msg, privateKey, pubKey) fun decryptNIP44( payload: String, privateKey: ByteArray, pubKey: ByteArray, - ): String? { - if (payload.isEmpty()) return null - return if (payload[0] == '{') { - decryptNIP44FromJackson(payload, privateKey, pubKey) - } else { - decryptNIP44FromBase64(payload, privateKey, pubKey) - } - } + ): String? = nip44.decrypt(payload, privateKey, pubKey) + /** NIP 49 Utils */ fun decryptNIP49( payload: String, password: String, @@ -290,87 +175,5 @@ object CryptoUtils { fun encryptNIP49( key: HexKey, password: String, - ): String? { - return nip49.encrypt(key, password, 16, Nip49.EncryptedInfo.CLIENT_DOES_NOT_TRACK) - } - - class EncryptedInfoString( - val ciphertext: String, - val nonce: String, - val v: Int, - val mac: String?, - ) - - fun decryptNIP44FromJackson( - json: String, - privateKey: ByteArray, - pubKey: ByteArray, - ): String? { - return try { - val info = Event.mapper.readValue(json, EncryptedInfoString::class.java) - - when (info.v) { - Nip04.EncryptedInfo.V -> { - val encryptedInfo = - Nip04.EncryptedInfo( - ciphertext = Base64.getDecoder().decode(info.ciphertext), - nonce = Base64.getDecoder().decode(info.nonce), - ) - decryptNIP04(encryptedInfo, privateKey, pubKey) - } - Nip44v1.EncryptedInfo.V -> { - val encryptedInfo = - Nip44v1.EncryptedInfo( - ciphertext = Base64.getDecoder().decode(info.ciphertext), - nonce = Base64.getDecoder().decode(info.nonce), - ) - decryptNIP44v1(encryptedInfo, privateKey, pubKey) - } - Nip44v2.EncryptedInfo.V -> { - val encryptedInfo = - Nip44v2.EncryptedInfo( - ciphertext = Base64.getDecoder().decode(info.ciphertext), - nonce = Base64.getDecoder().decode(info.nonce), - mac = Base64.getDecoder().decode(info.mac), - ) - decryptNIP44v2(encryptedInfo, privateKey, pubKey) - } - else -> null - } - } catch (e: Exception) { - Log.e("CryptoUtils", "Could not identify the version for NIP44 payload $json") - e.printStackTrace() - null - } - } - - fun decryptNIP44FromBase64( - payload: String, - privateKey: ByteArray, - pubKey: ByteArray, - ): String? { - if (payload.isEmpty()) return null - - return try { - val byteArray = Base64.getDecoder().decode(payload) - - when (byteArray[0].toInt()) { - Nip04.EncryptedInfo.V -> decryptNIP04(payload, privateKey, pubKey) - Nip44v1.EncryptedInfo.V -> decryptNIP44v1(payload, privateKey, pubKey) - Nip44v2.EncryptedInfo.V -> decryptNIP44v2(payload, privateKey, pubKey) - else -> null - } - } catch (e: Exception) { - Log.e("CryptoUtils", "Could not identify the version for NIP44 payload $payload") - e.printStackTrace() - null - } - } - - fun sum( - first: ByteArray, - second: ByteArray, - ): ByteArray { - return secp256k1.privKeyTweakAdd(first, second) - } + ): String = nip49.encrypt(key, password) } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip01/Nip01.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip01/Nip01.kt new file mode 100644 index 000000000..3bbf58ea3 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip01/Nip01.kt @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.crypto.nip01 + +import com.vitorpamplona.quartz.crypto.CryptoUtils +import com.vitorpamplona.quartz.crypto.CryptoUtils.random +import fr.acinq.secp256k1.Secp256k1 +import java.security.MessageDigest +import java.security.SecureRandom + +class Nip01( + val secp256k1: Secp256k1, + val random: SecureRandom, +) { + /** Provides a 32B "private key" aka random number */ + fun privkeyCreate() = random(32) + + fun pubkeyCreate(privKey: ByteArray) = secp256k1.pubKeyCompress(secp256k1.pubkeyCreate(privKey)).copyOfRange(1, 33) + + fun sign( + data: ByteArray, + privKey: ByteArray, + auxrand32: ByteArray? = null, + ): ByteArray = secp256k1.signSchnorr(data, privKey, auxrand32) + + fun verify( + signature: ByteArray, + hash: ByteArray, + pubKey: ByteArray, + ): Boolean = secp256k1.verifySchnorr(signature, hash, pubKey) + + fun sha256(data: ByteArray): ByteArray { + // Creates a new buffer every time + return MessageDigest.getInstance("SHA-256").digest(data) + } + + fun signString( + message: String, + privKey: ByteArray, + auxrand32: ByteArray = random(32), + ): ByteArray = sign(CryptoUtils.sha256(message.toByteArray()), privKey, auxrand32) +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip04.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip04/Nip04.kt similarity index 93% rename from quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip04.kt rename to quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip04/Nip04.kt index 857432663..5d242dd66 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip04.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip04/Nip04.kt @@ -18,9 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz.crypto +package com.vitorpamplona.quartz.crypto.nip04 import android.util.Log +import com.vitorpamplona.quartz.crypto.SharedKeyCache +import com.vitorpamplona.quartz.crypto.nip44.Nip44v1 import com.vitorpamplona.quartz.encoders.Hex import fr.acinq.secp256k1.Secp256k1 import java.security.SecureRandom @@ -29,7 +31,10 @@ import javax.crypto.Cipher import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec -class Nip04(val secp256k1: Secp256k1, val random: SecureRandom) { +class Nip04( + val secp256k1: Secp256k1, + val random: SecureRandom, +) { private val sharedKeyCache = SharedKeyCache() private val h02 = Hex.decode("02") @@ -41,9 +46,7 @@ class Nip04(val secp256k1: Secp256k1, val random: SecureRandom) { msg: String, privateKey: ByteArray, pubKey: ByteArray, - ): String { - return encrypt(msg, getSharedSecret(privateKey, pubKey)).encodeToNIP04() - } + ): String = encrypt(msg, getSharedSecret(privateKey, pubKey)).encodeToNIP04() fun encrypt( msg: String, @@ -146,8 +149,8 @@ class Nip04(val secp256k1: Secp256k1, val random: SecureRandom) { } } - fun decodeFromNIP04(payload: String): EncryptedInfo? { - return try { + fun decodeFromNIP04(payload: String): EncryptedInfo? = + try { val parts = payload.split("?iv=") EncryptedInfo( ciphertext = Base64.getDecoder().decode(parts[0]), @@ -157,15 +160,14 @@ class Nip04(val secp256k1: Secp256k1, val random: SecureRandom) { Log.w("NIP04", "Unable to Parse encrypted payload: $payload") null } - } } - fun encodePayload(): String { - return Base64.getEncoder() + fun encodePayload(): String = + Base64 + .getEncoder() .encodeToString( byteArrayOf(V.toByte()) + nonce + ciphertext, ) - } fun encodeToNIP04(): String { val nonce = Base64.getEncoder().encodeToString(nonce) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Bip32SeedDerivation.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Bip32SeedDerivation.kt index d82899894..8c7bbeed5 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Bip32SeedDerivation.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Bip32SeedDerivation.kt @@ -20,14 +20,16 @@ */ package com.vitorpamplona.quartz.crypto.nip06 -import com.vitorpamplona.quartz.crypto.CryptoUtils +import fr.acinq.secp256k1.Secp256k1 import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec /* Simplified from: https://github.com/ACINQ/bitcoin-kmp/ */ -object Bip32SeedDerivation { +class Bip32SeedDerivation( + val secp256k1: Secp256k1, +) { class ExtendedPrivateKey( val secretkeybytes: ByteArray, val chaincode: ByteArray, @@ -53,6 +55,15 @@ object Bip32SeedDerivation { return mac.doFinal(data) } + fun isPrivKeyValid(il: ByteArray): Boolean = secp256k1.secKeyVerify(il) + + fun pubkeyCreateBitcoin(privKey: ByteArray) = secp256k1.pubKeyCompress(secp256k1.pubkeyCreate(privKey)) + + fun sum( + first: ByteArray, + second: ByteArray, + ): ByteArray = secp256k1.privKeyTweakAdd(first, second) + fun derivePrivateKey( parent: ExtendedPrivateKey, index: Long, @@ -62,17 +73,17 @@ object Bip32SeedDerivation { val data = arrayOf(0.toByte()).toByteArray() + parent.secretkeybytes + writeInt32BE(index.toInt()) hmac512(parent.chaincode, data) } else { - val data = CryptoUtils.pubkeyCreateBitcoin(parent.secretkeybytes) + writeInt32BE(index.toInt()) + val data = pubkeyCreateBitcoin(parent.secretkeybytes) + writeInt32BE(index.toInt()) hmac512(parent.chaincode, data) } val il = i.take(32).toByteArray() val ir = i.takeLast(32).toByteArray() - require(CryptoUtils.isPrivKeyValid(il)) { "cannot generate child private key: IL is invalid" } + require(isPrivKeyValid(il)) { "cannot generate child private key: IL is invalid" } - val key = CryptoUtils.sum(il, parent.secretkeybytes) + val key = sum(il, parent.secretkeybytes) - require(CryptoUtils.isPrivKeyValid(key)) { "cannot generate child private key: resulting private key is invalid" } + require(isPrivKeyValid(key)) { "cannot generate child private key: resulting private key is invalid" } return ExtendedPrivateKey(key, ir) } @@ -94,7 +105,7 @@ object Bip32SeedDerivation { fun derivePrivateKey( parent: ExtendedPrivateKey, chain: List, - ): ExtendedPrivateKey = chain.fold(parent, Bip32SeedDerivation::derivePrivateKey) + ): ExtendedPrivateKey = chain.fold(parent, this::derivePrivateKey) fun derivePrivateKey( parent: ExtendedPrivateKey, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Bip39Mnemonics.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Bip39Mnemonics.kt index a52e50175..d92d790ba 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Bip39Mnemonics.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Bip39Mnemonics.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.quartz.crypto.nip06 -import com.vitorpamplona.quartz.crypto.CryptoUtils -import com.vitorpamplona.quartz.crypto.PBKDF +import com.vitorpamplona.quartz.crypto.nip49.PBKDF +import java.security.MessageDigest // CODE FROM: https://github.com/ACINQ/bitcoin-kmp/ @@ -37,6 +37,11 @@ object Bip39Mnemonics { return zeroes + digits } + fun sha256(data: ByteArray): ByteArray { + // Creates a new buffer every time + return MessageDigest.getInstance("SHA-256").digest(data) + } + private fun toBinary(x: ByteArray): List = x.map(Bip39Mnemonics::toBinary).flatten() private fun fromBinary(bin: List): Int = bin.fold(0) { acc, flag -> if (flag) 2 * acc + 1 else 2 * acc } @@ -45,13 +50,12 @@ object Bip39Mnemonics { items: List, size: Int, acc: List> = emptyList(), - ): List> { - return when { + ): List> = + when { items.isEmpty() -> acc items.size < size -> acc + listOf(items) else -> group(items.drop(size), size, acc + listOf(items.take(size))) } - } /** * @param mnemonics list of mnemonic words @@ -80,20 +84,19 @@ object Bip39Mnemonics { val databits = bits.subList(0, bitlength) val checksumbits = bits.subList(bitlength, bits.size) val data = group(databits, 8).map { fromBinary(it) }.map { it.toByte() }.toByteArray() - val check = toBinary(CryptoUtils.sha256(data)).take(data.size / 4) + val check = toBinary(sha256(data)).take(data.size / 4) require(check == checksumbits) { "invalid checksum" } } fun validate(mnemonics: String): Unit = validate(mnemonics.split(" ")) - fun isValid(mnemonics: String): Boolean { - return try { + fun isValid(mnemonics: String): Boolean = + try { validate(mnemonics) true } catch (e: Exception) { false } - } /** * BIP39 entropy encoding @@ -108,7 +111,7 @@ object Bip39Mnemonics { wordlist: Array, ): List { require(wordlist.size == 2048) { "invalid word list (size should be 2048)" } - val digits = toBinary(entropy) + toBinary(CryptoUtils.sha256(entropy)).take(entropy.size / 4) + val digits = toBinary(entropy) + toBinary(sha256(entropy)).take(entropy.size / 4) return group(digits, 11).map(Bip39Mnemonics::fromBinary).map { wordlist[it] } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Nip06.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Nip06.kt index d5628e4bc..8bb79e827 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Nip06.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip06/Nip06.kt @@ -20,29 +20,31 @@ */ package com.vitorpamplona.quartz.crypto.nip06 -class Nip06 { +import fr.acinq.secp256k1.Secp256k1 + +class Nip06( + val secp256k1: Secp256k1, +) { + val derivation = Bip32SeedDerivation(secp256k1) + // m/44'/1237'/'/0/0 private val nip6Base: KeyPath = KeyPath("") .derive(Hardener.hardened(44L)) .derive(Hardener.hardened(1237L)) - private fun nip6Path(account: Long): KeyPath { - return nip6Base.derive(Hardener.hardened(account)) + private fun nip6Path(account: Long): KeyPath = + nip6Base + .derive(Hardener.hardened(account)) .derive(0L) .derive(0L) - } - fun isValidMnemonic(mnemonic: String): Boolean { - return Bip39Mnemonics.isValid(mnemonic) - } + fun isValidMnemonic(mnemonic: String): Boolean = Bip39Mnemonics.isValid(mnemonic) fun privateKeyFromSeed( seed: ByteArray, account: Long = 0, - ): ByteArray { - return Bip32SeedDerivation.derivePrivateKey(Bip32SeedDerivation.generate(seed), nip6Path(account)) - } + ): ByteArray = derivation.derivePrivateKey(derivation.generate(seed), nip6Path(account)) fun privateKeyFromMnemonic( mnemonic: String, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/Hkdf.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Hkdf.kt similarity index 94% rename from quartz/src/main/java/com/vitorpamplona/quartz/crypto/Hkdf.kt rename to quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Hkdf.kt index 55db69dde..258670df1 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/Hkdf.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Hkdf.kt @@ -18,13 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz.crypto +package com.vitorpamplona.quartz.crypto.nip44 import java.nio.ByteBuffer import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec -class Hkdf(val algorithm: String = "HmacSHA256", val hashLen: Int = 32) { +class Hkdf( + val algorithm: String = "HmacSHA256", + val hashLen: Int = 32, +) { fun extract( key: ByteArray, salt: ByteArray, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Nip44.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Nip44.kt new file mode 100644 index 000000000..793549be3 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Nip44.kt @@ -0,0 +1,148 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.crypto.nip44 + +import android.util.Log +import com.vitorpamplona.quartz.crypto.nip04.Nip04 +import com.vitorpamplona.quartz.events.Event +import fr.acinq.secp256k1.Secp256k1 +import java.security.SecureRandom +import java.util.Base64 + +class Nip44( + secp256k1: Secp256k1, + random: SecureRandom, + val nip04: Nip04, +) { + public val v1 = Nip44v1(secp256k1, random) + public val v2 = Nip44v2(secp256k1, random) + + fun clearCache() { + v1.clearCache() + v2.clearCache() + } + + /** NIP 44v2 Utils */ + fun getSharedSecret( + privateKey: ByteArray, + pubKey: ByteArray, + ): ByteArray = v2.getConversationKey(privateKey, pubKey) + + fun computeSharedSecret( + privateKey: ByteArray, + pubKey: ByteArray, + ): ByteArray = v2.computeConversationKey(privateKey, pubKey) + + fun encrypt( + msg: String, + privateKey: ByteArray, + pubKey: ByteArray, + ): Nip44v2.EncryptedInfo { + // current version should be used. + return v2.encrypt(msg, privateKey, pubKey) + } + + // Always decrypt from any version/any encoding + fun decrypt( + payload: String, + privateKey: ByteArray, + pubKey: ByteArray, + ): String? { + if (payload.isEmpty()) return null + return if (payload[0] == '{') { + decryptNIP44FromJackson(payload, privateKey, pubKey) + } else { + decryptNIP44FromBase64(payload, privateKey, pubKey) + } + } + + class EncryptedInfoString( + val ciphertext: String, + val nonce: String, + val v: Int, + val mac: String?, + ) + + fun decryptNIP44FromJackson( + json: String, + privateKey: ByteArray, + pubKey: ByteArray, + ): String? = + try { + val info = Event.mapper.readValue(json, EncryptedInfoString::class.java) + + when (info.v) { + Nip04.EncryptedInfo.V -> { + val encryptedInfo = + Nip04.EncryptedInfo( + ciphertext = Base64.getDecoder().decode(info.ciphertext), + nonce = Base64.getDecoder().decode(info.nonce), + ) + nip04.decrypt(encryptedInfo, privateKey, pubKey) + } + Nip44v1.EncryptedInfo.V -> { + val encryptedInfo = + Nip44v1.EncryptedInfo( + ciphertext = Base64.getDecoder().decode(info.ciphertext), + nonce = Base64.getDecoder().decode(info.nonce), + ) + v1.decrypt(encryptedInfo, privateKey, pubKey) + } + Nip44v2.EncryptedInfo.V -> { + val encryptedInfo = + Nip44v2.EncryptedInfo( + ciphertext = Base64.getDecoder().decode(info.ciphertext), + nonce = Base64.getDecoder().decode(info.nonce), + mac = Base64.getDecoder().decode(info.mac), + ) + v2.decrypt(encryptedInfo, privateKey, pubKey) + } + else -> null + } + } catch (e: Exception) { + Log.e("CryptoUtils", "Could not identify the version for NIP44 payload $json") + e.printStackTrace() + null + } + + fun decryptNIP44FromBase64( + payload: String, + privateKey: ByteArray, + pubKey: ByteArray, + ): String? { + if (payload.isEmpty()) return null + + return try { + val byteArray = Base64.getDecoder().decode(payload) + + when (byteArray[0].toInt()) { + Nip04.EncryptedInfo.V -> nip04.decrypt(payload, privateKey, pubKey) + Nip44v1.EncryptedInfo.V -> v1.decrypt(payload, privateKey, pubKey) + Nip44v2.EncryptedInfo.V -> v2.decrypt(payload, privateKey, pubKey) + else -> null + } + } catch (e: Exception) { + Log.e("CryptoUtils", "Could not identify the version for NIP44 payload $payload") + e.printStackTrace() + null + } + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip44v1.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Nip44v1.kt similarity index 93% rename from quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip44v1.kt rename to quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Nip44v1.kt index 5872c5d43..926402447 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip44v1.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Nip44v1.kt @@ -18,18 +18,22 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz.crypto +package com.vitorpamplona.quartz.crypto.nip44 import android.util.Log import com.goterl.lazysodium.SodiumAndroid import com.goterl.lazysodium.utils.Key +import com.vitorpamplona.quartz.crypto.SharedKeyCache import com.vitorpamplona.quartz.encoders.Hex import fr.acinq.secp256k1.Secp256k1 import java.security.MessageDigest import java.security.SecureRandom import java.util.Base64 -class Nip44v1(val secp256k1: Secp256k1, val random: SecureRandom) { +class Nip44v1( + val secp256k1: Secp256k1, + val random: SecureRandom, +) { private val sharedKeyCache = SharedKeyCache() private val h02 = Hex.decode("02") private val libSodium = SodiumAndroid() @@ -97,15 +101,13 @@ class Nip44v1(val secp256k1: Secp256k1, val random: SecureRandom) { fun decrypt( encryptedInfo: EncryptedInfo, sharedSecret: ByteArray, - ): String? { - return cryptoStreamXChaCha20Xor( + ): String? = + cryptoStreamXChaCha20Xor( libSodium = libSodium, messageBytes = encryptedInfo.ciphertext, nonce = encryptedInfo.nonce, key = Key.fromBytes(sharedSecret), - ) - ?.decodeToString() - } + )?.decodeToString() fun getSharedSecret( privateKey: ByteArray, @@ -155,11 +157,11 @@ class Nip44v1(val secp256k1: Secp256k1, val random: SecureRandom) { } } - fun encodePayload(): String { - return Base64.getEncoder() + fun encodePayload(): String = + Base64 + .getEncoder() .encodeToString( byteArrayOf(V.toByte()) + nonce + ciphertext, ) - } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip44v2.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Nip44v2.kt similarity index 92% rename from quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip44v2.kt rename to quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Nip44v2.kt index 88fd5ba96..54cbf1c40 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip44v2.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/Nip44v2.kt @@ -18,11 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz.crypto +package com.vitorpamplona.quartz.crypto.nip44 import android.util.Log import com.goterl.lazysodium.LazySodiumAndroid import com.goterl.lazysodium.SodiumAndroid +import com.vitorpamplona.quartz.crypto.SharedKeyCache import com.vitorpamplona.quartz.encoders.Hex import com.vitorpamplona.quartz.encoders.toHexKey import fr.acinq.secp256k1.Secp256k1 @@ -33,7 +34,10 @@ import java.util.Base64 import kotlin.math.floor import kotlin.math.log2 -class Nip44v2(val secp256k1: Secp256k1, val random: SecureRandom) { +class Nip44v2( + val secp256k1: Secp256k1, + val random: SecureRandom, +) { private val sharedKeyCache = SharedKeyCache() private val libSodium = SodiumAndroid() @@ -55,9 +59,7 @@ class Nip44v2(val secp256k1: Secp256k1, val random: SecureRandom) { msg: String, privateKey: ByteArray, pubKey: ByteArray, - ): EncryptedInfo { - return encrypt(msg, getConversationKey(privateKey, pubKey)) - } + ): EncryptedInfo = encrypt(msg, getConversationKey(privateKey, pubKey)) fun encrypt( plaintext: String, @@ -99,17 +101,13 @@ class Nip44v2(val secp256k1: Secp256k1, val random: SecureRandom) { payload: String, privateKey: ByteArray, pubKey: ByteArray, - ): String? { - return decrypt(payload, getConversationKey(privateKey, pubKey)) - } + ): String? = decrypt(payload, getConversationKey(privateKey, pubKey)) fun decrypt( decoded: EncryptedInfo, privateKey: ByteArray, pubKey: ByteArray, - ): String? { - return decrypt(decoded, getConversationKey(privateKey, pubKey)) - } + ): String? = decrypt(decoded, getConversationKey(privateKey, pubKey)) fun decrypt( payload: String, @@ -173,7 +171,11 @@ class Nip44v2(val secp256k1: Secp256k1, val random: SecureRandom) { check(unpaddedLen <= maxPlaintextSize) { "Message is too long ($unpaddedLen): $plaintext" } val prefix = - ByteBuffer.allocate(2).order(ByteOrder.BIG_ENDIAN).putShort(unpaddedLen.toShort()).array() + ByteBuffer + .allocate(2) + .order(ByteOrder.BIG_ENDIAN) + .putShort(unpaddedLen.toShort()) + .array() val suffix = ByteArray(calcPaddedLen(unpaddedLen) - unpaddedLen) return ByteBuffer.wrap(prefix + unpadded + suffix).array() } @@ -182,13 +184,12 @@ class Nip44v2(val secp256k1: Secp256k1, val random: SecureRandom) { byte1: Byte, byte2: Byte, bigEndian: Boolean, - ): Int { - return if (bigEndian) { + ): Int = + if (bigEndian) { (byte1.toInt() and 0xFF shl 8 or (byte2.toInt() and 0xFF)) } else { (byte2.toInt() and 0xFF shl 8 or (byte1.toInt() and 0xFF)) } - } fun unpad(padded: ByteArray): String { val unpaddedLen: Int = bytesToInt(padded[0], padded[1], true) @@ -273,11 +274,11 @@ class Nip44v2(val secp256k1: Secp256k1, val random: SecureRandom) { } } - fun encodePayload(): String { - return Base64.getEncoder() + fun encodePayload(): String = + Base64 + .getEncoder() .encodeToString( byteArrayOf(V.toByte()) + nonce + ciphertext + mac, ) - } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/SodiumUtils.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/SodiumUtils.kt similarity index 95% rename from quartz/src/main/java/com/vitorpamplona/quartz/crypto/SodiumUtils.kt rename to quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/SodiumUtils.kt index 8d5c748a0..9961e4b1f 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/SodiumUtils.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip44/SodiumUtils.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz.crypto +package com.vitorpamplona.quartz.crypto.nip44 import com.goterl.lazysodium.SodiumAndroid import com.goterl.lazysodium.utils.Key @@ -66,9 +66,7 @@ fun cryptoStreamXchacha20Xor( messageLen: Long, nonce: ByteArray, key: ByteArray, -): Int { - return cryptoStreamXchacha20XorIc(libSodium, cipher, message, messageLen, nonce, 0, key) -} +): Int = cryptoStreamXchacha20XorIc(libSodium, cipher, message, messageLen, nonce, 0, key) fun cryptoStreamXChaCha20Xor( libSodium: SodiumAndroid, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip49.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/Nip49.kt similarity index 90% rename from quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip49.kt rename to quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/Nip49.kt index f537ef836..70a19252b 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/Nip49.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/Nip49.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz.crypto +package com.vitorpamplona.quartz.crypto.nip49 import android.util.Log import com.goterl.lazysodium.LazySodiumAndroid @@ -32,16 +32,17 @@ import fr.acinq.secp256k1.Secp256k1 import java.security.SecureRandom import java.text.Normalizer -class Nip49(val secp256k1: Secp256k1, val random: SecureRandom) { +class Nip49( + val secp256k1: Secp256k1, + val random: SecureRandom, +) { private val libSodium = SodiumAndroid() private val lazySodium = LazySodiumAndroid(libSodium) fun decrypt( nCryptSec: String, password: String, - ): HexKey { - return decrypt(EncryptedInfo.decodePayload(nCryptSec), password) - } + ): HexKey = decrypt(EncryptedInfo.decodePayload(nCryptSec), password) fun decrypt( encryptedInfo: EncryptedInfo?, @@ -75,11 +76,9 @@ class Nip49(val secp256k1: Secp256k1, val random: SecureRandom) { fun encrypt( secretKeyHex: String, password: String, - logn: Int, - ksb: Byte, - ): String? { - return encrypt(secretKeyHex.hexToByteArray(), password, logn, ksb) - } + logn: Int = 16, + ksb: Byte = EncryptedInfo.CLIENT_DOES_NOT_TRACK, + ): String = encrypt(secretKeyHex.hexToByteArray(), password, logn, ksb) fun encrypt( secretKey: ByteArray, @@ -104,9 +103,12 @@ class Nip49(val secp256k1: Secp256k1, val random: SecureRandom) { // byte[] ad, long adLen, // byte[] nSec, byte[] nPub, byte[] k lazySodium.cryptoAeadXChaCha20Poly1305IetfEncrypt( - ciphertext, longArrayOf(48), - secretKey, secretKey.size.toLong(), - byteArrayOf(ksb), 1, + ciphertext, + longArrayOf(48), + secretKey, + secretKey.size.toLong(), + byteArrayOf(ksb), + 1, key, nonce, key, @@ -163,8 +165,8 @@ class Nip49(val secp256k1: Secp256k1, val random: SecureRandom) { } // ln(n.toDouble()).toInt().toByte(), - fun encodePayload(): String { - return Bech32.encodeBytes( + fun encodePayload(): String = + Bech32.encodeBytes( hrp = "ncryptsec", byteArrayOf( version, @@ -172,6 +174,5 @@ class Nip49(val secp256k1: Secp256k1, val random: SecureRandom) { ) + salt + nonce + keySecurity + encryptedKey, Bech32.Encoding.Bech32, ) - } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/PBKDF.java b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/PBKDF.java similarity index 98% rename from quartz/src/main/java/com/vitorpamplona/quartz/crypto/PBKDF.java rename to quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/PBKDF.java index 638a8b315..6b7adfacd 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/PBKDF.java +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/PBKDF.java @@ -1,6 +1,6 @@ // Copyright (C) 2011 - Will Glozer. All rights reserved. -package com.vitorpamplona.quartz.crypto; +package com.vitorpamplona.quartz.crypto.nip49; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/SCrypt.java b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/SCrypt.java similarity index 99% rename from quartz/src/main/java/com/vitorpamplona/quartz/crypto/SCrypt.java rename to quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/SCrypt.java index c464013a2..bd5c89610 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/SCrypt.java +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/SCrypt.java @@ -1,6 +1,6 @@ // Copyright (C) 2011 - Will Glozer. All rights reserved. -package com.vitorpamplona.quartz.crypto; +package com.vitorpamplona.quartz.crypto.nip49; import javax.crypto.Mac; import java.security.GeneralSecurityException; diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/SecretKeyOrEmptySpec.java b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/SecretKeyOrEmptySpec.java similarity index 99% rename from quartz/src/main/java/com/vitorpamplona/quartz/crypto/SecretKeyOrEmptySpec.java rename to quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/SecretKeyOrEmptySpec.java index 7e3766bdc..d4e347c28 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/SecretKeyOrEmptySpec.java +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip49/SecretKeyOrEmptySpec.java @@ -23,7 +23,7 @@ * questions. */ -package com.vitorpamplona.quartz.crypto; +package com.vitorpamplona.quartz.crypto.nip49; import java.security.MessageDigest; import java.security.spec.KeySpec; diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/signers/NostrSignerInternal.kt b/quartz/src/main/java/com/vitorpamplona/quartz/signers/NostrSignerInternal.kt index 2537287b5..5728c3190 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/signers/NostrSignerInternal.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/signers/NostrSignerInternal.kt @@ -31,7 +31,9 @@ import com.vitorpamplona.quartz.events.EventFactory import com.vitorpamplona.quartz.events.LnZapPrivateEvent import com.vitorpamplona.quartz.events.LnZapRequestEvent -class NostrSignerInternal(val keyPair: KeyPair) : NostrSigner(keyPair.pubKey.toHexKey()) { +class NostrSignerInternal( + val keyPair: KeyPair, +) : NostrSigner(keyPair.pubKey.toHexKey()) { override fun sign( createdAt: Long, kind: Int, @@ -52,10 +54,9 @@ class NostrSignerInternal(val keyPair: KeyPair) : NostrSigner(keyPair.pubKey.toH fun isUnsignedPrivateEvent( kind: Int, tags: Array>, - ): Boolean { - return kind == LnZapRequestEvent.KIND && + ): Boolean = + kind == LnZapRequestEvent.KIND && tags.any { t -> t.size > 1 && t[0] == "anon" && t[1].isBlank() } - } fun signNormal( createdAt: Long, @@ -123,12 +124,12 @@ class NostrSignerInternal(val keyPair: KeyPair) : NostrSigner(keyPair.pubKey.toH if (keyPair.privKey == null) return onReady( - CryptoUtils.encryptNIP44v2( - decryptedContent, - keyPair.privKey, - toPublicKey.hexToByteArray(), - ) - .encodePayload(), + CryptoUtils + .encryptNIP44( + decryptedContent, + keyPair.privKey, + toPublicKey.hexToByteArray(), + ).encodePayload(), ) } @@ -139,12 +140,12 @@ class NostrSignerInternal(val keyPair: KeyPair) : NostrSigner(keyPair.pubKey.toH ) { if (keyPair.privKey == null) return - CryptoUtils.decryptNIP44( - payload = encryptedContent, - privateKey = keyPair.privKey, - pubKey = fromPublicKey.hexToByteArray(), - ) - ?.let { onReady(it) } + CryptoUtils + .decryptNIP44( + payload = encryptedContent, + privateKey = keyPair.privKey, + pubKey = fromPublicKey.hexToByteArray(), + )?.let { onReady(it) } } private fun signPrivateZap( diff --git a/quartz/src/test/java/com/vitorpamplona/quartz/encoders/TimeUtilsTest.kt b/quartz/src/test/java/com/vitorpamplona/quartz/utils/TimeUtilsTest.kt similarity index 95% rename from quartz/src/test/java/com/vitorpamplona/quartz/encoders/TimeUtilsTest.kt rename to quartz/src/test/java/com/vitorpamplona/quartz/utils/TimeUtilsTest.kt index 34528d91b..19b296238 100644 --- a/quartz/src/test/java/com/vitorpamplona/quartz/encoders/TimeUtilsTest.kt +++ b/quartz/src/test/java/com/vitorpamplona/quartz/utils/TimeUtilsTest.kt @@ -18,10 +18,8 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz.encoders +package com.vitorpamplona.quartz.utils -import com.vitorpamplona.quartz.utils.DualCase -import com.vitorpamplona.quartz.utils.containsAny import junit.framework.TestCase import org.junit.Test @@ -30,8 +28,7 @@ class TimeUtilsTest { """Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32. The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham. -""" - .intern() +""".intern() val atTheMiddle = DualCase("Lorem Ipsum".lowercase(), "Lorem Ipsum".uppercase()) val atTheBeginning = DualCase("contrAry".lowercase(), "contrAry".uppercase()) From 215fba83cf89ded69d5a5d31f9fb68f725c00c27 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Tue, 25 Jun 2024 18:50:11 +0000 Subject: [PATCH 23/49] New Crowdin translations by GitHub Action --- amethyst/src/main/res/values-ar/strings.xml | 3 +++ .../src/main/res/values-bn-rBD/strings.xml | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/amethyst/src/main/res/values-ar/strings.xml b/amethyst/src/main/res/values-ar/strings.xml index 2140ccd9c..48dc59382 100644 --- a/amethyst/src/main/res/values-ar/strings.xml +++ b/amethyst/src/main/res/values-ar/strings.xml @@ -3,8 +3,10 @@ أشر إلى رمز (QR Code) أظهر QR صورة الملف الشخصي + صورة ملفك الشخصي مسح رمز ال QR عرض على أي حال + تم إخفاء هذا المنشور لأنه يشير إلى المستخدمين الذين قمت بإخفائهم أو الكلمات التي قمت بإخفائها تم وضع علامة على المنشور على أنه غير لائق بواسطة المنشور غير موجود صورة القناة @@ -464,6 +466,7 @@ مثل [Nfty](https://ntfy.sh/). بعد تثبيتك التطبيق قم باختياره من الإعدادات العنوان + iPhone 13 الشرط الفئة الموقع الجغرافيّ diff --git a/amethyst/src/main/res/values-bn-rBD/strings.xml b/amethyst/src/main/res/values-bn-rBD/strings.xml index 50caf7aa5..8be25d74f 100644 --- a/amethyst/src/main/res/values-bn-rBD/strings.xml +++ b/amethyst/src/main/res/values-bn-rBD/strings.xml @@ -485,11 +485,31 @@ ওয়ালেট %1$s স্বাক্ষরের অ্যাপ খোলা যাচ্ছে না স্বাক্ষরের অনুরোধ প্রত্যাখ্যান করা হয়েছে + কোনটি নয় + বিক্রেতাকে একটি বার্তা পাঠান + হাই %1$s, এটা কি এখনও পাওয়া যায়? + হাই %1$s, এটা কি এখনও পাওয়া যায়? + একটি পণ্য বিক্রি করুন + শিরোনাম + iPhone 13 শর্ত ক্যাটাগরি + অবস্থান + শহর, রাজ্য, দেশ নতুন ভাল ন্যায্য + পোশাক + আনুষাঙ্গিক + পোষা প্রাণী + খেলাধুলা + ফিটনেস + দপ্তর + খাদ্য + নিরাপত্তা-ফিল্টার + নতুন পোস্ট + বুস্ট বা উদ্ধৃতি + পোল নিষ্ক্রিয় করুন ঠিকানা সঠিক নয় QR কোড স্ক্যান করুন From 5e417dd890147a08f17c23bfb16d5540eaaf3781 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 25 Jun 2024 18:19:14 -0400 Subject: [PATCH 24/49] Fixes the rendering of highlights when no user is present and includes options to render by `e` tags --- .../amethyst/ui/components/ClickableRoute.kt | 4 +- .../amethyst/ui/note/types/Highlight.kt | 206 ++++++++++++++---- .../com/vitorpamplona/quartz/events/Event.kt | 2 + .../quartz/events/EventInterface.kt | 2 + .../quartz/events/HighlightEvent.kt | 2 + 5 files changed, 175 insertions(+), 41 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt index dd7cbea9a..17c459e41 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt @@ -138,7 +138,7 @@ private fun LoadAndDisplayEvent( } @Composable -private fun DisplayEvent( +fun DisplayEvent( hex: HexKey, kind: Int?, additionalChars: String?, @@ -293,7 +293,7 @@ public fun DisplayUser( } @Composable -private fun RenderUserAsClickableText( +public fun RenderUserAsClickableText( baseUser: User, additionalChars: String?, nav: (String) -> Unit, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt index 20a7cc275..5c5e08412 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt @@ -40,19 +40,27 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.AnnotatedString +import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.components.ClickableUrl import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji +import com.vitorpamplona.amethyst.ui.components.DisplayEvent +import com.vitorpamplona.amethyst.ui.components.LoadNote +import com.vitorpamplona.amethyst.ui.components.RenderUserAsClickableText import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.components.measureSpaceWidth import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.encoders.ATag +import com.vitorpamplona.quartz.encoders.HexKey +import com.vitorpamplona.quartz.events.BaseTextNoteEvent import com.vitorpamplona.quartz.events.EmptyTagList import com.vitorpamplona.quartz.events.HighlightEvent import com.vitorpamplona.quartz.events.LongTextNoteEvent +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import java.net.URL @Composable @@ -72,6 +80,7 @@ fun RenderHighlight( authorHex = noteEvent.author(), url = noteEvent.inUrl(), postAddress = noteEvent.inPost(), + postVersion = noteEvent.inPostVersion(), makeItShort = makeItShort, canPreview = canPreview, quotesLeft = quotesLeft, @@ -81,12 +90,14 @@ fun RenderHighlight( ) } +@OptIn(ExperimentalLayoutApi::class) @Composable fun DisplayHighlight( highlight: String, authorHex: String?, url: String?, postAddress: ATag?, + postVersion: HexKey?, makeItShort: Boolean, canPreview: Boolean, quotesLeft: Int, @@ -112,54 +123,151 @@ fun DisplayHighlight( nav = nav, ) - DisplayQuoteAuthor(authorHex ?: "", url, postAddress, accountViewModel, nav) -} - -@OptIn(ExperimentalLayoutApi::class) -@Composable -private fun DisplayQuoteAuthor( - authorHex: String, - url: String?, - postAddress: ATag?, - accountViewModel: AccountViewModel, - nav: (String) -> Unit, -) { - var userBase by remember { mutableStateOf(accountViewModel.getUserIfExists(authorHex)) } - - if (userBase == null) { - LaunchedEffect(Unit) { - accountViewModel.checkGetOrCreateUser(authorHex) { newUserBase -> - userBase = newUserBase - } - } - } - val spaceWidth = measureSpaceWidth(textStyle = LocalTextStyle.current) FlowRow( horizontalArrangement = Arrangement.spacedBy(spaceWidth), verticalArrangement = Arrangement.Center, ) { - userBase?.let { userBase -> - val userMetadata by userBase.live().userMetadataInfo.observeAsState() - - CreateClickableTextWithEmoji( - clickablePart = userMetadata?.bestName() ?: userBase.pubkeyDisplayHex(), - maxLines = 1, - route = "User/${userBase.pubkeyHex}", - nav = nav, - tags = userMetadata?.tags, - ) - } - - url?.let { url -> LoadAndDisplayUrl(url) } - - postAddress?.let { address -> LoadAndDisplayPost(address, accountViewModel, nav) } + DisplayQuoteAuthor( + authorHex = authorHex, + url = url, + postAddress = postAddress, + postVersion = postVersion, + accountViewModel = accountViewModel, + nav = nav, + ) } } @Composable -fun LoadAndDisplayUrl(url: String) { +private fun DisplayQuoteAuthor( + authorHex: String?, + url: String?, + postAddress: ATag?, + postVersion: HexKey?, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + var userBase by remember { mutableStateOf(authorHex?.let { accountViewModel.getUserIfExists(it) }) } + + if (userBase == null && authorHex != null) { + LaunchedEffect(authorHex) { + accountViewModel.checkGetOrCreateUser(authorHex) { newUserBase -> + userBase = newUserBase + } + } + } + + var addressable by remember { + mutableStateOf(postAddress?.let { accountViewModel.getAddressableNoteIfExists(it.toTag()) }) + } + + if (addressable == null && postAddress != null) { + LaunchedEffect(key1 = postAddress) { + val newNote = + withContext(Dispatchers.IO) { + accountViewModel.getOrCreateAddressableNote(postAddress) + } + if (addressable != newNote) { + addressable = newNote + } + } + } + + var version by remember { + mutableStateOf(postVersion?.let { accountViewModel.getNoteIfExists(it) }) + } + + if (version == null && postVersion != null) { + LaunchedEffect(key1 = postVersion) { + val newNote = + withContext(Dispatchers.IO) { + accountViewModel.getOrCreateNote(postVersion) + } + if (version != newNote) { + version = newNote + } + } + } + + if (addressable != null) { + addressable?.let { + DisplayEntryForNote(it, userBase, accountViewModel, nav) + } + } else if (version != null) { + version?.let { + DisplayEntryForNote(it, userBase, accountViewModel, nav) + } + } else if (url != null) { + DisplayEntryForAUrl(url, userBase, accountViewModel, nav) + } else if (userBase != null) { + userBase?.let { + DisplayEntryForUser(it, accountViewModel, nav) + } + } +} + +@Composable +fun DisplayEntryForUser( + userBase: User, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + val userMetadata by userBase.live().userMetadataInfo.observeAsState() + + CreateClickableTextWithEmoji( + clickablePart = userMetadata?.bestName() ?: userBase.pubkeyDisplayHex(), + maxLines = 1, + route = "User/${userBase.pubkeyHex}", + nav = nav, + tags = userMetadata?.tags, + ) +} + +@Composable +fun DisplayEntryForNote( + note: Note, + userBase: User?, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + val noteState by note.live().metadata.observeAsState() + + val author = userBase ?: noteState?.note?.author + + if (author != null) { + RenderUserAsClickableText(author, null, nav) + } + + val noteEvent = noteState?.note?.event as? BaseTextNoteEvent ?: return + + val description = noteEvent.firstTagFor("title", "subject", "alt") + + Text("-", maxLines = 1) + + if (description != null) { + ClickableText( + text = AnnotatedString(description), + onClick = { routeFor(note, accountViewModel.userProfile())?.let { nav(it) } }, + style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary), + ) + } else { + DisplayEvent(noteEvent.id, noteEvent.kind, "", accountViewModel, nav) + } +} + +@Composable +fun DisplayEntryForAUrl( + url: String, + userBase: User?, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + if (userBase != null) { + DisplayEntryForUser(userBase, accountViewModel, nav) + } + val validatedUrl = remember { try { @@ -171,7 +279,9 @@ fun LoadAndDisplayUrl(url: String) { } validatedUrl?.host?.let { host -> - Text("-", maxLines = 1) + if (userBase != null) { + Text("-", maxLines = 1) + } ClickableUrl(urlText = host, url = url) } } @@ -198,3 +308,21 @@ private fun LoadAndDisplayPost( } } } + +@Composable +private fun LoadAndDisplayPostVersion( + postEvent: HexKey, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + LoadNote(baseNoteHex = postEvent, accountViewModel) { baseNote -> + baseNote?.let { note -> + val noteState by note.live().metadata.observeAsState() + val noteEvent = noteState?.note?.event as? BaseTextNoteEvent ?: return@LoadNote + + Text("-", maxLines = 1) + + DisplayEvent(noteEvent.id, noteEvent.kind, "", accountViewModel, nav) + } + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt index 5dcd4710a..19521379e 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt @@ -121,6 +121,8 @@ open class Event( override fun taggedUrls() = tags.filter { it.size > 1 && it[0] == "r" }.map { it[1] } + override fun firstTagFor(vararg key: String) = tags.firstOrNull { it.size > 1 && it[0] in key }?.let { it[1] } + override fun firstTaggedUser() = tags.firstOrNull { it.size > 1 && it[0] == "p" }?.let { it[1] } override fun firstTaggedEvent() = tags.firstOrNull { it.size > 1 && it[0] == "e" }?.let { it[1] } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/EventInterface.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/EventInterface.kt index 5465a50f3..db11a3ea4 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/EventInterface.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/EventInterface.kt @@ -133,6 +133,8 @@ interface EventInterface { fun taggedUrls(): List + fun firstTagFor(vararg key: String): String? + fun firstTaggedAddress(): ATag? fun firstTaggedUser(): HexKey? diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/HighlightEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/HighlightEvent.kt index 5f6253e84..398e46fbc 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/HighlightEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/HighlightEvent.kt @@ -42,6 +42,8 @@ class HighlightEvent( fun inPost() = firstTaggedAddress() + fun inPostVersion() = firstTaggedEvent() + companion object { const val KIND = 9802 const val ALT = "Highlight/quote event" From cc6551b11b4459bad30c4f9ae7e684fc2f5e9464 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 25 Jun 2024 18:19:43 -0400 Subject: [PATCH 25/49] Removes old highlight rendering functions --- .../amethyst/ui/note/types/Highlight.kt | 44 ------------------- 1 file changed, 44 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt index 5c5e08412..e66f76a1d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt @@ -46,19 +46,16 @@ import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.components.ClickableUrl import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji import com.vitorpamplona.amethyst.ui.components.DisplayEvent -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.RenderUserAsClickableText import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.components.measureSpaceWidth import com.vitorpamplona.amethyst.ui.navigation.routeFor -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.events.BaseTextNoteEvent import com.vitorpamplona.quartz.events.EmptyTagList import com.vitorpamplona.quartz.events.HighlightEvent -import com.vitorpamplona.quartz.events.LongTextNoteEvent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.net.URL @@ -285,44 +282,3 @@ fun DisplayEntryForAUrl( ClickableUrl(urlText = host, url = url) } } - -@Composable -private fun LoadAndDisplayPost( - postAddress: ATag, - accountViewModel: AccountViewModel, - nav: (String) -> Unit, -) { - LoadAddressableNote(aTag = postAddress, accountViewModel) { aTag -> - aTag?.let { note -> - val noteState by note.live().metadata.observeAsState() - val noteEvent = noteState?.note?.event as? LongTextNoteEvent ?: return@LoadAddressableNote - - noteEvent.title()?.let { - Text("-", maxLines = 1) - ClickableText( - text = AnnotatedString(it), - onClick = { routeFor(note, accountViewModel.userProfile())?.let { nav(it) } }, - style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary), - ) - } - } - } -} - -@Composable -private fun LoadAndDisplayPostVersion( - postEvent: HexKey, - accountViewModel: AccountViewModel, - nav: (String) -> Unit, -) { - LoadNote(baseNoteHex = postEvent, accountViewModel) { baseNote -> - baseNote?.let { note -> - val noteState by note.live().metadata.observeAsState() - val noteEvent = noteState?.note?.event as? BaseTextNoteEvent ?: return@LoadNote - - Text("-", maxLines = 1) - - DisplayEvent(noteEvent.id, noteEvent.kind, "", accountViewModel, nav) - } - } -} From d6ab376f2d6b9d7c219e5720c59296aa9827a685 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 25 Jun 2024 18:26:11 -0400 Subject: [PATCH 26/49] Fixes position of the hash verification icon on NIP-95 images. --- .../vitorpamplona/amethyst/ui/components/ZoomableContentView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index 74b2295ca..195cdac5f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -258,7 +258,7 @@ fun LocalImageView( content.isVerified?.let { AnimatedVisibility( visible = controllerVisible.value, - modifier = Modifier, + modifier = Modifier.align(Alignment.TopEnd), enter = remember { fadeIn() }, exit = remember { fadeOut() }, ) { From e358387ba1c5291c6070e0ea07de22e2695ad339 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Wed, 26 Jun 2024 16:33:24 -0300 Subject: [PATCH 27/49] check for localhost when adding a new relay --- .../com/vitorpamplona/quartz/encoders/RelayUrlFormatter.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/encoders/RelayUrlFormatter.kt b/quartz/src/main/java/com/vitorpamplona/quartz/encoders/RelayUrlFormatter.kt index eaa41f497..2679e9a0b 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/encoders/RelayUrlFormatter.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/encoders/RelayUrlFormatter.kt @@ -31,7 +31,9 @@ class RelayUrlFormatter { fun normalize(url: String): String { val newUrl = if (!url.startsWith("wss://") && !url.startsWith("ws://")) { - if (url.endsWith(".onion") || url.endsWith(".onion/")) { + // TODO: How to identify relays on the local network? + val isLocalHost = url.contains("127.0.0.1") || url.contains("localhost") + if (url.endsWith(".onion") || url.endsWith(".onion/") || isLocalHost) { "ws://${url.trim()}" } else { "wss://${url.trim()}" From fb59499a0d49a676317c8a573836bd03f701b8c4 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Wed, 26 Jun 2024 19:45:14 +0000 Subject: [PATCH 28/49] New Crowdin translations by GitHub Action --- amethyst/src/main/res/values-zh-rCN/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/amethyst/src/main/res/values-zh-rCN/strings.xml b/amethyst/src/main/res/values-zh-rCN/strings.xml index c5961bdd4..a83417094 100644 --- a/amethyst/src/main/res/values-zh-rCN/strings.xml +++ b/amethyst/src/main/res/values-zh-rCN/strings.xml @@ -303,6 +303,7 @@ 打闪最低金额 打闪最高金额 共识 + (0–100)% 后关闭 无法投票 @@ -445,6 +446,7 @@ 设置 始终 仅限 WiFi + 未计量的 WiFi 从不 完整版 简化版 @@ -533,6 +535,7 @@ 打闪设置缺失 用户 %1$s 尚未设置接收聪的闪电地址 百分比 + 25 与此用户拆分打闪 将打闪转发到 找不到闪电钱包 @@ -599,9 +602,11 @@ 你好,这个还能买到吗? 出售物品 标题 + iPhone 13 条件 分类 价格(聪) + 1000 地点 市,省,国家 全新 @@ -655,6 +660,7 @@ 提升或引用 点赞 打闪 + 修改快速回应 %1$s 的个人头像 中继器 %1$s 展开中继列表 From 0fad7b313b29455bd7fd0d9fe3299894a19e9f42 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 26 Jun 2024 16:20:25 -0400 Subject: [PATCH 29/49] Fixing alignment of the close button on Chat's reply preview --- .../amethyst/ui/screen/loggedIn/ChannelScreen.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index 2052fe115..bb1c5556f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -393,7 +393,6 @@ fun DisplayReplyingToNote( .heightIn(max = 100.dp) .verticalScroll(rememberScrollState()) .animateContentSize(), - verticalAlignment = Alignment.CenterVertically, ) { if (replyingNote != null) { Column(remember { Modifier.weight(1f) }) { @@ -408,9 +407,9 @@ fun DisplayReplyingToNote( ) } - Column(Modifier.padding(end = 10.dp)) { + Column(Modifier.padding(start = 5.dp)) { IconButton( - modifier = Modifier.size(30.dp), + modifier = Modifier.size(20.dp), onClick = onCancel, ) { Icon( @@ -418,8 +417,7 @@ fun DisplayReplyingToNote( null, modifier = Modifier - .padding(end = 5.dp) - .size(30.dp), + .size(20.dp), tint = MaterialTheme.colorScheme.placeholderText, ) } From 7e31401b86d7e981ed3bf4a94ee92b34cf265f26 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 26 Jun 2024 17:06:30 -0400 Subject: [PATCH 30/49] updates versions --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index df13a1771..57771fa2a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,8 +15,8 @@ composeBom = "2024.06.00" coreKtx = "1.13.1" espressoCore = "3.6.0" firebaseBom = "33.1.1" -fragmentKtx = "1.8.0" -gms = "4.4.1" +fragmentKtx = "1.8.1" +gms = "4.4.2" jacksonModuleKotlin = "2.17.1" jna = "5.14.0" junit = "4.13.2" From ca5c0d6ee47e7f44c5ce3a471cd52265f9ffbc42 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 27 Jun 2024 10:00:17 -0400 Subject: [PATCH 31/49] Adds author picture when writing posts and replies. --- .../amethyst/ui/actions/NewPostView.kt | 29 ++++++++++++++----- .../ui/screen/loggedIn/ChannelScreen.kt | 27 ++++++++++++----- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt index c6a2b83b2..b8f4019b9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt @@ -52,7 +52,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.selection.toggleable -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -81,6 +80,7 @@ import androidx.compose.material3.Slider import androidx.compose.material3.Surface import androidx.compose.material3.Switch import androidx.compose.material3.Text +import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable @@ -158,6 +158,7 @@ import com.vitorpamplona.amethyst.ui.theme.Font14SP import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.Size18Modifier +import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.Size5dp import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer @@ -390,7 +391,16 @@ fun NewPostView( } } - MessageField(postViewModel) + Row( + modifier = Modifier.padding(vertical = Size10dp), + ) { + BaseUserPicture( + accountViewModel.userProfile(), + Size35dp, + accountViewModel = accountViewModel, + ) + MessageField(postViewModel) + } if (postViewModel.wantsPoll) { Row( @@ -661,7 +671,7 @@ private fun MessageField(postViewModel: NewPostViewModel) { } } - OutlinedTextField( + MyTextField( value = postViewModel.message, onValueChange = { postViewModel.updateMessage(it) }, keyboardOptions = @@ -671,11 +681,7 @@ private fun MessageField(postViewModel: NewPostViewModel) { modifier = Modifier .fillMaxWidth() - .border( - width = 1.dp, - color = MaterialTheme.colorScheme.surface, - shape = RoundedCornerShape(8.dp), - ).focusRequester(focusRequester) + .focusRequester(focusRequester) .onFocusChanged { if (it.isFocused) { keyboardController?.show() @@ -699,6 +705,13 @@ private fun MessageField(postViewModel: NewPostViewModel) { ), visualTransformation = UrlUserTagTransformation(MaterialTheme.colorScheme.primary), textStyle = LocalTextStyle.current.copy(textDirection = TextDirection.Content), + contentPadding = + TextFieldDefaults.contentPaddingWithoutLabel( + start = 10.dp, + top = 5.dp, + end = 10.dp, + bottom = 5.dp, + ), ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index bb1c5556f..1aaf078a9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -28,6 +28,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsFocusedAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.defaultMinSize @@ -60,6 +61,8 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextFieldColors import androidx.compose.material3.TextFieldDefaults +import androidx.compose.material3.TextFieldDefaults.contentPaddingWithLabel +import androidx.compose.material3.TextFieldDefaults.contentPaddingWithoutLabel import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.DisposableEffect @@ -516,6 +519,22 @@ fun MyTextField( interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, shape: Shape = TextFieldDefaults.shape, colors: TextFieldColors = TextFieldDefaults.colors(), + contentPadding: PaddingValues = + if (label == null) { + TextFieldDefaults.contentPaddingWithoutLabel( + start = 10.dp, + top = 12.dp, + end = 10.dp, + bottom = 12.dp, + ) + } else { + TextFieldDefaults.contentPaddingWithLabel( + start = 10.dp, + top = 12.dp, + end = 10.dp, + bottom = 12.dp, + ) + }, ) { // COPIED FROM TEXT FIELD // The only change is the contentPadding below @@ -575,13 +594,7 @@ fun MyTextField( isError = isError, interactionSource = interactionSource, colors = colors, - contentPadding = - TextFieldDefaults.contentPaddingWithoutLabel( - start = 10.dp, - top = 12.dp, - end = 10.dp, - bottom = 12.dp, - ), + contentPadding = contentPadding, ) }, ) From 372eaabb5043f249530b962c67090ff090572fea Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 27 Jun 2024 12:13:53 -0400 Subject: [PATCH 32/49] Swipe to delete drafts. --- .../amethyst/ui/components/SwipeToDelete.kt | 113 ++++++++++++++++++ .../amethyst/ui/note/elements/DropDownMenu.kt | 6 +- .../ui/screen/RememberForeverStates.kt | 7 +- .../ui/screen/loggedIn/DraftListScreen.kt | 79 ++++++++++-- 4 files changed, 193 insertions(+), 12 deletions(-) create mode 100644 amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SwipeToDelete.kt diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SwipeToDelete.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SwipeToDelete.kt new file mode 100644 index 000000000..6d542110e --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SwipeToDelete.kt @@ -0,0 +1,113 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.components + +import androidx.compose.animation.animateColorAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.SwipeToDismissBox +import androidx.compose.material3.SwipeToDismissBoxState +import androidx.compose.material3.SwipeToDismissBoxValue.EndToStart +import androidx.compose.material3.SwipeToDismissBoxValue.Settled +import androidx.compose.material3.SwipeToDismissBoxValue.StartToEnd +import androidx.compose.material3.rememberSwipeToDismissBoxState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SwipeToDeleteContainer( + modifier: Modifier = Modifier, + onStartToEnd: () -> Unit, + onEndToStart: () -> Unit, + content: @Composable (RowScope.() -> Unit), +) { + val dismissState = + rememberSwipeToDismissBoxState( + confirmValueChange = { + when (it) { + StartToEnd -> { + onStartToEnd() + } + EndToStart -> { + onEndToStart() + } + Settled -> return@rememberSwipeToDismissBoxState false + } + return@rememberSwipeToDismissBoxState true + }, + ) + + SwipeToDismissBox( + state = dismissState, + modifier = modifier, + backgroundContent = { DismissBackground(dismissState) }, + content = content, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DismissBackground(dismissState: SwipeToDismissBoxState) { + val color by animateColorAsState( + if (dismissState.currentValue > dismissState.targetValue) { + Color(0xFFFF1744) + } else { + Color.Transparent + }, + label = "DismissBackground", + ) + + Row( + modifier = + Modifier + .fillMaxSize() + .background(color) + .padding(20.dp, 8.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Icon( + Icons.Default.Delete, + contentDescription = stringRes(id = R.string.request_deletion), + ) + Spacer(modifier = Modifier) + Icon( + Icons.Default.Delete, + contentDescription = stringRes(id = R.string.request_deletion), + ) + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt index 374f8bc8a..ef758e62a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt @@ -361,10 +361,8 @@ fun NoteDropDownMenu( DropdownMenuItem( text = { Text(stringRes(R.string.request_deletion)) }, onClick = { - scope.launch(Dispatchers.IO) { - accountViewModel.delete(note) - onDismiss() - } + accountViewModel.delete(note) + onDismiss() }, ) } else { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/RememberForeverStates.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/RememberForeverStates.kt index d4c0f453e..b47a2fec0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/RememberForeverStates.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/RememberForeverStates.kt @@ -33,7 +33,10 @@ import kotlin.math.roundToInt private val savedScrollStates = mutableMapOf() -private data class ScrollState(val index: Int, val scrollOffsetFraction: Float) +private data class ScrollState( + val index: Int, + val scrollOffsetFraction: Float, +) object ScrollStateKeys { const val GLOBAL_SCREEN = "Global" @@ -43,6 +46,8 @@ object ScrollStateKeys { val HOME_FOLLOWS = Route.Home.base + "Follows" val HOME_REPLIES = Route.Home.base + "FollowsReplies" + val DRAFTS = Route.Home.base + "Drafts" + val DISCOVER_CONTENT = Route.Home.base + "DiscoverContent" val DISCOVER_MARKETPLACE = Route.Home.base + "Marketplace" val DISCOVER_LIVE = Route.Home.base + "Live" diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt index 0a502c666..c249cc878 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt @@ -20,15 +20,34 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.viewmodel.compose.viewModel +import com.vitorpamplona.amethyst.ui.components.SwipeToDeleteContainer +import com.vitorpamplona.amethyst.ui.note.NoteCompose +import com.vitorpamplona.amethyst.ui.screen.FeedState import com.vitorpamplona.amethyst.ui.screen.NostrDraftEventsFeedViewModel -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.ui.screen.RefresheableBox +import com.vitorpamplona.amethyst.ui.screen.RenderFeedState +import com.vitorpamplona.amethyst.ui.screen.SaveableFeedState +import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys.DRAFTS +import com.vitorpamplona.amethyst.ui.theme.DividerThickness +import com.vitorpamplona.amethyst.ui.theme.FeedPadding @Composable fun DraftListScreen( @@ -72,10 +91,56 @@ private fun RenderDraftListScreen( onDispose { lifeCycleOwner.lifecycle.removeObserver(observer) } } - RefresheableFeedView( - feedViewModel, - null, - accountViewModel = accountViewModel, - nav = nav, - ) + RefresheableBox(feedViewModel) { + SaveableFeedState(feedViewModel, DRAFTS) { listState -> + RenderFeedState( + feedViewModel, + accountViewModel, + listState, + nav, + null, + onLoaded = { DraftFeedLoaded(it, listState, null, accountViewModel, nav) }, + ) + } + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +private fun DraftFeedLoaded( + state: FeedState.Loaded, + listState: LazyListState, + routeForLastRead: String?, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + LazyColumn( + contentPadding = FeedPadding, + state = listState, + ) { + itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { _, item -> + SwipeToDeleteContainer( + modifier = Modifier.fillMaxWidth().animateContentSize(), + onStartToEnd = { accountViewModel.delete(item) }, + onEndToStart = { accountViewModel.delete(item) }, + ) { + Row(Modifier.fillMaxWidth().animateItemPlacement().background(MaterialTheme.colorScheme.background)) { + NoteCompose( + item, + routeForLastRead = routeForLastRead, + modifier = Modifier.fillMaxWidth(), + isBoostedNote = false, + isHiddenFeed = state.showHidden.value, + quotesLeft = 3, + accountViewModel = accountViewModel, + nav = nav, + ) + } + } + + HorizontalDivider( + thickness = DividerThickness, + ) + } + } } From 39c9b4d50f1e5cb95e456653e322c4c8f51f729d Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 27 Jun 2024 12:19:55 -0400 Subject: [PATCH 33/49] Adjusting default zaps for the Zap the Devs button --- .../vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt index 7bbf84b53..c931ada0c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt @@ -491,7 +491,7 @@ fun customZapClick( } else if (accountViewModel.account.zapAmountChoices.size == 1) { val amount = accountViewModel.account.zapAmountChoices.first() - if (amount > 600) { + if (amount > 1100) { accountViewModel.zap( baseNote, amount * 1000, @@ -509,7 +509,7 @@ fun customZapClick( // recommends amounts for a monthly release. } } else if (accountViewModel.account.zapAmountChoices.size > 1) { - if (accountViewModel.account.zapAmountChoices.any { it > 600 }) { + if (accountViewModel.account.zapAmountChoices.any { it > 1100 }) { onMultipleChoices(accountViewModel.account.zapAmountChoices) } else { onMultipleChoices(listOf(1000L, 5_000L, 10_000L)) From a89440cba2832ae00864a3c29443298b0402a8ae Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 27 Jun 2024 15:28:09 -0400 Subject: [PATCH 34/49] Moves to non-deterministic signatures --- .../quartz/crypto/nip01/Nip01Test.kt | 93 +++++++++++++++++++ .../quartz/crypto/nip01/Nip01.kt | 7 +- 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip01/Nip01Test.kt diff --git a/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip01/Nip01Test.kt b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip01/Nip01Test.kt new file mode 100644 index 000000000..5c93f1cbb --- /dev/null +++ b/quartz/src/androidTest/java/com/vitorpamplona/quartz/crypto/nip01/Nip01Test.kt @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.crypto.nip01 + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.vitorpamplona.quartz.encoders.hexToByteArray +import com.vitorpamplona.quartz.encoders.toHexKey +import fr.acinq.secp256k1.Secp256k1 +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import java.security.SecureRandom + +@RunWith(AndroidJUnit4::class) +class Nip01Test { + private val nip01 = Nip01(Secp256k1.get(), SecureRandom()) + private val privateKey = "f410f88bcec6cbfda04d6a273c7b1dd8bba144cd45b71e87109cfa11dd7ed561".hexToByteArray() + + @Test + fun testGetPublicFromPrivateKey() { + assertEquals( + "7d4b8806f1fd713c287235411bf95aa81b7242ead892733ec84b3f2719845be6", + nip01.pubkeyCreate(privateKey).toHexKey(), + ) + } + + @Test + fun testDeterministicSign() { + assertEquals( + "1484d0e0bd62165e822e31f1f4cc8e1ce8e20c30a060e24fb0ecd7baf7c624f661fb7a3e4f0ddb43018e5f0b4892c929af64d8b7a86021aa081ec8231e3dfa37", + nip01.signDeterministic(nip01.sha256("Test".toByteArray()), privateKey).toHexKey(), + ) + } + + @Test + fun testSha256() { + assertEquals( + "532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25", + nip01.sha256("Test".toByteArray()).toHexKey(), + ) + } + + @Test + fun testDeterministicVerify() { + assertTrue( + nip01.verify( + "1484d0e0bd62165e822e31f1f4cc8e1ce8e20c30a060e24fb0ecd7baf7c624f661fb7a3e4f0ddb43018e5f0b4892c929af64d8b7a86021aa081ec8231e3dfa37".hexToByteArray(), + nip01.sha256("Test".toByteArray()), + nip01.pubkeyCreate(privateKey), + ), + ) + } + + @Test + fun testNonDeterministicSign() { + assertNotEquals( + "1484d0e0bd62165e822e31f1f4cc8e1ce8e20c30a060e24fb0ecd7baf7c624f661fb7a3e4f0ddb43018e5f0b4892c929af64d8b7a86021aa081ec8231e3dfa37", + nip01.sign(nip01.sha256("Test".toByteArray()), privateKey).toHexKey(), + ) + } + + @Test + fun testNonDeterministicSignVerify() { + val signature = nip01.sign(nip01.sha256("Test".toByteArray()), privateKey) + assertTrue( + nip01.verify( + signature, + nip01.sha256("Test".toByteArray()), + nip01.pubkeyCreate(privateKey), + ), + ) + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip01/Nip01.kt b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip01/Nip01.kt index 3bbf58ea3..eb5159735 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip01/Nip01.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/crypto/nip01/Nip01.kt @@ -38,9 +38,14 @@ class Nip01( fun sign( data: ByteArray, privKey: ByteArray, - auxrand32: ByteArray? = null, + auxrand32: ByteArray? = random(32), ): ByteArray = secp256k1.signSchnorr(data, privKey, auxrand32) + fun signDeterministic( + data: ByteArray, + privKey: ByteArray, + ): ByteArray = secp256k1.signSchnorr(data, privKey, null) + fun verify( signature: ByteArray, hash: ByteArray, From 989099c791d767341f80ce66e6ff684a178f71bd Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 27 Jun 2024 16:47:46 -0400 Subject: [PATCH 35/49] Refactors PlaybackService --- .../playback/CustomMediaSourceFactory.kt | 63 +++++++++++++++++++ .../playback/MultiPlayerPlaybackManager.kt | 14 ++--- .../service/playback/PlaybackService.kt | 52 +-------------- 3 files changed, 72 insertions(+), 57 deletions(-) create mode 100644 amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/CustomMediaSourceFactory.kt diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/CustomMediaSourceFactory.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/CustomMediaSourceFactory.kt new file mode 100644 index 000000000..0b79bd061 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/CustomMediaSourceFactory.kt @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.service.playback + +import androidx.media3.common.MediaItem +import androidx.media3.common.util.UnstableApi +import androidx.media3.datasource.okhttp.OkHttpDataSource +import androidx.media3.exoplayer.drm.DrmSessionManagerProvider +import androidx.media3.exoplayer.source.DefaultMediaSourceFactory +import androidx.media3.exoplayer.source.MediaSource +import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy +import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.ammolite.service.HttpClientManager + +/** + * HLS LiveStreams cannot use cache. + */ +@UnstableApi +class CustomMediaSourceFactory : MediaSource.Factory { + private var cachingFactory: MediaSource.Factory = + DefaultMediaSourceFactory(Amethyst.instance.videoCache.get(HttpClientManager.getHttpClient())) + private var nonCachingFactory: MediaSource.Factory = + DefaultMediaSourceFactory(OkHttpDataSource.Factory(HttpClientManager.getHttpClient())) + + override fun setDrmSessionManagerProvider(drmSessionManagerProvider: DrmSessionManagerProvider): MediaSource.Factory { + cachingFactory.setDrmSessionManagerProvider(drmSessionManagerProvider) + nonCachingFactory.setDrmSessionManagerProvider(drmSessionManagerProvider) + return this + } + + override fun setLoadErrorHandlingPolicy(loadErrorHandlingPolicy: LoadErrorHandlingPolicy): MediaSource.Factory { + cachingFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy) + nonCachingFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy) + return this + } + + override fun getSupportedTypes(): IntArray = nonCachingFactory.supportedTypes + + override fun createMediaSource(mediaItem: MediaItem): MediaSource { + if (mediaItem.mediaId.contains(".m3u8", true)) { + return nonCachingFactory.createMediaSource(mediaItem) + } + return cachingFactory.createMediaSource(mediaItem) + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/MultiPlayerPlaybackManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/MultiPlayerPlaybackManager.kt index f87528a12..e1ba0d90a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/MultiPlayerPlaybackManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/MultiPlayerPlaybackManager.kt @@ -68,14 +68,13 @@ class MultiPlayerPlaybackManager( private fun getCallbackIntent( callbackUri: String, applicationContext: Context, - ): PendingIntent { - return PendingIntent.getActivity( + ): PendingIntent = + PendingIntent.getActivity( applicationContext, 0, Intent(Intent.ACTION_VIEW, callbackUri.toUri(), applicationContext, MainActivity::class.java), PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT, ) - } @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) fun getMediaSession( @@ -86,8 +85,6 @@ class MultiPlayerPlaybackManager( applicationContext: Context, ): MediaSession { val existingSession = playingMap.get(id) ?: cache.get(id) - // avoids saving positions for live streams otherwise caching goes crazy - val mustCachePositions = !uri.contains(".m3u8", true) if (existingSession != null) return existingSession val player = @@ -111,6 +108,9 @@ class MultiPlayerPlaybackManager( player.addListener( object : Player.Listener { + // avoids saving positions for live streams otherwise caching goes crazy + val mustCachePositions = !uri.contains(".m3u8", true) + override fun onIsPlayingChanged(isPlaying: Boolean) { if (isPlaying) { player.setWakeMode(C.WAKE_MODE_NETWORK) @@ -180,7 +180,5 @@ class MultiPlayerPlaybackManager( } } - fun playingContent(): Collection { - return playingMap.values - } + fun playingContent(): Collection = playingMap.values } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt index 449055818..0c73a3c99 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/PlaybackService.kt @@ -23,70 +23,23 @@ package com.vitorpamplona.amethyst.service.playback import android.content.Intent import android.util.Log import androidx.annotation.OptIn -import androidx.media3.common.MediaItem import androidx.media3.common.util.UnstableApi -import androidx.media3.datasource.okhttp.OkHttpDataSource -import androidx.media3.exoplayer.drm.DrmSessionManagerProvider -import androidx.media3.exoplayer.source.DefaultMediaSourceFactory -import androidx.media3.exoplayer.source.MediaSource -import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy import androidx.media3.session.MediaSession import androidx.media3.session.MediaSessionService -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.ammolite.service.HttpClientManager -/** - * HLS LiveStreams cannot use cache. - */ -@UnstableApi -class CustomMediaSourceFactory() : MediaSource.Factory { - private var cachingFactory: MediaSource.Factory = - DefaultMediaSourceFactory(Amethyst.instance.videoCache.get(HttpClientManager.getHttpClient())) - private var nonCachingFactory: MediaSource.Factory = - DefaultMediaSourceFactory(OkHttpDataSource.Factory(HttpClientManager.getHttpClient())) - - override fun setDrmSessionManagerProvider(drmSessionManagerProvider: DrmSessionManagerProvider): MediaSource.Factory { - cachingFactory.setDrmSessionManagerProvider(drmSessionManagerProvider) - nonCachingFactory.setDrmSessionManagerProvider(drmSessionManagerProvider) - return this - } - - override fun setLoadErrorHandlingPolicy(loadErrorHandlingPolicy: LoadErrorHandlingPolicy): MediaSource.Factory { - cachingFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy) - nonCachingFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy) - return this - } - - override fun getSupportedTypes(): IntArray { - return nonCachingFactory.supportedTypes - } - - override fun createMediaSource(mediaItem: MediaItem): MediaSource { - if (mediaItem.mediaId.contains(".m3u8", true)) { - return nonCachingFactory.createMediaSource(mediaItem) - } - return cachingFactory.createMediaSource(mediaItem) - } -} - class PlaybackService : MediaSessionService() { private var videoViewedPositionCache = VideoViewedPositionCache() private var managerAllInOne: MultiPlayerPlaybackManager? = null @OptIn(UnstableApi::class) - fun newAllInOneDataSource(): MediaSource.Factory { - // This might be needed for live kit. - // return WssOrHttpFactory(HttpClientManager.getHttpClient()) - return CustomMediaSourceFactory() - } - fun lazyDS(): MultiPlayerPlaybackManager { managerAllInOne?.let { return it } - val newInstance = MultiPlayerPlaybackManager(newAllInOneDataSource(), videoViewedPositionCache) + val newInstance = MultiPlayerPlaybackManager(CustomMediaSourceFactory(), videoViewedPositionCache) managerAllInOne = newInstance return newInstance } @@ -102,10 +55,11 @@ class PlaybackService : MediaSessionService() { HttpClientManager.proxyChangeListeners.add(this@PlaybackService::onProxyUpdated) } + @OptIn(UnstableApi::class) private fun onProxyUpdated() { val toDestroyAllInOne = managerAllInOne - managerAllInOne = MultiPlayerPlaybackManager(newAllInOneDataSource(), videoViewedPositionCache) + managerAllInOne = MultiPlayerPlaybackManager(CustomMediaSourceFactory(), videoViewedPositionCache) toDestroyAllInOne?.releaseAppPlayers() } From 4ee3694292d7e14d16189b6bf9420feace13da3c Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 27 Jun 2024 16:49:05 -0400 Subject: [PATCH 36/49] Fixes error when trying to decrypt the PrivateOutboxRelayList event for an account that is not currently active. --- .../service/NostrAccountDataSource.kt | 1 - .../NIP90ContentDiscoveryResponseEvent.kt | 2 +- .../events/PrivateOutboxRelayListEvent.kt | 68 +++++++++---------- .../quartz/signers/ExternalSignerLauncher.kt | 15 ++-- 4 files changed, 39 insertions(+), 47 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt index 586332510..3d236215a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt @@ -122,7 +122,6 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { ContactListEvent.KIND, AdvertisedRelayListEvent.KIND, ChatMessageRelayListEvent.KIND, - PrivateOutboxRelayListEvent.KIND, SearchRelayListEvent.KIND, FileServersEvent.KIND, MuteListEvent.KIND, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/NIP90ContentDiscoveryResponseEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/NIP90ContentDiscoveryResponseEvent.kt index 535bed7b6..9e0ba0500 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/NIP90ContentDiscoveryResponseEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/NIP90ContentDiscoveryResponseEvent.kt @@ -57,7 +57,7 @@ class NIP90ContentDiscoveryResponseEvent( } } } catch (e: Throwable) { - Log.w("GeneralList", "Error parsing the JSON ${e.message}") + Log.w("NIP90ContentDiscoveryResponseEvent", "Error parsing the JSON ${e.message}") } return events ?: listOf() diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateOutboxRelayListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateOutboxRelayListEvent.kt index 0121ebec6..07551542a 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateOutboxRelayListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateOutboxRelayListEvent.kt @@ -41,27 +41,25 @@ class PrivateOutboxRelayListEvent( override fun dTag() = FIXED_D_TAG - fun relays(): List? { - return tags.mapNotNull { - if (it.size > 1 && it[0] == "relay") { - it[1] - } else { - null - } - }.plus( - privateTagsCache?.mapNotNull { + fun relays(): List? = + tags + .mapNotNull { if (it.size > 1 && it[0] == "relay") { it[1] } else { null } - } ?: emptyList(), - ).ifEmpty { null } - } + }.plus( + privateTagsCache?.mapNotNull { + if (it.size > 1 && it[0] == "relay") { + it[1] + } else { + null + } + } ?: emptyList(), + ).ifEmpty { null } - fun cachedPrivateTags(): Array>? { - return privateTagsCache - } + fun cachedPrivateTags(): Array>? = privateTagsCache fun privateTags( signer: NostrSigner, @@ -79,11 +77,15 @@ class PrivateOutboxRelayListEvent( try { signer.nip44Decrypt(content, pubKey) { - privateTagsCache = mapper.readValue>>(it) - privateTagsCache?.let { onReady(it) } + try { + privateTagsCache = mapper.readValue>>(it) + privateTagsCache?.let { onReady(it) } + } catch (e: Throwable) { + Log.w("PrivateOutboxRelayListEvent", "Error parsing the JSON: ${e.message}. Json `$it` from event `${toNostrUri()}`") + } } } catch (e: Throwable) { - Log.w("GeneralList", "Error parsing the JSON ${e.message}") + Log.w("PrivateOutboxRelayListEvent", "Error decrypting content: ${e.message}. Event: `${toNostrUri()}`") } } @@ -92,13 +94,9 @@ class PrivateOutboxRelayListEvent( const val FIXED_D_TAG = "" val TAGS = arrayOf(arrayOf("alt", "Relay list to store private content from this author")) - fun createAddressATag(pubKey: HexKey): ATag { - return ATag(KIND, pubKey, FIXED_D_TAG, null) - } + fun createAddressATag(pubKey: HexKey): ATag = ATag(KIND, pubKey, FIXED_D_TAG, null) - fun createAddressTag(pubKey: HexKey): String { - return ATag.assembleATag(KIND, pubKey, FIXED_D_TAG) - } + fun createAddressTag(pubKey: HexKey): String = ATag.assembleATag(KIND, pubKey, FIXED_D_TAG) fun encryptTags( privateTags: Array>? = null, @@ -114,11 +112,11 @@ class PrivateOutboxRelayListEvent( ) } - fun createTagArray(relays: List): Array> { - return relays.map { - arrayOf("relay", it) - }.toTypedArray() - } + fun createTagArray(relays: List): Array> = + relays + .map { + arrayOf("relay", it) + }.toTypedArray() fun updateRelayList( earlierVersion: PrivateOutboxRelayListEvent, @@ -128,11 +126,13 @@ class PrivateOutboxRelayListEvent( onReady: (PrivateOutboxRelayListEvent) -> Unit, ) { val tags = - earlierVersion.privateTagsCache?.filter { it[0] != "relay" }?.plus( - relays.map { - arrayOf("relay", it) - }, - )?.toTypedArray() ?: emptyArray() + earlierVersion.privateTagsCache + ?.filter { it[0] != "relay" } + ?.plus( + relays.map { + arrayOf("relay", it) + }, + )?.toTypedArray() ?: emptyArray() encryptTags(tags, signer) { signer.sign(createdAt, KIND, TAGS, it) { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/signers/ExternalSignerLauncher.kt b/quartz/src/main/java/com/vitorpamplona/quartz/signers/ExternalSignerLauncher.kt index a3dcf9952..bd6b0644d 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/signers/ExternalSignerLauncher.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/signers/ExternalSignerLauncher.kt @@ -52,9 +52,7 @@ class Permission( val type: String, val kind: Int? = null, ) { - fun toJson(): String { - return "{\"type\":\"${type}\",\"kind\":$kind}" - } + fun toJson(): String = "{\"type\":\"${type}\",\"kind\":$kind}" } class Result( @@ -89,9 +87,7 @@ class Result( /** * Parses the json with a string of events to an Array of Event objects. */ - fun fromJsonArray(json: String): Array { - return mapper.readValue(json) - } + fun fromJsonArray(json: String): Array = mapper.readValue(json) } } @@ -272,9 +268,7 @@ class ExternalSignerLauncher( signerType: SignerType, data: Array, columnName: String = "signature", - ): kotlin.Result { - return getDataFromResolver(signerType, data, columnName, contentResolver) - } + ): kotlin.Result = getDataFromResolver(signerType, data, columnName, contentResolver) private fun getDataFromResolver( signerType: SignerType, @@ -298,8 +292,7 @@ class ExternalSignerLauncher( "1", null, null, - ) - .use { + ).use { if (it == null) { return kotlin.Result.success(null) } From 6c0b22f12990faa586ff6559cce0a843b8cadff1 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 27 Jun 2024 16:49:05 -0400 Subject: [PATCH 37/49] Fixes error when trying to decrypt the PrivateOutboxRelayList event for an account that is not currently active. --- .../service/NostrAccountDataSource.kt | 10 ++- .../NIP90ContentDiscoveryResponseEvent.kt | 2 +- .../events/PrivateOutboxRelayListEvent.kt | 68 +++++++++---------- .../quartz/signers/ExternalSignerLauncher.kt | 15 ++-- 4 files changed, 47 insertions(+), 48 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt index 586332510..0d91a22f8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt @@ -104,7 +104,14 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { types = COMMON_FEED_TYPES, filter = Filter( - kinds = listOf(StatusEvent.KIND, AdvertisedRelayListEvent.KIND, ChatMessageRelayListEvent.KIND, SearchRelayListEvent.KIND, PrivateOutboxRelayListEvent.KIND), + kinds = + listOf( + StatusEvent.KIND, + AdvertisedRelayListEvent.KIND, + ChatMessageRelayListEvent.KIND, + SearchRelayListEvent.KIND, + PrivateOutboxRelayListEvent.KIND, + ), authors = listOf(account.userProfile().pubkeyHex), limit = 10, ), @@ -122,7 +129,6 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { ContactListEvent.KIND, AdvertisedRelayListEvent.KIND, ChatMessageRelayListEvent.KIND, - PrivateOutboxRelayListEvent.KIND, SearchRelayListEvent.KIND, FileServersEvent.KIND, MuteListEvent.KIND, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/NIP90ContentDiscoveryResponseEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/NIP90ContentDiscoveryResponseEvent.kt index 535bed7b6..9e0ba0500 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/NIP90ContentDiscoveryResponseEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/NIP90ContentDiscoveryResponseEvent.kt @@ -57,7 +57,7 @@ class NIP90ContentDiscoveryResponseEvent( } } } catch (e: Throwable) { - Log.w("GeneralList", "Error parsing the JSON ${e.message}") + Log.w("NIP90ContentDiscoveryResponseEvent", "Error parsing the JSON ${e.message}") } return events ?: listOf() diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateOutboxRelayListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateOutboxRelayListEvent.kt index 0121ebec6..07551542a 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateOutboxRelayListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateOutboxRelayListEvent.kt @@ -41,27 +41,25 @@ class PrivateOutboxRelayListEvent( override fun dTag() = FIXED_D_TAG - fun relays(): List? { - return tags.mapNotNull { - if (it.size > 1 && it[0] == "relay") { - it[1] - } else { - null - } - }.plus( - privateTagsCache?.mapNotNull { + fun relays(): List? = + tags + .mapNotNull { if (it.size > 1 && it[0] == "relay") { it[1] } else { null } - } ?: emptyList(), - ).ifEmpty { null } - } + }.plus( + privateTagsCache?.mapNotNull { + if (it.size > 1 && it[0] == "relay") { + it[1] + } else { + null + } + } ?: emptyList(), + ).ifEmpty { null } - fun cachedPrivateTags(): Array>? { - return privateTagsCache - } + fun cachedPrivateTags(): Array>? = privateTagsCache fun privateTags( signer: NostrSigner, @@ -79,11 +77,15 @@ class PrivateOutboxRelayListEvent( try { signer.nip44Decrypt(content, pubKey) { - privateTagsCache = mapper.readValue>>(it) - privateTagsCache?.let { onReady(it) } + try { + privateTagsCache = mapper.readValue>>(it) + privateTagsCache?.let { onReady(it) } + } catch (e: Throwable) { + Log.w("PrivateOutboxRelayListEvent", "Error parsing the JSON: ${e.message}. Json `$it` from event `${toNostrUri()}`") + } } } catch (e: Throwable) { - Log.w("GeneralList", "Error parsing the JSON ${e.message}") + Log.w("PrivateOutboxRelayListEvent", "Error decrypting content: ${e.message}. Event: `${toNostrUri()}`") } } @@ -92,13 +94,9 @@ class PrivateOutboxRelayListEvent( const val FIXED_D_TAG = "" val TAGS = arrayOf(arrayOf("alt", "Relay list to store private content from this author")) - fun createAddressATag(pubKey: HexKey): ATag { - return ATag(KIND, pubKey, FIXED_D_TAG, null) - } + fun createAddressATag(pubKey: HexKey): ATag = ATag(KIND, pubKey, FIXED_D_TAG, null) - fun createAddressTag(pubKey: HexKey): String { - return ATag.assembleATag(KIND, pubKey, FIXED_D_TAG) - } + fun createAddressTag(pubKey: HexKey): String = ATag.assembleATag(KIND, pubKey, FIXED_D_TAG) fun encryptTags( privateTags: Array>? = null, @@ -114,11 +112,11 @@ class PrivateOutboxRelayListEvent( ) } - fun createTagArray(relays: List): Array> { - return relays.map { - arrayOf("relay", it) - }.toTypedArray() - } + fun createTagArray(relays: List): Array> = + relays + .map { + arrayOf("relay", it) + }.toTypedArray() fun updateRelayList( earlierVersion: PrivateOutboxRelayListEvent, @@ -128,11 +126,13 @@ class PrivateOutboxRelayListEvent( onReady: (PrivateOutboxRelayListEvent) -> Unit, ) { val tags = - earlierVersion.privateTagsCache?.filter { it[0] != "relay" }?.plus( - relays.map { - arrayOf("relay", it) - }, - )?.toTypedArray() ?: emptyArray() + earlierVersion.privateTagsCache + ?.filter { it[0] != "relay" } + ?.plus( + relays.map { + arrayOf("relay", it) + }, + )?.toTypedArray() ?: emptyArray() encryptTags(tags, signer) { signer.sign(createdAt, KIND, TAGS, it) { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/signers/ExternalSignerLauncher.kt b/quartz/src/main/java/com/vitorpamplona/quartz/signers/ExternalSignerLauncher.kt index a3dcf9952..bd6b0644d 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/signers/ExternalSignerLauncher.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/signers/ExternalSignerLauncher.kt @@ -52,9 +52,7 @@ class Permission( val type: String, val kind: Int? = null, ) { - fun toJson(): String { - return "{\"type\":\"${type}\",\"kind\":$kind}" - } + fun toJson(): String = "{\"type\":\"${type}\",\"kind\":$kind}" } class Result( @@ -89,9 +87,7 @@ class Result( /** * Parses the json with a string of events to an Array of Event objects. */ - fun fromJsonArray(json: String): Array { - return mapper.readValue(json) - } + fun fromJsonArray(json: String): Array = mapper.readValue(json) } } @@ -272,9 +268,7 @@ class ExternalSignerLauncher( signerType: SignerType, data: Array, columnName: String = "signature", - ): kotlin.Result { - return getDataFromResolver(signerType, data, columnName, contentResolver) - } + ): kotlin.Result = getDataFromResolver(signerType, data, columnName, contentResolver) private fun getDataFromResolver( signerType: SignerType, @@ -298,8 +292,7 @@ class ExternalSignerLauncher( "1", null, null, - ) - .use { + ).use { if (it == null) { return kotlin.Result.success(null) } From 700974a5ae27a5f4274463ca8e13dd0d29a879ac Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 27 Jun 2024 16:57:57 -0400 Subject: [PATCH 38/49] Updates testing libs --- gradle/libs.versions.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 57771fa2a..787c98808 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ accompanistAdaptive = "0.34.0" activityCompose = "1.9.0" agp = "8.5.0" androidKotlinGeohash = "1.0" -androidxJunit = "1.2.0" +androidxJunit = "1.2.1" appcompat = "1.7.0" audiowaveform = "1.1.1" benchmark = "1.2.4" @@ -13,7 +13,7 @@ blurhash = "1.0.0" coil = "2.6.0" composeBom = "2024.06.00" coreKtx = "1.13.1" -espressoCore = "3.6.0" +espressoCore = "3.6.1" firebaseBom = "33.1.1" fragmentKtx = "1.8.1" gms = "4.4.2" @@ -31,7 +31,7 @@ media3 = "1.3.1" mockk = "1.13.11" navigationCompose = "2.7.7" okhttp = "5.0.0-alpha.14" -runner = "1.6.0" +runner = "1.6.1" rfc3986 = "0.1.0" secp256k1KmpJniAndroid = "0.15.0" securityCryptoKtx = "1.1.0-alpha06" From 2f9438d48d3e38e958250be5d0e84a1f8d1c1eea Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 27 Jun 2024 21:00:06 +0000 Subject: [PATCH 39/49] New Crowdin translations by GitHub Action --- amethyst/src/main/res/values-fr/strings.xml | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/amethyst/src/main/res/values-fr/strings.xml b/amethyst/src/main/res/values-fr/strings.xml index ca8038690..4a5264570 100644 --- a/amethyst/src/main/res/values-fr/strings.xml +++ b/amethyst/src/main/res/values-fr/strings.xml @@ -14,6 +14,7 @@ Impossible de déchiffrer le message Image de groupe Contenu choquant + Spam Le nombre d\'événements spam provenant de ce relais Falsification d\'identité Comportement illégal @@ -44,11 +45,15 @@ Connectez-vous avec une clé privée pour ne plus Suivre Vous utilisez une clé publique et les clés publiques sont en lecture seule. Connectez-vous avec une clé privée pour pouvoir masquer un mot ou une phrase Vous utilisez une clé publique et les clés publiques sont en lecture seule. Connectez-vous avec une clé privée pour pouvoir afficher un mot ou une phrase + Zaps Nombre de vues + Boost boosté modifié modification #%1$s + original Citation + Fork Proposer une Modification Nouveau montant en Sats Ajouter @@ -77,6 +82,7 @@ Nom de canal Mon groupe spectaculaire Url de l\'image + Description "à propos" Quoi de neuf ? Envoyer @@ -122,6 +128,8 @@ Nouvelles demandes Utilisateurs bloqués Nouveaux sujets + Conversations + Notes Réponses "Suivis" "Signalements" @@ -182,6 +190,7 @@ Chat public messages reçus Retirer + Auto traduit de vers Montre en %1$s en premier @@ -190,6 +199,9 @@ Adresse Nostr jamais maintenant + h + m + d Nudité Blasphème / Discours haineux Signaler Discours haineux @@ -286,8 +298,13 @@ Champs requis: Bénéficiaires du Zap Description du sondage primaire… + Option %s Description de l\'option du Sondage Champs optionnels : + Zap minimum + Zap maximum + Consensus + (0–100)% Clôturer après jours Impossible de voter @@ -312,11 +329,13 @@ Un bateau bleu sur une plage de sable blanc au coucher du soleil Type de Zap Zap Type pour toutes les options + Public Tout le monde peut voir la transaction et le message Privé L\'expéditeur et le receveur peuvent se voir et lire le message Anonyme Le receveur et le public ne savent pas qui a envoyé le paiement + Non-Zap Aucune trace sur Nostr, seulement sur le Lightning Serveur fichier Adresse LN ou @Utilisateur @@ -348,6 +367,7 @@ Vous notifie lorsqu\'un message privé est reçu Zaps reçus Vous notifie lorsque quelqu\'un vous zap + %1$s sats De %1$s pour %1$s Notifier: @@ -377,7 +397,9 @@ Le nombre d\'octets qui ont été reçus depuis ce relais, y compris les filtres et les événements Une erreur s\'est produite en récupérant les informations du relay depuis %1$s Propriétaire + Version Logiciel + Contact NIPs supportés Frais d\'admission URL de payments @@ -426,9 +448,11 @@ Paramètres Toujours Wifi uniquement + WiFi illimité Jamais Complet Simplifié + Performance Système Clair Sombre @@ -461,6 +485,7 @@ Nouvelle Fonctionnalité Pour activer ce mode, Amethyst doit envoyer un message NIP-17 (GiftWrapped, Sealed Direct et Group Messages). Le protocole NIP-17 est nouveau et la plupart des clients ne l\'ont pas encore mis en oeuvre. Assurez-vous que le destinataire utilise un client compatible. Activer + Public Nouveau Groupe Public ou Privé Privé À @@ -512,6 +537,7 @@ Configuration lightning manquante L\'utilisateur %1$s n\'a pas configuré d\'adresse Lightning pour recevoir des sats Pourcentage + 25 Diviser les zaps avec Transférer les zaps à Portefeuilles Lightning introuvables @@ -578,9 +604,11 @@ Bonjour, est-ce toujours disponible ? Vendre un Objet Titre + iPhone 13 État Catégorie Prix (en Sats) + 1000 Emplacement Ville, État, Pays Neuf @@ -598,6 +626,9 @@ Articles de collection Livres Animaux de compagnie + Sports + Fitness + Art Artisanat Accueil Bureau @@ -613,10 +644,14 @@ Impossible de préparer le fichier local à téléverser: %1$s Modifier le brouillon Se connecter avec un QR Code + Route Accueil Rechercher Découvrir + Messages + Notifications Général + Vidéos courtes Filtres de Sécurité Nouveau Message Nouveaux Shorts : images ou vidéos @@ -626,6 +661,8 @@ Répondre Booster ou Citer J\'aime + Zap + Modifier les réactions rapides Photo de Profil de %1$s Relais %1$s Développer la liste des relais @@ -680,13 +717,16 @@ Faire un don maintenant vous a été apporté par : Cette version vous a été apportée par : + Version %1$s Merci ! Limite maximale Écritures limitées Forké depuis + FORK Dépôt Git : %1$s Web : Clone : + OTS: %1$s Preuve d\'horodatage Il y a une preuve que ce message a été signé avant %1$s. La preuve a été estampillée dans la blockchain Bitcoin à cette date et à cette heure. Modifier le Message From c18df3a1578636e09c2c8ac2b406cf4934c86c4a Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 27 Jun 2024 19:03:29 -0400 Subject: [PATCH 40/49] Fixes extra } when rendering hashtags from Markdown --- .../amethyst/ui/components/RichTextViewer.kt | 7 +++++- .../markdown/MarkdownMediaRenderer.kt | 7 +++--- .../commons/richtext/RichTextParser.kt | 25 +++++++------------ 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index a499e4b98..66daf83e2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -564,7 +564,12 @@ fun HashTag( Text( text = annotatedTermsString, - modifier = remember { Modifier.clickable { nav("Hashtag/${segment.hashtag}") } }, + modifier = + remember { + Modifier.clickable { + nav("Hashtag/${segment.hashtag}") + } + }, inlineContent = if (hashtagIcon != null) { mapOf("inlineContent" to InlineIcon(hashtagIcon)) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt index 95e5bf3eb..e84e56592 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt @@ -66,8 +66,8 @@ class MarkdownMediaRenderer( override fun shouldRenderLinkPreview( title: String?, uri: String, - ): Boolean { - return if (canPreview && uri.startsWith("http")) { + ): Boolean = + if (canPreview && uri.startsWith("http")) { if (title.isNullOrBlank() || title == uri) { true } else { @@ -76,7 +76,6 @@ class MarkdownMediaRenderer( } else { false } - } override fun renderImage( title: String?, @@ -183,7 +182,7 @@ class MarkdownMediaRenderer( richTextStringBuilder: RichTextString.Builder, ) { val tagWithoutHash = tag.removePrefix("#") - renderAsCompleteLink(tag, "nostr:Hashtag?id=$tagWithoutHash}", richTextStringBuilder) + renderAsCompleteLink(tag, "nostr:Hashtag?id=$tagWithoutHash", richTextStringBuilder) val hashtagIcon: HashtagIcon? = checkForHashtagWithIcon(tagWithoutHash) if (hashtagIcon != null) { diff --git a/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParser.kt b/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParser.kt index 6d97e120c..226263367 100644 --- a/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParser.kt +++ b/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParser.kt @@ -41,7 +41,7 @@ import java.net.URL import java.util.regex.Pattern import kotlin.coroutines.cancellation.CancellationException -class RichTextParser() { +class RichTextParser { fun parseMediaUrl( fullUrl: String, eventTags: ImmutableListOfLists, @@ -168,15 +168,14 @@ class RichTextParser() { private fun isNumber(word: String) = numberPattern.matcher(word).matches() - private fun isPhoneNumberChar(c: Char): Boolean { - return when (c) { + private fun isPhoneNumberChar(c: Char): Boolean = + when (c) { in '0'..'9' -> true '-' -> true ' ' -> true '.' -> true else -> false } - } fun isPotentialPhoneNumber(word: String): Boolean { if (word.length !in 7..14) return false @@ -191,13 +190,9 @@ class RichTextParser() { return isPotentialNumber } - fun isDate(word: String): Boolean { - return shortDatePattern.matcher(word).matches() || longDatePattern.matcher(word).matches() - } + fun isDate(word: String): Boolean = shortDatePattern.matcher(word).matches() || longDatePattern.matcher(word).matches() - private fun isArabic(text: String): Boolean { - return text.any { it in '\u0600'..'\u06FF' || it in '\u0750'..'\u077F' } - } + private fun isArabic(text: String): Boolean = text.any { it in '\u0600'..'\u06FF' || it in '\u0750'..'\u077F' } private fun wordIdentifier( word: String, @@ -331,15 +326,14 @@ class RichTextParser() { it.uppercase() } - private fun removeQueryParamsForExtensionComparison(fullUrl: String): String { - return if (fullUrl.contains("?")) { + private fun removeQueryParamsForExtensionComparison(fullUrl: String): String = + if (fullUrl.contains("?")) { fullUrl.split("?")[0].lowercase() } else if (fullUrl.contains("#")) { fullUrl.split("#")[0].lowercase() } else { fullUrl.lowercase() } - } fun isImageOrVideoUrl(url: String): Boolean { val removedParamsFromUrl = removeQueryParamsForExtensionComparison(url) @@ -358,8 +352,8 @@ class RichTextParser() { return videoExtensions.any { removedParamsFromUrl.endsWith(it) } } - fun isValidURL(url: String?): Boolean { - return try { + fun isValidURL(url: String?): Boolean = + try { URL(url).toURI() true } catch (e: MalformedURLException) { @@ -367,7 +361,6 @@ class RichTextParser() { } catch (e: URISyntaxException) { false } - } fun parseImageOrVideo(fullUrl: String): BaseMediaContent { val removedParamsFromUrl = removeQueryParamsForExtensionComparison(fullUrl) From 6a626c98659ba953d6bcab49073d677d438d7b52 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 27 Jun 2024 20:12:04 -0400 Subject: [PATCH 41/49] Renders relay lists in the feed. --- .../amethyst/ui/note/NoteCompose.kt | 9 ++ .../amethyst/ui/note/types/RelayList.kt | 136 +++++++++++++++++- .../amethyst/ui/screen/ThreadFeedView.kt | 12 ++ 3 files changed, 151 insertions(+), 6 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index d6d7cd777..775ac5870 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -75,8 +75,11 @@ import com.vitorpamplona.amethyst.ui.note.elements.Reward import com.vitorpamplona.amethyst.ui.note.elements.ShowForkInformation import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay +import com.vitorpamplona.amethyst.ui.note.types.DisplayDMRelayList +import com.vitorpamplona.amethyst.ui.note.types.DisplayNIP65RelayList import com.vitorpamplona.amethyst.ui.note.types.DisplayPeopleList import com.vitorpamplona.amethyst.ui.note.types.DisplayRelaySet +import com.vitorpamplona.amethyst.ui.note.types.DisplaySearchRelayList import com.vitorpamplona.amethyst.ui.note.types.EditState import com.vitorpamplona.amethyst.ui.note.types.FileHeaderDisplay import com.vitorpamplona.amethyst.ui.note.types.FileStorageHeaderDisplay @@ -137,6 +140,7 @@ import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor import com.vitorpamplona.amethyst.ui.theme.normalWithTopMarginNoteModifier import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.replyModifier +import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent import com.vitorpamplona.quartz.events.AppDefinitionEvent import com.vitorpamplona.quartz.events.AudioHeaderEvent import com.vitorpamplona.quartz.events.AudioTrackEvent @@ -147,6 +151,7 @@ import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent import com.vitorpamplona.quartz.events.ChannelMetadataEvent import com.vitorpamplona.quartz.events.ChatMessageEvent +import com.vitorpamplona.quartz.events.ChatMessageRelayListEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent import com.vitorpamplona.quartz.events.CommunityDefinitionEvent import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent @@ -173,6 +178,7 @@ import com.vitorpamplona.quartz.events.ReactionEvent import com.vitorpamplona.quartz.events.RelaySetEvent import com.vitorpamplona.quartz.events.ReportEvent import com.vitorpamplona.quartz.events.RepostEvent +import com.vitorpamplona.quartz.events.SearchRelayListEvent import com.vitorpamplona.quartz.events.TextNoteEvent import com.vitorpamplona.quartz.events.TextNoteModificationEvent import com.vitorpamplona.quartz.events.VideoEvent @@ -604,6 +610,9 @@ private fun RenderNoteRow( is FhirResourceEvent -> RenderFhirResource(baseNote, accountViewModel, nav) is PeopleListEvent -> DisplayPeopleList(baseNote, backgroundColor, accountViewModel, nav) is RelaySetEvent -> DisplayRelaySet(baseNote, backgroundColor, accountViewModel, nav) + is ChatMessageRelayListEvent -> DisplayDMRelayList(baseNote, backgroundColor, accountViewModel, nav) + is AdvertisedRelayListEvent -> DisplayNIP65RelayList(baseNote, backgroundColor, accountViewModel, nav) + is SearchRelayListEvent -> DisplaySearchRelayList(baseNote, backgroundColor, accountViewModel, nav) is PinListEvent -> RenderPinListEvent(baseNote, backgroundColor, accountViewModel, nav) is EmojiPackEvent -> RenderEmojiPack(baseNote, true, backgroundColor, accountViewModel) is LiveActivitiesEvent -> RenderLiveActivityEvent(baseNote, accountViewModel, nav) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt index 59f0a69e3..8ddbac954 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt @@ -43,6 +43,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.actions.relays.AllRelayListView import com.vitorpamplona.amethyst.ui.components.ShowMoreButton @@ -50,8 +51,14 @@ import com.vitorpamplona.amethyst.ui.note.AddRelayButton import com.vitorpamplona.amethyst.ui.note.RemoveRelayButton import com.vitorpamplona.amethyst.ui.note.getGradient import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.ammolite.relays.RelayBriefInfoCache +import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent +import com.vitorpamplona.quartz.events.ChatMessageRelayListEvent import com.vitorpamplona.quartz.events.RelaySetEvent +import com.vitorpamplona.quartz.events.SearchRelayListEvent +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @Composable @@ -70,6 +77,119 @@ fun DisplayRelaySet( ) } + DisplayRelaySet( + relays, + noteEvent.firstTagFor("title", "name") ?: "#${noteEvent.dTag()}", + noteEvent.description(), + backgroundColor, + accountViewModel, + nav, + ) +} + +@Composable +fun DisplayNIP65RelayList( + baseNote: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + val noteEvent = baseNote.event as? AdvertisedRelayListEvent ?: return + + val writeRelays by + remember(baseNote) { + mutableStateOf( + noteEvent.writeRelays().map { RelayBriefInfoCache.RelayBriefInfo(it) }.toImmutableList(), + ) + } + + val readRelays by + remember(baseNote) { + mutableStateOf( + noteEvent.readRelays()?.map { RelayBriefInfoCache.RelayBriefInfo(it) }?.toImmutableList() ?: persistentListOf(), + ) + } + + DisplayRelaySet( + writeRelays, + stringRes(id = R.string.public_home_section), + null, + backgroundColor, + accountViewModel, + nav, + ) + + DisplayRelaySet( + readRelays, + stringRes(id = R.string.public_notif_section), + null, + backgroundColor, + accountViewModel, + nav, + ) +} + +@Composable +fun DisplayDMRelayList( + baseNote: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + val noteEvent = baseNote.event as? ChatMessageRelayListEvent ?: return + + val relays by + remember(baseNote) { + mutableStateOf( + noteEvent.relays().map { RelayBriefInfoCache.RelayBriefInfo(it) }.toImmutableList(), + ) + } + + DisplayRelaySet( + relays, + stringRes(id = R.string.dm_relays_title), + null, + backgroundColor, + accountViewModel, + nav, + ) +} + +@Composable +fun DisplaySearchRelayList( + baseNote: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + val noteEvent = baseNote.event as? SearchRelayListEvent ?: return + + val relays by + remember(baseNote) { + mutableStateOf( + noteEvent.relays().map { RelayBriefInfoCache.RelayBriefInfo(it) }.toImmutableList(), + ) + } + + DisplayRelaySet( + relays, + stringRes(id = R.string.search_relays_title), + null, + backgroundColor, + accountViewModel, + nav, + ) +} + +@Composable +fun DisplayRelaySet( + relays: ImmutableList, + relayListName: String, + relayDescription: String?, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { var expanded by remember { mutableStateOf(false) } val toMembersShow = @@ -79,10 +199,6 @@ fun DisplayRelaySet( relays.take(3) } - val relayListName by remember { derivedStateOf { "#${noteEvent.dTag()}" } } - - val relayDescription by remember { derivedStateOf { noteEvent.description() } } - Text( text = relayListName, fontWeight = FontWeight.Bold, @@ -156,11 +272,19 @@ private fun RelayOptionsAction( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val userStateRelayInfo by accountViewModel.account.userProfile().live().relayInfo.observeAsState() + val userStateRelayInfo by accountViewModel.account + .userProfile() + .live() + .relayInfo + .observeAsState() val isCurrentlyOnTheUsersList by remember(userStateRelayInfo) { derivedStateOf { - userStateRelayInfo?.user?.latestContactList?.relays()?.none { it.key == relay } == true + userStateRelayInfo + ?.user + ?.latestContactList + ?.relays() + ?.none { it.key == relay } == true } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index f63b2fcdf..0164315ba 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -111,8 +111,11 @@ import com.vitorpamplona.amethyst.ui.note.showAmount import com.vitorpamplona.amethyst.ui.note.types.AudioHeader import com.vitorpamplona.amethyst.ui.note.types.AudioTrackHeader import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay +import com.vitorpamplona.amethyst.ui.note.types.DisplayDMRelayList +import com.vitorpamplona.amethyst.ui.note.types.DisplayNIP65RelayList import com.vitorpamplona.amethyst.ui.note.types.DisplayPeopleList import com.vitorpamplona.amethyst.ui.note.types.DisplayRelaySet +import com.vitorpamplona.amethyst.ui.note.types.DisplaySearchRelayList import com.vitorpamplona.amethyst.ui.note.types.EditState import com.vitorpamplona.amethyst.ui.note.types.FileHeaderDisplay import com.vitorpamplona.amethyst.ui.note.types.FileStorageHeaderDisplay @@ -147,6 +150,7 @@ import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.ui.theme.lessImportantLink import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.selectedNote +import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent import com.vitorpamplona.quartz.events.AppDefinitionEvent import com.vitorpamplona.quartz.events.AudioHeaderEvent import com.vitorpamplona.quartz.events.AudioTrackEvent @@ -154,6 +158,7 @@ import com.vitorpamplona.quartz.events.BadgeDefinitionEvent import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent import com.vitorpamplona.quartz.events.ChannelMetadataEvent +import com.vitorpamplona.quartz.events.ChatMessageRelayListEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent import com.vitorpamplona.quartz.events.CommunityDefinitionEvent import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent @@ -176,6 +181,7 @@ import com.vitorpamplona.quartz.events.PollNoteEvent import com.vitorpamplona.quartz.events.PrivateDmEvent import com.vitorpamplona.quartz.events.RelaySetEvent import com.vitorpamplona.quartz.events.RepostEvent +import com.vitorpamplona.quartz.events.SearchRelayListEvent import com.vitorpamplona.quartz.events.TextNoteModificationEvent import com.vitorpamplona.quartz.events.VideoEvent import com.vitorpamplona.quartz.events.WikiNoteEvent @@ -528,6 +534,12 @@ private fun FullBleedNoteCompose( accountViewModel, nav, ) + } else if (noteEvent is ChatMessageRelayListEvent) { + DisplayDMRelayList(baseNote, backgroundColor, accountViewModel, nav) + } else if (noteEvent is AdvertisedRelayListEvent) { + DisplayNIP65RelayList(baseNote, backgroundColor, accountViewModel, nav) + } else if (noteEvent is SearchRelayListEvent) { + DisplaySearchRelayList(baseNote, backgroundColor, accountViewModel, nav) } else if (noteEvent is FhirResourceEvent) { RenderFhirResource(baseNote, accountViewModel, nav) } else if (noteEvent is GitRepositoryEvent) { From e181296a910e14b6d00052d03cc1c5d15eab8e67 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 27 Jun 2024 20:12:56 -0400 Subject: [PATCH 42/49] adds auth.nostr1.com as an option --- amethyst/src/main/res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 63ed8c01e..6d8f93237 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -821,7 +821,7 @@ Using Regular Relays Set up your Private Inbox relays This setting lets everybody know which relays to use when sending messages to you. Without them you might miss some messages. - Good options are:\n - inbox.nostr.wine (paid)\n - you.nostr1.com (personal relays - paid) + Good options are:\n - inbox.nostr.wine (paid)\n - auth.nostr1.com (free)\n - you.nostr1.com (personal relays - paid) Insert between 1–3 relays to serve as your private inbox. DM Inbox relays should accept any message from anyone, but only allow you to download them. Set up now @@ -837,7 +837,7 @@ Public Inbox Relays This relay type receives all replies, comments, likes and zaps to your posts. They can be paid or free relays. Limits set by the relay operator can limit the notifications you receive for the good and for the bad. For example, if you are being attacked by comment spam, paid relays can filter the spam out. Insert between 1–3 relays. DM Inbox Relays - Insert between 1–3 relays to serve as your private inbox. Others will use these relays to send DMs to you. DM Inbox relays should accept any message from anyone, but only allow you to download them. Good options are:\n - inbox.nostr.wine (paid)\n - you.nostr1.com (personal relays - paid) + Insert between 1–3 relays to serve as your private inbox. Others will use these relays to send DMs to you. DM Inbox relays should accept any message from anyone, but only allow you to download them. Good options are:\n - inbox.nostr.wine (paid)\n - auth.nostr1.com (free)\n - you.nostr1.com (personal relays - paid) Private Relays Insert between 1–3 relays to store events no one else can see, like your Drafts and/or app settings. Ideally, these relays are either local or require authentication before downloading each user\'s content. General Relays From a9cbbf66bdd8a6430e9d689984170814ece9b2e8 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 28 Jun 2024 10:40:55 -0400 Subject: [PATCH 43/49] Adds uploading error messages for common HTTP status codes. --- .../amethyst/service/HttpStatusMessages.kt | 63 +++++++++++++++++++ .../amethyst/service/Nip96Uploader.kt | 49 ++++++++++----- .../amethyst/ui/actions/EditPostViewModel.kt | 41 ++++++++---- .../amethyst/ui/actions/NewMediaModel.kt | 1 + .../amethyst/ui/actions/NewPostViewModel.kt | 1 + .../ui/actions/NewUserMetadataViewModel.kt | 1 + amethyst/src/main/res/values/strings.xml | 33 ++++++++++ 7 files changed, 161 insertions(+), 28 deletions(-) create mode 100644 amethyst/src/main/java/com/vitorpamplona/amethyst/service/HttpStatusMessages.kt diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/HttpStatusMessages.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/HttpStatusMessages.kt new file mode 100644 index 000000000..009038d54 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/HttpStatusMessages.kt @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.service + +import com.vitorpamplona.amethyst.R + +class HttpStatusMessages { + companion object { + fun resourceIdFor(statusCode: Int = 0): Int? = + when (statusCode) { + 400 -> R.string.http_status_400 + 401 -> R.string.http_status_401 + 402 -> R.string.http_status_402 + 403 -> R.string.http_status_403 + 404 -> R.string.http_status_404 + 405 -> R.string.http_status_405 + 406 -> R.string.http_status_406 + 407 -> R.string.http_status_407 + 408 -> R.string.http_status_408 + 409 -> R.string.http_status_409 + 410 -> R.string.http_status_410 + 411 -> R.string.http_status_411 + 412 -> R.string.http_status_412 + 413 -> R.string.http_status_413 + 414 -> R.string.http_status_414 + 415 -> R.string.http_status_415 + 416 -> R.string.http_status_416 + 417 -> R.string.http_status_417 + 426 -> R.string.http_status_426 + + 500 -> R.string.http_status_500 + 501 -> R.string.http_status_501 + 502 -> R.string.http_status_502 + 503 -> R.string.http_status_503 + 504 -> R.string.http_status_504 + 505 -> R.string.http_status_505 + 506 -> R.string.http_status_506 + 507 -> R.string.http_status_507 + 508 -> R.string.http_status_508 + 511 -> R.string.http_status_511 + + else -> null + } + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt index 7d069d0f1..a2b915363 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/Nip96Uploader.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.service import android.content.ContentResolver +import android.content.Context import android.net.Uri import android.provider.OpenableColumns import android.webkit.MimeTypeMap @@ -29,7 +30,9 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.amethyst.BuildConfig +import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.ammolite.service.HttpClientManager import kotlinx.coroutines.delay import kotlinx.coroutines.suspendCancellableCoroutine @@ -48,7 +51,9 @@ val charPool: List = ('a'..'z') + ('A'..'Z') + ('0'..'9') fun randomChars() = List(16) { charPool.random() }.joinToString("") -class Nip96Uploader(val account: Account?) { +class Nip96Uploader( + val account: Account?, +) { suspend fun uploadImage( uri: Uri, contentType: String?, @@ -58,6 +63,7 @@ class Nip96Uploader(val account: Account?) { server: Nip96MediaServers.ServerName, contentResolver: ContentResolver, onProgress: (percentage: Float) -> Unit, + context: Context, ): PartialEvent { val serverInfo = Nip96Retriever() @@ -74,6 +80,7 @@ class Nip96Uploader(val account: Account?) { serverInfo, contentResolver, onProgress, + context, ) } @@ -86,6 +93,7 @@ class Nip96Uploader(val account: Account?) { server: Nip96Retriever.ServerInfo, contentResolver: ContentResolver, onProgress: (percentage: Float) -> Unit, + context: Context, ): PartialEvent { checkNotInMainThread() @@ -111,6 +119,7 @@ class Nip96Uploader(val account: Account?) { sensitiveContent, server, onProgress, + context, ) } @@ -122,6 +131,7 @@ class Nip96Uploader(val account: Account?) { sensitiveContent: String?, server: Nip96Retriever.ServerInfo, onProgress: (percentage: Float) -> Unit, + context: Context, ): PartialEvent { checkNotInMainThread() @@ -130,11 +140,11 @@ class Nip96Uploader(val account: Account?) { contentType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) } ?: "" val client = HttpClientManager.getHttpClient() - val requestBody: RequestBody val requestBuilder = Request.Builder() - requestBody = - MultipartBody.Builder() + val requestBody: RequestBody = + MultipartBody + .Builder() .setType(MultipartBody.FORM) .addFormDataPart("expiration", "") .addFormDataPart("size", length.toString()) @@ -142,8 +152,7 @@ class Nip96Uploader(val account: Account?) { alt?.let { body.addFormDataPart("alt", it) } sensitiveContent?.let { body.addFormDataPart("content-warning", it) } contentType?.let { body.addFormDataPart("content_type", it) } - } - .addFormDataPart( + }.addFormDataPart( "file", "$fileName.$extension", object : RequestBody() { @@ -155,8 +164,7 @@ class Nip96Uploader(val account: Account?) { inputStream.source().use(sink::writeAll) } }, - ) - .build() + ).build() nip98Header(server.apiUrl)?.let { requestBuilder.addHeader("Authorization", it) } @@ -178,11 +186,16 @@ class Nip96Uploader(val account: Account?) { } else if (result.status == "success" && result.nip94Event != null) { return result.nip94Event } else { - throw RuntimeException("Failed to upload with message: ${result.message}") + throw RuntimeException(stringRes(context, R.string.failed_to_upload_with_message, result.message)) } } } else { - throw RuntimeException("Error Uploading image: ${response.code}") + val explanation = HttpStatusMessages.resourceIdFor(response.code) + if (explanation != null) { + throw RuntimeException(stringRes(context, R.string.failed_to_upload_with_message, stringRes(context, explanation))) + } else { + throw RuntimeException(stringRes(context, R.string.failed_to_upload_with_message, response.code)) + } } } } @@ -191,6 +204,7 @@ class Nip96Uploader(val account: Account?) { hash: String, contentType: String?, server: Nip96Retriever.ServerInfo, + context: Context, ): Boolean { val extension = contentType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) } ?: "" @@ -216,7 +230,12 @@ class Nip96Uploader(val account: Account?) { return result.status == "success" } } else { - throw RuntimeException("Error Uploading image: ${response.code}") + val explanation = HttpStatusMessages.resourceIdFor(response.code) + if (explanation != null) { + throw RuntimeException(stringRes(context, R.string.failed_to_delete_with_message, stringRes(context, explanation))) + } else { + throw RuntimeException(stringRes(context, R.string.failed_to_delete_with_message, response.code)) + } } } } @@ -233,7 +252,8 @@ class Nip96Uploader(val account: Account?) { onProgress((currentResult.percentage ?: 100) / 100f) val request: Request = - Request.Builder() + Request + .Builder() .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") .url(result.processingUrl) .build() @@ -257,13 +277,12 @@ class Nip96Uploader(val account: Account?) { } } - suspend fun nip98Header(url: String): String? { - return withTimeoutOrNull(5000) { + suspend fun nip98Header(url: String): String? = + withTimeoutOrNull(5000) { suspendCancellableCoroutine { continuation -> nip98Header(url, "POST") { authorizationToken -> continuation.resume(authorizationToken) } } } - } fun nip98Header( url: String, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt index a951d4a7a..53aa0a0e8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt @@ -53,7 +53,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch @Stable -open class EditPostViewModel() : ViewModel() { +open class EditPostViewModel : ViewModel() { var accountViewModel: AccountViewModel? = null var account: Account? = null @@ -185,6 +185,7 @@ open class EditPostViewModel() : ViewModel() { server = server.server, contentResolver = contentResolver, onProgress = {}, + context = context, ) createNIP94Record( @@ -235,13 +236,12 @@ open class EditPostViewModel() : ViewModel() { NostrSearchEventOrUserDataSource.clear() } - open fun findUrlInMessage(): String? { - return message.text.split('\n').firstNotNullOfOrNull { paragraph -> + open fun findUrlInMessage(): String? = + message.text.split('\n').firstNotNullOfOrNull { paragraph -> paragraph.split(' ').firstOrNull { word: String -> RichTextParser.isValidURL(word) || RichTextParser.isUrlWithoutScheme(word) } } - } open fun updateMessage(it: TextFieldValue) { message = it @@ -249,14 +249,18 @@ open class EditPostViewModel() : ViewModel() { if (it.selection.collapsed) { val lastWord = - it.text.substring(0, it.selection.end).substringAfterLast("\n").substringAfterLast(" ") + it.text + .substring(0, it.selection.end) + .substringAfterLast("\n") + .substringAfterLast(" ") userSuggestionAnchor = it.selection userSuggestionsMainMessage = UserSuggestionAnchor.MAIN_MESSAGE if (lastWord.startsWith("@") && lastWord.length > 2) { NostrSearchEventOrUserDataSource.search(lastWord.removePrefix("@")) viewModelScope.launch(Dispatchers.IO) { userSuggestions = - LocalCache.findUsersStartingWith(lastWord.removePrefix("@")) + LocalCache + .findUsersStartingWith(lastWord.removePrefix("@")) .sortedWith(compareBy({ account?.isFollowing(it) }, { it.toBestDisplayName() }, { it.pubkeyHex })) .reversed() } @@ -271,7 +275,10 @@ open class EditPostViewModel() : ViewModel() { userSuggestionAnchor?.let { if (userSuggestionsMainMessage == UserSuggestionAnchor.MAIN_MESSAGE) { val lastWord = - message.text.substring(0, it.end).substringAfterLast("\n").substringAfterLast(" ") + message.text + .substring(0, it.end) + .substringAfterLast("\n") + .substringAfterLast(" ") val lastWordStart = it.end - lastWord.length val wordToInsert = "@${item.pubkeyNpub()}" @@ -288,12 +295,11 @@ open class EditPostViewModel() : ViewModel() { } } - fun canPost(): Boolean { - return message.text.isNotBlank() && + fun canPost(): Boolean = + message.text.isNotBlank() && !isUploadingImage && !wantsInvoice && contentToAddUrl == null - } suspend fun createNIP94Record( uploadingResult: Nip96Uploader.PartialEvent, @@ -304,11 +310,20 @@ open class EditPostViewModel() : ViewModel() { // Images don't seem to be ready immediately after upload val imageUrl = uploadingResult.tags?.firstOrNull { it.size > 1 && it[0] == "url" }?.get(1) val remoteMimeType = - uploadingResult.tags?.firstOrNull { it.size > 1 && it[0] == "m" }?.get(1)?.ifBlank { null } + uploadingResult.tags + ?.firstOrNull { it.size > 1 && it[0] == "m" } + ?.get(1) + ?.ifBlank { null } val originalHash = - uploadingResult.tags?.firstOrNull { it.size > 1 && it[0] == "ox" }?.get(1)?.ifBlank { null } + uploadingResult.tags + ?.firstOrNull { it.size > 1 && it[0] == "ox" } + ?.get(1) + ?.ifBlank { null } val dim = - uploadingResult.tags?.firstOrNull { it.size > 1 && it[0] == "dim" }?.get(1)?.ifBlank { null } + uploadingResult.tags + ?.firstOrNull { it.size > 1 && it[0] == "dim" } + ?.get(1) + ?.ifBlank { null } val magnet = uploadingResult.tags ?.firstOrNull { it.size > 1 && it[0] == "magnet" } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt index c9d3ccf79..d3cdcfa45 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt @@ -139,6 +139,7 @@ open class NewMediaModel : ViewModel() { onProgress = { percent: Float -> uploadingPercentage.value = 0.2f + (0.2f * percent) }, + context = context, ) createNIP94Record( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt index 4dd0e23a5..55dc95a68 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt @@ -801,6 +801,7 @@ open class NewPostViewModel : ViewModel() { server = server.server, contentResolver = contentResolver, onProgress = {}, + context = context, ) createNIP94Record( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt index 02dc193f1..93fac1474 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt @@ -184,6 +184,7 @@ class NewUserMetadataViewModel : ViewModel() { server = account.defaultFileServer, contentResolver = contentResolver, onProgress = {}, + context = context, ) val url = result.tags?.firstOrNull { it.size > 1 && it[0] == "url" }?.get(1) diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 6d8f93237..0a6fd89e1 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -760,6 +760,8 @@ Server did not provide a URL after uploading Could not download uploaded media from the server Could not prepare local file to upload: %1$s + Failed to upload: %1$s + Failed to delete: %1$s Edit draft @@ -895,4 +897,35 @@ Requesting Job from DVM Payment request sent, waiting for confirmation from your wallet Waiting for DVM to confirm payment or send results + + Bad Request - The server can’t or won’t process the request. + Unauthorized - The user doesn’t have valid authentication credentials + Payment Required - The server requires payment to complete the request + Forbidden - The user doesn’t have access rights to make the request + Not Found - The server can’t find the requested address + Method Not Allowed - The server supports the request method, but not the target resource + Not Acceptable - The server doesn’t find any content that satisfies the request. + Proxy Authentication Required - The user doesn’t have valid authentication credentials + Request Timeout - The server timed out waiting for somebody else + Conflict - The server can’t fulfill the request because there’s a conflict with the resource + Gone - The content requested has been permanently deleted from the server and will not be reinstated + Length Required - The server rejects the request because it requires a defined + Precondition Failed - The request\'s preconditions in the header fields that the server fails to meet + Payload Too Large - The request is larger than the server’s defined limits, and the server refuses to process it + URI Too Long - The url requested by the client is too long for the server to process. + Unsupported Media Type - The request uses a media format the server does not support + Range Not Satisfiable - The server can’t fulfill the value indicated in the request’s Range header field. + Expectation Failed - The server can’t meet the requirements indicated by the Expect request header field + Upgrade Required - The server refuses to process the request using the current protocol unless the client upgrades to a different protocol. + + Internal Server Error - The server has encountered an unexpected error and cannot complete the request + Not Implemented - The server can’t fulfill the request or doesn’t recognize the request method + Bad Gateway - The server acts as a gateway and got an invalid response from the host + Service Unavailable - This often occurs when a server is overloaded or down for maintenance + Gateway Timeout - The server was acting as a gateway or proxy and timed out, waiting for a response + HTTP Version Not Supported - The server doesn’t support the HTTP version in the request + Variant Also Negotiates - The server has an internal configuration error + Insufficient Storage - The server doesn’t have enough storage to process the request successfully + Loop Detected - The server detects an infinite loop while processing the request + Network Authentication Required - The client must be authenticated to access the network From a57ba2550ce2bae308cba1a4e50d862d495de22c Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Fri, 28 Jun 2024 14:43:45 +0000 Subject: [PATCH 44/49] New Crowdin translations by GitHub Action --- amethyst/src/main/res/values-zh-rCN/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/amethyst/src/main/res/values-zh-rCN/strings.xml b/amethyst/src/main/res/values-zh-rCN/strings.xml index a83417094..0c0e685f1 100644 --- a/amethyst/src/main/res/values-zh-rCN/strings.xml +++ b/amethyst/src/main/res/values-zh-rCN/strings.xml @@ -103,6 +103,7 @@ 添加中继器 显示名称 我的显示名称 + Nostr 太酷了 欢迎! 用户名 我的用户名 @@ -386,6 +387,7 @@ 当帖子有你的关注的报告时警告 新回应符号 未选择回应类型。长按可更改 + Zapraiser 为这个帖子添加目标聪金额。支持的客户端可以将此显示为奖励捐赠的进度条 目标聪金额 Zapraiser 位于 %1$s。距离目标%2$s聪 @@ -671,6 +673,7 @@ 比特币发票 取消比特币发票 取消出售物品 + Zapraiser 取消 Zapraiser 地点 移除地点 From 347b82ef7f5161294862d1480201688e67cd0a81 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 28 Jun 2024 13:28:05 -0400 Subject: [PATCH 45/49] Fixes when the logged in accounts only include the current account. --- .../vitorpamplona/amethyst/service/NostrAccountDataSource.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt index 0d91a22f8..4df69e1e4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt @@ -118,7 +118,8 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { ) fun createOtherAccountsBaseFilter(): TypedFilter? { - if (otherAccounts.isEmpty()) return null + val otherAuthors = otherAccounts.filter { it != account.userProfile().pubkeyHex } + if (otherAuthors.isEmpty()) return null return TypedFilter( types = EVENT_FINDER_TYPES, filter = @@ -134,7 +135,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") { MuteListEvent.KIND, PeopleListEvent.KIND, ), - authors = otherAccounts.filter { it != account.userProfile().pubkeyHex }, + authors = otherAuthors, limit = 100, ), ) From f0044afeabed4bf7f06a368577a731deb7aa8a26 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 28 Jun 2024 14:06:08 -0400 Subject: [PATCH 46/49] Fixes bug on string resources. --- .../EventNotificationConsumer.kt | 25 ++++++++++++++++--- .../amethyst/ui/StringResourceCache.kt | 4 +-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt index 4ff65b474..7580bdc2e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt @@ -205,38 +205,54 @@ class EventNotificationConsumer( event: LnZapEvent, acc: Account, ) { + Log.d("EventNotificationConsumer", "Notify Start ${event.toNostrUri()}") val noteZapEvent = LocalCache.getNoteIfExists(event.id) ?: return + Log.d("EventNotificationConsumer", "Notify Not Notified Yet") + // old event being re-broadcast if (event.createdAt < TimeUtils.fifteenMinutesAgo()) return + Log.d("EventNotificationConsumer", "Notify Not an old event") + val noteZapRequest = event.zapRequest?.id?.let { LocalCache.checkGetOrCreateNote(it) } ?: return val noteZapped = event.zappedPost().firstOrNull()?.let { LocalCache.checkGetOrCreateNote(it) } ?: return + Log.d("EventNotificationConsumer", "Notify ZapRequest $noteZapRequest zapped $noteZapped") + if ((event.amount ?: BigDecimal.ZERO) < BigDecimal.TEN) return + Log.d("EventNotificationConsumer", "Notify Amount Bigger than 10") + if (event.isTaggedUser(acc.userProfile().pubkeyHex)) { val amount = showAmount(event.amount) + + Log.d("EventNotificationConsumer", "Notify Amount $amount") + (noteZapRequest.event as? LnZapRequestEvent)?.let { event -> acc.decryptZapContentAuthor(noteZapRequest) { + Log.d("EventNotificationConsumer", "Notify Decrypted if Private Zap ${event.id}") + val author = LocalCache.getOrCreateUser(it.pubKey) val senderInfo = Pair(author, it.content.ifBlank { null }) acc.decryptContent(noteZapped) { + Log.d("EventNotificationConsumer", "Notify Decrypted if Private Note") + val zappedContent = it.split("\n").get(0) val user = senderInfo.first.toBestDisplayName() - var title = - stringRes(applicationContext, R.string.app_notification_zaps_channel_message, amount) + var title = stringRes(applicationContext, R.string.app_notification_zaps_channel_message, amount) senderInfo.second?.ifBlank { null }?.let { title += " ($it)" } + var content = stringRes( applicationContext, R.string.app_notification_zaps_channel_message_from, user, ) - zappedContent?.let { + zappedContent.let { content += " " + stringRes( @@ -247,6 +263,9 @@ class EventNotificationConsumer( } val userPicture = senderInfo?.first?.profilePicture() val noteUri = "nostr:Notifications" + + Log.d("EventNotificationConsumer", "Notify ${event.id} $content $title $noteUri") + notificationManager() .sendZapNotification( event.id, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt index 2caf1d52b..c193a35aa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt @@ -73,7 +73,7 @@ fun stringRes( return String .format( res.configuration.locales.get(0), - resourceCache.get(id) ?: res.getString(id), + resourceCache.get(id) ?: res.getString(id).also { resourceCache.put(id, it) }, *args, - ).also { resourceCache.put(id, it) } + ) } From 7c7f704173afa330444146440b3a6332df22ee9d Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 28 Jun 2024 16:25:44 -0400 Subject: [PATCH 47/49] v0.88.5 --- amethyst/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amethyst/build.gradle b/amethyst/build.gradle index b39f077c5..869259684 100644 --- a/amethyst/build.gradle +++ b/amethyst/build.gradle @@ -12,8 +12,8 @@ android { applicationId "com.vitorpamplona.amethyst" minSdk 26 targetSdk 34 - versionCode 381 - versionName "0.88.4" + versionCode 382 + versionName "0.88.5" buildConfigField "String", "RELEASE_NOTES_ID", "\"2a34cbadd03212c8162e1ff896ba12641821088a2ec8d5e40d54aa80c0510800\"" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From 6eb7b4599083dcf8c7f29b9c9aa49948c4abd5d5 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Fri, 28 Jun 2024 20:27:40 +0000 Subject: [PATCH 48/49] New Crowdin translations by GitHub Action --- .../src/main/res/values-pl-rPL/strings.xml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/amethyst/src/main/res/values-pl-rPL/strings.xml b/amethyst/src/main/res/values-pl-rPL/strings.xml index 95481cddd..3a4ad34ef 100644 --- a/amethyst/src/main/res/values-pl-rPL/strings.xml +++ b/amethyst/src/main/res/values-pl-rPL/strings.xml @@ -14,6 +14,7 @@ Nie można odszyfrować wiadomości Zdjęcie grupy Niedozwolona zawartość + Spam Liczba spamu z tego transmitera Podszywanie się Antyspołeczne zachowanie @@ -199,6 +200,8 @@ nigdy teraz godz. + m + d Nagość Wulgaryzmy / Mowa nienawiści Zgłoś nienawistną mowę @@ -301,6 +304,7 @@ Minimalny Zap Maksymalny Zap Konsensus + (0–100)% Zamknij po dni Nie można głosować @@ -383,6 +387,7 @@ Ostrzegaj, gdy posty zostały zgłoszone przez osoby które obserwujesz Nowy Symbol Odzewu Brak wstępnie wybranych typów reakcji dla tego użytkownika. Przytrzymaj przycisk serce, aby zmienić + Zapraiser Dodaje docelową liczbę satów do podniesienia dla tego wpisu. W zależności od aplikacji może być pokazywany to jako pasek postępu, aby zachęcić do darowizn Docelowa kwota w Satach Zapraiser przy: %1$s. %2$s satach do celu @@ -414,6 +419,7 @@ Minimalny poW Autoryzacja Płatność + Cashu Token Wykup Wyślij do Zap Wallet Otwórz w Portfelu Cashu @@ -507,6 +513,7 @@ Głosy są oceniane na podstawie ilości zapperów. Możesz ustawić minimalną kwotę, aby uniknąć spamerów i maksymalną kwotę, aby uniknąć przejęcia ankiety przez dużych zapperów. Użyj tej samej kwoty w obu polach, aby upewnić się, że każdy głos ma taką samą wartość. Pozostaw to pole puste, aby zaakceptować dowolną kwotę. Nie można wysłać zapa Wyślij wiadomość użytkownikowi + OK Nieudane połączenie z %1$s: %2$s Nie udało się skompilować adresu URL NIP-11 dla %1$s: %2$s Nieudane połączenie z %1$s: %2$s @@ -527,6 +534,7 @@ Brakująca konfiguracja LN Użytkownik %1$s nie ma skonfigurowanego adresu LN, aby odbierać saty Procentowo + 25 Podziel zapsy z Przesyłanie zapasów do Nie znaleziono portfeli Lightning @@ -593,9 +601,11 @@ Cześć, czy to jest nadal dostępne? Sprzedaj przedmiot Tytuł + iPhone 13 Stan Kategoria Cena (w Satach) + 1000 Lokalizacja Miasto, Województwo, Kraj Nowość @@ -614,6 +624,7 @@ Książki Zwierzęta domowe Sporty + Fitness Sztuka Rzemiosło AGD @@ -628,6 +639,8 @@ Serwer nie podał adresu URL po załadowaniu Nie można pobrać przesłanych plików z serwera Nie można przygotować pliku lokalnego do przesłania: %1$s + Nie udało się przesłać: %1$s + Nie udało się usunąć: %1$s Edytuj wersję roboczą Zaloguj się przy użyciu QR kodu Ścieżka @@ -647,6 +660,7 @@ Odpowiedz Zrepostuj lub Zacytuj Lubię + Zap Zmień odzew Zdjęcie profilowe %1$s Transmiter %1$s @@ -658,6 +672,7 @@ Faktura Bitcoin Anuluj fakturę Bitcoin Anuluj sprzedaż przedmiotu + Zapraiser Anuluj Zapraiser Lokalizacja Usuń lokalizację @@ -710,6 +725,7 @@ Repozytorium Git: %1$s Strona internetowa: Klonuj: + OTS: %1$s Potwierdzenie znacznika czasu Istnieje dowód na to, że ten post został podpisany przed %1$s. Dowód został opatrzony pieczęcią w łańcuchu bloków Bitcoin w tym dniu i czasie. Edytuj wpis @@ -737,4 +753,27 @@ Zapytanie o pracę z DVM Prośba o płatność została wysłana, oczekiwanie na potwierdzenie z Twojego portfela Oczekiwanie na potwierdzenie płatności lub wysłanie wyników DVM + Błędne żądanie-Serwer nie może lub nie chce przetworzyć żądania. + Nieautoryzowany - użytkownik nie ma prawidłowych danych uwierzytelniających + Wymagana płatność - serwer wymaga płatności, aby wypełnić żądanie + Zabronione - użytkownik nie ma praw dostępu, aby złożyć żądanie + Nie znaleziono - serwer nie może odnaleźć żądanego adresu + Metoda niedozwolona - serwer obsługuje metodę żądania, ale nie docelowy zasób + Niedopuszczalne - Serwer nie znalazł żadnej zawartości spełniającej żądanie. + Wymagane uwierzytelnianie proxy - użytkownik nie ma prawidłowych danych uwierzytelniania + Limit czasu żądania - serwer przekroczył limit czasu, oczekując na kogoś innego + Konflikt - serwer nie może spełnić żądania, ponieważ istnieje konflikt z zasobem + Przepadło - Żądana zawartość została trwale usunięta z serwera i nie zostanie przywrócona + Wymagana długość - serwer odrzuca żądanie, ponieważ wymaga zdefiniowanej + URI Zbyt długi - URL klienta jest zbyt długi, aby serwer mógł go przetworzyć. + Nieobsługiwany format plików - żądanie używa formatu multimediów, którego serwer nie obsługuje + Wymagana aktualizacja - serwer odmawia przetwarzania żądania przy użyciu bieżącego protokołu, chyba że klient uaktualni go do innego protokołu. + Wewnętrzny błąd serwera - serwer napotkał nieoczekiwany błąd i nie może zakończyć żądania + Nie zaimplementowano - serwer nie może spełnić żądania lub nie rozpoznaje metody żądania + Usługa niedostępna - Często zdarza się, gdy serwer jest przeciążony lub wyłączony w celu konserwacji + Wersja HTTP nie jest obsługiwana - serwer nie obsługuje wersji HTTP w zapytaniu + Wariant również Negocjacje - serwer ma błąd konfiguracji wewnętrznej + Niewystarczająca pojemność - serwer nie ma wystarczającej pojemność, aby pomyślnie przetworzyć żądanie + Wykryta pętla - serwer wykrywa nieskończoną pętlę podczas przetwarzania żądania + Wymagane uwierzytelnienie sieciowe - Klient musi być uwierzytelniony aby uzyskać dostęp do sieci From 1fafb6a503f564b383f09439e2921cff722ace54 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 28 Jun 2024 16:58:45 -0400 Subject: [PATCH 49/49] updates create release script to match new directories --- .github/workflows/create-release.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 24e124faf..a1579b7de 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -99,7 +99,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/apk/play/release/app-play-universal-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/play/release/amethyst-play-universal-release-unsigned-signed.apk asset_name: amethyst-googleplay-universal-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -110,7 +110,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/apk/play/release/app-play-x86-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/play/release/amethyst-play-x86-release-unsigned-signed.apk asset_name: amethyst-googleplay-x86-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -121,7 +121,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/apk/play/release/app-play-x86_64-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/play/release/amethyst-play-x86_64-release-unsigned-signed.apk asset_name: amethyst-googleplay-x86_64-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -132,7 +132,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/apk/play/release/app-play-arm64-v8a-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/play/release/amethyst-play-arm64-v8a-release-unsigned-signed.apk asset_name: amethyst-googleplay-arm64-v8a-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -143,7 +143,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/apk/play/release/app-play-armeabi-v7a-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/play/release/amethyst-play-armeabi-v7a-release-unsigned-signed.apk asset_name: amethyst-googleplay-armeabi-v7a-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -155,7 +155,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/apk/fdroid/release/app-fdroid-universal-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/fdroid/release/amethyst-fdroid-universal-release-unsigned-signed.apk asset_name: amethyst-fdroid-universal-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -166,7 +166,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/apk/fdroid/release/app-fdroid-x86-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/fdroid/release/amethyst-fdroid-x86-release-unsigned-signed.apk asset_name: amethyst-fdroid-x86-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -177,7 +177,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/apk/fdroid/release/app-fdroid-x86_64-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/fdroid/release/amethyst-fdroid-x86_64-release-unsigned-signed.apk asset_name: amethyst-fdroid-x86_64-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -188,7 +188,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/apk/fdroid/release/app-fdroid-arm64-v8a-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/fdroid/release/amethyst-fdroid-arm64-v8a-release-unsigned-signed.apk asset_name: amethyst-fdroid-arm64-v8a-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -199,7 +199,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/apk/fdroid/release/app-fdroid-armeabi-v7a-release-unsigned-signed.apk + asset_path: amethyst/build/outputs/apk/fdroid/release/amethyst-fdroid-armeabi-v7a-release-unsigned-signed.apk asset_name: amethyst-fdroid-armeabi-v7a-${{ github.ref_name }}.apk asset_content_type: application/zip @@ -213,7 +213,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/bundle/playRelease/app-play-release.aab + asset_path: amethyst/build/outputs/bundle/playRelease/amethyst-play-release.aab asset_name: amethyst-googleplay-${{ github.ref_name }}.aab asset_content_type: application/zip @@ -225,6 +225,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: amethyst/build/outputs/bundle/fdroidRelease/app-fdroid-release.aab + asset_path: amethyst/build/outputs/bundle/fdroidRelease/amethyst-fdroid-release.aab asset_name: amethyst-fdroid-${{ github.ref_name }}.aab asset_content_type: application/zip