Skip to content

Commit fd02681

Browse files
committed
feat(fc): add room sharing support
Signed-off-by: Brandon McAnsh <[email protected]>
1 parent f63e3b8 commit fd02681

File tree

16 files changed

+151
-33
lines changed

16 files changed

+151
-33
lines changed

flipchatApp/src/main/kotlin/xyz/flipchat/app/data/RoomInfo.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.compose.ui.graphics.Color
44
import com.getcode.model.ID
55
import com.getcode.model.Kin
66
import com.getcode.ui.utils.generateComplementaryColorPalette
7+
import com.getcode.utils.base58
78

89
data class RoomInfo(
910
val id: ID? = null,
@@ -12,7 +13,8 @@ data class RoomInfo(
1213
val memberCount: Int = 0,
1314
val hostId: ID? = null,
1415
val hostName: String? = null,
15-
val coverCharge: Kin = Kin.fromQuarks(0)
16+
val roomNumber: Long = 0,
17+
val coverCharge: Kin = Kin.fromQuarks(0),
1618
) {
1719
val customTitle: String = runCatching { Regex("^#\\d+:\\s*(.*)").find(title)?.groupValues?.get(1).orEmpty() }.getOrDefault("")
1820

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/conversation/ConversationScreen.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ data class ConversationScreen(
100100
}
101101
}
102102

103-
LaunchedEffect(chatId) {
104-
if (chatId != null) {
103+
LaunchedEffect(roomNumber) {
104+
if (roomNumber != null) {
105105
vm.dispatchEvent(
106-
ConversationViewModel.Event.OnChatIdChanged(chatId)
106+
ConversationViewModel.Event.OnRoomNumberChanged(roomNumber)
107107
)
108108
}
109109
}

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/info/ChatInfoViewModel.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package xyz.flipchat.app.features.chat.info
22

3+
import android.content.Intent
34
import androidx.lifecycle.viewModelScope
45
import com.getcode.manager.BottomBarManager
56
import com.getcode.manager.TopBarManager
@@ -21,6 +22,7 @@ import xyz.flipchat.app.beta.Lab
2122
import xyz.flipchat.app.beta.Labs
2223
import xyz.flipchat.chat.RoomController
2324
import xyz.flipchat.app.data.RoomInfo
25+
import xyz.flipchat.app.util.IntentUtils
2426
import xyz.flipchat.services.user.UserManager
2527
import javax.inject.Inject
2628

@@ -51,7 +53,9 @@ class ChatInfoViewModel @Inject constructor(
5153
data class OnChangeCover(val roomId: ID) : Event
5254
data class OnCoverChanged(val cover: Kin) : Event
5355
data class OnChangeName(val id: ID, val title: String) : Event
54-
data class OnNameChanged(val name: String): Event
56+
data class OnNameChanged(val name: String) : Event
57+
data object OnShareRoomClicked : Event
58+
data class ShareRoom(val intent: Intent) : Event
5559
data object LeaveRoom : Event
5660
data object OnLeaveRoomConfirmed : Event
5761
data object OnLeftRoom : Event
@@ -134,6 +138,12 @@ class ChatInfoViewModel @Inject constructor(
134138
dispatchEvent(Event.OnLeftRoom)
135139
}
136140
).launchIn(viewModelScope)
141+
142+
eventFlow
143+
.filterIsInstance<Event.OnShareRoomClicked>()
144+
.map { IntentUtils.shareRoom(stateFlow.value.roomInfo.roomNumber) }
145+
.onEach { dispatchEvent(Event.ShareRoom(it)) }
146+
.launchIn(viewModelScope)
137147
}
138148

139149
companion object {
@@ -150,6 +160,7 @@ class ChatInfoViewModel @Inject constructor(
150160
memberCount = args.memberCount,
151161
hostId = args.ownerId,
152162
hostName = args.hostName,
163+
roomNumber = args.roomNumber,
153164
coverCharge = Kin.fromQuarks(args.coverChargeQuarks)
154165
)
155166
)
@@ -158,6 +169,8 @@ class ChatInfoViewModel @Inject constructor(
158169
is Event.OnChangeCover,
159170
Event.OnLeaveRoomConfirmed,
160171
is Event.OnChangeName,
172+
is Event.OnShareRoomClicked,
173+
is Event.ShareRoom,
161174
Event.OnLeftRoom -> { state -> state }
162175

163176
is Event.OnRequestInFlight -> { state -> state.copy(requestBeingSent = event.sending) }

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/info/RoomInfoScreen.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import com.getcode.navigation.RoomInfoArgs
2929
import com.getcode.navigation.core.LocalCodeNavigator
3030
import xyz.flipchat.app.ui.room.RoomCard
3131
import com.getcode.theme.CodeTheme
32+
import com.getcode.ui.components.AppBarDefaults
3233
import com.getcode.ui.components.AppBarWithTitle
3334
import com.getcode.ui.theme.ButtonState
3435
import com.getcode.ui.theme.CodeButton
@@ -53,6 +54,7 @@ class RoomInfoScreen(private val info: RoomInfoArgs) : Screen, Parcelable {
5354
override fun Content() {
5455
val viewModel = getViewModel<ChatInfoViewModel>()
5556
val navigator = LocalCodeNavigator.current
57+
val context = LocalContext.current
5658

5759
LaunchedEffect(info) {
5860
viewModel.dispatchEvent(ChatInfoViewModel.Event.OnInfoChanged(info))
@@ -75,6 +77,14 @@ class RoomInfoScreen(private val info: RoomInfoArgs) : Screen, Parcelable {
7577
}.launchIn(this)
7678
}
7779

80+
LaunchedEffect(viewModel) {
81+
viewModel.eventFlow
82+
.filterIsInstance<ChatInfoViewModel.Event.ShareRoom>()
83+
.onEach {
84+
context.startActivity(it.intent)
85+
}.launchIn(this)
86+
}
87+
7888
LaunchedEffect(viewModel) {
7989
viewModel.eventFlow
8090
.filterIsInstance<ChatInfoViewModel.Event.OnChangeName>()
@@ -89,7 +99,10 @@ class RoomInfoScreen(private val info: RoomInfoArgs) : Screen, Parcelable {
8999
) {
90100
AppBarWithTitle(
91101
backButton = true,
92-
onBackIconClicked = { navigator.pop() }
102+
onBackIconClicked = { navigator.pop() },
103+
endContent = {
104+
AppBarDefaults.Share { viewModel.dispatchEvent(ChatInfoViewModel.Event.OnShareRoomClicked) }
105+
}
93106
)
94107
RoomInfoScreenContent(viewModel)
95108
}

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/lookup/confirm/JoinConfirmationViewModel.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ class JoinConfirmationViewModel @Inject constructor(
221221
memberCount = args.memberCount,
222222
hostId = args.ownerId,
223223
hostName = args.hostName,
224+
roomNumber = args.roomNumber,
224225
coverCharge = Kin.fromQuarks(args.coverChargeQuarks)
225226
),
226227
)

flipchatApp/src/main/kotlin/xyz/flipchat/app/inject/AppModule.kt

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import xyz.flipchat.app.util.AndroidLocale
3535
import xyz.flipchat.app.util.FcTab
3636
import xyz.flipchat.app.util.Router
3737
import xyz.flipchat.app.util.RouterImpl
38+
import xyz.flipchat.controllers.ChatsController
3839
import xyz.flipchat.services.billing.BillingClient
3940
import xyz.flipchat.services.billing.GooglePlayBillingClient
4041
import xyz.flipchat.services.billing.StubBillingClient
@@ -59,12 +60,14 @@ object AppModule {
5960
@Provides
6061
fun providesWifiManager(
6162
@ApplicationContext context: Context,
62-
): WifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
63+
): WifiManager =
64+
context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
6365

6466
@Provides
6567
fun providesConnectivityManager(
6668
@ApplicationContext context: Context,
67-
): ConnectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
69+
): ConnectivityManager =
70+
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
6871

6972
@Provides
7073
fun providesTelephonyManager(
@@ -96,6 +99,7 @@ object AppModule {
9699
Api25Vibrator(vibrator)
97100
}
98101
}
102+
99103
else -> Api31Vibrator(context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager)
100104
}
101105

@@ -107,13 +111,14 @@ object AppModule {
107111
telephonyManager: TelephonyManager,
108112
wifiManager: WifiManager
109113
): NetworkConnectivityListener = when (Build.VERSION.SDK_INT) {
110-
in Build.VERSION_CODES.N .. Build.VERSION_CODES.P -> {
114+
in Build.VERSION_CODES.N..Build.VERSION_CODES.P -> {
111115
Api24NetworkObserver(
112116
wifiManager,
113117
connectivityManager,
114118
telephonyManager
115119
)
116120
}
121+
117122
else -> Api29NetworkObserver(
118123
connectivityManager,
119124
telephonyManager
@@ -128,18 +133,22 @@ object AppModule {
128133

129134
@Provides
130135
fun providesDeeplinkRouter(
131-
userManager: UserManager
136+
userManager: UserManager,
137+
chatsController: ChatsController,
138+
resources: ResourceHelper,
132139
): Router = RouterImpl(
133-
userManager = userManager,
134-
tabIndexResolver = { resolved ->
135-
when (resolved) {
136-
FcTab.Chat -> FcTab.Chat.ordinal
137-
FcTab.Cash -> FcTab.Cash.ordinal
138-
FcTab.Settings -> FcTab.Settings.ordinal
139-
}
140-
},
141-
indexTabResolver = { index -> FcTab.entries[index] }
142-
)
140+
userManager = userManager,
141+
chatsController = chatsController,
142+
resources = resources,
143+
tabIndexResolver = { resolved ->
144+
when (resolved) {
145+
FcTab.Chat -> FcTab.Chat.ordinal
146+
FcTab.Cash -> FcTab.Cash.ordinal
147+
FcTab.Settings -> FcTab.Settings.ordinal
148+
}
149+
},
150+
indexTabResolver = { index -> FcTab.entries[index] }
151+
)
143152

144153
@Singleton
145154
@Provides

flipchatApp/src/main/kotlin/xyz/flipchat/app/ui/room/RoomCard.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ private fun Preview_RoomCard() {
210210
title = "Room #237",
211211
hostName = "Ivy",
212212
memberCount = 24,
213+
roomNumber = 0
213214
)
214215
)
215216
}

flipchatApp/src/main/kotlin/xyz/flipchat/app/util/IntentUtils.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,20 @@ object IntentUtils {
1717
data = Uri.parse("tel:$number")
1818
flags = Intent.FLAG_ACTIVITY_NEW_TASK
1919
}
20+
21+
fun shareRoom(roomNumber: Long): Intent {
22+
val shareLink = "https://app.flipchat.xyz/room/$roomNumber"
23+
24+
val sendIntent: Intent = Intent().apply {
25+
action = Intent.ACTION_SEND
26+
putExtra(Intent.EXTRA_TEXT, shareLink)
27+
type = "text/plain"
28+
}
29+
30+
val shareIntent = Intent.createChooser(sendIntent, null).apply {
31+
flags = Intent.FLAG_ACTIVITY_NEW_TASK
32+
}
33+
34+
return shareIntent
35+
}
2036
}

flipchatApp/src/main/kotlin/xyz/flipchat/app/util/Router.kt

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import cafe.adriel.voyager.core.registry.ScreenRegistry
55
import cafe.adriel.voyager.core.screen.Screen
66
import com.getcode.model.ID
77
import com.getcode.navigation.NavScreenProvider
8+
import com.getcode.navigation.RoomInfoArgs
89
import com.getcode.navigation.screens.ChildNavTab
10+
import com.getcode.util.resources.ResourceHelper
911
import com.getcode.vendor.Base58
1012
import dev.theolm.rinku.DeepLink
1113
import kotlinx.coroutines.CoroutineScope
@@ -17,13 +19,16 @@ import kotlinx.coroutines.launch
1719
import xyz.flipchat.app.features.home.tabs.CashTab
1820
import xyz.flipchat.app.features.home.tabs.ChatTab
1921
import xyz.flipchat.app.features.home.tabs.SettingsTab
22+
import xyz.flipchat.controllers.ChatsController
23+
import xyz.flipchat.internal.db.FcAppDatabase
24+
import xyz.flipchat.services.extensions.titleOrFallback
2025
import xyz.flipchat.services.user.UserManager
2126

2227
interface Router {
2328
fun checkTabs()
2429
val rootTabs: List<ChildNavTab>
2530
fun getInitialTabIndex(deeplink: DeepLink?): Int
26-
fun processDestination(deeplink: DeepLink?): List<Screen>
31+
suspend fun processDestination(deeplink: DeepLink?): List<Screen>
2732
fun processType(deeplink: DeepLink?): DeeplinkType?
2833
fun tabForIndex(index: Int): FcTab
2934
}
@@ -35,11 +40,13 @@ enum class FcTab {
3540
sealed interface DeeplinkType {
3641
data class Login(val entropy: String) : DeeplinkType
3742
data class OpenRoomById(val roomId: ID) : DeeplinkType
38-
data class OpenRoomByNumber(val number: Long) : DeeplinkType
43+
data class OpenRoomByNumber(val number: Long, val messageId: ID? = null) : DeeplinkType
3944
}
4045

4146
class RouterImpl(
4247
private val userManager: UserManager,
48+
private val chatsController: ChatsController,
49+
private val resources: ResourceHelper,
4350
private val tabIndexResolver: (FcTab) -> Int,
4451
private val indexTabResolver: (Int) -> FcTab,
4552
) : Router, CoroutineScope by CoroutineScope(Dispatchers.IO) {
@@ -52,6 +59,9 @@ class RouterImpl(
5259
val room = listOf("room")
5360
}
5461

62+
private val db: FcAppDatabase
63+
get() = FcAppDatabase.requireInstance()
64+
5565
override fun tabForIndex(index: Int) = indexTabResolver(index)
5666

5767
private val commonTabs = listOf(ChatTab, CashTab)
@@ -86,7 +96,7 @@ class RouterImpl(
8696
} ?: 0
8797
}
8898

89-
override fun processDestination(deeplink: DeepLink?): List<Screen> {
99+
override suspend fun processDestination(deeplink: DeepLink?): List<Screen> {
90100
return deeplink?.let {
91101
val type = processType(deeplink) ?: return emptyList()
92102
when (type) {
@@ -96,10 +106,40 @@ class RouterImpl(
96106
ScreenRegistry.get(NavScreenProvider.Room.Messages(chatId = type.roomId))
97107
)
98108

99-
is DeeplinkType.OpenRoomByNumber -> listOf(
100-
ScreenRegistry.get(NavScreenProvider.AppHomeScreen()),
101-
ScreenRegistry.get(NavScreenProvider.Room.Messages(roomNumber = type.number))
102-
)
109+
is DeeplinkType.OpenRoomByNumber -> {
110+
val conversation = db.conversationDao().findConversationRaw(type.number)
111+
val screens = mutableListOf(ScreenRegistry.get(NavScreenProvider.AppHomeScreen()))
112+
if (conversation != null) {
113+
screens.add(ScreenRegistry.get(NavScreenProvider.Room.Messages(conversation.id)))
114+
} else {
115+
val lookup = chatsController.lookupRoom(type.number).getOrNull()
116+
if (lookup != null) {
117+
val (room, members) = lookup
118+
val moderator = members.firstOrNull { it.isModerator }
119+
120+
val args = RoomInfoArgs(
121+
roomId = room.id,
122+
roomNumber = room.roomNumber,
123+
roomTitle = room.titleOrFallback(
124+
resources,
125+
includeRoomPrefix = false
126+
),
127+
memberCount = members.count(),
128+
ownerId = room.ownerId,
129+
hostName = moderator?.identity?.displayName,
130+
coverChargeQuarks = room.coverCharge.quarks,
131+
)
132+
133+
screens.add(
134+
ScreenRegistry.get(
135+
NavScreenProvider.Room.Lookup.Confirm(args = args, returnToSender = true)
136+
)
137+
)
138+
}
139+
}
140+
141+
screens
142+
}
103143
}
104144
} ?: emptyList()
105145
}
@@ -142,7 +182,12 @@ class RouterImpl(
142182
val number = runCatching {
143183
deeplink.pathSegments[1].toLongOrNull()
144184
}.getOrNull() ?: return null
145-
DeeplinkType.OpenRoomByNumber(number = number)
185+
186+
val messageId = runCatching {
187+
deeplink.data.toUri().getQueryParameter("m")?.let { Base58.decode(it).toList() }
188+
}.getOrNull()
189+
190+
DeeplinkType.OpenRoomByNumber(number = number, messageId = messageId)
146191
}
147192

148193
else -> null

services/flipchat/chat/src/main/kotlin/xyz/flipchat/services/internal/db/ConversationDao.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ interface ConversationDao {
6666
@Query("SELECT * FROM conversations WHERE idBase58 = :id")
6767
suspend fun findConversationRaw(id: String): Conversation?
6868

69+
@RewriteQueriesToDropUnusedColumns
70+
@Query("SELECT * FROM conversations WHERE roomNumber = :number")
71+
suspend fun findConversationRaw(number: Long): Conversation?
72+
6973
suspend fun findConversationRaw(id: ID): Conversation? {
7074
return findConversationRaw(id.base58)
7175
}

0 commit comments

Comments
 (0)