Adds server selection support

This commit is contained in:
Vitor Pamplona 2023-04-26 14:23:06 -04:00
parent 86fe9b4a65
commit a669e37774
10 changed files with 120 additions and 24 deletions

View File

@ -12,6 +12,7 @@ import com.vitorpamplona.amethyst.service.model.ContactListEvent
import com.vitorpamplona.amethyst.service.model.Event
import com.vitorpamplona.amethyst.service.model.Event.Companion.getRefinedEvent
import com.vitorpamplona.amethyst.service.model.LnZapEvent
import com.vitorpamplona.amethyst.ui.actions.ServersAvailable
import com.vitorpamplona.amethyst.ui.note.Nip47URI
import fr.acinq.secp256k1.Hex
import nostr.postr.Persona
@ -44,6 +45,7 @@ private object PrefKeys {
const val TRANSLATE_TO = "translateTo"
const val ZAP_AMOUNTS = "zapAmounts"
const val DEFAULT_ZAPTYPE = "defaultZapType"
const val DEFAULT_FILE_SERVER = "defaultFileServer"
const val ZAP_PAYMENT_REQUEST_SERVER = "zapPaymentServer"
const val LATEST_CONTACT_LIST = "latestContactList"
const val HIDE_DELETE_REQUEST_DIALOG = "hide_delete_request_dialog"
@ -194,6 +196,7 @@ object LocalPreferences {
putString(PrefKeys.TRANSLATE_TO, account.translateTo)
putString(PrefKeys.ZAP_AMOUNTS, gson.toJson(account.zapAmountChoices))
putString(PrefKeys.DEFAULT_ZAPTYPE, gson.toJson(account.defaultZapType))
putString(PrefKeys.DEFAULT_FILE_SERVER, gson.toJson(account.defaultFileServer))
putString(PrefKeys.ZAP_PAYMENT_REQUEST_SERVER, gson.toJson(account.zapPaymentRequest))
putString(PrefKeys.LATEST_CONTACT_LIST, Event.gson.toJson(account.backupContactList))
putBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, account.hideDeleteRequestDialog)
@ -225,6 +228,11 @@ object LocalPreferences {
object : TypeToken<LnZapEvent.ZapType>() {}.type
) ?: LnZapEvent.ZapType.PUBLIC
val defaultFileServer = gson.fromJson(
getString(PrefKeys.DEFAULT_FILE_SERVER, "IMGUR"),
object : TypeToken<ServersAvailable>() {}.type
) ?: ServersAvailable.IMGUR
val zapPaymentRequestServer = try {
getString(PrefKeys.ZAP_PAYMENT_REQUEST_SERVER, null)?.let {
gson.fromJson(it, Nip47URI::class.java)
@ -269,6 +277,7 @@ object LocalPreferences {
translateTo,
zapAmountChoices,
defaultZapType,
defaultFileServer,
zapPaymentRequestServer,
hideDeleteRequestDialog,
hideBlockAlertDialog,

View File

@ -11,6 +11,7 @@ import com.vitorpamplona.amethyst.service.relays.Constants
import com.vitorpamplona.amethyst.service.relays.FeedType
import com.vitorpamplona.amethyst.service.relays.Relay
import com.vitorpamplona.amethyst.service.relays.RelayPool
import com.vitorpamplona.amethyst.ui.actions.ServersAvailable
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
import com.vitorpamplona.amethyst.ui.note.Nip47URI
import kotlinx.coroutines.DelicateCoroutinesApi
@ -45,6 +46,7 @@ class Account(
var translateTo: String = Locale.getDefault().language,
var zapAmountChoices: List<Long> = listOf(500L, 1000L, 5000L),
var defaultZapType: LnZapEvent.ZapType = LnZapEvent.ZapType.PRIVATE,
var defaultFileServer: ServersAvailable = ServersAvailable.IMGUR,
var zapPaymentRequest: Nip47URI? = null,
var hideDeleteRequestDialog: Boolean = false,
var hideBlockAlertDialog: Boolean = false,
@ -652,6 +654,12 @@ class Account(
saveable.invalidateData()
}
fun changeDefaultFileServer(server: ServersAvailable) {
defaultFileServer = server
live.invalidateData()
saveable.invalidateData()
}
fun changeZapAmounts(newAmounts: List<Long>) {
zapAmountChoices = newAmounts
live.invalidateData()

View File

@ -7,13 +7,17 @@ import android.media.MediaScannerConnection
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.webkit.MimeTypeMap
import androidx.annotation.RequiresApi
import com.vitorpamplona.amethyst.BuildConfig
import okhttp3.*
import okio.BufferedSource
import okio.IOException
import okio.buffer
import okio.sink
import okio.source
import java.io.File
import java.util.UUID
object ImageSaver {
/**
@ -74,6 +78,38 @@ object ImageSaver {
})
}
fun saveImage(
byteArray: ByteArray,
mimeType: String?,
context: Context,
onSuccess: () -> Any?,
onError: (Throwable) -> Any?
) {
try {
val extension = mimeType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) } ?: ""
val buffer = byteArray.inputStream().source().buffer()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
saveContentQ(
displayName = UUID.randomUUID().toString(),
contentType = mimeType ?: "",
contentSource = buffer,
contentResolver = context.contentResolver
)
} else {
saveContentDefault(
fileName = UUID.randomUUID().toString() + ".$extension",
contentSource = buffer,
context = context
)
}
onSuccess()
} catch (e: Exception) {
e.printStackTrace()
onError(e)
}
}
@RequiresApi(Build.VERSION_CODES.Q)
private fun saveContentQ(
displayName: String,

View File

@ -14,6 +14,7 @@ import java.util.*
object ImageUploader {
fun uploadImage(
uri: Uri,
server: ServersAvailable,
contentResolver: ContentResolver,
onSuccess: (String, String?) -> Unit,
onError: (Throwable) -> Unit

View File

@ -58,6 +58,7 @@ import com.vitorpamplona.amethyst.service.model.TextNoteEvent
import com.vitorpamplona.amethyst.ui.components.*
import com.vitorpamplona.amethyst.ui.note.ReplyInformation
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner
import com.vitorpamplona.amethyst.ui.screen.loggedIn.UserLine
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
import kotlinx.coroutines.Dispatchers
@ -206,8 +207,10 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n
if (url != null) {
ImageVideoDescription(
url,
onAdd = { description ->
postViewModel.upload(url, description, context)
account.defaultFileServer,
onAdd = { description, server ->
postViewModel.upload(url, description, server, context)
account.changeDefaultFileServer(server)
},
onCancel = {
postViewModel.contentToAddUrl = null
@ -485,10 +488,15 @@ fun SearchButton(onPost: () -> Unit = {}, isActive: Boolean, modifier: Modifier
}
}
enum class ServersAvailable() {
IMGUR
}
@Composable
fun ImageVideoDescription(
uri: Uri,
onAdd: (String) -> Unit,
defaultServer: ServersAvailable,
onAdd: (String, ServersAvailable) -> Unit,
onCancel: () -> Unit
) {
val resolver = LocalContext.current.contentResolver
@ -498,6 +506,15 @@ fun ImageVideoDescription(
val isImage = mediaType.startsWith("image")
val isVideo = mediaType.startsWith("video")
val fileServers = listOf(
Pair(ServersAvailable.IMGUR, "imgur.com")
)
val fileServerOptions = fileServers.map { it.second }
var selectedServer by remember { mutableStateOf(defaultServer) }
var message by remember { mutableStateOf("") }
Column(
modifier = Modifier
.fillMaxWidth()
@ -595,8 +612,26 @@ fun ImageVideoDescription(
}
}
var message by remember { mutableStateOf("") }
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
TextSpinner(
label = stringResource(id = R.string.file_server),
placeholder = fileServers.filter { it.first == defaultServer }.first().second,
options = fileServerOptions,
onSelect = {
selectedServer = fileServers[it].first
},
modifier = Modifier
.weight(1f)
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
OutlinedTextField(
label = { Text(text = stringResource(R.string.content_description)) },
modifier = Modifier.fillMaxWidth(),
@ -612,13 +647,14 @@ fun ImageVideoDescription(
capitalization = KeyboardCapitalization.Sentences
)
)
}
Button(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 10.dp),
onClick = {
onAdd(message)
onAdd(message, selectedServer)
},
shape = RoundedCornerShape(15.dp),
colors = ButtonDefaults.buttonColors(

View File

@ -110,12 +110,13 @@ open class NewPostViewModel : ViewModel() {
cancel()
}
fun upload(it: Uri, description: String, context: Context) {
fun upload(it: Uri, description: String, server: ServersAvailable, context: Context) {
isUploadingImage = true
contentToAddUrl = null
ImageUploader.uploadImage(
uri = it,
server = server,
contentResolver = context.contentResolver,
onSuccess = { imageUrl, mimeType ->
createNIP97Record(imageUrl, mimeType, description)

View File

@ -170,6 +170,7 @@ class NewUserMetadataViewModel : ViewModel() {
ImageUploader.uploadImage(
uri = it,
server = account.defaultFileServer,
contentResolver = context.contentResolver,
onSuccess = { imageUrl, mimeType ->
onUploading(false)

View File

@ -233,7 +233,7 @@ fun ChannelScreen(
tint = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
modifier = Modifier.padding(start = 5.dp)
) {
channelScreenModel.upload(it, "", context)
channelScreenModel.upload(it, "", account.defaultFileServer, context)
}
},
colors = TextFieldDefaults.textFieldColors(

View File

@ -194,7 +194,7 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr
tint = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
modifier = Modifier.padding(start = 5.dp)
) {
chatRoomScreenModel.upload(it, "", context)
chatRoomScreenModel.upload(it, "", account.defaultFileServer, context)
}
},
colors = TextFieldDefaults.textFieldColors(

View File

@ -303,7 +303,8 @@
<string name="content_description_add_image">Add Image</string>
<string name="content_description_add_video">Add Video</string>
<string name="content_description_add_document">Add Document</string>
<string name="add_content">Create and Add</string>
<string name="add_content">Add to Message</string>
<string name="content_description">Description of the contents</string>
<string name="content_description_example">A blue boat in a white sandy beach at sunset</string>
@ -322,4 +323,7 @@
<string name="zap_type_nonzap">Non-Zap</string>
<string name="zap_type_nonzap_explainer">No trace in Nostr, only in Lightning</string>
<string name="file_server">File Server</string>
</resources>