diff --git a/briar b/briar
index b9bac8b6a54da1d83ee03f933b8779aaff398742..93439d9c170b224727e8e1891c106d38162539de 160000
--- a/briar
+++ b/briar
@@ -1 +1 @@
-Subproject commit b9bac8b6a54da1d83ee03f933b8779aaff398742
+Subproject commit 93439d9c170b224727e8e1891c106d38162539de
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItem.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItem.kt
index afbfcbf6dad2a8c744bbca395b963e781b200c85..ae8a42a5330bd5bd7bdca97ea26d9b41bfe9733c 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItem.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItem.kt
@@ -97,10 +97,10 @@ fun loadContactItem(
 ): ContactItem {
     val authorInfo = authorManager.getAuthorInfo(txn, contact)
     return ContactItem(
-        contact,
-        authorInfo,
-        connectionRegistry.isConnected(contact.id),
-        conversationManager.getGroupCount(txn, contact.id),
-        authorInfo.avatarHeader?.let { ImageUtils.loadImage(txn, attachmentReader, it) },
+        contact = contact,
+        authorInfo = authorInfo,
+        isConnected = connectionRegistry.isConnected(contact.id),
+        groupCount = conversationManager.getGroupCount(txn, contact.id),
+        avatar = authorInfo.avatarHeader?.let { ImageUtils.loadImage(txn, attachmentReader, it) },
     )
 }
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItemView.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItemView.kt
index bae6112798841f110379930a4083af5186c9f649..18a3a808561a29f9fa64ec746d67bfbee08531ab 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItemView.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItemView.kt
@@ -32,8 +32,11 @@ import androidx.compose.material.MaterialTheme
 import androidx.compose.material.ProvideTextStyle
 import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.loadImageBitmap
+import androidx.compose.ui.res.useResource
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.semantics.text
 import androidx.compose.ui.text.style.TextOverflow.Companion.Ellipsis
