Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opt/solana #4669

Merged
merged 15 commits into from
Jun 6, 2024
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
Loading