Skip to content

Commit

Permalink
Opt/solana (#4669)
Browse files Browse the repository at this point in the history
* getLatestBlockhash use commitment confirmed

* Extract TransactionStateFragment

* SendAndConfirmTransaction

* Revert "SendAndConfirmTransaction"

This reverts commit 5a6ed4c.

* SendTransaction in state page

* add priority fee for transfer

* Tweak priority fee response

* Tweak json key

* fix typo

* Update priority fee api path

* Improve transaction state page

* Hide keyboard when click swap

* Keep state tip for swap

---------

Co-authored-by: Crossle Song <crosslesong@gmail.com>
  • Loading branch information
Tougee and crossle authored Jun 6, 2024
1 parent 3849b8e commit c79cb9b
Show file tree
Hide file tree
Showing 46 changed files with 672 additions and 345 deletions.
9 changes: 5 additions & 4 deletions app/src/main/java/one/mixin/android/MixinApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -428,13 +428,14 @@ open class MixinApplication :
OkHttpClient.Builder()
.addInterceptor { chain ->
val original = chain.request()
val requestBuilder = original.newBuilder()
.header("User-Agent", API_UA)
.method(original.method, original.body)
val requestBuilder =
original.newBuilder()
.header("User-Agent", API_UA)
.method(original.method, original.body)
val request = requestBuilder.build()
chain.proceed(request)
}
.build()
.build(),
)
.components {
if (SDK_INT >= Build.VERSION_CODES.P) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package one.mixin.android.api.request.web3

data class PriorityFeeRequest(
val transaction: String,
)
29 changes: 26 additions & 3 deletions app/src/main/java/one/mixin/android/api/response/Web3Token.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
import one.mixin.android.Constants
import one.mixin.android.api.response.web3.PriorityFeeResponse
import one.mixin.android.api.response.web3.SwapChain
import one.mixin.android.api.response.web3.SwapToken
import one.mixin.android.extension.base64Encode
Expand All @@ -21,6 +22,8 @@ import org.sol4k.Transaction
import org.sol4k.VersionedTransaction
import org.sol4k.instruction.CreateAssociatedTokenAccountInstruction
import org.sol4k.instruction.Instruction
import org.sol4k.instruction.SetComputeUnitLimitInstruction
import org.sol4k.instruction.SetComputeUnitPriceInstruction
import org.sol4k.instruction.SplTransferInstruction
import org.sol4k.instruction.TransferInstruction
import org.sol4k.lamportToSol
Expand Down Expand Up @@ -84,7 +87,7 @@ fun Web3Token.toSwapToken(): SwapToken {
price = null,
),
balance = balance,
price = price
price = price,
)
}

