mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-10-11 00:54:30 +02:00
Merge remote-tracking branch 'origin/HEAD' into less_memory_test_branch
This commit is contained in:
114
.github/workflows/create-release.yml
vendored
114
.github/workflows/create-release.yml
vendored
@@ -28,10 +28,19 @@ jobs:
|
|||||||
- name: Build AAB
|
- name: Build AAB
|
||||||
run: ./gradlew clean bundleRelease --stacktrace
|
run: ./gradlew clean bundleRelease --stacktrace
|
||||||
|
|
||||||
- name: Sign AAB
|
- name: Sign AAB (Google Play)
|
||||||
uses: r0adkll/sign-android-release@v1
|
uses: r0adkll/sign-android-release@v1
|
||||||
with:
|
with:
|
||||||
releaseDirectory: app/build/outputs/bundle/release
|
releaseDirectory: app/build/outputs/bundle/playRelease
|
||||||
|
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
||||||
|
alias: ${{ secrets.KEY_ALIAS }}
|
||||||
|
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||||
|
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Sign AAB (F-Droid)
|
||||||
|
uses: r0adkll/sign-android-release@v1
|
||||||
|
with:
|
||||||
|
releaseDirectory: app/build/outputs/bundle/fdroidRelease
|
||||||
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
||||||
alias: ${{ secrets.KEY_ALIAS }}
|
alias: ${{ secrets.KEY_ALIAS }}
|
||||||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||||
@@ -40,10 +49,19 @@ jobs:
|
|||||||
- name: Build APK
|
- name: Build APK
|
||||||
run: ./gradlew assembleRelease --stacktrace --no-daemon
|
run: ./gradlew assembleRelease --stacktrace --no-daemon
|
||||||
|
|
||||||
- name: Sign APK
|
- name: Sign APK (Google Play)
|
||||||
uses: r0adkll/sign-android-release@v1
|
uses: r0adkll/sign-android-release@v1
|
||||||
with:
|
with:
|
||||||
releaseDirectory: app/build/outputs/apk/release
|
releaseDirectory: app/build/outputs/apk/play/release
|
||||||
|
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
||||||
|
alias: ${{ secrets.KEY_ALIAS }}
|
||||||
|
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||||
|
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Sign APK (F-Droid)
|
||||||
|
uses: r0adkll/sign-android-release@v1
|
||||||
|
with:
|
||||||
|
releaseDirectory: app/build/outputs/apk/fdroid/release
|
||||||
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
||||||
alias: ${{ secrets.KEY_ALIAS }}
|
alias: ${{ secrets.KEY_ALIAS }}
|
||||||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||||
@@ -60,24 +78,96 @@ jobs:
|
|||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
|
||||||
- name: Upload APK Asset
|
# Google Play APK
|
||||||
id: upload-release-asset-apk
|
- name: Upload Play APK Universal Asset
|
||||||
|
id: upload-release-asset-play-universal-apk
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path: app/build/outputs/apk/release/app-release-unsigned-signed.apk
|
asset_path: app/build/outputs/apk/play/release/app-play-universal-release-unsigned-signed.apk
|
||||||
asset_name: app-release-${{ github.ref_name }}.apk
|
asset_name: amethyst-googleplay-universal-${{ github.ref_name }}.apk
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
|
|
||||||
- name: Upload AAB Asset
|
- name: Upload Play APK x86 Asset
|
||||||
id: upload-release-asset-aab
|
id: upload-release-asset-play-x86-apk
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path: app/build/outputs/bundle/release/app-release.aab
|
asset_path: app/build/outputs/apk/play/release/app-play-x86-release-unsigned-signed.apk
|
||||||
asset_name: app-release-${{ github.ref_name }}.aab
|
asset_name: amethyst-googleplay-x86-${{ github.ref_name }}.apk
|
||||||
|
asset_content_type: application/zip
|
||||||
|
|
||||||
|
- name: Upload Play APK x86_64 Asset
|
||||||
|
id: upload-release-asset-play-x86-64-apk
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
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_name: amethyst-googleplay-x86_64-${{ github.ref_name }}.apk
|
||||||
|
asset_content_type: application/zip
|
||||||
|
|
||||||
|
# F-Droid APK
|
||||||
|
- name: Upload F-Droid APK Universal Asset
|
||||||
|
id: upload-release-asset-fdroid-universal-apk
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
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_name: amethyst-fdroid-universal-${{ github.ref_name }}.apk
|
||||||
|
asset_content_type: application/zip
|
||||||
|
|
||||||
|
- name: Upload F-Droid APK x86 Asset
|
||||||
|
id: upload-release-asset-fdroid-x86-apk
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
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_name: amethyst-fdroid-x86-${{ github.ref_name }}.apk
|
||||||
|
asset_content_type: application/zip
|
||||||
|
|
||||||
|
- name: Upload F-Droid APK x86_64 Asset
|
||||||
|
id: upload-release-asset-fdroid-x86-64-apk
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
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_name: amethyst-fdroid-x86_64-${{ github.ref_name }}.apk
|
||||||
|
asset_content_type: application/zip
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Google Play AAB
|
||||||
|
- name: Upload Google Play AAB Asset
|
||||||
|
id: upload-release-asset-play-aab
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
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_name: amethyst-googleplay-${{ github.ref_name }}.aab
|
||||||
|
asset_content_type: application/zip
|
||||||
|
|
||||||
|
# FDroid AAB
|
||||||
|
- name: Upload F-Droid AAB Asset
|
||||||
|
id: upload-release-asset-fdroid-aab
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
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_name: amethyst-fdroid-${{ github.ref_name }}.aab
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
@@ -12,8 +12,8 @@ android {
|
|||||||
applicationId "com.vitorpamplona.amethyst"
|
applicationId "com.vitorpamplona.amethyst"
|
||||||
minSdk 26
|
minSdk 26
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode 91
|
versionCode 95
|
||||||
versionName "0.24.2"
|
versionName "0.25.3"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
@@ -33,19 +33,45 @@ android {
|
|||||||
resValue "string", "app_name", "@string/app_name_debug"
|
resValue "string", "app_name", "@string/app_name_debug"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flavorDimensions "channel"
|
||||||
|
|
||||||
|
productFlavors {
|
||||||
|
play {
|
||||||
|
dimension "channel"
|
||||||
|
}
|
||||||
|
|
||||||
|
fdroid {
|
||||||
|
dimension "channel"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
splits {
|
||||||
|
abi {
|
||||||
|
enable true
|
||||||
|
reset()
|
||||||
|
include "x86", "x86_64"
|
||||||
|
universalApk true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_11
|
sourceCompatibility JavaVersion.VERSION_11
|
||||||
targetCompatibility JavaVersion.VERSION_11
|
targetCompatibility JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = '11'
|
jvmTarget = '11'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
compose true
|
compose true
|
||||||
}
|
}
|
||||||
|
|
||||||
composeOptions {
|
composeOptions {
|
||||||
kotlinCompilerExtensionVersion "1.4.3"
|
kotlinCompilerExtensionVersion "1.4.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
resources {
|
resources {
|
||||||
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
||||||
@@ -66,10 +92,10 @@ dependencies {
|
|||||||
implementation("androidx.navigation:navigation-compose:$nav_version")
|
implementation("androidx.navigation:navigation-compose:$nav_version")
|
||||||
|
|
||||||
// Observe Live data as State
|
// Observe Live data as State
|
||||||
implementation 'androidx.compose.runtime:runtime-livedata:1.4.0-beta02'
|
implementation "androidx.compose.runtime:runtime-livedata:$compose_ui_version"
|
||||||
|
|
||||||
implementation 'androidx.compose.material:material:1.4.0-beta02'
|
implementation "androidx.compose.material:material:$compose_ui_version"
|
||||||
implementation "androidx.compose.material:material-icons-extended:1.4.0-beta02"
|
implementation "androidx.compose.material:material-icons-extended:$compose_ui_version"
|
||||||
|
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version"
|
implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version"
|
||||||
@@ -135,10 +161,10 @@ dependencies {
|
|||||||
implementation "com.halilibo.compose-richtext:richtext-commonmark:0.16.0"
|
implementation "com.halilibo.compose-richtext:richtext-commonmark:0.16.0"
|
||||||
|
|
||||||
// Local model for language identification
|
// Local model for language identification
|
||||||
implementation 'com.google.mlkit:language-id:17.0.4'
|
playImplementation 'com.google.mlkit:language-id:17.0.4'
|
||||||
|
|
||||||
// Google services model the translate text
|
// Google services model the translate text
|
||||||
implementation 'com.google.mlkit:translate:17.0.1'
|
playImplementation 'com.google.mlkit:translate:17.0.1'
|
||||||
|
|
||||||
// Automatic memory leak detection
|
// Automatic memory leak detection
|
||||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'
|
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'
|
||||||
|
@@ -0,0 +1,26 @@
|
|||||||
|
package com.vitorpamplona.amethyst.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TranslateableRichTextViewer(
|
||||||
|
content: String,
|
||||||
|
canPreview: Boolean,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
tags: List<List<String>>?,
|
||||||
|
backgroundColor: Color,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
navController: NavController
|
||||||
|
) = ExpandableRichTextViewer(
|
||||||
|
content,
|
||||||
|
canPreview,
|
||||||
|
modifier,
|
||||||
|
tags,
|
||||||
|
backgroundColor,
|
||||||
|
accountViewModel,
|
||||||
|
navController
|
||||||
|
)
|
@@ -79,7 +79,7 @@ object LocalPreferences {
|
|||||||
}
|
}
|
||||||
val prefs = encryptedPreferences()
|
val prefs = encryptedPreferences()
|
||||||
prefs.edit().apply {
|
prefs.edit().apply {
|
||||||
putString(PrefKeys.SAVED_ACCOUNTS, accounts.joinToString(comma))
|
putString(PrefKeys.SAVED_ACCOUNTS, accounts.joinToString(comma).ifBlank { null })
|
||||||
}.apply()
|
}.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ object LocalPreferences {
|
|||||||
if (accounts.remove(npub)) {
|
if (accounts.remove(npub)) {
|
||||||
val prefs = encryptedPreferences()
|
val prefs = encryptedPreferences()
|
||||||
prefs.edit().apply {
|
prefs.edit().apply {
|
||||||
putString(PrefKeys.SAVED_ACCOUNTS, accounts.joinToString(comma))
|
putString(PrefKeys.SAVED_ACCOUNTS, accounts.joinToString(comma).ifBlank { null })
|
||||||
}.apply()
|
}.apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -319,7 +319,7 @@ class Account(
|
|||||||
LocalCache.consume(signedEvent, null)
|
LocalCache.consume(signedEvent, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendPrivateMeesage(message: String, toUser: String, replyingTo: Note? = null) {
|
fun sendPrivateMessage(message: String, toUser: String, replyingTo: Note? = null) {
|
||||||
if (!isWriteable()) return
|
if (!isWriteable()) return
|
||||||
val user = LocalCache.users[toUser] ?: return
|
val user = LocalCache.users[toUser] ?: return
|
||||||
|
|
||||||
|
@@ -218,7 +218,9 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n
|
|||||||
|
|
||||||
Row(modifier = Modifier.fillMaxWidth()) {
|
Row(modifier = Modifier.fillMaxWidth()) {
|
||||||
UploadFromGallery(
|
UploadFromGallery(
|
||||||
isUploading = postViewModel.isUploadingImage
|
isUploading = postViewModel.isUploadingImage,
|
||||||
|
tint = MaterialTheme.colors.primary,
|
||||||
|
modifier = Modifier.padding(bottom = 10.dp)
|
||||||
) {
|
) {
|
||||||
postViewModel.upload(it, context)
|
postViewModel.upload(it, context)
|
||||||
}
|
}
|
||||||
|
@@ -4,23 +4,38 @@ import android.net.Uri
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.compose.animation.core.LinearEasing
|
||||||
|
import androidx.compose.animation.core.animateFloat
|
||||||
|
import androidx.compose.animation.core.infiniteRepeatable
|
||||||
|
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.AddPhotoAlternate
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.draw.rotate
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||||
import com.google.accompanist.permissions.isGranted
|
import com.google.accompanist.permissions.isGranted
|
||||||
import com.google.accompanist.permissions.rememberPermissionState
|
import com.google.accompanist.permissions.rememberPermissionState
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
@OptIn(ExperimentalPermissionsApi::class)
|
@OptIn(ExperimentalPermissionsApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun UploadFromGallery(
|
fun UploadFromGallery(
|
||||||
isUploading: Boolean,
|
isUploading: Boolean,
|
||||||
|
tint: Color,
|
||||||
|
modifier: Modifier,
|
||||||
onImageChosen: (Uri) -> Unit
|
onImageChosen: (Uri) -> Unit
|
||||||
) {
|
) {
|
||||||
val cameraPermissionState =
|
val cameraPermissionState =
|
||||||
@@ -43,66 +58,113 @@ fun UploadFromGallery(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
}
|
||||||
Box() {
|
|
||||||
TextButton(
|
UploadBoxButton(isUploading, tint, modifier) {
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.TopCenter),
|
|
||||||
enabled = !isUploading,
|
|
||||||
onClick = {
|
|
||||||
showGallerySelect = true
|
showGallerySelect = true
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
UploadBoxButton(isUploading, tint, modifier) {
|
||||||
|
cameraPermissionState.launchPermissionRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun UploadBoxButton(
|
||||||
|
isUploading: Boolean,
|
||||||
|
tint: Color,
|
||||||
|
modifier: Modifier,
|
||||||
|
onClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
|
Box() {
|
||||||
|
IconButton(
|
||||||
|
modifier = modifier.align(Alignment.Center),
|
||||||
|
enabled = !isUploading,
|
||||||
|
onClick = {
|
||||||
|
onClick()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
if (!isUploading) {
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(id = R.drawable.ic_add_photo),
|
imageVector = Icons.Default.AddPhotoAlternate,
|
||||||
contentDescription = stringResource(id = R.string.upload_image),
|
contentDescription = stringResource(id = R.string.upload_image),
|
||||||
modifier = Modifier
|
modifier = Modifier.height(25.dp),
|
||||||
.height(20.dp)
|
tint = tint
|
||||||
.padding(end = 8.dp),
|
)
|
||||||
tint = MaterialTheme.colors.primary
|
} else {
|
||||||
|
LoadingAnimation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LoadingAnimation(
|
||||||
|
indicatorSize: Dp = 20.dp,
|
||||||
|
circleColors: List<Color> = listOf(
|
||||||
|
Color(0xFF5851D8),
|
||||||
|
Color(0xFF833AB4),
|
||||||
|
Color(0xFFC13584),
|
||||||
|
Color(0xFFE1306C),
|
||||||
|
Color(0xFFFD1D1D),
|
||||||
|
Color(0xFFF56040),
|
||||||
|
Color(0xFFF77737),
|
||||||
|
Color(0xFFFCAF45),
|
||||||
|
Color(0xFFFFDC80),
|
||||||
|
Color(0xFF5851D8)
|
||||||
|
),
|
||||||
|
animationDuration: Int = 1000
|
||||||
|
) {
|
||||||
|
val infiniteTransition = rememberInfiniteTransition()
|
||||||
|
|
||||||
|
val rotateAnimation by infiniteTransition.animateFloat(
|
||||||
|
initialValue = 0f,
|
||||||
|
targetValue = 360f,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = tween(
|
||||||
|
durationMillis = animationDuration,
|
||||||
|
easing = LinearEasing
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!isUploading) {
|
CircularProgressIndicator(
|
||||||
Text(stringResource(R.string.upload_image))
|
modifier = Modifier
|
||||||
} else {
|
.size(size = indicatorSize)
|
||||||
Text(stringResource(R.string.uploading))
|
.rotate(degrees = rotateAnimation)
|
||||||
}
|
.border(
|
||||||
}
|
width = 4.dp,
|
||||||
}
|
brush = Brush.sweepGradient(circleColors),
|
||||||
}
|
shape = CircleShape
|
||||||
} else {
|
),
|
||||||
Column {
|
progress = 1f,
|
||||||
Button(
|
strokeWidth = 1.dp,
|
||||||
onClick = { cameraPermissionState.launchPermissionRequest() },
|
color = MaterialTheme.colors.background // Set background color
|
||||||
enabled = !isUploading
|
)
|
||||||
) {
|
|
||||||
if (!isUploading) {
|
|
||||||
Text(stringResource(R.string.upload_image))
|
|
||||||
} else {
|
|
||||||
Text(stringResource(R.string.uploading))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GallerySelect(
|
fun GallerySelect(
|
||||||
onImageUri: (Uri?) -> Unit = { }
|
onImageUri: (Uri?) -> Unit = { }
|
||||||
) {
|
) {
|
||||||
|
var hasLaunched by remember { mutableStateOf(AtomicBoolean(false)) }
|
||||||
val launcher = rememberLauncherForActivityResult(
|
val launcher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.GetContent(),
|
contract = ActivityResultContracts.GetContent(),
|
||||||
onResult = { uri: Uri? ->
|
onResult = { uri: Uri? ->
|
||||||
onImageUri(uri)
|
onImageUri(uri)
|
||||||
|
hasLaunched.set(false)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LaunchGallery() {
|
fun LaunchGallery() {
|
||||||
SideEffect {
|
SideEffect {
|
||||||
|
if (!hasLaunched.getAndSet(true)) {
|
||||||
launcher.launch("image/*")
|
launcher.launch("image/*")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LaunchGallery()
|
LaunchGallery()
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,20 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.components
|
package com.vitorpamplona.amethyst.ui.components
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
|
import coil.ImageLoader
|
||||||
|
import coil.decode.DataSource
|
||||||
|
import coil.decode.ImageSource
|
||||||
|
import coil.fetch.Fetcher
|
||||||
|
import coil.fetch.SourceResult
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import java.nio.ByteBuffer
|
import coil.request.Options
|
||||||
|
import okio.Buffer
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
|
import kotlin.time.ExperimentalTime
|
||||||
|
import kotlin.time.measureTimedValue
|
||||||
|
|
||||||
private fun toHex(color: Color): String {
|
private fun toHex(color: Color): String {
|
||||||
val argb = color.toArgb()
|
val argb = color.toArgb()
|
||||||
@@ -40,8 +49,7 @@ private fun svgString(msg: String): String {
|
|||||||
val mouth = mouths[mouthIndex]
|
val mouth = mouths[mouthIndex]
|
||||||
val accessory = accessories[accIndex]
|
val accessory = accessories[accIndex]
|
||||||
|
|
||||||
return """
|
return """<svg id="$hashHex" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
|
||||||
<svg id="$hashHex" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
|
|
||||||
<defs>
|
<defs>
|
||||||
<style>
|
<style>
|
||||||
.cls-bg{fill:${toHex(bgColor)}}.cls-fill-1{fill:${toHex(fgColor)};}.cls-fill-2{fill:${toHex(fgColor)};}
|
.cls-bg{fill:${toHex(bgColor)}}.cls-fill-1{fill:${toHex(fgColor)};}.cls-fill-2{fill:${toHex(fgColor)};}
|
||||||
@@ -50,19 +58,45 @@ private fun svgString(msg: String): String {
|
|||||||
</defs>
|
</defs>
|
||||||
<title>Robohash $hashHex</title>
|
<title>Robohash $hashHex</title>
|
||||||
${background}${body.paths}${face.paths}${eye.paths}${mouth.paths}${accessory.paths}
|
${background}${body.paths}${face.paths}${eye.paths}${mouth.paths}${accessory.paths}
|
||||||
</svg>
|
</svg>"""
|
||||||
""".trimIndent()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class HashImageFetcher(
|
||||||
|
private val context: Context,
|
||||||
|
private val data: Uri
|
||||||
|
) : Fetcher {
|
||||||
|
|
||||||
|
@OptIn(ExperimentalTime::class)
|
||||||
|
override suspend fun fetch(): SourceResult {
|
||||||
|
val (value, elapsed) = measureTimedValue {
|
||||||
|
val source = try {
|
||||||
|
Buffer().apply { write(svgString(data.toString()).toByteArray()) }
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceResult(
|
||||||
|
source = ImageSource(source, context),
|
||||||
|
mimeType = null,
|
||||||
|
dataSource = DataSource.MEMORY
|
||||||
|
)
|
||||||
|
}
|
||||||
|
println("Elapsed: $elapsed")
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
class Factory : Fetcher.Factory<Uri> {
|
||||||
|
override fun create(data: Uri, options: Options, imageLoader: ImageLoader): Fetcher {
|
||||||
|
return HashImageFetcher(options.context, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
object Robohash {
|
object Robohash {
|
||||||
fun imageRequest(context: Context, message: String): ImageRequest {
|
fun imageRequest(context: Context, message: String): ImageRequest {
|
||||||
return ImageRequest
|
return ImageRequest
|
||||||
.Builder(context)
|
.Builder(context)
|
||||||
.data(
|
.data("robohash:$message")
|
||||||
ByteBuffer.wrap(
|
.fetcherFactory(HashImageFetcher.Factory())
|
||||||
svgString(message).toByteArray()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.crossfade(100)
|
.crossfade(100)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
@@ -99,6 +99,7 @@ fun MainTopBar(scaffoldState: ScaffoldState, accountViewModel: AccountViewModel)
|
|||||||
Column() {
|
Column() {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
elevation = 0.dp,
|
elevation = 0.dp,
|
||||||
|
backgroundColor = MaterialTheme.colors.surface,
|
||||||
title = {
|
title = {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
@@ -344,7 +344,7 @@ fun ChatroomMessageCompose(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteQuickActionMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel)
|
NoteDropDownMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -52,7 +52,6 @@ class AccountStateViewModel() : ViewModel() {
|
|||||||
Account(Persona(Hex.decode(key)))
|
Account(Persona(Hex.decode(key)))
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalPreferences.updatePrefsForLogin(account)
|
|
||||||
login(account)
|
login(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +63,6 @@ class AccountStateViewModel() : ViewModel() {
|
|||||||
|
|
||||||
fun newKey() {
|
fun newKey() {
|
||||||
val account = Account(Persona())
|
val account = Account(Persona())
|
||||||
LocalPreferences.updatePrefsForLogin(account)
|
|
||||||
login(account)
|
login(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.compose.animation.animateContentSize
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -65,7 +66,9 @@ import com.vitorpamplona.amethyst.model.Channel
|
|||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.service.NostrChannelDataSource
|
import com.vitorpamplona.amethyst.service.NostrChannelDataSource
|
||||||
import com.vitorpamplona.amethyst.ui.actions.NewChannelView
|
import com.vitorpamplona.amethyst.ui.actions.NewChannelView
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.actions.PostButton
|
import com.vitorpamplona.amethyst.ui.actions.PostButton
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.UploadFromGallery
|
||||||
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
||||||
import com.vitorpamplona.amethyst.ui.dal.ChannelFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.ChannelFeedFilter
|
||||||
@@ -82,9 +85,10 @@ fun ChannelScreen(
|
|||||||
) {
|
) {
|
||||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||||
val account = accountState?.account
|
val account = accountState?.account
|
||||||
|
val context = LocalContext.current
|
||||||
|
val channelScreenModel: NewPostViewModel = viewModel()
|
||||||
|
|
||||||
if (account != null && channelId != null) {
|
if (account != null && channelId != null) {
|
||||||
val newPost = remember { mutableStateOf(TextFieldValue("")) }
|
|
||||||
val replyTo = remember { mutableStateOf<Note?>(null) }
|
val replyTo = remember { mutableStateOf<Note?>(null) }
|
||||||
|
|
||||||
ChannelFeedFilter.loadMessagesBetween(account, channelId)
|
ChannelFeedFilter.loadMessagesBetween(account, channelId)
|
||||||
@@ -98,6 +102,9 @@ fun ChannelScreen(
|
|||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
feedViewModel.invalidateData()
|
feedViewModel.invalidateData()
|
||||||
|
channelScreenModel.imageUploadingError.collect { error ->
|
||||||
|
Toast.makeText(context, error, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DisposableEffect(channelId) {
|
DisposableEffect(channelId) {
|
||||||
@@ -178,8 +185,10 @@ fun ChannelScreen(
|
|||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
TextField(
|
TextField(
|
||||||
value = newPost.value,
|
value = channelScreenModel.message,
|
||||||
onValueChange = { newPost.value = it },
|
onValueChange = {
|
||||||
|
channelScreenModel.updateMessage(it)
|
||||||
|
},
|
||||||
keyboardOptions = KeyboardOptions.Default.copy(
|
keyboardOptions = KeyboardOptions.Default.copy(
|
||||||
capitalization = KeyboardCapitalization.Sentences
|
capitalization = KeyboardCapitalization.Sentences
|
||||||
),
|
),
|
||||||
@@ -195,15 +204,24 @@ fun ChannelScreen(
|
|||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
PostButton(
|
PostButton(
|
||||||
onPost = {
|
onPost = {
|
||||||
account.sendChannelMessage(newPost.value.text, channel.idHex, replyTo.value, null)
|
account.sendChannelMessage(channelScreenModel.message.text, channel.idHex, replyTo.value, null)
|
||||||
newPost.value = TextFieldValue("")
|
channelScreenModel.message = TextFieldValue("")
|
||||||
replyTo.value = null
|
replyTo.value = null
|
||||||
feedViewModel.refresh() // Don't wait a full second before updating
|
feedViewModel.refresh() // Don't wait a full second before updating
|
||||||
},
|
},
|
||||||
newPost.value.text.isNotBlank(),
|
isActive = channelScreenModel.message.text.isNotBlank() && !channelScreenModel.isUploadingImage,
|
||||||
modifier = Modifier.padding(end = 10.dp)
|
modifier = Modifier.padding(end = 10.dp)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
leadingIcon = {
|
||||||
|
UploadFromGallery(
|
||||||
|
isUploading = channelScreenModel.isUploadingImage,
|
||||||
|
tint = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
|
||||||
|
modifier = Modifier.padding(start = 5.dp)
|
||||||
|
) {
|
||||||
|
channelScreenModel.upload(it, context)
|
||||||
|
}
|
||||||
|
},
|
||||||
colors = TextFieldDefaults.textFieldColors(
|
colors = TextFieldDefaults.textFieldColors(
|
||||||
focusedIndicatorColor = Color.Transparent,
|
focusedIndicatorColor = Color.Transparent,
|
||||||
unfocusedIndicatorColor = Color.Transparent
|
unfocusedIndicatorColor = Color.Transparent
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.compose.animation.animateContentSize
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@@ -36,6 +37,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||||
@@ -50,7 +52,9 @@ import com.vitorpamplona.amethyst.R
|
|||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.service.NostrChatroomDataSource
|
import com.vitorpamplona.amethyst.service.NostrChatroomDataSource
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.actions.PostButton
|
import com.vitorpamplona.amethyst.ui.actions.PostButton
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.UploadFromGallery
|
||||||
import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status
|
import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status
|
||||||
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
||||||
@@ -64,9 +68,10 @@ import com.vitorpamplona.amethyst.ui.screen.NostrChatRoomFeedViewModel
|
|||||||
fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navController: NavController) {
|
fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navController: NavController) {
|
||||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||||
val account = accountState?.account
|
val account = accountState?.account
|
||||||
|
val context = LocalContext.current
|
||||||
|
val chatRoomScreenModel: NewPostViewModel = viewModel()
|
||||||
|
|
||||||
if (account != null && userId != null) {
|
if (account != null && userId != null) {
|
||||||
val newPost = remember { mutableStateOf(TextFieldValue("")) }
|
|
||||||
val replyTo = remember { mutableStateOf<Note?>(null) }
|
val replyTo = remember { mutableStateOf<Note?>(null) }
|
||||||
|
|
||||||
ChatroomFeedFilter.loadMessagesBetween(account, userId)
|
ChatroomFeedFilter.loadMessagesBetween(account, userId)
|
||||||
@@ -77,6 +82,9 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr
|
|||||||
|
|
||||||
LaunchedEffect(userId) {
|
LaunchedEffect(userId) {
|
||||||
feedViewModel.refresh()
|
feedViewModel.refresh()
|
||||||
|
chatRoomScreenModel.imageUploadingError.collect { error ->
|
||||||
|
Toast.makeText(context, error, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DisposableEffect(userId) {
|
DisposableEffect(userId) {
|
||||||
@@ -156,8 +164,8 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr
|
|||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
TextField(
|
TextField(
|
||||||
value = newPost.value,
|
value = chatRoomScreenModel.message,
|
||||||
onValueChange = { newPost.value = it },
|
onValueChange = { chatRoomScreenModel.updateMessage(it) },
|
||||||
keyboardOptions = KeyboardOptions.Default.copy(
|
keyboardOptions = KeyboardOptions.Default.copy(
|
||||||
capitalization = KeyboardCapitalization.Sentences
|
capitalization = KeyboardCapitalization.Sentences
|
||||||
),
|
),
|
||||||
@@ -173,15 +181,24 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr
|
|||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
PostButton(
|
PostButton(
|
||||||
onPost = {
|
onPost = {
|
||||||
account.sendPrivateMeesage(newPost.value.text, userId, replyTo.value)
|
account.sendPrivateMessage(chatRoomScreenModel.message.text, userId, replyTo.value)
|
||||||
newPost.value = TextFieldValue("")
|
chatRoomScreenModel.message = TextFieldValue("")
|
||||||
replyTo.value = null
|
replyTo.value = null
|
||||||
feedViewModel.refresh() // Don't wait a full second before updating
|
feedViewModel.refresh() // Don't wait a full second before updating
|
||||||
},
|
},
|
||||||
newPost.value.text.isNotBlank(),
|
isActive = chatRoomScreenModel.message.text.isNotBlank() && !chatRoomScreenModel.isUploadingImage,
|
||||||
modifier = Modifier.padding(end = 10.dp)
|
modifier = Modifier.padding(end = 10.dp)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
leadingIcon = {
|
||||||
|
UploadFromGallery(
|
||||||
|
isUploading = chatRoomScreenModel.isUploadingImage,
|
||||||
|
tint = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
|
||||||
|
modifier = Modifier.padding(start = 5.dp)
|
||||||
|
) {
|
||||||
|
chatRoomScreenModel.upload(it, context)
|
||||||
|
}
|
||||||
|
},
|
||||||
colors = TextFieldDefaults.textFieldColors(
|
colors = TextFieldDefaults.textFieldColors(
|
||||||
focusedIndicatorColor = Color.Transparent,
|
focusedIndicatorColor = Color.Transparent,
|
||||||
unfocusedIndicatorColor = Color.Transparent
|
unfocusedIndicatorColor = Color.Transparent
|
||||||
|
@@ -25,6 +25,8 @@ import com.google.accompanist.pager.PagerState
|
|||||||
import com.google.accompanist.pager.pagerTabIndicatorOffset
|
import com.google.accompanist.pager.pagerTabIndicatorOffset
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.HomeConversationsFeedFilter
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.HomeNewThreadFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||||
import com.vitorpamplona.amethyst.ui.screen.FeedView
|
import com.vitorpamplona.amethyst.ui.screen.FeedView
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
|
||||||
@@ -43,10 +45,12 @@ fun HomeScreen(
|
|||||||
scrollToTop: Boolean = false
|
scrollToTop: Boolean = false
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val account = accountViewModel.accountLiveData.value?.account ?: return
|
||||||
|
|
||||||
LaunchedEffect(accountViewModel) {
|
LaunchedEffect(accountViewModel) {
|
||||||
|
HomeNewThreadFeedFilter.account = account
|
||||||
|
HomeConversationsFeedFilter.account = account
|
||||||
NostrHomeDataSource.resetFilters()
|
NostrHomeDataSource.resetFilters()
|
||||||
|
|
||||||
homeFeedViewModel.refresh()
|
homeFeedViewModel.refresh()
|
||||||
repliesFeedViewModel.refresh()
|
repliesFeedViewModel.refresh()
|
||||||
}
|
}
|
||||||
|
@@ -54,6 +54,7 @@ import com.vitorpamplona.amethyst.model.Note
|
|||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.service.NostrGlobalDataSource
|
import com.vitorpamplona.amethyst.service.NostrGlobalDataSource
|
||||||
import com.vitorpamplona.amethyst.service.NostrSearchEventOrUserDataSource
|
import com.vitorpamplona.amethyst.service.NostrSearchEventOrUserDataSource
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.GlobalFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.note.ChannelName
|
import com.vitorpamplona.amethyst.ui.note.ChannelName
|
||||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||||
import com.vitorpamplona.amethyst.ui.note.UserCompose
|
import com.vitorpamplona.amethyst.ui.note.UserCompose
|
||||||
@@ -81,8 +82,11 @@ fun SearchScreen(
|
|||||||
scrollToTop: Boolean = false
|
scrollToTop: Boolean = false
|
||||||
) {
|
) {
|
||||||
val lifeCycleOwner = LocalLifecycleOwner.current
|
val lifeCycleOwner = LocalLifecycleOwner.current
|
||||||
|
val account = accountViewModel.accountLiveData.value?.account ?: return
|
||||||
|
|
||||||
LaunchedEffect(accountViewModel) {
|
LaunchedEffect(accountViewModel) {
|
||||||
|
GlobalFeedFilter.account = account
|
||||||
|
NostrGlobalDataSource.resetFilters()
|
||||||
feedViewModel.refresh()
|
feedViewModel.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,10 +8,10 @@
|
|||||||
<string name="show_anyway">Laat toch zien</string>
|
<string name="show_anyway">Laat toch zien</string>
|
||||||
<string name="post_was_flagged_as_inappropriate_by">Bericht gemarkeerd als ongepast door</string>
|
<string name="post_was_flagged_as_inappropriate_by">Bericht gemarkeerd als ongepast door</string>
|
||||||
<string name="post_not_found">Bericht niet gevonden</string>
|
<string name="post_not_found">Bericht niet gevonden</string>
|
||||||
<string name="channel_image">Groepsafbeelding</string>
|
<string name="channel_image">Kanaalafbeelding</string>
|
||||||
<string name="referenced_event_not_found">Verwezen event niet gevonden</string>
|
<string name="referenced_event_not_found">Verwezen event niet gevonden</string>
|
||||||
<string name="could_not_decrypt_the_message">Note versleuteld met encryptie</string>
|
<string name="could_not_decrypt_the_message">Note versleuteld met encryptie</string>
|
||||||
<string name="group_picture">Kanaal-afbeelding</string>
|
<string name="group_picture">Groepafbeelding</string>
|
||||||
<string name="explicit_content">Expliciete inhoud</string>
|
<string name="explicit_content">Expliciete inhoud</string>
|
||||||
<string name="spam">Spam</string>
|
<string name="spam">Spam</string>
|
||||||
<string name="impersonation">Imitatie</string>
|
<string name="impersonation">Imitatie</string>
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
<string name="lightning_invoice">Lightning invoice</string>
|
<string name="lightning_invoice">Lightning invoice</string>
|
||||||
<string name="pay">Betalen</string>
|
<string name="pay">Betalen</string>
|
||||||
<string name="lightning_tips">Lightning Tips</string>
|
<string name="lightning_tips">Lightning Tips</string>
|
||||||
<string name="note_to_receiver">Notitie aan ontvanger</string>
|
<string name="note_to_receiver">Note aan ontvanger</string>
|
||||||
<string name="thank_you_so_much">Hartelijk bedankt!</string>
|
<string name="thank_you_so_much">Hartelijk bedankt!</string>
|
||||||
<string name="amount_in_sats">Bedrag in sats</string>
|
<string name="amount_in_sats">Bedrag in sats</string>
|
||||||
<string name="send_sats">Verstuur sats</string>
|
<string name="send_sats">Verstuur sats</string>
|
||||||
@@ -97,16 +97,16 @@
|
|||||||
<string name="uploading">Uploaden…</string>
|
<string name="uploading">Uploaden…</string>
|
||||||
<string name="user_does_not_have_a_lightning_address_setup_to_receive_sats">Gebruiker heeft geen Lightning Adress ingesteld om sats te ontvangen</string>
|
<string name="user_does_not_have_a_lightning_address_setup_to_receive_sats">Gebruiker heeft geen Lightning Adress ingesteld om sats te ontvangen</string>
|
||||||
<string name="reply_here">"hier reageren.. "</string>
|
<string name="reply_here">"hier reageren.. "</string>
|
||||||
<string name="copies_the_note_id_to_the_clipboard_for_sharing">Kopieert Notitie ID naar klembord om te delen</string>
|
<string name="copies_the_note_id_to_the_clipboard_for_sharing">Kopieert note ID naar klembord om te delen</string>
|
||||||
<string name="copy_channel_id_note_to_the_clipboard">Kopieer kanaal ID (Notitie) naar klembord</string>
|
<string name="copy_channel_id_note_to_the_clipboard">Kopieer kanaal ID (note) naar klembord</string>
|
||||||
<string name="edits_the_channel_metadata">Past de kanaal-metadata aan</string>
|
<string name="edits_the_channel_metadata">Past de kanaal-metadata aan</string>
|
||||||
<string name="join">Lid worden</string>
|
<string name="join">Lid worden</string>
|
||||||
<string name="known">Bekend</string>
|
<string name="known">Bekend</string>
|
||||||
<string name="new_requests">Nieuw verzoek</string>
|
<string name="new_requests">Nieuw verzoek</string>
|
||||||
<string name="blocked_users">Geblokeerde gebruikers</string>
|
<string name="blocked_users">Geblokeerde gebruikers</string>
|
||||||
<string name="new_threads">Nieuwe notities</string>
|
<string name="new_threads">Nieuwe notes</string>
|
||||||
<string name="conversations">Gesprekken</string>
|
<string name="conversations">Gesprekken</string>
|
||||||
<string name="notes">Notities</string>
|
<string name="notes">Notes</string>
|
||||||
<string name="replies">Reacties</string>
|
<string name="replies">Reacties</string>
|
||||||
<string name="follows">"Volgend"</string>
|
<string name="follows">"Volgend"</string>
|
||||||
<string name="reports">"Rapporten"</string>
|
<string name="reports">"Rapporten"</string>
|
||||||
@@ -174,9 +174,9 @@
|
|||||||
<string name="report_hateful_speech">Haatdragende taal rapporteren</string>
|
<string name="report_hateful_speech">Haatdragende taal rapporteren</string>
|
||||||
<string name="report_nudity_porn">Naaktheid / porno rapporteren</string>
|
<string name="report_nudity_porn">Naaktheid / porno rapporteren</string>
|
||||||
<string name="others">anderen</string>
|
<string name="others">anderen</string>
|
||||||
<string name="mark_all_known_as_read">Alle bekende als gelezen markeren</string>
|
<string name="mark_all_known_as_read">Bekende markeren als gelezen</string>
|
||||||
<string name="mark_all_new_as_read">Alle nieuwe als gelezen markeren</string>
|
<string name="mark_all_new_as_read">Nieuwe markeren als gelezen</string>
|
||||||
<string name="mark_all_as_read">Alles als gelezen markeren</string>
|
<string name="mark_all_as_read">Alles markeren als gelezen</string>
|
||||||
<string name="backup_keys">Back-up sleutels</string>
|
<string name="backup_keys">Back-up sleutels</string>
|
||||||
<string name="account_backup_tips_md" tools:ignore="Typos">
|
<string name="account_backup_tips_md" tools:ignore="Typos">
|
||||||
## Sleutel back-up en veiligheidstips
|
## Sleutel back-up en veiligheidstips
|
||||||
@@ -193,19 +193,38 @@
|
|||||||
<string name="badge_award_image_for">"Badge award afbeelding voor %1$s"</string>
|
<string name="badge_award_image_for">"Badge award afbeelding voor %1$s"</string>
|
||||||
<string name="new_badge_award_notif">Je hebt een nieuwe Badge award ontvangen</string>
|
<string name="new_badge_award_notif">Je hebt een nieuwe Badge award ontvangen</string>
|
||||||
<string name="award_granted_to">Badge award gegeven aan</string>
|
<string name="award_granted_to">Badge award gegeven aan</string>
|
||||||
<string name="copied_note_text_to_clipboard">Notitie tekst gekopieerd naar klembord</string>
|
<string name="copied_note_text_to_clipboard">Note tekst gekopieerd naar klembord</string>
|
||||||
<string name="copied_user_id_to_clipboard" tools:ignore="Typos">@npub auteur gekopieerd naar klembord</string>
|
<string name="copied_user_id_to_clipboard" tools:ignore="Typos">@npub auteur gekopieerd naar klembord</string>
|
||||||
<string name="copied_note_id_to_clipboard" tools:ignore="Typos">Notitie ID (@note1) gekopieerd naar klembord</string>
|
<string name="copied_note_id_to_clipboard" tools:ignore="Typos">Note ID (@note1) gekopieerd naar klembord</string>
|
||||||
<string name="select_text_dialog_top">Selecteer tekst</string>
|
<string name="select_text_dialog_top">Selecteer tekst</string>
|
||||||
<string name="quick_action_select">Selecteer</string>
|
<string name="quick_action_select">Selecteer</string>
|
||||||
<string name="quick_action_share_browser_link">Deel browserlink</string>
|
<string name="quick_action_share_browser_link">Deel browserlink</string>
|
||||||
<string name="quick_action_share">Delen</string>
|
<string name="quick_action_share">Delen</string>
|
||||||
<string name="quick_action_copy_user_id">Auteur ID</string>
|
<string name="quick_action_copy_user_id">Auteur ID</string>
|
||||||
<string name="quick_action_copy_note_id">Notitie ID</string>
|
<string name="quick_action_copy_note_id">Note ID</string>
|
||||||
<string name="quick_action_copy_text">Kopieer tekst</string>
|
<string name="quick_action_copy_text">Kopieer tekst</string>
|
||||||
<string name="quick_action_delete">Verwijderen</string>
|
<string name="quick_action_delete">Verwijderen</string>
|
||||||
<string name="quick_action_unfollow">Ontvolgen</string>
|
<string name="quick_action_unfollow">Ontvolgen</string>
|
||||||
<string name="quick_action_follow">Volgen</string>
|
<string name="quick_action_follow">Volgen</string>
|
||||||
<string name="quick_action_request_deletion_alert_title">Verzoek om te verwijderen</string>
|
<string name="quick_action_request_deletion_alert_title">Verzoek om te verwijderen</string>
|
||||||
<string name="quick_action_request_deletion_alert_body">Amethyst zal vragen om uw notitie te verwijderen van de relays waarmee u momenteel verbonden bent. Er is geen garantie dat uw notitie permanent wordt verwijderd van deze relays, of van andere relays waar het kan worden opgeslagen.</string>
|
<string name="quick_action_request_deletion_alert_body">Amethyst zal vragen om uw note te verwijderen van de relays waarmee u momenteel verbonden bent. Er is geen garantie dat uw note permanent wordt verwijderd van deze relays, of van andere relays waar het kan worden opgeslagen.</string>
|
||||||
|
<string name="github" translatable="false">Github Gist w/ Proof</string>
|
||||||
|
<string name="telegram" translatable="false">Telegram</string>
|
||||||
|
<string name="mastodon" translatable="false">Mastodon Post ID w/ Proof</string>
|
||||||
|
<string name="twitter" translatable="false">Twitter Status w/ Proof</string>
|
||||||
|
<string name="github_proof_url_template" translatable="false">https://gist.github.com/<user>/<gist></string>
|
||||||
|
<string name="telegram_proof_url_template" translatable="false">https://t.me/<proof post></string>
|
||||||
|
<string name="mastodon_proof_url_template" translatable="false">https://<server>/<user>/<proof post></string>
|
||||||
|
<string name="twitter_proof_url_template" translatable="false">https://twitter.com/<user>/status/<proof post></string>
|
||||||
|
<string name="private_conversation_notification">"<Kan privébericht niet ontsleutelen>\n\nJe werd genoemd in een privégesprek tussen %1$s en %2$s."</string>
|
||||||
|
<string name="quick_action_delete_button">Verwijderen</string>
|
||||||
|
<string name="quick_action_dont_show_again_button">Niet meer laten zien</string>
|
||||||
|
<string name="account_switch_add_account_dialog_title">Nieuw account toevoegen</string>
|
||||||
|
<string name="drawer_accounts">Accounts</string>
|
||||||
|
<string name="account_switch_select_account">Account selecteren</string>
|
||||||
|
<string name="account_switch_add_account_btn">Nieuw account toevoegen</string>
|
||||||
|
<string name="account_switch_active_account">Account activeren</string>
|
||||||
|
<string name="account_switch_has_private_key">Heeft privésleutel</string>
|
||||||
|
<string name="account_switch_pubkey_only">Alleen lezen, geen privésleutel</string>
|
||||||
|
<string name="back">Terug</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
fragment_version = "1.5.5"
|
fragment_version = "1.5.5"
|
||||||
lifecycle_version = '2.6.0-rc1'
|
lifecycle_version = '2.6.0'
|
||||||
compose_ui_version = '1.4.0-beta02'
|
compose_ui_version = '1.4.0-rc01'
|
||||||
nav_version = "2.5.3"
|
nav_version = "2.5.3"
|
||||||
room_version = "2.4.3"
|
room_version = "2.4.3"
|
||||||
accompanist_version = "0.28.0"
|
accompanist_version = "0.28.0"
|
||||||
}
|
}
|
||||||
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application' version '7.4.1' apply false
|
id 'com.android.application' version '7.4.2' apply false
|
||||||
id 'com.android.library' version '7.4.1' apply false
|
id 'com.android.library' version '7.4.2' apply false
|
||||||
id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
|
id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
|
||||||
id 'org.jetbrains.kotlin.jvm' version '1.8.10' apply false
|
id 'org.jetbrains.kotlin.jvm' version '1.8.10' apply false
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user