diff --git a/src/main/kotlin/org/briarproject/briar/desktop/BriarService.kt b/src/main/kotlin/org/briarproject/briar/desktop/BriarService.kt
index 96421379a9de135ad2c67e9f3af966a743e6c864..c96cd5a45913f6add92abffd7fa0cd8e11793007 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/BriarService.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/BriarService.kt
@@ -1,6 +1,7 @@
 package org.briarproject.briar.desktop
 
 import androidx.compose.desktop.Window
+import androidx.compose.material.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.compositionLocalOf
@@ -18,6 +19,7 @@ import org.briarproject.briar.api.conversation.ConversationManager
 import org.briarproject.briar.api.messaging.MessagingManager
 import org.briarproject.briar.desktop.dialogs.Login
 import org.briarproject.briar.desktop.dialogs.Registration
+import org.briarproject.briar.desktop.paul.theme.DarkColorPallet
 import org.briarproject.briar.desktop.paul.views.BriarUIStateManager
 import javax.annotation.concurrent.Immutable
 import javax.inject.Inject
@@ -80,28 +82,30 @@ constructor(
         val title = "Briar Desktop"
         var screenState by remember { mutableStateOf<Screen>(Screen.Login) }
         Window(title = title) {
-            when (val screen = screenState) {
-                is Screen.Login ->
-                    Login(
-                        "Briar",
-                        onResult = {
-                            try {
-                                accountManager.signIn(it)
-                                signedIn()
-                                screenState = Screen.Main
-                            } catch (e: DecryptionException) {
-                                // failure, try again
+            MaterialTheme(colors = DarkColorPallet) {
+                when (val screen = screenState) {
+                    is Screen.Login ->
+                        Login(
+                            "Briar",
+                            onResult = {
+                                try {
+                                    accountManager.signIn(it)
+                                    signedIn()
+                                    screenState = Screen.Main
+                                } catch (e: DecryptionException) {
+                                    // failure, try again
+                                }
                             }
-                        }
-                    )
+                        )
 
-                is Screen.Main ->
-                    CompositionLocalProvider(
-                        CM provides conversationManager,
-                        MM provides messagingManager
-                    ) {
-                        BriarUIStateManager(contacts)
-                    }
+                    is Screen.Main ->
+                        CompositionLocalProvider(
+                            CM provides conversationManager,
+                            MM provides messagingManager
+                        ) {
+                            BriarUIStateManager(contacts)
+                        }
+                }
             }
         }
     }
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Login.kt b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Login.kt
index f1a532eb80b12d6e04a095bc35bbcea198fc8df5..2da6d8aa6d56fe03aceebf3e3840b645d1f6f2b2 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Login.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Login.kt
@@ -1,6 +1,7 @@
 package org.briarproject.briar.desktop.dialogs
 
 import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Spacer
@@ -20,8 +21,10 @@ import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.res.svgResource
 import androidx.compose.ui.unit.dp
+import org.briarproject.briar.desktop.paul.theme.briarBlack
 
 // TODO: Error handling
 @Composable
@@ -29,8 +32,9 @@ fun Login(
     title: String,
     onResult: (result: String) -> Unit
 ) =
+    // All the changes in this file are be temporary -Paul, just changing colors so I can see the button and text field
     Column(
-        modifier = Modifier.padding(16.dp).fillMaxSize(),
+        modifier = Modifier.padding(16.dp).fillMaxSize().background(briarBlack),
         verticalArrangement = Arrangement.Center,
         horizontalAlignment = Alignment.CenterHorizontally
     ) {
@@ -60,6 +64,6 @@ private fun TheTextField(onResult: (result: String) -> Unit) {
             onResult.invoke(password)
         }
     ) {
-        Text("Login")
+        Text("Login", color = Color.Black)
     }
 }
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarSidebar.kt b/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarSidebar.kt
index 64dbb66c523c61c4ab84570259a18a2437c028ab..e4e3dccf4a511a26126b8f72c935ab61c98ae50c 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarSidebar.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarSidebar.kt
@@ -33,43 +33,42 @@ import org.briarproject.briar.desktop.paul.theme.briarBlack
 import org.briarproject.briar.desktop.paul.theme.briarBlue
 
 @Composable
-fun BriarSidebar(uiMode: String, onModeChange: (String) -> Unit) {
-    Surface(modifier = Modifier.width(66.dp).fillMaxHeight(), color = briarBlue) {
+fun BriarSidebar(uiMode: String, setMode: (String) -> Unit) {
+    Surface(modifier = Modifier.width(56.dp).fillMaxHeight(), color = briarBlue) {
         Column(verticalArrangement = Arrangement.Top) {
             IconButton(
-                modifier = Modifier.align(Alignment.CenterHorizontally)
-                    .padding(top = 9.dp, bottom = 10.dp),
+                modifier = Modifier.align(Alignment.CenterHorizontally).padding(top = 5.dp, bottom = 4.dp),
                 onClick = {}
             ) {
                 Image(
                     bitmap = imageFromResource("images/profile_images/p0.png"),
                     "my_profile_image",
-                    modifier = Modifier.size(48.dp).align(Alignment.CenterHorizontally).clip(
+                    modifier = Modifier.size(44.dp).align(Alignment.CenterHorizontally).clip(
                         CircleShape
                     ).border(2.dp, color = Color.White, CircleShape)
                 )
             }
             BriarSidebarButton(
                 uiMode = uiMode,
-                onModeChange = onModeChange,
+                setMode = setMode,
                 "Contacts",
                 Icons.Filled.Contacts
             )
             BriarSidebarButton(
                 uiMode = uiMode,
-                onModeChange = onModeChange,
+                setMode = setMode,
                 "Private Groups",
                 Icons.Filled.Group
             )
             BriarSidebarButton(
                 uiMode = uiMode,
-                onModeChange = onModeChange,
+                setMode = setMode,
                 "Forums",
                 Icons.Filled.Forum
             )
             BriarSidebarButton(
                 uiMode = uiMode,
-                onModeChange = onModeChange,
+                setMode = setMode,
                 "Blogs",
                 Icons.Filled.ChromeReaderMode
             )
@@ -77,19 +76,19 @@ fun BriarSidebar(uiMode: String, onModeChange: (String) -> Unit) {
         Column(verticalArrangement = Arrangement.Bottom) {
             BriarSidebarButton(
                 uiMode = uiMode,
-                onModeChange = onModeChange,
+                setMode = setMode,
                 "Transports",
                 Icons.Filled.WifiTethering
             )
             BriarSidebarButton(
                 uiMode = uiMode,
-                onModeChange = onModeChange,
+                setMode = setMode,
                 "Settings",
                 Icons.Filled.Settings
             )
             BriarSidebarButton(
                 uiMode = uiMode,
-                onModeChange = onModeChange,
+                setMode = setMode,
                 "Sign Out",
                 Icons.Filled.Logout
             )
@@ -98,18 +97,13 @@ fun BriarSidebar(uiMode: String, onModeChange: (String) -> Unit) {
 }
 
 @Composable
-fun BriarSidebarButton(
-    uiMode: String,
-    onModeChange: (String) -> Unit,
-    thisMode: String,
-    icon: ImageVector
-) {
+fun BriarSidebarButton(uiMode: String, setMode: (String) -> Unit, thisMode: String, icon: ImageVector) {
     val bg = if (uiMode == thisMode) briarBlack else briarBlue
-    Column() {
+    Column {
         IconButton(
             modifier = Modifier.align(Alignment.CenterHorizontally).background(color = bg)
-                .padding(vertical = 9.dp, horizontal = 12.dp),
-            onClick = { onModeChange(thisMode) }
+                .padding(vertical = 4.dp, horizontal = 12.dp),
+            onClick = { setMode(thisMode) }
         ) {
             Icon(icon, thisMode, tint = Color.White, modifier = Modifier.size(30.dp))
         }
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarUIStateManager.kt b/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarUIStateManager.kt
index e0b9c0c40275bb3f7d44c7a69acf43b5982f42d2..188ca429701b4c14b78dc4480925d68c522bc04e 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarUIStateManager.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarUIStateManager.kt
@@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
@@ -25,28 +24,26 @@ fun BriarUIStateManager(
     contacts: List<Contact>
 ) {
     // current selected mode, changed using the sidebar buttons
-    val (uiMode, onModeChange) = remember { mutableStateOf("Contacts") }
+    val (uiMode, setMode) = remember { mutableStateOf("Contacts") }
+    // TODO Figure out how to handle accounts with 0 contacts
     // current selected contact
-    val uiContact: MutableState<Contact> = remember { mutableStateOf(contacts[0]) }
-    // current selected private message
-    val (uiPrivateMsg, onPMSelect) = remember { mutableStateOf(0) }
+    val (contact, setContact) = remember { mutableStateOf(contacts[0]) }
     // current selected forum
-    val (uiForum, onForumSelect) = remember { mutableStateOf(0) }
+    val (forum, setForum) = remember { mutableStateOf(0) }
     // current blog state
-    val (uiBlog, onBlogSelect) = remember { mutableStateOf(0) }
+    val (blog, setBlog) = remember { mutableStateOf(0) }
     // current transport state
-    val (uiTransports, onTransportSelect) = remember { mutableStateOf(0) }
+    val (transport, setTransport) = remember { mutableStateOf(0) }
     // current settings state
-    val (uiSettings, onSettingSelect) = remember { mutableStateOf(0) }
-    // current profile
-    var Profile: String
+    val (setting, setSetting) = remember { mutableStateOf(0) }
     // Other global state that we need to track should go here also
     Row() {
-        BriarSidebar(uiMode, onModeChange)
+        BriarSidebar(uiMode, setMode)
         when (uiMode) {
             "Contacts" -> PrivateMessageView(
+                contact,
                 contacts,
-                uiContact
+                setContact
             )
             else -> Box(modifier = Modifier.fillMaxSize().background(briarBlack)) {
                 Text("TBD", modifier = Modifier.align(Alignment.Center), color = Color.White)
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/paul/views/PrivateMessageView.kt b/src/main/kotlin/org/briarproject/briar/desktop/paul/views/PrivateMessageView.kt
index 65971e55ea823c382d19d4906ffb1f4f721b64c8..d8483431ddf0c2d9193db55313726d2bcaf40f2e 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/paul/views/PrivateMessageView.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/paul/views/PrivateMessageView.kt
@@ -1,40 +1,55 @@
 package org.briarproject.briar.desktop.paul.views
 
+import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxWithConstraints
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.items
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.BasicTextField
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material.AlertDialog
 import androidx.compose.material.CircularProgressIndicator
 import androidx.compose.material.Divider
+import androidx.compose.material.DropdownMenu
+import androidx.compose.material.DropdownMenuItem
 import androidx.compose.material.Icon
 import androidx.compose.material.IconButton
-import androidx.compose.material.OutlinedTextField
+import androidx.compose.material.Scaffold
 import androidx.compose.material.Text
 import androidx.compose.material.TextButton
 import androidx.compose.material.TextField
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Add
-import androidx.compose.material.icons.filled.AddCircle
-import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.material.icons.filled.ArrowRight
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material.icons.filled.DoneAll
 import androidx.compose.material.icons.filled.MoreVert
+import androidx.compose.material.icons.filled.PersonAdd
+import androidx.compose.material.icons.filled.Schedule
+import androidx.compose.material.icons.filled.Search
 import androidx.compose.material.icons.filled.Send
+import androidx.compose.material.icons.filled.SwapHoriz
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.MutableState
@@ -46,6 +61,8 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.drawscope.withTransform
 import androidx.compose.ui.graphics.imageFromResource
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.input.TextFieldValue
@@ -74,47 +91,41 @@ import org.briarproject.briar.desktop.paul.theme.divider
 import org.briarproject.briar.desktop.paul.theme.lightGray
 import java.util.Collections
 
-val HEADER_SIZE = 66.dp
+val HEADER_SIZE = 56.dp
+
+// Right drawer state
+enum class ContactInfoDrawerState {
+    MakeIntro,
+    ConnectBT,
+    ConnectRD
+}
 
 @Composable
 fun PrivateMessageView(
+    currContact: Contact,
     contacts: List<Contact>,
-    uiContact: MutableState<Contact>
+    onContactSelect: (Contact) -> Unit
 ) {
-    // Local State for managing the Add Contact Popup
-    val (AddContactDialog, onCancelAdd) = remember { mutableStateOf(false) }
-    AddContactDialog(AddContactDialog, onCancelAdd)
+    val (addContactDialog, onContactAdd) = remember { mutableStateOf(false) }
+    val (dropdownExpanded, setExpanded) = remember { mutableStateOf(false) }
+    val (infoDrawer, setInfoDrawer) = remember { mutableStateOf(false) }
+    val (contactDrawerState, setDrawerState) = remember { mutableStateOf(ContactInfoDrawerState.MakeIntro) }
+    AddContactDialog(addContactDialog, onContactAdd)
+    Divider(color = divider, modifier = Modifier.fillMaxHeight().width(1.dp))
+    ContactList(currContact, contacts, onContactSelect, onContactAdd)
     Column(modifier = Modifier.fillMaxHeight()) {
         Row(modifier = Modifier.fillMaxWidth()) {
-            Divider(color = divider, modifier = Modifier.fillMaxHeight().width(1.dp))
-            Column(modifier = Modifier.fillMaxHeight().background(color = briarBlack).width(275.dp)) {
-                Row(
-                    modifier = Modifier.fillMaxWidth().height(HEADER_SIZE).padding(horizontal = 16.dp),
-                    horizontalArrangement = Arrangement.SpaceBetween,
-                ) {
-                    Text(
-                        "Contacts",
-                        fontSize = 24.sp,
-                        color = Color.White,
-                        modifier = Modifier.align(Alignment.CenterVertically)
-                    )
-                    IconButton(
-                        onClick = { onCancelAdd(true) },
-                        modifier = Modifier.align(Alignment.CenterVertically).background(color = briarDarkGray)
-                    ) {
-                        Icon(Icons.Filled.Add, "add contact", tint = Color.White, modifier = Modifier.size(24.dp))
-                    }
-                }
-                Divider(color = divider, thickness = 1.dp, modifier = Modifier.fillMaxWidth())
-                Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
-                    for (c in contacts) {
-                        ContactCard(uiContact, c)
-                    }
-                }
-            }
             Divider(color = divider, modifier = Modifier.fillMaxHeight().width(1.dp))
             Column(modifier = Modifier.weight(1f).fillMaxHeight().background(color = darkGray)) {
-                DrawMessageRow(uiContact.value)
+                DrawMessageRow(
+                    currContact,
+                    contacts,
+                    dropdownExpanded,
+                    setExpanded,
+                    infoDrawer,
+                    setInfoDrawer,
+                    contactDrawerState
+                )
             }
         }
     }
@@ -198,30 +209,87 @@ fun AddContactDialog(isVisible: Boolean, onCancel: (Boolean) -> Unit) {
 }
 
 @Composable
-fun ContactCard(selContact: MutableState<Contact>, contact: Contact) {
+fun SearchTextField(searchValue: String, onValueChange: (String) -> Unit, onContactAdd: (Boolean) -> Unit) {
+    BasicTextField(
+        value = searchValue,
+        onValueChange = onValueChange,
+        singleLine = true,
+        modifier = Modifier.padding(horizontal = 8.dp),
+        textStyle = TextStyle(color = Color.White, fontSize = 16.sp),
+        decorationBox = { innerTextField ->
+            Row(
+                Modifier
+                    .background(darkGray, CircleShape)
+                    .border(1.dp, divider, CircleShape)
+                    .fillMaxWidth(),
+                verticalAlignment = Alignment.CenterVertically,
+                horizontalArrangement = Arrangement.SpaceBetween
+            ) {
+                Icon(
+                    Icons.Filled.Search,
+                    "search contacts",
+                    tint = Color.White,
+                    modifier = Modifier.padding(top = 8.dp, bottom = 8.dp, start = 16.dp)
+                )
+                Box(Modifier.width(132.dp).padding(vertical = 8.dp, horizontal = 2.dp)) {
+                    if (searchValue.isEmpty()) {
+                        Text("Contacts", color = Color.Gray)
+                    }
+                    innerTextField()
+                }
+                IconButton(
+                    onClick = { onContactAdd(true) },
+                    modifier = Modifier.padding(end = 4.dp).size(32.dp).background(
+                        briarBlueMsg, CircleShape
+                    )
+                ) {
+                    Icon(Icons.Filled.PersonAdd, "add contact", tint = Color.White, modifier = Modifier.size(20.dp))
+                }
+            }
+        },
+        cursorBrush = SolidColor(Color.White),
+    )
+}
+
+@Composable
+fun ContactCard(contact: Contact, selContact: Contact, onSel: (Contact) -> Unit, drawDetails: Boolean) {
     var bgColor = briarBlack
-    if (selContact.value.id == contact.id) {
+    if (selContact.id == contact.id && drawDetails) {
         bgColor = darkGray
     }
     Row(
         modifier = Modifier.fillMaxWidth().height(HEADER_SIZE).background(bgColor)
-            .clickable(
-                onClick = {
-                    selContact.value = contact
-                }
-            ),
+            .clickable(onClick = { onSel(contact) }),
         horizontalArrangement = Arrangement.SpaceBetween
     ) {
         Row(modifier = Modifier.align(Alignment.CenterVertically).padding(horizontal = 16.dp)) {
+            // TODO Pull profile pictures
             Image(
-                // TODO: use correct image
-                // bitmap = imageFromResource("images/profile_images/" + contact.profile_pic),
-                bitmap = imageFromResource("images/profile_images/p1.png"),
+                bitmap = imageFromResource("images/profile_images/p0.png"),
                 "image",
-                modifier = Modifier.size(40.dp).align(Alignment.CenterVertically).clip(
+                modifier = Modifier.size(36.dp).align(Alignment.CenterVertically).clip(
                     CircleShape
                 ).border(2.dp, color = Color.White, CircleShape)
             )
+            // Draw notification badges
+            if (drawDetails) {
+                androidx.compose.foundation.Canvas(
+                    modifier = Modifier.align(Alignment.CenterVertically),
+                    onDraw = {
+                        val size = 10.dp.toPx()
+                        withTransform({ translate(left = -6f, top = -12f) }) {
+                            drawCircle(
+                                color = Color.White,
+                                radius = (size + 2.dp.toPx()) / 2f,
+                            )
+                            drawCircle(
+                                color = briarBlueMsg,
+                                radius = size / 2f,
+                            )
+                        }
+                    }
+                )
+            }
             Column(modifier = Modifier.align(Alignment.CenterVertically).padding(start = 12.dp)) {
                 Text(
                     contact.author.name,
@@ -229,8 +297,9 @@ fun ContactCard(selContact: MutableState<Contact>, contact: Contact) {
                     color = Color.White,
                     modifier = Modifier.align(Alignment.Start).padding(bottom = 2.dp)
                 )
+                // TODO add proper last message time
                 Text(
-                    "1 min",
+                    "10 min ago",
                     fontSize = 10.sp,
                     color = Color.LightGray,
                     modifier = Modifier.align(Alignment.Start)
@@ -238,15 +307,15 @@ fun ContactCard(selContact: MutableState<Contact>, contact: Contact) {
             }
         }
         androidx.compose.foundation.Canvas(
-            modifier = Modifier.padding(horizontal = 29.dp).size(22.dp).align(Alignment.CenterVertically),
+            modifier = Modifier.padding(start = 32.dp, end = 18.dp).size(22.dp).align(Alignment.CenterVertically),
             onDraw = {
                 val size = 16.dp.toPx()
                 drawCircle(
                     color = Color.White,
                     radius = size / 2f
                 )
-                val online = true
-                if (online) {
+                // TODO check if contact online
+                if (true) {
                     drawCircle(
                         color = briarGreen,
                         radius = 14.dp.toPx() / 2f
@@ -260,32 +329,80 @@ fun ContactCard(selContact: MutableState<Contact>, contact: Contact) {
             }
         )
     }
-
     Divider(color = divider, thickness = 1.dp, modifier = Modifier.fillMaxWidth())
 }
 
+@Composable
+fun ContactList(
+    currContact: Contact,
+    contacts: List<Contact>,
+    onContactSelect: (Contact) -> Unit,
+    onContactAdd: (Boolean) -> Unit
+) {
+    var searchValue by remember { mutableStateOf("") }
+    var filteredContacts = ArrayList<Contact>()
+    filteredContacts = if (searchValue.isEmpty()) {
+        ArrayList(contacts)
+    } else {
+        val resultList = ArrayList<Contact>()
+        for (c in contacts) {
+            if (c.author.name.lowercase().contains(searchValue.lowercase())
+            ) {
+                resultList.add(c)
+            }
+        }
+        resultList
+    }
+    Scaffold(
+        modifier = Modifier.fillMaxHeight().width(246.dp),
+        backgroundColor = briarBlack,
+        topBar = {
+            Column(
+                modifier = Modifier.fillMaxWidth().background(briarBlack),
+            ) {
+                Row(Modifier.height(HEADER_SIZE), verticalAlignment = Alignment.CenterVertically) {
+                    SearchTextField(searchValue, onValueChange = { searchValue = it }, onContactAdd)
+                }
+                Divider(color = divider, thickness = 1.dp, modifier = Modifier.fillMaxWidth())
+            }
+        },
+        content = {
+            Column(Modifier.verticalScroll(rememberScrollState())) {
+                for (c in filteredContacts) {
+                    ContactCard(c, currContact, onContactSelect, true)
+                }
+            }
+        },
+    )
+}
+
 @Composable
 fun TextBubble(m: SimpleMessage) {
     Column(Modifier.fillMaxWidth()) {
         if (m.local) {
-            Column(Modifier.fillMaxWidth(fraction = 0.9f).align(Alignment.End)) {
-                Column(Modifier.background(briarBlueMsg).padding(8.dp).align(Alignment.End)) {
+            Column(Modifier.fillMaxWidth(fraction = 0.8f).align(Alignment.End)) {
+                Column(
+                    Modifier.background(
+                        briarBlueMsg,
+                        RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp, bottomStart = 10.dp)
+                    ).padding(8.dp).align(Alignment.End)
+                ) {
                     Text(m.message, fontSize = 14.sp, color = Color.White, modifier = Modifier.align(Alignment.Start))
                     Row(modifier = Modifier.padding(top = 4.dp)) {
                         Text(m.time, Modifier.padding(end = 4.dp), fontSize = 10.sp, color = Color.LightGray)
                         if (m.delivered) {
                             Icon(
-                                Icons.Filled.Check,
+                                Icons.Filled.DoneAll,
                                 "sent",
                                 tint = Color.LightGray,
-                                modifier = Modifier.size(10.dp).align(Alignment.CenterVertically)
+                                modifier = Modifier.size(12.dp).align(Alignment.CenterVertically)
                             )
                         } else {
                             Icon(
-                                Icons.Filled.Send,
+                                Icons.Filled.Schedule,
                                 "sending",
                                 tint = Color.LightGray,
-                                modifier = Modifier.size(10.dp).align(Alignment.CenterVertically)
+                                modifier = Modifier.size(12.dp).align(Alignment.CenterVertically)
                             )
                         }
                     }
@@ -293,25 +410,28 @@ fun TextBubble(m: SimpleMessage) {
             }
         } else {
             Column(Modifier.fillMaxWidth(fraction = 0.9f).align(Alignment.Start)) {
-                Column(Modifier.background(briarGrayMsg).padding(8.dp).align(Alignment.Start)) {
+                Column(
+                    Modifier.background(
+                        briarGrayMsg,
+                        RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp, bottomEnd = 10.dp)
+                    ).padding(8.dp).align(Alignment.Start)
+                ) {
                     Text(m.message, fontSize = 14.sp, color = Color.White, modifier = Modifier.align(Alignment.Start))
                     Row(modifier = Modifier.padding(top = 4.dp)) {
                         Text(m.time, Modifier.padding(end = 4.dp), fontSize = 10.sp, color = Color.LightGray)
                         if (m.delivered) {
                             Icon(
-                                Icons.Filled.Check,
+                                Icons.Filled.DoneAll,
                                 "sent",
                                 tint = Color.LightGray,
-                                modifier = Modifier.size(10.dp).align(Alignment.CenterVertically)
+                                modifier = Modifier.size(12.dp).align(Alignment.CenterVertically)
                             )
                         } else {
                             Icon(
-                                Icons.Filled.Send,
+                                Icons.Filled.Schedule,
                                 "sending",
                                 tint = Color.LightGray,
-                                modifier = Modifier.size(10.dp).align(
-                                    Alignment.CenterVertically
-                                )
+                                modifier = Modifier.size(12.dp).align(Alignment.CenterVertically)
                             )
                         }
                     }
@@ -328,10 +448,9 @@ fun DrawTextBubbles(chat: UiState<Chat>) {
         is UiState.Error -> Loader()
         is UiState.Success ->
             LazyColumn(
-                Modifier.fillMaxWidth().padding(horizontal = 8.dp),
                 verticalArrangement = Arrangement.spacedBy(8.dp),
                 reverseLayout = true,
-                contentPadding = PaddingValues(vertical = 8.dp)
+                contentPadding = PaddingValues(top = 8.dp, start = 8.dp, end = 8.dp)
             ) {
                 items(chat.data.messages) { m ->
                     TextBubble(m)
@@ -351,55 +470,340 @@ fun Loader() {
 }
 
 @Composable
-fun DrawMessageRow(uiContact: Contact) {
-    Box(Modifier.fillMaxHeight()) {
-        Box(modifier = Modifier.fillMaxWidth().height(HEADER_SIZE + 1.dp)) {
-            Row(modifier = Modifier.align(Alignment.Center)) {
-                Image(
-                    // TODO: use correct image
-                    // bitmap = imageFromResource("images/profile_images/" + UIContact.profile_pic),
-                    bitmap = imageFromResource("images/profile_images/p2.png"),
-                    "sel_contact_prof",
-                    modifier = Modifier.size(36.dp).align(
-                        Alignment.CenterVertically
-                    ).clip(
-                        CircleShape
-                    ).border(2.dp, color = Color.White, CircleShape)
+fun ContactDropDown(
+    expanded: Boolean,
+    isExpanded: (Boolean) -> Unit,
+    isInfoDrawer: (Boolean) -> Unit
+) {
+    var connectionMode by remember { mutableStateOf(false) }
+    var contactMode by remember { mutableStateOf(false) }
+    DropdownMenu(
+        expanded = expanded,
+        onDismissRequest = { isExpanded(false) },
+        modifier = Modifier.background(briarBlack)
+    ) {
+        DropdownMenuItem(onClick = { isInfoDrawer(true); isExpanded(false) }) {
+            Text("Make Introduction", fontSize = 14.sp)
+        }
+        DropdownMenuItem(onClick = {}) {
+            Text("Disappearing Messages", fontSize = 14.sp)
+        }
+        DropdownMenuItem(onClick = {}) {
+            Text("Delete all messages", fontSize = 14.sp)
+        }
+        DropdownMenuItem(onClick = { connectionMode = true; isExpanded(false) }) {
+            Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
+                Text("Connections", fontSize = 14.sp, modifier = Modifier.align(Alignment.CenterVertically))
+                Icon(Icons.Filled.ArrowRight, "connections", modifier = Modifier.align(Alignment.CenterVertically))
+            }
+        }
+        DropdownMenuItem(onClick = { contactMode = true; isExpanded(false) }) {
+            Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
+                Text("Contact", fontSize = 14.sp, modifier = Modifier.align(Alignment.CenterVertically))
+                Icon(Icons.Filled.ArrowRight, "connections", modifier = Modifier.align(Alignment.CenterVertically))
+            }
+        }
+    }
+    if (connectionMode) {
+        DropdownMenu(
+            expanded = connectionMode,
+            onDismissRequest = { connectionMode = false },
+            modifier = Modifier.background(briarBlack)
+        ) {
+            DropdownMenuItem(onClick = { false }) {
+                Text("Connections", color = lightGray, fontSize = 12.sp)
+            }
+            DropdownMenuItem(onClick = { false }) {
+                Text("Connect via Bluetooth", fontSize = 14.sp)
+            }
+            DropdownMenuItem(onClick = { false }) {
+                Text("Connect via Removable Device", fontSize = 14.sp)
+            }
+        }
+    }
+    if (contactMode) {
+        DropdownMenu(
+            expanded = contactMode,
+            onDismissRequest = { contactMode = false },
+            modifier = Modifier.background(briarBlack)
+        ) {
+            DropdownMenuItem(onClick = { false }) {
+                Text("Contact", color = lightGray, fontSize = 12.sp)
+            }
+            DropdownMenuItem(onClick = { false }) {
+                Text("Change contact name", fontSize = 14.sp)
+            }
+            DropdownMenuItem(onClick = { false }) {
+                Text("Delete contact", fontSize = 14.sp)
+            }
+        }
+    }
+}
+
+@Composable
+fun MsgColumnHeader(
+    uiContact: Contact,
+    expanded: Boolean,
+    isExpanded: (Boolean) -> Unit,
+    isInfoDrawer: (Boolean) -> Unit
+) {
+    Box(modifier = Modifier.fillMaxWidth().height(HEADER_SIZE + 1.dp)) {
+        Row(modifier = Modifier.align(Alignment.Center)) {
+            Image(
+                // TODO Fix profile picture resources
+                bitmap = imageFromResource("images/profile_images/p0.png"),
+                "sel_contact_prof",
+                modifier = Modifier.size(36.dp).align(
+                    Alignment.CenterVertically
+                ).clip(
+                    CircleShape
+                ).border(2.dp, color = Color.White, CircleShape)
+            )
+            androidx.compose.foundation.Canvas(
+                modifier = Modifier.align(Alignment.CenterVertically),
+                onDraw = {
+                    val size = 10.dp.toPx()
+                    // TODO hook up online indicator logic
+                    val onlineColor = if (true) briarGreen else briarBlack
+                    withTransform({ translate(left = -6f, top = 12f) }) {
+                        drawCircle(
+                            color = Color.White,
+                            radius = (size + 2.dp.toPx()) / 2f,
+                        )
+                        drawCircle(
+                            color = onlineColor,
+                            radius = size / 2f,
+                        )
+                    }
+                }
+            )
+            Text(
+                uiContact.author.name,
+                color = Color.White,
+                modifier = Modifier.align(Alignment.CenterVertically).padding(start = 12.dp),
+                fontSize = 20.sp
+            )
+        }
+        IconButton(
+            onClick = { isExpanded(!expanded) },
+            modifier = Modifier.align(Alignment.CenterEnd).padding(end = 16.dp)
+        ) {
+            Icon(Icons.Filled.MoreVert, "contact info", tint = Color.White, modifier = Modifier.size(24.dp))
+            ContactDropDown(expanded, isExpanded, isInfoDrawer)
+        }
+        Divider(color = divider, thickness = 1.dp, modifier = Modifier.fillMaxWidth().align(Alignment.BottomCenter))
+    }
+}
+
+@Composable
+fun MsgInput(currContact: Contact) {
+    var text by remember { mutableStateOf("") }
+    Row(
+        verticalAlignment = Alignment.CenterVertically,
+        modifier = Modifier.padding(8.dp)
+    ) {
+        BasicTextField(
+            value = text,
+            onValueChange = { text = it },
+            maxLines = 10,
+            textStyle = TextStyle(color = Color.White, fontSize = 16.sp, lineHeight = 16.sp),
+            decorationBox = { innerTextField ->
+                Box(
+                    Modifier
+                        .background(darkGray, RoundedCornerShape(size = 20.dp))
+                        .border(1.dp, divider, RoundedCornerShape(size = 20.dp))
+                        .fillMaxWidth(),
+                    contentAlignment = Alignment.TopCenter,
+                ) {
+                    IconButton(
+                        onClick = {},
+                        Modifier.padding(4.dp).size(32.dp).align(Alignment.TopStart)
+                            .background(briarBlueMsg, CircleShape),
+                    ) {
+                        Icon(
+                            Icons.Filled.Add,
+                            "add attachment",
+                            tint = Color.White,
+                            modifier = Modifier.size(24.dp),
+                        )
+                    }
+                    Box(
+                        Modifier.padding(vertical = 8.dp, horizontal = 48.dp).align(Alignment.Center).fillMaxWidth()
+                    ) {
+                        if (text.isEmpty()) {
+                            Text("Message", color = Color.Gray)
+                        }
+                        innerTextField()
+                    }
+                    IconButton(
+                        onClick = { },
+                        modifier = Modifier.padding(4.dp).size(32.dp).align(Alignment.TopEnd),
+                    ) {
+                        Icon(Icons.Filled.Send, "send message", tint = briarGreen, modifier = Modifier.size(24.dp))
+                    }
+                }
+            },
+            cursorBrush = SolidColor(Color.White),
+        )
+    }
+}
+
+@Composable
+fun ContactDrawerMakeIntro(currContact: Contact, contacts: List<Contact>, isInfoDrawer: (Boolean) -> Unit) {
+    var introNextPg by remember { mutableStateOf(false) }
+    val (introContact, onCancelSel) = remember { mutableStateOf(currContact) }
+    if (!introNextPg) {
+        Column() {
+            Row(Modifier.fillMaxWidth().height(HEADER_SIZE)) {
+                IconButton(
+                    onClick = { isInfoDrawer(false) },
+                    Modifier.padding(horizontal = 11.dp).size(32.dp).align(Alignment.CenterVertically)
+                ) {
+                    Icon(Icons.Filled.Close, "close make intro screen", tint = Color.White)
+                }
+                Text(
+                    text = "Introduce " + currContact.author.name + " to:",
+                    color = Color.White,
+                    fontSize = 16.sp,
+                    modifier = Modifier.align(Alignment.CenterVertically)
                 )
+            }
+            Divider(color = divider, modifier = Modifier.fillMaxWidth().height(1.dp))
+            Column(Modifier.verticalScroll(rememberScrollState())) {
+                for (c in contacts) {
+                    if (c.id != currContact.id) {
+                        ContactCard(c, currContact, { onCancelSel(c); introNextPg = true }, false)
+                    }
+                }
+            }
+        }
+    } else {
+        Column() {
+            Row(Modifier.fillMaxWidth().height(HEADER_SIZE)) {
+                IconButton(
+                    onClick = { introNextPg = false },
+                    Modifier.padding(horizontal = 11.dp).size(32.dp).align(Alignment.CenterVertically)
+                ) {
+                    Icon(Icons.Filled.ArrowBack, "go back to make intro contact screen", tint = Color.White)
+                }
                 Text(
-                    uiContact.author.name,
+                    text = "Introduce Contacts",
                     color = Color.White,
-                    modifier = Modifier.align(Alignment.CenterVertically).padding(start = 12.dp),
-                    fontSize = 24.sp
+                    fontSize = 16.sp,
+                    modifier = Modifier.align(Alignment.CenterVertically)
+                )
+            }
+            // Divider(color = divider, modifier = Modifier.fillMaxWidth().height(1.dp) )
+            Row(Modifier.fillMaxWidth().padding(12.dp), horizontalArrangement = Arrangement.SpaceAround) {
+                Column(Modifier.align(Alignment.CenterVertically)) {
+                    Image(
+                        // TODO Proper profile pic
+                        bitmap = imageFromResource("images/profile_images/p0.png"),
+                        "image",
+                        modifier = Modifier.size(40.dp).align(Alignment.CenterHorizontally).clip(
+                            CircleShape
+                        ).border(2.dp, color = Color.White, CircleShape)
+                    )
+                    Text(
+                        currContact.author.name,
+                        color = Color.White,
+                        fontSize = 16.sp,
+                        modifier = Modifier.padding(top = 4.dp)
+                    )
+                }
+                Icon(Icons.Filled.SwapHoriz, "swap", tint = Color.White, modifier = Modifier.size(48.dp))
+                Column(Modifier.align(Alignment.CenterVertically)) {
+                    // TODO Profile pic again
+                    Image(
+                        bitmap = imageFromResource("images/profile_images/p0.png"),
+                        "image",
+                        modifier = Modifier.size(40.dp).align(Alignment.CenterHorizontally).clip(
+                            CircleShape
+                        ).border(2.dp, color = Color.White, CircleShape)
+                    )
+                    Text(
+                        introContact.author.name,
+                        color = Color.White,
+                        fontSize = 16.sp,
+                        modifier = Modifier.padding(top = 4.dp)
+                    )
+                }
+            }
+            var introText by remember { mutableStateOf(TextFieldValue("")) }
+            Row(Modifier.padding(8.dp)) {
+                TextField(
+                    introText,
+                    { introText = it },
+                    placeholder = { Text(text = "Add a message (optional)") },
+                    textStyle = TextStyle(color = Color.White)
                 )
             }
-            IconButton(onClick = {}, modifier = Modifier.align(Alignment.CenterEnd).padding(end = 16.dp)) {
-                Icon(Icons.Filled.MoreVert, "contact info", tint = Color.White, modifier = Modifier.size(24.dp))
+            Row(Modifier.padding(8.dp)) {
+                TextButton(
+                    onClick = { isInfoDrawer(false); introNextPg = false; },
+                    Modifier.fillMaxWidth().background(briarDarkGray)
+                ) {
+                    Text("MAKE INTRODUCTION")
+                }
             }
-            Divider(
-                color = divider,
-                thickness = 1.dp,
-                modifier = Modifier.fillMaxWidth().align(Alignment.BottomCenter)
-            )
         }
-        Box(Modifier.padding(top = HEADER_SIZE + 1.dp, bottom = HEADER_SIZE)) {
-            val chat = ChatState(uiContact.id)
-            DrawTextBubbles(chat.value)
+    }
+}
+
+@Composable
+fun ContactInfoDrawer(
+    currContact: Contact,
+    contacts: List<Contact>,
+    isInfoDrawer: (Boolean) -> Unit,
+    drawerState: ContactInfoDrawerState
+) {
+    Row() {
+        when (drawerState) {
+            ContactInfoDrawerState.MakeIntro -> ContactDrawerMakeIntro(currContact, contacts, isInfoDrawer)
         }
-        var text by remember { mutableStateOf(TextFieldValue("")) }
-        Box(Modifier.align(Alignment.BottomCenter).background(darkGray)) {
-            OutlinedTextField(
-                value = text,
-                trailingIcon = { Icon(Icons.Filled.Send, "send message", tint = briarGreen) },
-                leadingIcon = { Icon(Icons.Filled.AddCircle, contentDescription = "add file") },
-                modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp).fillMaxWidth(),
-                label = { Text(text = "Message") },
-                textStyle = TextStyle(color = Color.White),
-                placeholder = { Text(text = "Your message to " + uiContact.author.name) },
-                onValueChange = {
-                    text = it
-                },
-            )
+    }
+}
+
+@Composable
+fun DrawMessageRow(
+    currContact: Contact,
+    contacts: List<Contact>,
+    expanded: Boolean,
+    setExpanded: (Boolean) -> Unit,
+    infoDrawer: Boolean,
+    setInfoDrawer: (Boolean) -> Unit,
+    drawerState: ContactInfoDrawerState
+) {
+    BoxWithConstraints(Modifier.fillMaxSize()) {
+        val animatedInfoDrawerOffsetX by animateDpAsState(
+            if (infoDrawer) {
+                -275.dp
+            } else {
+                0.dp
+            }
+        )
+        Scaffold(
+            topBar = { MsgColumnHeader(currContact, expanded, setExpanded, setInfoDrawer) },
+            content = { padding ->
+                Box(modifier = Modifier.padding(padding)) {
+                    val chat = ChatState(currContact.id)
+                    DrawTextBubbles(chat.value)
+                }
+            },
+            bottomBar = { MsgInput(currContact) },
+            backgroundColor = darkGray,
+            modifier = Modifier.offset()
+        )
+        if (infoDrawer) {
+            // TODO Find non-hacky way of setting scrim
+            // This dims the entire app while the drawer is open by making a very very large slightly see-through black box
+            Box(Modifier.requiredSize(maxWidth, maxHeight).background(Color(0, 0, 0, 100)))
+            Column(
+                modifier = Modifier.fillMaxHeight().width(275.dp).offset(maxWidth + animatedInfoDrawerOffsetX)
+                    .background(briarBlack, RoundedCornerShape(topStart = 10.dp, bottomStart = 10.dp))
+            ) {
+                ContactInfoDrawer(currContact, contacts, setInfoDrawer, drawerState)
+            }
         }
     }
 }