Skip to content

Commit 81f2b5f

Browse files
committed
1.0.5.1
1 parent a1fdbe5 commit 81f2b5f

File tree

16 files changed

+375
-65
lines changed

16 files changed

+375
-65
lines changed

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ dependencies {
6969
implementation("com.google.firebase:firebase-analytics-ktx:21.3.0")
7070

7171
// TPU
72+
implementation("androidx.core:core-splashscreen:1.0.1")
7273
implementation("com.github.wax911:android-emojify:1.7.1")
7374
implementation("androidx.activity:activity:1.7.2")
7475
implementation("com.google.accompanist:accompanist-permissions:0.31.4-beta")

app/src/main/java/com/troplo/privateuploader/MainScreen.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ fun MainScreen() {
7373
}
7474

7575
LaunchedEffect(closePanels) {
76+
Log.d("MainScreen", "closePanels: $closePanels")
7677
if(!closePanels) return@LaunchedEffect
7778
panelState.closePanels()
7879
closePanels = false

app/src/main/java/com/troplo/privateuploader/api/ApiService.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,11 @@ object TpuApi {
366366
@Path("userId") userId: Int,
367367
@Body friendNicknameRequest: FriendNicknameRequest
368368
): Call<Unit>
369+
370+
@DELETE("chats/{associationId}/association")
371+
fun leaveChat(
372+
@Path("associationId") associationId: Int
373+
): Call<Unit>
369374
}
370375

371376
val retrofitService: TpuApiService by lazy {

app/src/main/java/com/troplo/privateuploader/api/stores/ChatStore.kt

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ package com.troplo.privateuploader.api
33
import android.content.Context
44
import android.util.Log
55
import androidx.compose.runtime.mutableStateListOf
6+
import com.troplo.privateuploader.data.model.AddChatUsersEvent
67
import com.troplo.privateuploader.data.model.Chat
8+
import com.troplo.privateuploader.data.model.RemoveChatEvent
9+
import com.troplo.privateuploader.data.model.RemoveChatUserEvent
710
import com.troplo.privateuploader.data.model.Typing
811
import com.troplo.privateuploader.data.model.UploadTarget
912
import io.socket.client.Socket
@@ -21,21 +24,22 @@ object ChatStore {
2124
var associationId = MutableStateFlow(0)
2225
var typers = MutableStateFlow(emptyList<Typing>())
2326
var jumpToMessage = MutableStateFlow(0)
27+
var hasInit = false
2428

2529
// To upload to TPU, uses URI Android system
2630
var attachmentsToUpload = mutableStateListOf<UploadTarget>()
2731

2832
val chats: StateFlow<List<Chat>>
2933
get() = _chats
3034

31-
fun initializeChats(token: String) {
35+
fun initializeChats() {
3236
try {
33-
if (_chats.value.isNotEmpty()) return
3437
CoroutineScope(Dispatchers.IO).launch {
3538
val response = TpuApi.retrofitService.getChats().execute().body() ?: emptyList()
3639
_chats.value = response
3740
}
38-
41+
if(hasInit) return
42+
hasInit = true
3943
val socket: Socket? = SocketHandler.getSocket()
4044
if (socket != null) {
4145
socket.on("chatCreated") {
@@ -45,6 +49,47 @@ object ChatStore {
4549
// add it to the top
4650
_chats.value = listOf(chat).plus(_chats.value)
4751
}
52+
53+
socket.on("removeChat") {
54+
val jsonArray = it[0] as JSONObject
55+
val payload = jsonArray.toString()
56+
val chat = SocketHandler.gson.fromJson(payload, RemoveChatEvent::class.java)
57+
_chats.value = _chats.value.filter { it.id != chat.id }
58+
}
59+
60+
socket.on("removeChatUser") {
61+
val jsonArray = it[0] as JSONObject
62+
val payload = jsonArray.toString()
63+
val assoc = SocketHandler.gson.fromJson(payload, RemoveChatUserEvent::class.java)
64+
val chatIndex = _chats.value.indexOfFirst { it.id == assoc.chatId }
65+
if (chatIndex != -1) {
66+
val chat = _chats.value[chatIndex]
67+
val userIndex = chat.users.indexOfFirst { it.id == assoc.id }
68+
if (userIndex != -1) {
69+
_chats.value = _chats.value.toMutableList().apply {
70+
this[chatIndex] = chat.copy(users = chat.users.toMutableList().apply {
71+
this.removeAt(userIndex)
72+
})
73+
}
74+
}
75+
}
76+
}
77+
78+
socket.on("addChatUsers") {
79+
val jsonArray = it[0] as JSONObject
80+
val payload = jsonArray.toString()
81+
val users = SocketHandler.gson.fromJson(payload, AddChatUsersEvent::class.java)
82+
83+
val chatIndex = _chats.value.indexOfFirst { it.id == users.chatId }
84+
if (chatIndex != -1) {
85+
val chat = _chats.value[chatIndex]
86+
_chats.value = _chats.value.toMutableList().apply {
87+
this[chatIndex] = chat.copy(users = chat.users.toMutableList().apply {
88+
this.addAll(users.users)
89+
})
90+
}
91+
}
92+
}
4893
} else {
4994
Log.d("TPU.Untagged", "Socket is null")
5095
}
Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.troplo.privateuploader.components.chat
22

3+
import android.widget.Toast
4+
import androidx.compose.foundation.clickable
35
import androidx.compose.foundation.layout.Arrangement
46
import androidx.compose.foundation.layout.Column
57
import androidx.compose.foundation.layout.WindowInsets
68
import androidx.compose.foundation.layout.padding
79
import androidx.compose.material.icons.Icons
10+
import androidx.compose.material.icons.filled.ExitToApp
811
import androidx.compose.material.icons.filled.Settings
912
import androidx.compose.material3.ExperimentalMaterial3Api
1013
import androidx.compose.material3.Icon
@@ -14,9 +17,18 @@ import androidx.compose.material3.Text
1417
import androidx.compose.material3.rememberModalBottomSheetState
1518
import androidx.compose.runtime.Composable
1619
import androidx.compose.runtime.MutableState
20+
import androidx.compose.runtime.mutableStateOf
21+
import androidx.compose.runtime.remember
1722
import androidx.compose.ui.Modifier
23+
import androidx.compose.ui.platform.LocalContext
1824
import androidx.compose.ui.unit.dp
25+
import androidx.lifecycle.ViewModel
26+
import androidx.lifecycle.viewModelScope
27+
import com.troplo.privateuploader.api.TpuApi
28+
import com.troplo.privateuploader.components.core.dialogs.DeleteConfirmDialog
1929
import com.troplo.privateuploader.data.model.Chat
30+
import kotlinx.coroutines.Dispatchers
31+
import kotlinx.coroutines.launch
2032

2133
@OptIn(ExperimentalMaterial3Api::class)
2234
@Composable
@@ -28,6 +40,14 @@ fun ChatActions(
2840
val bottomSheetState = rememberModalBottomSheetState(
2941
skipPartiallyExpanded = true
3042
)
43+
val viewModel = remember { ChatActionsViewModel() }
44+
val leaveChat = remember { mutableStateOf(false) }
45+
46+
if (leaveChat.value) {
47+
DeleteConfirmDialog(open = leaveChat, onConfirm = {
48+
viewModel.leaveChat(chat.value?.association?.id ?: 0)
49+
}, title = "chat", name = chat.value?.name, terminology = "Leave")
50+
}
3151

3252
ModalBottomSheet(
3353
onDismissRequest = { openBottomSheet.value = false },
@@ -38,15 +58,64 @@ fun ChatActions(
3858
modifier = Modifier.padding(bottom = 8.dp),
3959
verticalArrangement = Arrangement.spacedBy(2.dp)
4060
) {
41-
ListItem(
42-
headlineContent = { Text("Settings") },
43-
leadingContent = {
44-
Icon(
45-
Icons.Default.Settings,
46-
contentDescription = "Settings icon"
47-
)
48-
}
49-
)
61+
if (chat.value?.type == "group" && (chat.value?.association?.rank == "admin" || chat.value?.association?.rank == "owner")) {
62+
val context = LocalContext.current
63+
ListItem(
64+
headlineContent = { Text("Group Settings") },
65+
modifier = Modifier.clickable {
66+
Toast.makeText(context, "Coming soon to mobile!", Toast.LENGTH_SHORT).show()
67+
},
68+
leadingContent = {
69+
Icon(
70+
Icons.Default.Settings,
71+
contentDescription = "Settings icon"
72+
)
73+
}
74+
)
75+
}
76+
77+
if (chat.value?.type == "group") {
78+
ListItem(
79+
headlineContent = { Text("Leave Group") },
80+
supportingContent = {
81+
Text("You will not be able to rejoin unless invited back.")
82+
},
83+
leadingContent = {
84+
Icon(
85+
Icons.Default.ExitToApp,
86+
contentDescription = "Leave icon"
87+
)
88+
},
89+
modifier = Modifier.clickable {
90+
leaveChat.value = true
91+
}
92+
)
93+
} else {
94+
ListItem(
95+
headlineContent = { Text("Leave DM") },
96+
supportingContent = {
97+
Text("The recipient will not be able to contact you unless you re-initiate the DM.")
98+
},
99+
leadingContent = {
100+
Icon(
101+
Icons.Default.ExitToApp,
102+
contentDescription = "Leave icon"
103+
)
104+
}
105+
)
106+
}
107+
}
108+
}
109+
}
110+
111+
class ChatActionsViewModel : ViewModel() {
112+
val loading = mutableStateOf(false)
113+
fun leaveChat(id: Int) {
114+
loading.value = true
115+
viewModelScope.launch(Dispatchers.IO) {
116+
val response = TpuApi.retrofitService.leaveChat(id).execute()
117+
118+
loading.value = false
50119
}
51120
}
52121
}

app/src/main/java/com/troplo/privateuploader/components/chat/ChatItem.kt

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,33 @@
11
package com.troplo.privateuploader.components.chat
22

3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.clickable
35
import androidx.compose.foundation.gestures.detectTapGestures
6+
import androidx.compose.foundation.layout.Column
7+
import androidx.compose.foundation.layout.Row
8+
import androidx.compose.foundation.layout.Spacer
49
import androidx.compose.foundation.layout.fillMaxWidth
10+
import androidx.compose.foundation.layout.height
511
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.foundation.layout.size
13+
import androidx.compose.foundation.layout.width
14+
import androidx.compose.foundation.shape.RoundedCornerShape
615
import androidx.compose.material3.Badge
716
import androidx.compose.material3.ExperimentalMaterial3Api
17+
import androidx.compose.material3.Icon
818
import androidx.compose.material3.MaterialTheme
919
import androidx.compose.material3.NavigationDrawerItem
20+
import androidx.compose.material3.Surface
1021
import androidx.compose.material3.Text
1122
import androidx.compose.runtime.Composable
1223
import androidx.compose.runtime.MutableState
1324
import androidx.compose.runtime.collectAsState
1425
import androidx.compose.runtime.mutableStateOf
1526
import androidx.compose.runtime.remember
27+
import androidx.compose.ui.Alignment
1628
import androidx.compose.ui.Modifier
29+
import androidx.compose.ui.draw.clip
30+
import androidx.compose.ui.graphics.Color
1731
import androidx.compose.ui.input.pointer.pointerInput
1832
import androidx.compose.ui.unit.dp
1933
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
@@ -37,7 +51,7 @@ fun ChatItem(
3751
if (id.value == chat.association?.id) {
3852
unread.value = 0
3953
}
40-
NavigationDrawerItem(
54+
NavigationItem(
4155
badge = {
4256
if (unread.value!! > 0) {
4357
Badge(
@@ -60,14 +74,12 @@ fun ChatItem(
6074
onLongPress = {
6175
chatCtx.value = chat
6276
chatActions.value = true
77+
},
78+
onTap = {
79+
openChat(chat.association?.id ?: 0)
6380
}
6481
)
6582
},
66-
onClick = {
67-
chat.association?.let {
68-
openChat(it.id)
69-
}
70-
},
7183
label = {
7284
Text(
7385
text = chatName,
@@ -96,4 +108,38 @@ fun ChatItem(
96108
)
97109
}
98110
)
111+
}
112+
113+
@Composable
114+
fun NavigationItem(
115+
modifier: Modifier = Modifier,
116+
label: @Composable () -> Unit,
117+
icon: @Composable () -> Unit,
118+
onClick: (() -> Unit)? = null,
119+
selected: Boolean = false,
120+
badge: @Composable (() -> Unit)? = null,
121+
subtitle: @Composable (() -> Unit)? = null
122+
) {
123+
Row(
124+
modifier = modifier
125+
.fillMaxWidth()
126+
.height(56.dp)
127+
.clip(RoundedCornerShape(16.dp))
128+
.clickable { onClick?.invoke() }
129+
.padding(horizontal = 8.dp)
130+
.background(
131+
color = if (selected) MaterialTheme.colorScheme.surfaceContainer else Color.Transparent,
132+
shape = RoundedCornerShape(16.dp)
133+
)
134+
.then(modifier),
135+
verticalAlignment = Alignment.CenterVertically
136+
) {
137+
icon()
138+
Spacer(modifier = Modifier.width(16.dp))
139+
Column {
140+
label()
141+
if (subtitle !== null) subtitle()
142+
}
143+
badge?.invoke()
144+
}
99145
}

app/src/main/java/com/troplo/privateuploader/components/chat/MarkdownText.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ fun MarkdownText(
6363
val preventLinkClick = remember { mutableStateOf(false) }
6464
val markdownRender: Markwon =
6565
remember { createMarkdownRender(context, onLinkClicked, preventLinkClick) }
66-
Log.d("Test", "Test")
6766
AndroidView(
6867
modifier = modifier,
6968
factory = { ctx ->

app/src/main/java/com/troplo/privateuploader/components/core/dialogs/DeleteConfirmDialog.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ import androidx.compose.ui.platform.LocalTextInputService
1919
import com.troplo.privateuploader.components.core.LoadingButton
2020

2121
@Composable
22-
fun DeleteConfirmDialog(open: MutableState<Boolean>, onConfirm: () -> Unit, title: String, name: String?, important: Boolean = false, loading: MutableState<Boolean> = mutableStateOf(false)) {
22+
fun DeleteConfirmDialog(open: MutableState<Boolean>, onConfirm: () -> Unit, title: String, name: String?, important: Boolean = false, loading: MutableState<Boolean> = mutableStateOf(false), terminology: String = "Delete", message: String? = null) {
2323
val confirm = remember { mutableStateOf("") }
2424
AlertDialog(
2525
onDismissRequest = {
2626
open.value = false
2727
},
2828
title = {
29-
Text(text = "Delete $title?")
29+
Text(text = if(title == "") "$terminology?" else "$terminology $title?")
3030
},
3131
text = {
3232
Column {
33-
Text(text = "Are you sure you want to delete the $title? This is irreversible!")
33+
Text(text = message ?: "Are you sure you want to ${terminology.lowercase()} the $title? This is irreversible!")
3434
if (important) {
3535
Text("Please type \"$name\" to confirm.")
3636
OutlinedTextField(
@@ -42,7 +42,7 @@ fun DeleteConfirmDialog(open: MutableState<Boolean>, onConfirm: () -> Unit, titl
4242
},
4343
confirmButton = {
4444
LoadingButton(
45-
text = "Delete",
45+
text = terminology,
4646
loading = loading.value,
4747
onClick = onConfirm,
4848
enabled = !important || confirm.value == name,

app/src/main/java/com/troplo/privateuploader/components/gallery/dialogs/AddToCollectionDialog.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ fun AddToCollectionDialog(open: MutableState<Boolean>, item: Upload) {
5050
Text(text = "Add to collection")
5151
},
5252
text = {
53-
Text(text = "Add ${item.name} to a collection?")
5453
ExposedDropdownMenuBox(
5554
expanded = expanded,
5655
onExpandedChange = { expanded = !expanded },

0 commit comments

Comments
 (0)