Expand Down Expand Up @@ -172,19 +175,20 @@ suspend fun Web3Token.buildTransaction(
fromAddress: String,
toAddress: String,
v: String,
estimatePriorityFee: (suspend (String) -> PriorityFeeResponse?)? = null,
): JsSignMessage {
if (chainName.equals("solana", true)) {
JsSigner.useSolana()
val sender = PublicKey(fromAddress)
val receiver = PublicKey(toAddress)
val instructions = mutableListOf<Instruction>()
val conn = Connection(RpcUrl.MAINNNET)
if (isSolToken()) {
val amount = solToLamport(v).toLong()
instructions.add(TransferInstruction(sender, receiver, amount))
} else {
val tokenMintAddress = PublicKey(assetKey)
val (receiveAssociatedAccount) = PublicKey.findProgramDerivedAddress(receiver, tokenMintAddress)
val conn = Connection(RpcUrl.MAINNNET)
val receiveAssociatedAccountInfo =
withContext(Dispatchers.IO) {
conn.getAccountInfo(receiveAssociatedAccount)
Expand Down Expand Up @@ -228,7 +232,26 @@ suspend fun Web3Token.buildTransaction(
instructions,
sender,
)
val tx = transaction.serialize().base64Encode()
var tx = transaction.serialize().base64Encode()

val priorityFeeResponse = estimatePriorityFee?.invoke(tx)
if (priorityFeeResponse != null && priorityFeeResponse.unitPrice > 0) {
val newInstructions = mutableListOf<Instruction>()
newInstructions.add(
SetComputeUnitLimitInstruction(
units = priorityFeeResponse.unitLimit,
),
)
newInstructions.add(
SetComputeUnitPriceInstruction(
microLamports = priorityFeeResponse.unitPrice,
),
)
newInstructions.addAll(instructions)
val newTransaction = Transaction(toAddress, newInstructions, sender)
tx = newTransaction.serialize().base64Encode()
}

return JsSignMessage(0, JsSignMessage.TYPE_RAW_TRANSACTION, data = tx)
} else {
JsSigner.useEvm()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ import android.os.Parcelable
import android.text.SpannedString
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
import one.mixin.android.MixinApplication
import one.mixin.android.R
import one.mixin.android.extension.buildAmountSymbol
import one.mixin.android.extension.colorFromAttribute
import one.mixin.android.extension.numberFormat
import one.mixin.android.extension.numberFormat2
import one.mixin.android.ui.setting.getLanguagePos
import one.mixin.android.util.getLanguage
import one.mixin.android.util.needsSpaceBetweenWords
import one.mixin.android.vo.Fiats
import one.mixin.android.web3.details.Web3TransactionDirection
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package one.mixin.android.api.response.web3

import com.google.gson.annotations.SerializedName

data class PriorityFeeResponse(
@SerializedName("unit_price")
val unitPrice: Long,
@SerializedName("unit_limit")
val unitLimit: Int,
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package one.mixin.android.api.response.web3
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
import one.mixin.android.api.response.wrappedSolTokenAssetKey
import one.mixin.android.api.response.solanaNativeTokenAssetKey
import one.mixin.android.api.response.wrappedSolTokenAssetKey
import java.math.BigDecimal
import java.math.RoundingMode

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package one.mixin.android.api.service

import one.mixin.android.api.MixinResponse
import one.mixin.android.api.request.web3.PriorityFeeRequest
import one.mixin.android.api.response.Web3Account
import one.mixin.android.api.response.Web3Token
import one.mixin.android.api.response.Web3Transaction
import one.mixin.android.api.response.web3.PriorityFeeResponse
import one.mixin.android.vo.ChainDapp
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
import retrofit2.http.Query

Expand All @@ -31,4 +35,9 @@ interface Web3Service {
suspend fun web3Tokens(
@Query("addresses") addresses: String,
): MixinResponse<List<Web3Token>>

@POST("estimate-priority-fees")
suspend fun getPriorityFee(
@Body priorityFeeRequest: PriorityFeeRequest,
): MixinResponse<PriorityFeeResponse>
}
20 changes: 15 additions & 5 deletions app/src/main/java/one/mixin/android/compose/CoilImage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,35 @@ import coil.compose.AsyncImage
import coil.request.ImageRequest

@Composable
fun CoilImage(model: String?, placeholder: Int, modifier: Modifier, contentScale: ContentScale = ContentScale.Fit) {
fun CoilImage(
model: String?,
placeholder: Int,
modifier: Modifier,
contentScale: ContentScale = ContentScale.Fit,
) {
AsyncImage(
modifier = modifier,
model = model,
contentDescription = null,
placeholder = painterResource(id = placeholder),
error = painterResource(id = placeholder),
contentScale = contentScale
contentScale = contentScale,
)
}

@Composable
fun CoilImage(model: ImageRequest, placeholder: Int, modifier: Modifier, contentScale: ContentScale = ContentScale.Fit) {
fun CoilImage(
model: ImageRequest,
placeholder: Int,
modifier: Modifier,
contentScale: ContentScale = ContentScale.Fit,
) {
AsyncImage(
modifier = modifier,
model = model,
contentDescription = null,
placeholder = painterResource(id = placeholder),
error = painterResource(id = placeholder),
contentScale = contentScale
contentScale = contentScale,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ fun ImageView.loadImage(
data: String?,
@DrawableRes holder: Int? = null,
base64Holder: String? = null,
onSuccess: ((
request: ImageRequest, result: SuccessResult
) -> Unit)? = null,
onSuccess: (
(
request: ImageRequest,
result: SuccessResult,
) -> Unit
)? = null,
onError: ((request: ImageRequest, result: ErrorResult) -> Unit)? = null,
transformation: Transformation? = null,
) {
Expand All @@ -45,7 +48,7 @@ fun ImageView.loadImage(
onSuccess?.let {
listener(
onSuccess = onSuccess,
onError = onError ?: { _, _ -> }
onError = onError ?: { _, _ -> },
)
}
}
Expand Down Expand Up @@ -322,10 +325,10 @@ fun RLottieImageView.loadSticker(
loadLottie(it, cacheKey)

"GIF" -> {
loadImage(url,null,null)
loadImage(url, null, null)
}

else -> loadImage(url,null,null)
else -> loadImage(url, null, null)
}
}
}
Expand Down
76 changes: 39 additions & 37 deletions app/src/main/java/one/mixin/android/job/GenerateAvatarJob.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,45 +53,46 @@ class GenerateAvatarJob(

override fun getRetryLimit() = 0

override fun onRun() = runBlocking{
val users = mutableListOf<User>()
texts = ArrayMap()
if (list == null) {
users.addAll(participantDao.getParticipantsAvatar(groupId))
} else {
val us = runBlocking { userDao.findMultiUsersByIds(list.toSet()) }
users.addAll(us)
}
val name = getIconUrlName(groupId, users)
val f = applicationContext.getGroupAvatarPath(name, false)
val icon = conversationDao.getGroupIconUrl(groupId)
if (f.exists()) {
if (f.absolutePath != name) {
conversationDao.updateGroupIconUrl(groupId, f.absolutePath)
override fun onRun() =
runBlocking {
val users = mutableListOf<User>()
texts = ArrayMap()
if (list == null) {
users.addAll(participantDao.getParticipantsAvatar(groupId))
} else {
val us = runBlocking { userDao.findMultiUsersByIds(list.toSet()) }
users.addAll(us)
}
val name = getIconUrlName(groupId, users)
val f = applicationContext.getGroupAvatarPath(name, false)
val icon = conversationDao.getGroupIconUrl(groupId)
if (f.exists()) {
if (f.absolutePath != name) {
conversationDao.updateGroupIconUrl(groupId, f.absolutePath)
}
RxBus.publish(AvatarEvent(groupId, f.absolutePath))
return@runBlocking
}
RxBus.publish(AvatarEvent(groupId, f.absolutePath))
return@runBlocking
}

val result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
val c = Canvas(result)
val bitmaps = mutableListOf<Bitmap>()
try {
getBitmaps(bitmaps, users)
} catch (e: Exception) {
return@runBlocking
}
drawInternal(c, bitmaps)
result.saveGroupAvatar(applicationContext, name)
if (icon != null && icon != f.absolutePath) {
val result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
val c = Canvas(result)
val bitmaps = mutableListOf<Bitmap>()
try {
File(icon).delete()
getBitmaps(bitmaps, users)
} catch (e: Exception) {
return@runBlocking
}
drawInternal(c, bitmaps)
result.saveGroupAvatar(applicationContext, name)
if (icon != null && icon != f.absolutePath) {
try {
File(icon).delete()
} catch (e: Exception) {
}
}
conversationDao.updateGroupIconUrl(groupId, f.absolutePath)
RxBus.publish(AvatarEvent(groupId, f.absolutePath))
}
conversationDao.updateGroupIconUrl(groupId, f.absolutePath)
RxBus.publish(AvatarEvent(groupId, f.absolutePath))
}

private fun drawInternal(
canvas: Canvas,
Expand Down Expand Up @@ -360,10 +361,11 @@ class GenerateAvatarJob(
texts[i] = AvatarView.checkEmoji(user.fullName)
bitmaps.add(getBitmapByPlaceHolder(user.userId))
} else {
val request = ImageRequest.Builder(applicationContext)
.data(item)
.allowHardware(false) // Disable hardware bitmaps since we're getting a Bitmap
.build()
val request =
ImageRequest.Builder(applicationContext)
.data(item)
.allowHardware(false) // Disable hardware bitmaps since we're getting a Bitmap
.build()

val result = applicationContext.imageLoader.execute(request)
val bitmap = (result as? SuccessResult)?.drawable?.toBitmap()
Expand Down
39 changes: 22 additions & 17 deletions app/src/main/java/one/mixin/android/job/NotificationGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ import one.mixin.android.vo.isTranscript
import one.mixin.android.vo.isVideo
import one.mixin.android.websocket.SystemConversationAction
import one.mixin.android.widget.picker.toTimeInterval
import timber.log.Timber

const val KEY_REPLY = "key_reply"
const val CONVERSATION_ID = "conversation_id"
Expand Down Expand Up @@ -606,23 +605,29 @@ object NotificationGenerator : Injector() {
}
}


private fun loadImageWithCoil(context: Context, url: String?, width: Int, height: Int, onComplete: (Bitmap?) -> Unit) {
private fun loadImageWithCoil(
context: Context,
url: String?,
width: Int,
height: Int,
onComplete: (Bitmap?) -> Unit,
) {
val imageLoader = context.imageLoader
val request = ImageRequest.Builder(context)
.data(url)
.size(width, height)
.transformations(CircleCropTransformation())
.target(
onSuccess = { drawable ->
val bitmap = (drawable as? BitmapDrawable)?.bitmap
onComplete(bitmap)
},
onError = {
onComplete(null)
}
)
.build()
val request =
ImageRequest.Builder(context)
.data(url)
.size(width, height)
.transformations(CircleCropTransformation())
.target(
onSuccess = { drawable ->
val bitmap = (drawable as? BitmapDrawable)?.bitmap
onComplete(bitmap)
},
onError = {
onComplete(null)
},
)
.build()

imageLoader.enqueue(request)
}
Expand Down
Loading

0 comments on commit c79cb9b

Please sign in to comment.