@@ -65,7 +68,11 @@ fun main() = preview(
     "unread" to 3,
     "timestamp" to Instant.now().toEpochMilli(),
     "selected" to false,
+    "showAvatar" to false,
 ) {
+    val avatar = remember {
+        useResource("images/logo_circle.ico") { loadImageBitmap(it) }
+    }
     Column(Modifier.selectableGroup()) {
         ListItemView(getBooleanParameter("selected")) {
             val item = ContactItem(
@@ -78,7 +85,7 @@ fun main() = preview(
                 isEmpty = getBooleanParameter("isEmpty"),
                 unread = getIntParameter("unread"),
                 timestamp = getLongParameter("timestamp"),
-                avatar = null,
+                avatar = if (getBooleanParameter("showAvatar")) avatar else null,
             )
             ContactItemView(item)
         }
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItemViewSmall.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItemViewSmall.kt
index fda601dc0d796f32c5d2c00c219bd6b394382434..6c7ffa1dce018294bca837b7a143c3be4bba4de2 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItemViewSmall.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactItemViewSmall.kt
@@ -22,7 +22,6 @@ import androidx.compose.foundation.layout.Arrangement.spacedBy
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.foundation.selection.selectableGroup
 import androidx.compose.material.MaterialTheme
@@ -82,14 +81,12 @@ fun main() = preview(
 fun ContactItemViewSmall(
     contactItem: ContactItem,
     showConnectionState: Boolean = true,
+    modifier: Modifier = Modifier,
 ) = Row(
     horizontalArrangement = spacedBy(8.dp),
     verticalAlignment = Alignment.CenterVertically,
-    modifier = Modifier
+    modifier = modifier
         .fillMaxWidth()
-        .padding(vertical = 8.dp)
-        // makes sure that ConnectionIndicator is aligned with AddContact button
-        .padding(start = 16.dp, end = 20.dp)
         .semantics {
             text = getDescription(contactItem, showConnectionState)
         }
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt
index 759db1864af83c247c9ac92e16cf68a17eede07e..a31a8015738d497ff3700072d25bc476f19fa658 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactList.kt
@@ -18,8 +18,6 @@
 
 package org.briarproject.briar.desktop.contact
 
-import androidx.compose.foundation.VerticalScrollbar
-import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxSize
@@ -28,8 +26,6 @@ import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.items
-import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.foundation.rememberScrollbarAdapter
 import androidx.compose.foundation.selection.selectableGroup
 import androidx.compose.material.MaterialTheme
 import androidx.compose.material.Surface
@@ -38,7 +34,6 @@ import androidx.compose.material.icons.filled.PersonAdd
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.semantics.contentDescription
 import androidx.compose.ui.semantics.semantics
@@ -55,6 +50,7 @@ import org.briarproject.briar.desktop.ui.Constants.COLUMN_WIDTH
 import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE
 import org.briarproject.briar.desktop.ui.ListItemView
 import org.briarproject.briar.desktop.ui.SearchTextField
+import org.briarproject.briar.desktop.ui.VerticallyScrollableArea
 import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
 import org.briarproject.briar.desktop.utils.PreviewUtils.preview
 import java.time.Instant
@@ -126,8 +122,6 @@ fun ContactList(
     setFilterBy: (String) -> Unit,
     onContactAdd: () -> Unit,
 ) {
-    val scrollState = rememberLazyListState()
-
     Surface(
         modifier = Modifier.fillMaxHeight().width(COLUMN_WIDTH),
         color = MaterialTheme.colors.surfaceVariant
@@ -146,7 +140,7 @@ fun ContactList(
                 )
             }
 
-            Box(modifier = Modifier.fillMaxSize()) {
+            VerticallyScrollableArea(modifier = Modifier.fillMaxSize()) { scrollState ->
                 LazyColumn(
                     state = scrollState,
                     modifier = Modifier
@@ -181,11 +175,6 @@ fun ContactList(
                         }
                     }
                 }
-
-                VerticalScrollbar(
-                    adapter = rememberScrollbarAdapter(scrollState),
-                    modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight()
-                )
             }
         }
     }
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumSharingViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumSharingViewModel.kt
deleted file mode 100644
index 7e6ac6a5a97ffb10db2119fa5817f4eda47e4362..0000000000000000000000000000000000000000
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumSharingViewModel.kt
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Briar Desktop
- * Copyright (C) 2021-2022 The Briar Project
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-package org.briarproject.briar.desktop.forums
-
-import androidx.compose.runtime.mutableStateListOf
-import androidx.compose.runtime.mutableStateOf
-import mu.KotlinLogging
-import org.briarproject.bramble.api.connection.ConnectionRegistry
-import org.briarproject.bramble.api.contact.ContactManager
-import org.briarproject.bramble.api.db.TransactionManager
-import org.briarproject.bramble.api.event.Event
-import org.briarproject.bramble.api.event.EventBus
-import org.briarproject.bramble.api.lifecycle.LifecycleManager
-import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent
-import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent
-import org.briarproject.bramble.api.sync.GroupId
-import org.briarproject.briar.api.attachment.AttachmentReader
-import org.briarproject.briar.api.conversation.ConversationManager
-import org.briarproject.briar.api.forum.ForumSharingManager
-import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent
-import org.briarproject.briar.api.identity.AuthorManager
-import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent
-import org.briarproject.briar.desktop.contact.ContactItem
-import org.briarproject.briar.desktop.threading.BriarExecutors
-import org.briarproject.briar.desktop.threading.UiExecutor
-import org.briarproject.briar.desktop.utils.ImageUtils.loadImage
-import org.briarproject.briar.desktop.utils.clearAndAddAll
-import org.briarproject.briar.desktop.utils.removeFirst
-import org.briarproject.briar.desktop.utils.replaceFirst
-import org.briarproject.briar.desktop.viewmodel.EventListenerDbViewModel
-import org.briarproject.briar.desktop.viewmodel.asList
-import org.briarproject.briar.desktop.viewmodel.asState
-import org.briarproject.briar.desktop.viewmodel.update
-import javax.inject.Inject
-
-class ForumSharingViewModel @Inject constructor(
-    private val forumSharingManager: ForumSharingManager,
-    private val contactManager: ContactManager,
-    private val authorManager: AuthorManager,
-    private val conversationManager: ConversationManager,
-    private val connectionRegistry: ConnectionRegistry,
-    private val attachmentReader: AttachmentReader,
-    briarExecutors: BriarExecutors,
-    lifecycleManager: LifecycleManager,
-    db: TransactionManager,
-    eventBus: EventBus,
-) : EventListenerDbViewModel(briarExecutors, lifecycleManager, db, eventBus) {
-
-    companion object {
-        private val LOG = KotlinLogging.logger {}
-    }
-
-    private lateinit var groupId: GroupId
-
-    private val _currentlySharedWith = mutableStateListOf<ContactItem>()
-    val currentlySharedWith = _currentlySharedWith.asList()
-
-    private val _sharingInfo = mutableStateOf(SharingInfo(0, 0))
-    val sharingInfo = _sharingInfo.asState()
-
-    @UiExecutor
-    fun setGroupId(groupId: GroupId) {
-        if (this::groupId.isInitialized && groupId == this.groupId) return
-        this.groupId = groupId
-        loadSharedWith()
-    }
-
-    @UiExecutor
-    override fun eventOccurred(e: Event) {
-        when {
-            e is ForumInvitationResponseReceivedEvent && e.messageHeader.shareableId == groupId && e.messageHeader.wasAccepted() ->
-                runOnDbThreadWithTransaction(false) { txn ->
-                    val contact = contactManager.getContact(txn, e.contactId)
-                    val authorInfo = authorManager.getAuthorInfo(txn, contact)
-                    val connected = connectionRegistry.isConnected(contact.id)
-                    val item = ContactItem(
-                        contact,
-                        authorInfo,
-                        connected,
-                        conversationManager.getGroupCount(txn, contact.id), // todo: not necessary to be shown here
-                        authorInfo.avatarHeader?.let { loadImage(txn, attachmentReader, it) },
-                    )
-                    txn.attach {
-                        _currentlySharedWith.add(item)
-                        _sharingInfo.update { addContact(connected) }
-                    }
-                }
-
-            e is ContactLeftShareableEvent && e.groupId == groupId -> {
-                _currentlySharedWith.removeFirst { it.id == e.contactId }
-                val connected = connectionRegistry.isConnected(e.contactId)
-                _sharingInfo.update { removeContact(connected) }
-            }
-
-            e is ContactConnectedEvent -> {
-                val isMember = _currentlySharedWith.replaceFirst({ it.id == e.contactId }) {
-                    it.updateIsConnected(true)
-                }
-                if (isMember) _sharingInfo.update { updateContactConnected(true) }
-            }
-
-            e is ContactDisconnectedEvent -> {
-                val isMember = _currentlySharedWith.replaceFirst({ it.id == e.contactId }) {
-                    it.updateIsConnected(false)
-                }
-                if (isMember) _sharingInfo.update { updateContactConnected(false) }
-            }
-        }
-    }
-
-    private fun loadSharedWith() = runOnDbThreadWithTransaction(true) { txn ->
-        var online = 0
-        val list = forumSharingManager.getSharedWith(txn, groupId).map { contact ->
-            val authorInfo = authorManager.getAuthorInfo(txn, contact)
-            val connected = connectionRegistry.isConnected(contact.id)
-            if (connected) online++
-            ContactItem(
-                contact,
-                authorInfo,
-                connected,
-                conversationManager.getGroupCount(txn, contact.id), // todo: not necessary to be shown here
-                authorInfo.avatarHeader?.let { loadImage(txn, attachmentReader, it) },
-            )
-        }
-        txn.attach {
-            _currentlySharedWith.clearAndAddAll(list)
-            _sharingInfo.value = SharingInfo(list.size, online)
-        }
-    }
-
-    data class SharingInfo(val total: Int, val online: Int) {
-        fun addContact(connected: Boolean) = copy(
-            total = total + 1,
-            online = if (connected) online + 1 else online
-        )
-
-        fun removeContact(connected: Boolean) = copy(
-            total = total - 1,
-            online = if (connected) online - 1 else online
-        )
-
-        fun updateContactConnected(connected: Boolean) = copy(
-            total = total,
-            online = if (connected) online + 1 else online - 1
-        )
-    }
-}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupConversationScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupConversationScreen.kt
index b8a8adbb4c768c3c7027e6845c905c5f96ed877b..642152e4520067fe6f2496712ffcaaaa56567f3f 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupConversationScreen.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupConversationScreen.kt
@@ -53,6 +53,9 @@ import androidx.compose.ui.text.style.TextOverflow.Companion.Ellipsis
 import androidx.compose.ui.unit.dp
 import org.briarproject.briar.desktop.contact.ContactDropDown.State.CLOSED
 import org.briarproject.briar.desktop.contact.ContactDropDown.State.MAIN
+import org.briarproject.briar.desktop.forums.sharing.ForumSharingActionDrawerContent
+import org.briarproject.briar.desktop.forums.sharing.ForumSharingStatusDrawerContent
+import org.briarproject.briar.desktop.forums.sharing.ForumSharingViewModel
 import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE
 import org.briarproject.briar.desktop.ui.HorizontalDivider
 import org.briarproject.briar.desktop.ui.getInfoDrawerHandler
@@ -139,8 +142,23 @@ private fun GroupConversationHeader(
                         onClick = {
                             close()
                             infoDrawerHandler.open {
-                                ForumSharingDrawerContent(
-                                    groupId = groupItem.id,
+                                ForumSharingActionDrawerContent(
+                                    close = infoDrawerHandler::close,
+                                    viewModel = forumSharingViewModel,
+                                )
+                            }
+                        }
+                    ) {
+                        Text(
+                            i18n("forum.sharing.action.title"),
+                            style = MaterialTheme.typography.body2,
+                        )
+                    }
+                    DropdownMenuItem(
+                        onClick = {
+                            close()
+                            infoDrawerHandler.open {
+                                ForumSharingStatusDrawerContent(
                                     close = infoDrawerHandler::close,
                                     viewModel = forumSharingViewModel,
                                 )
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ThreadedConversationViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ThreadedConversationViewModel.kt
index 3351fa255a49ae5333b45d0bd201e27b4a1ccf98..08aa3bbea804179f769b625b394164cca261adea 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ThreadedConversationViewModel.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ThreadedConversationViewModel.kt
@@ -40,6 +40,7 @@ import org.briarproject.briar.api.forum.ForumManager
 import org.briarproject.briar.api.forum.ForumPostHeader
 import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent
 import org.briarproject.briar.client.MessageTreeImpl
+import org.briarproject.briar.desktop.forums.sharing.ForumSharingViewModel
 import org.briarproject.briar.desktop.threading.BriarExecutors
 import org.briarproject.briar.desktop.threading.UiExecutor
 import org.briarproject.briar.desktop.viewmodel.EventListenerDbViewModel
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/sharing/ForumSharingActionDrawerContent.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/sharing/ForumSharingActionDrawerContent.kt
new file mode 100644
index 0000000000000000000000000000000000000000..815e43f9abbd92691e28cdb969373cc0b8619c38
--- /dev/null
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/sharing/ForumSharingActionDrawerContent.kt
@@ -0,0 +1,174 @@
+/*
+ * Briar Desktop
+ * Copyright (C) 2021-2022 The Briar Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package org.briarproject.briar.desktop.forums.sharing
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material.Button
+import androidx.compose.material.Checkbox
+import androidx.compose.material.IconButton
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.material.TextField
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import org.briarproject.briar.api.sharing.SharingManager.SharingStatus.ERROR
+import org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITE_RECEIVED
+import org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITE_SENT
+import org.briarproject.briar.api.sharing.SharingManager.SharingStatus.NOT_SUPPORTED
+import org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHAREABLE
+import org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHARING
+import org.briarproject.briar.desktop.contact.ContactItemViewSmall
+import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE
+import org.briarproject.briar.desktop.ui.HorizontalDivider
+import org.briarproject.briar.desktop.ui.ListItemView
+import org.briarproject.briar.desktop.ui.VerticallyScrollableArea
+import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
+
+@Composable
+fun ForumSharingActionDrawerContent(
+    close: () -> Unit,
+    viewModel: ForumSharingViewModel,
+) = Column {
+    Row(Modifier.fillMaxWidth().height(HEADER_SIZE)) {
+        IconButton(
+            icon = Icons.Filled.Close,
+            contentDescription = i18n("access.forum.sharing.action.close"),
+            onClick = close,
+            modifier = Modifier.padding(start = 24.dp).size(24.dp).align(Alignment.CenterVertically)
+        )
+        Text(
+            text = i18n("forum.sharing.action.title"),
+            modifier = Modifier.align(Alignment.CenterVertically).padding(start = 16.dp),
+            style = MaterialTheme.typography.h3,
+        )
+    }
+    HorizontalDivider()
+    Box(Modifier.fillMaxWidth().weight(1f)) {
+        if (viewModel.contactList.value.isEmpty()) {
+            // todo: this might be shown to the user while the list is still loading
+            Text(
+                text = i18n("forum.sharing.action.no_contacts"),
+                style = MaterialTheme.typography.body1,
+                modifier = Modifier.padding(8.dp).align(Alignment.Center),
+            )
+        } else {
+            VerticallyScrollableArea { scrollState ->
+                LazyColumn(state = scrollState) {
+                    items(
+                        items = viewModel.contactList.value,
+                        key = { it.contactItem.id },
+                    ) { shareableContactItem ->
+                        ForumSharingActionListItem(
+                            shareableContactItem = shareableContactItem,
+                            shareable = shareableContactItem.status == SHAREABLE,
+                            selected = viewModel.isShareableSelected(shareableContactItem),
+                            onToggle = { viewModel.toggleShareable(shareableContactItem) },
+                        )
+                    }
+                }
+            }
+        }
+    }
+    Column(
+        verticalArrangement = Arrangement.spacedBy(8.dp),
+        modifier = Modifier.fillMaxWidth().padding(8.dp),
+    ) {
+        val shareForum = {
+            if (viewModel.buttonEnabled.value) {
+                viewModel.shareForum()
+                close()
+            }
+        }
+
+        TextField(
+            value = viewModel.sharingMessage.value,
+            onValueChange = viewModel::setSharingMessage,
+            onEnter = shareForum,
+            placeholder = {
+                Text(
+                    text = i18n("forum.sharing.action.add_message"),
+                    style = MaterialTheme.typography.body1,
+                )
+            },
+            modifier = Modifier.fillMaxWidth().heightIn(max = 100.dp)
+        )
+        Button(
+            onClick = shareForum,
+            modifier = Modifier.fillMaxWidth(),
+            enabled = viewModel.buttonEnabled.value,
+        ) {
+            Text(i18n("forum.sharing.action.title"))
+        }
+    }
+}
+
+@Composable
+private fun ForumSharingActionListItem(
+    shareableContactItem: ForumSharingViewModel.ShareableContactItem,
+    shareable: Boolean,
+    selected: Boolean,
+    onToggle: () -> Unit,
+) = ListItemView(
+    selected = if (shareable) selected else null,
+    onSelect = onToggle,
+) {
+    Row(verticalAlignment = Alignment.CenterVertically) {
+        Checkbox(
+            checked = selected,
+            onCheckedChange = { onToggle() },
+            enabled = shareable
+        )
+        Column(
+            verticalArrangement = Arrangement.spacedBy(8.dp),
+            modifier = Modifier.padding(8.dp)
+        ) {
+            ContactItemViewSmall(
+                shareableContactItem.contactItem,
+                showConnectionState = false,
+            )
+            if (!shareable) {
+                Text(
+                    when (shareableContactItem.status) {
+                        SHAREABLE -> ""
+                        SHARING -> i18n("forum.sharing.action.status.already_shared")
+                        INVITE_SENT -> i18n("forum.sharing.action.status.already_invited")
+                        INVITE_RECEIVED -> i18n("forum.sharing.action.status.invite_received")
+                        NOT_SUPPORTED -> i18n("forum.sharing.action.status.not_supported")
+                        ERROR -> i18n("forum.sharing.action.status.error")
+                    },
+                    style = MaterialTheme.typography.caption,
+                )
+            }
+        }
+    }
+}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumSharingDrawerContent.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/sharing/ForumSharingStatusDrawerContent.kt
similarity index 88%
rename from briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumSharingDrawerContent.kt
rename to briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/sharing/ForumSharingStatusDrawerContent.kt
index 3bfa7535a28e419000afaa8cf083c5f682b65b78..e24d697db7567836d0c57060d07f9f3454a0643a 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumSharingDrawerContent.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/sharing/ForumSharingStatusDrawerContent.kt
@@ -16,7 +16,7 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-package org.briarproject.briar.desktop.forums
+package org.briarproject.briar.desktop.forums.sharing
 
 import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy
 import androidx.compose.foundation.layout.Box
@@ -37,11 +37,9 @@ import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Close
 import androidx.compose.material.icons.filled.Info
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
-import org.briarproject.bramble.api.sync.GroupId
 import org.briarproject.briar.desktop.contact.ContactItemViewSmall
 import org.briarproject.briar.desktop.ui.Constants.HEADER_SIZE
 import org.briarproject.briar.desktop.ui.HorizontalDivider
@@ -49,14 +47,10 @@ import org.briarproject.briar.desktop.ui.ListItemView
 import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
 
 @Composable
-fun ForumSharingDrawerContent(
-    groupId: GroupId,
+fun ForumSharingStatusDrawerContent(
     close: () -> Unit,
     viewModel: ForumSharingViewModel,
 ) = Column {
-    LaunchedEffect(groupId) {
-        viewModel.setGroupId(groupId)
-    }
     Row(Modifier.fillMaxWidth().height(HEADER_SIZE)) {
         IconButton(
             icon = Icons.Filled.Close,
@@ -88,7 +82,8 @@ fun ForumSharingDrawerContent(
     }
     HorizontalDivider()
     Box(Modifier.fillMaxSize()) {
-        if (viewModel.currentlySharedWith.isEmpty()) {
+        if (viewModel.currentlySharedWith.value.isEmpty()) {
+            // todo: this might be shown to the user while the list is still loading
             Text(
                 text = i18n("forum.sharing.status.nobody"),
                 style = MaterialTheme.typography.body1,
@@ -96,9 +91,12 @@ fun ForumSharingDrawerContent(
             )
         } else {
             LazyColumn {
-                items(viewModel.currentlySharedWith) { contactItem ->
+                items(viewModel.currentlySharedWith.value) { contactItem ->
                     ListItemView {
-                        ContactItemViewSmall(contactItem)
+                        ContactItemViewSmall(
+                            contactItem,
+                            modifier = Modifier.padding(8.dp)
+                        )
                     }
                 }
             }
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/sharing/ForumSharingViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/sharing/ForumSharingViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..11c07d0b493a54fb9d8b7b8039a57b7b327db92a
--- /dev/null
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/sharing/ForumSharingViewModel.kt
@@ -0,0 +1,223 @@
+/*
+ * Briar Desktop
+ * Copyright (C) 2021-2022 The Briar Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package org.briarproject.briar.desktop.forums.sharing
+
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.mutableStateOf
+import mu.KotlinLogging
+import org.briarproject.bramble.api.connection.ConnectionRegistry
+import org.briarproject.bramble.api.contact.ContactId
+import org.briarproject.bramble.api.contact.ContactManager
+import org.briarproject.bramble.api.db.Transaction
+import org.briarproject.bramble.api.db.TransactionManager
+import org.briarproject.bramble.api.event.Event
+import org.briarproject.bramble.api.event.EventBus
+import org.briarproject.bramble.api.lifecycle.LifecycleManager
+import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent
+import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent
+import org.briarproject.bramble.api.sync.GroupId
+import org.briarproject.briar.api.attachment.AttachmentReader
+import org.briarproject.briar.api.conversation.ConversationManager
+import org.briarproject.briar.api.forum.ForumSharingManager
+import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent
+import org.briarproject.briar.api.identity.AuthorManager
+import org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_TEXT_LENGTH
+import org.briarproject.briar.api.sharing.SharingManager.SharingStatus
+import org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHAREABLE
+import org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHARING
+import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent
+import org.briarproject.briar.desktop.contact.ContactItem
+import org.briarproject.briar.desktop.contact.ContactsViewModel
+import org.briarproject.briar.desktop.threading.BriarExecutors
+import org.briarproject.briar.desktop.threading.UiExecutor
+import org.briarproject.briar.desktop.utils.InternationalizationUtils
+import org.briarproject.briar.desktop.viewmodel.asState
+import org.briarproject.briar.desktop.viewmodel.update
+import javax.inject.Inject
+
+class ForumSharingViewModel @Inject constructor(
+    private val forumSharingManager: ForumSharingManager,
+    contactManager: ContactManager,
+    authorManager: AuthorManager,
+    conversationManager: ConversationManager,
+    private val connectionRegistry: ConnectionRegistry,
+    attachmentReader: AttachmentReader,
+    briarExecutors: BriarExecutors,
+    lifecycleManager: LifecycleManager,
+    db: TransactionManager,
+    eventBus: EventBus,
+) : ContactsViewModel(
+    contactManager,
+    authorManager,
+    conversationManager,
+    connectionRegistry,
+    attachmentReader,
+    briarExecutors,
+    lifecycleManager,
+    db,
+    eventBus,
+) {
+
+    companion object {
+        private val LOG = KotlinLogging.logger {}
+    }
+
+    private lateinit var groupId: GroupId
+
+    private val _sharingStatus = mutableStateOf(emptyMap<ContactId, SharingStatus>())
+    private val _shareableSelected = mutableStateOf(emptySet<ContactId>())
+    private val _sharingMessage = mutableStateOf("")
+
+    val currentlySharedWith = derivedStateOf {
+        _contactList.filter { _sharingStatus.value[it.id] == SHARING }
+    }
+
+    data class ShareableContactItem(val status: SharingStatus, val contactItem: ContactItem)
+
+    val contactList = derivedStateOf {
+        _contactList.mapNotNull {
+            _sharingStatus.value[it.id]?.let { status ->
+                ShareableContactItem(status, it)
+            }
+        }.sortedWith(
+            // first all items that are SHAREABLE (false comes before true)
+            // second non-case-sensitive, alphabetical order on displayName
+            compareBy({ it.status != SHAREABLE }, { it.contactItem.displayName.lowercase(InternationalizationUtils.locale) })
+        )
+    }
+
+    val sharingMessage = _sharingMessage.asState()
+
+    val buttonEnabled = derivedStateOf { _shareableSelected.value.isNotEmpty() }
+
+    private val _sharingInfo = mutableStateOf(SharingInfo(0, 0))
+    val sharingInfo = _sharingInfo.asState()
+
+    override fun onInit() {
+        super.onInit()
+        loadContacts()
+    }
+
+    @UiExecutor
+    fun setGroupId(groupId: GroupId) {
+        if (this::groupId.isInitialized && groupId == this.groupId) return
+        this.groupId = groupId
+        reload()
+    }
+
+    private fun reload() {
+        _shareableSelected.value = emptySet()
+        _sharingMessage.value = ""
+        loadSharingStatus()
+    }
+
+    @UiExecutor
+    fun isShareableSelected(shareable: ShareableContactItem) =
+        _shareableSelected.value.contains(shareable.contactItem.id)
+
+    @UiExecutor
+    fun toggleShareable(shareable: ShareableContactItem) =
+        if (isShareableSelected(shareable)) _shareableSelected.value -= shareable.contactItem.id
+        else _shareableSelected.value += shareable.contactItem.id
+
+    @UiExecutor
+    fun setSharingMessage(message: String) {
+        _sharingMessage.value = message.take(MAX_INVITATION_TEXT_LENGTH)
+    }
+
+    @UiExecutor
+    fun shareForum() = runOnDbThreadWithTransaction(false) { txn ->
+        val message = _sharingMessage.value.ifEmpty { null }
+        _shareableSelected.value.forEach { contactId ->
+            forumSharingManager.sendInvitation(txn, groupId, contactId, message)
+        }
+        txn.attach { reload() }
+    }
+
+    @UiExecutor
+    override fun eventOccurred(e: Event?) {
+        super.eventOccurred(e)
+
+        when {
+            e is ForumInvitationResponseReceivedEvent && e.messageHeader.shareableId == groupId -> {
+                if (e.messageHeader.wasAccepted()) {
+                    _sharingStatus.value += e.contactId to SHARING
+                    val connected = connectionRegistry.isConnected(e.contactId)
+                    _sharingInfo.update { addContact(connected) }
+                } else {
+                    _sharingStatus.value += e.contactId to SHAREABLE
+                }
+            }
+
+            e is ContactLeftShareableEvent && e.groupId == groupId -> {
+                _sharingStatus.value += e.contactId to SHAREABLE
+                val connected = connectionRegistry.isConnected(e.contactId)
+                _sharingInfo.update { removeContact(connected) }
+            }
+
+            e is ContactConnectedEvent -> {
+                if (_sharingStatus.value[e.contactId] == SHARING)
+                    _sharingInfo.update { updateContactConnected(true) }
+            }
+
+            e is ContactDisconnectedEvent -> {
+                if (_sharingStatus.value[e.contactId] == SHARING)
+                    _sharingInfo.update { updateContactConnected(false) }
+            }
+        }
+    }
+
+    override fun loadContactsWithinTransaction(txn: Transaction) {
+        super.loadContactsWithinTransaction(txn)
+        if (this::groupId.isInitialized) loadSharingStatus(txn)
+    }
+
+    private fun loadSharingStatus(): Unit =
+        runOnDbThreadWithTransaction(true, this::loadSharingStatus)
+
+    private fun loadSharingStatus(txn: Transaction) {
+        val map = contactManager.getContacts(txn).associate { contact ->
+            contact.id to forumSharingManager.getSharingStatus(txn, groupId, contact)
+        }
+        txn.attach {
+            val sharing = map.filterValues { it == SHARING }.keys
+            val online =
+                sharing.fold(0) { acc, it -> if (connectionRegistry.isConnected(it)) acc + 1 else acc }
+            _sharingStatus.value = map
+            _sharingInfo.value = SharingInfo(sharing.size, online)
+        }
+    }
+
+    data class SharingInfo(val total: Int, val online: Int) {
+        fun addContact(connected: Boolean) = copy(
+            total = total + 1,
+            online = if (connected) online + 1 else online
+        )
+
+        fun removeContact(connected: Boolean) = copy(
+            total = total - 1,
+            online = if (connected) online - 1 else online
+        )
+
+        fun updateContactConnected(connected: Boolean) = copy(
+            total = total,
+            online = if (connected) online + 1 else online - 1
+        )
+    }
+}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt
index fc835a87e711ec6f04281cd51a61e7991139fa9b..151d4d2698948d11763647693406114e0d47fc4f 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/ContactDrawerMakeIntro.kt
@@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.lazy.LazyColumn
@@ -143,6 +144,7 @@ fun ContactDrawerMakeIntro(
                                 style = MaterialTheme.typography.body1,
                             )
                         },
+                        modifier = Modifier.heightIn(max = 200.dp)
                     )
                 }
                 Row(Modifier.padding(8.dp).weight(1f, true)) {
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/IntroductionViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/IntroductionViewModel.kt
index 361ec9f67357c94a74cfa1e7e38f4e2ef378a1b6..5327bb780d5b2e5c4bc5036419804daf9b4a7501 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/IntroductionViewModel.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/introduction/IntroductionViewModel.kt
@@ -28,6 +28,7 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager
 import org.briarproject.briar.api.attachment.AttachmentReader
 import org.briarproject.briar.api.conversation.ConversationManager
 import org.briarproject.briar.api.identity.AuthorManager
+import org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH
 import org.briarproject.briar.api.introduction.IntroductionManager
 import org.briarproject.briar.desktop.contact.ContactItem
 import org.briarproject.briar.desktop.contact.ContactsViewModel
@@ -93,7 +94,7 @@ constructor(
     }
 
     fun setIntroductionMessage(msg: String) {
-        _introductionMessage.value = msg
+        _introductionMessage.value = msg.take(MAX_INTRODUCTION_TEXT_LENGTH)
     }
 
     fun makeIntroduction() {
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/VerticallyScrollableArea.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/VerticallyScrollableArea.kt
new file mode 100644
index 0000000000000000000000000000000000000000..550aba858b16768da49cc8decc8f96cbe64a8ff3
--- /dev/null
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/VerticallyScrollableArea.kt
@@ -0,0 +1,44 @@
+/*
+ * Briar Desktop
+ * Copyright (C) 2021-2022 The Briar Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package org.briarproject.briar.desktop.ui
+
+import androidx.compose.foundation.VerticalScrollbar
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.lazy.LazyListState
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.rememberScrollbarAdapter
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+
+@Composable
+fun VerticallyScrollableArea(
+    modifier: Modifier = Modifier,
+    content: @Composable (scrollState: LazyListState) -> Unit,
+) = Box(modifier) {
+    val scrollState = rememberLazyListState()
+
+    content(scrollState)
+
+    VerticalScrollbar(
+        adapter = rememberScrollbarAdapter(scrollState),
+        modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight()
+    )
+}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelModule.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelModule.kt
index 6cccf37d388fb3ca6aa9eaea1ceb4c1b05913237..182c8cda279aa6b15f7f11d93e09319f3716ca68 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelModule.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelModule.kt
@@ -25,8 +25,8 @@ import dagger.multibindings.IntoMap
 import org.briarproject.briar.desktop.contact.ContactListViewModel
 import org.briarproject.briar.desktop.contact.add.remote.AddContactViewModel
 import org.briarproject.briar.desktop.conversation.ConversationViewModel
-import org.briarproject.briar.desktop.forums.ForumSharingViewModel
 import org.briarproject.briar.desktop.forums.ForumViewModel
+import org.briarproject.briar.desktop.forums.sharing.ForumSharingViewModel
 import org.briarproject.briar.desktop.introduction.IntroductionViewModel
 import org.briarproject.briar.desktop.login.StartupViewModel
 import org.briarproject.briar.desktop.navigation.SidebarViewModel
diff --git a/briar-desktop/src/main/resources/strings/BriarDesktop.properties b/briar-desktop/src/main/resources/strings/BriarDesktop.properties
index aab31710fae088482310f5ebec092af24e93a785..e00996e2827011be9fafaffdb6f3b0895435e96d 100644
--- a/briar-desktop/src/main/resources/strings/BriarDesktop.properties
+++ b/briar-desktop/src/main/resources/strings/BriarDesktop.properties
@@ -67,6 +67,7 @@ access.forums.unread_count={0, plural, one {one unread posts} other {{0} unread
 access.forums.last_post_timestamp=last post: {0}
 access.forums.jump_to_prev_unread=Jump to previous unread post
 access.forums.jump_to_next_unread=Jump to next unread post
+access.forum.sharing.action.close=Close sharing form
 access.forum.sharing.status.close=Close sharing status
 
 # Contacts
@@ -133,12 +134,14 @@ forum.sharing.status.info=Any member of a forum can share it with their contacts
 forum.sharing.status.with=Shared with {0} ({1} online)
 forum.sharing.status.nobody=Nobody
 forum.sharing.action.title=Share Forum
+forum.sharing.action.add_message=Add a message (optional)
 forum.sharing.action.choose_contacts=Choose Contacts
 forum.sharing.action.no_contacts=No contacts yet. You can only share forums with your contacts.
 forum.sharing.action.status.already_shared=Already sharing
 forum.sharing.action.status.already_invited=Invitation already sent
 forum.sharing.action.status.invite_received=Invitation already received
 forum.sharing.action.status.not_supported=Not supported by this contact
+forum.sharing.action.status.error=Error. This is a bug and not your fault
 
 # Private Groups
 groups.card.created=Created by {0}
diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/TestUtils.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/TestUtils.kt
index e06f6cde026bb1620b75cffd0e5ca8d722c1855f..6ea5bb0733e2cee4e760425a439f31559ffc0a05 100644
--- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/TestUtils.kt
+++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/TestUtils.kt
@@ -23,6 +23,9 @@ import org.briarproject.bramble.api.Bytes.compare
 import org.briarproject.bramble.api.FormatException
 import org.briarproject.bramble.api.contact.PendingContactId
 import org.briarproject.bramble.api.crypto.SecretKey
+import org.briarproject.bramble.api.event.Event
+import org.briarproject.bramble.api.event.EventBus
+import org.briarproject.bramble.api.event.EventListener
 import org.briarproject.bramble.api.identity.Author
 import org.briarproject.bramble.api.identity.LocalAuthor
 import org.briarproject.bramble.api.plugin.TransportId
@@ -30,6 +33,7 @@ import org.briarproject.bramble.api.properties.TransportProperties
 import org.briarproject.bramble.api.versioning.event.ClientVersionUpdatedEvent
 import org.briarproject.briar.api.forum.ForumManager
 import org.briarproject.briar.api.forum.event.ForumInvitationRequestReceivedEvent
+import org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHAREABLE
 import org.briarproject.briar.desktop.utils.FileUtils
 import java.io.IOException
 import java.nio.file.Files
@@ -162,7 +166,7 @@ object TestUtils {
                 creator.getBriarExecutors().onDbThread {
                     val contact = creator.getContactManager().getContact(e.contactId)
                     val sharingManager = creator.getForumSharingManager()
-                    if (sharingManager.canBeShared(forum.id, contact))
+                    if (sharingManager.getSharingStatus(forum.id, contact) == SHAREABLE)
                         sharingManager.sendInvitation(forum.id, e.contactId, null)
                 }
             }
@@ -170,12 +174,22 @@ object TestUtils {
 
         // accept invitation at all contacts
         drop(1).forEach { app ->
-            app.getEventBus().addListener { e ->
+            app.getEventBus().addListenerOnce { e ->
                 if (e is ForumInvitationRequestReceivedEvent) {
                     val contact = app.getContactManager().getContact(e.contactId)
                     app.getForumSharingManager().respondToInvitation(forum, contact, true)
+                    return@addListenerOnce true
                 }
+                false
             }
         }
     }
 }
+
+fun EventBus.addListenerOnce(listener: (Event) -> Boolean) =
+    addListener(object : EventListener {
+        override fun eventOccurred(e: Event) {
+            if (listener(e))
+                removeListener(this)
+        }
+    })
diff --git a/build.gradle.kts b/build.gradle.kts
index ae478abc47fbc734ff1df01ca6f2a2baf32fa5f9..bd1cf57024b4e9c47f815f98883a73f265d754b0 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -28,7 +28,6 @@ buildscript {
 
     // keep version here in sync when updating briar
     dependencies {
-        classpath("com.android.tools.build:gradle:4.1.3")
         classpath("ru.vyarus:gradle-animalsniffer-plugin:1.5.3")
         classpath(files("briar/libs/gradle-witness.jar"))
     }
@@ -39,9 +38,11 @@ buildscript {
         set("dagger_version", "2.43.2")
         set("okhttp_version", "3.12.13")
         set("jackson_version", "2.13.4")
-        set("tor_version", "0.4.5.14")
+        set("tor_version", "0.4.7.12")
         set("obfs4proxy_version", "0.0.14-tor1")
         set("snowflake_version", "2.3.1")
+        set("jsoup_version", "1.15.3")
+        set("bouncy_castle_version", "1.71")
         set("junit_version", "4.13.2")
         set("jmock_version", "2.12.0")
     }