Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/xmtp/xmtp-android into np/v…
Browse files Browse the repository at this point in the history
…3-consent-upgrades
  • Loading branch information
nplasterer committed Nov 7, 2024
2 parents 3f3ae1d + 9b9f628 commit 247341e
Show file tree
Hide file tree
Showing 87 changed files with 1,095 additions and 9,307 deletions.
26 changes: 15 additions & 11 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,34 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Configure JDK
uses: actions/setup-java@v4
with:
distribution: 'adopt'
java-version: '17'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3

- name: Run build with Gradle Wrapper
run: ./gradlew build
- name: Bump version and push tag
id: tag_version
uses: mathieudutour/[email protected]
with:
release_branches: "release"
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Create a GitHub release

- name: Tag version 3.0.0
run: |
git tag 3.0.0
git push origin 3.0.0
- name: Create a GitHub release for version 3.0.0
uses: ncipollo/release-action@v1
with:
tag: ${{ steps.tag_version.outputs.new_version }}
name: Release ${{ steps.tag_version.outputs.new_tag }}
body: ${{ steps.tag_version.outputs.changelog }}
tag: "3.0.0"
name: "Release 3.0.0"
body: "A XMTP MLS only SDK 3.0.0"

- name: Gradle Publish
env:
RELEASE_VERSION: ${{ steps.tag_version.outputs.new_version }}
RELEASE_VERSION: "3.0.0"
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
SIGN_KEY: ${{ secrets.OSSRH_GPG_SECRET_KEY }}
Expand Down
194 changes: 63 additions & 131 deletions README.md

Large diffs are not rendered by default.

15 changes: 4 additions & 11 deletions example/src/main/java/org/xmtp/android/example/ClientManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,22 @@ import org.xmtp.android.library.Client
import org.xmtp.android.library.ClientOptions
import org.xmtp.android.library.XMTPEnvironment
import org.xmtp.android.library.codecs.GroupUpdatedCodec
import org.xmtp.android.library.messages.PrivateKeyBundleV1Builder
import org.xmtp.android.library.messages.walletAddress
import java.security.SecureRandom

object ClientManager {

fun clientOptions(appContext: Context, address: String): ClientOptions {
val keyUtil = KeyUtil(appContext)
var encryptionKey = keyUtil.retrieveKey(address)
if (encryptionKey == null || encryptionKey.isEmpty()) {
encryptionKey = SecureRandom().generateSeed(32)
keyUtil.storeKey(address, encryptionKey)
}
val encryptionKey = keyUtil.retrieveKey(address)?.takeUnless { it.isEmpty() }
?: SecureRandom().generateSeed(32).also { keyUtil.storeKey(address, it) }

return ClientOptions(
api = ClientOptions.Api(
XMTPEnvironment.DEV,
appVersion = "XMTPAndroidExample/v1.0.0",
isSecure = true
),
enableV3 = true,
appContext = appContext,
dbEncryptionKey = encryptionKey
)
Expand All @@ -51,14 +46,12 @@ object ClientManager {
}

@UiThread
fun createClient(encodedPrivateKeyData: String, appContext: Context) {
fun createClient(address: String, appContext: Context) {
if (clientState.value is ClientState.Ready) return
GlobalScope.launch(Dispatchers.IO) {
try {
val v1Bundle =
PrivateKeyBundleV1Builder.fromEncodedData(data = encodedPrivateKeyData)
_client =
Client().buildFrom(v1Bundle, clientOptions(appContext, v1Bundle.walletAddress))
Client().build(address, clientOptions(appContext, address))
Client.register(codec = GroupUpdatedCodec())
_clientState.value = ClientState.Ready
} catch (e: Exception) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ class MainActivity : AppCompatActivity(),
ConversationDetailActivity.intent(
this,
topic = conversation.topic,
peerAddress = conversation.peerAddress
peerAddress = conversation.id
)
)
}
Expand Down
17 changes: 2 additions & 15 deletions example/src/main/java/org/xmtp/android/example/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,10 @@ class MainViewModel : ViewModel() {
viewModelScope.launch(Dispatchers.IO) {
val listItems = mutableListOf<MainListItem>()
try {
val conversations = ClientManager.client.conversations.list(includeGroups = true)
val hmacKeysResult = ClientManager.client.conversations.getHmacKeys()
val conversations = ClientManager.client.conversations.list()
val subscriptions: MutableList<Service.Subscription> = conversations.map {
val hmacKeys = hmacKeysResult.hmacKeysMap
val result = hmacKeys[it.topic]?.valuesList?.map { hmacKey ->
Service.Subscription.HmacKey.newBuilder().also { sub_key ->
sub_key.key = hmacKey.hmacKey
sub_key.thirtyDayPeriodsSinceEpoch = hmacKey.thirtyDayPeriodsSinceEpoch
}.build()
}

Service.Subscription.newBuilder().also { sub ->
if (!result.isNullOrEmpty()) {
sub.addAllHmacKeys(result)
}
sub.topic = it.topic
sub.isSilent = it.version == Conversation.Version.V1
}.build()
}.toMutableList()

Expand Down Expand Up @@ -105,7 +92,7 @@ class MainViewModel : ViewModel() {
val stream: StateFlow<MainListItem?> =
stateFlow(viewModelScope, null) { subscriptionCount ->
if (ClientManager.clientState.value is ClientManager.ClientState.Ready) {
ClientManager.client.conversations.streamAll()
ClientManager.client.conversations.stream()
.flowWhileShared(
subscriptionCount,
SharingStarted.WhileSubscribed(1000L)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,7 @@ class ConnectWalletFragment : Fragment() {
when (uiState) {
is ConnectWalletViewModel.ConnectUiState.Error -> showError(uiState.message)
ConnectWalletViewModel.ConnectUiState.Loading -> showLoading()
is ConnectWalletViewModel.ConnectUiState.Success -> signIn(
uiState.address,
uiState.encodedKeyData
)
is ConnectWalletViewModel.ConnectUiState.Success -> signIn(uiState.address)

ConnectWalletViewModel.ConnectUiState.Unknown -> Unit
}
Expand All @@ -103,10 +100,10 @@ class ConnectWalletFragment : Fragment() {
}
}

private fun signIn(address: String, encodedKey: String) {
private fun signIn(address: String) {
val accountManager = AccountManager.get(requireContext())
Account(address, resources.getString(R.string.account_type)).also { account ->
accountManager.addAccountExplicitly(account, encodedKey, null)
accountManager.addAccountExplicitly(account, address, null)
}
requireActivity().startActivity(Intent(requireActivity(), MainActivity::class.java))
requireActivity().finish()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import org.xmtp.android.library.Client
import org.xmtp.android.library.XMTPException
import org.xmtp.android.library.codecs.GroupUpdatedCodec
import org.xmtp.android.library.messages.PrivateKeyBuilder
import org.xmtp.android.library.messages.PrivateKeyBundleV1Builder

class ConnectWalletViewModel(application: Application) : AndroidViewModel(application) {

Expand Down Expand Up @@ -89,8 +88,7 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic
val client = Client().create(wallet, ClientManager.clientOptions(getApplication(), wallet.address))
Client.register(codec = GroupUpdatedCodec())
_uiState.value = ConnectUiState.Success(
wallet.address,
PrivateKeyBundleV1Builder.encodeData(client.v1keys)
wallet.address
)
} catch (e: XMTPException) {
_uiState.value = ConnectUiState.Error(e.message.orEmpty())
Expand All @@ -114,8 +112,7 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic
val client = Client().create(wallet, ClientManager.clientOptions(getApplication(), wallet.address))
Client.register(codec = GroupUpdatedCodec())
_uiState.value = ConnectUiState.Success(
wallet.address,
PrivateKeyBundleV1Builder.encodeData(client.v1keys)
wallet.address
)
} catch (e: Exception) {
_uiState.value = ConnectUiState.Error(e.message.orEmpty())
Expand All @@ -132,7 +129,7 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic
sealed class ConnectUiState {
object Unknown : ConnectUiState()
object Loading : ConnectUiState()
data class Success(val address: String, val encodedKeyData: String) : ConnectUiState()
data class Success(val address: String) : ConnectUiState()
data class Error(val message: String) : ConnectUiState()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ class ConversationDetailViewModel(private val savedStateHandle: SavedStateHandle
val listItems = mutableListOf<MessageListItem>()
try {
if (conversation == null) {
conversation = ClientManager.client.fetchConversation(
conversationTopic,
includeGroups = true
)
conversation = ClientManager.client.findConversationByTopic(conversationTopic!!)
}
conversation?.let {
if (conversation is Conversation.Group) {
Expand All @@ -79,10 +76,7 @@ class ConversationDetailViewModel(private val savedStateHandle: SavedStateHandle
if (conversation == null) {
conversation =
runBlocking {
ClientManager.client.fetchConversation(
conversationTopic,
includeGroups = false
)
ClientManager.client.findConversationByTopic(conversationTopic!!)
}
}
if (conversation != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,7 @@ class ConversationViewHolder(

fun bind(item: MainViewModel.MainListItem.ConversationItem) {
conversation = item.conversation
binding.peerAddress.text = if (item.conversation.peerAddress.contains(",")) {
val addresses = item.conversation.peerAddress.split(",")
addresses.joinToString(" & ") {
it.truncatedAddress()
}
} else {
item.conversation.peerAddress.truncatedAddress()
}
binding.peerAddress.text = item.conversation.id.truncatedAddress()

val messageBody: String = if (item.mostRecentMessage?.content<Any>() is String) {
item.mostRecentMessage.body.orEmpty()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class NewConversationBottomSheet : BottomSheetDialogFragment() {
ConversationDetailActivity.intent(
requireContext(),
topic = uiState.conversation.topic,
peerAddress = uiState.conversation.peerAddress
peerAddress = uiState.conversation.id
)
)
dismiss()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class NewGroupBottomSheet : BottomSheetDialogFragment() {
ConversationDetailActivity.intent(
requireContext(),
topic = uiState.conversation.topic,
peerAddress = uiState.conversation.peerAddress
peerAddress = uiState.conversation.id
)
)
dismiss()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,8 @@ import org.xmtp.android.example.R
import org.xmtp.android.example.conversation.ConversationDetailActivity
import org.xmtp.android.example.extension.truncatedAddress
import org.xmtp.android.example.utils.KeyUtil
import org.xmtp.android.library.Conversation
import org.xmtp.android.library.codecs.GroupUpdated
import org.xmtp.android.library.messages.EnvelopeBuilder
import org.xmtp.android.library.messages.Topic
import java.util.Date

class PushNotificationsService : FirebaseMessagingService() {

Expand Down Expand Up @@ -70,14 +67,14 @@ class PushNotificationsService : FirebaseMessagingService() {
ConversationDetailActivity.intent(
this,
topic = group.topic,
peerAddress = Conversation.Group(group).peerAddress
peerAddress = group.id
),
(PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
)

NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_xmtp_white)
.setContentTitle(Conversation.Group(group).peerAddress.truncatedAddress())
.setContentTitle(group.id.truncatedAddress())
.setContentText("New Group Chat")
.setAutoCancel(true)
.setColor(ContextCompat.getColor(this, R.color.black))
Expand All @@ -86,19 +83,15 @@ class PushNotificationsService : FirebaseMessagingService() {
.setContentIntent(pendingIntent)
} else {
val conversation =
runBlocking { ClientManager.client.fetchConversation(topic, includeGroups = true) }
runBlocking { ClientManager.client.findConversationByTopic(topic) }
if (conversation == null) {
Log.e(TAG, topic)
Log.e(TAG, "No keys or conversation persisted")
return
}
val decodedMessage = if (conversation is Conversation.Group) {
runBlocking { conversation.group.processMessage(encryptedMessageData).decode() }
} else {
val envelope = EnvelopeBuilder.buildFromString(topic, Date(), encryptedMessageData)
conversation.decode(envelope)
}
val peerAddress = conversation.peerAddress
val decodedMessage =
runBlocking { conversation.processMessage(encryptedMessageData).decode() }
val peerAddress = conversation.id

val body: String = if (decodedMessage.content<Any>() is String) {
decodedMessage.body
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ class KeyUtil(val context: Context) {
return accountManager.getPassword(account)
}

fun storeKey(address: String, key: ByteArray?) {
fun storeKey(address: String, dbEncryptionKey: ByteArray?) {
val alias = "xmtp-dev-${address.lowercase()}"

val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
val editor = prefs.edit()
editor.putString(alias, encodeToString(key, NO_WRAP))
editor.putString(alias, encodeToString(dbEncryptionKey, NO_WRAP))
editor.apply()
}

Expand Down
1 change: 1 addition & 0 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ dependencies {
api 'org.xmtp:proto-kotlin:3.71.0'

testImplementation 'junit:junit:4.13.2'
testImplementation 'androidx.test:monitor:1.7.2'
androidTestImplementation 'app.cash.turbine:turbine:1.1.0'
androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ class AttachmentTest {
Client.register(codec = AttachmentCodec())

val fixtures = fixtures()
val aliceClient = fixtures.aliceClient
val aliceClient = fixtures.alixClient
val aliceConversation = runBlocking {
aliceClient.conversations.newConversation(fixtures.bob.walletAddress)
aliceClient.conversations.newConversation(fixtures.bo.walletAddress)
}

runBlocking {
Expand All @@ -36,8 +36,8 @@ class AttachmentTest {
)
}
val messages = runBlocking { aliceConversation.messages() }
assertEquals(messages.size, 1)
if (messages.size == 1) {
assertEquals(messages.size, 2)
if (messages.size == 2) {
val content: Attachment? = messages[0].content()
assertEquals("test.txt", content?.filename)
assertEquals("text/plain", content?.mimeType)
Expand Down
Loading

0 comments on commit 247341e

Please sign in to comment.