Skip to content

Commit d7e929f

Browse files
committed
Merge branch 'release/1.28.2' into merge/1.28.2
2 parents 6a68927 + 2e5994a commit d7e929f

File tree

62 files changed

+1036
-2185
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1036
-2185
lines changed

app/build.gradle.kts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ configurations.configureEach {
2626
exclude(module = "commons-logging")
2727
}
2828

29-
val canonicalVersionCode = 426
30-
val canonicalVersionName = "1.28.1"
29+
val canonicalVersionCode = 427
30+
val canonicalVersionName = "1.28.2"
3131

3232
val postFixSize = 10
3333
val abiPostFix = mapOf(
@@ -402,6 +402,7 @@ dependencies {
402402
implementation(libs.phrase)
403403
implementation(libs.copper.flow)
404404
implementation(libs.kotlinx.coroutines.android)
405+
implementation(libs.kotlinx.coroutines.guava)
405406
implementation(libs.kovenant)
406407
implementation(libs.kovenant.android)
407408
implementation(libs.opencsv)

app/src/main/java/org/session/libsession/database/MessageDataProvider.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@ interface MessageDataProvider {
3939
fun isDeletedMessage(id: MessageId): Boolean
4040
fun handleSuccessfulAttachmentUpload(attachmentId: Long, attachmentStream: SignalServiceAttachmentStream, attachmentKey: ByteArray, uploadResult: UploadResult)
4141
fun handleFailedAttachmentUpload(attachmentId: Long)
42-
fun getMessageForQuote(timestamp: Long, author: Address): Triple<Long, Boolean, String>?
42+
fun getMessageForQuote(threadId: Long, timestamp: Long, author: Address): Triple<Long, Boolean, String>?
4343
fun getAttachmentsAndLinkPreviewFor(mmsId: Long): List<Attachment>
44-
fun getMessageBodyFor(timestamp: Long, author: String): String
4544
fun getAttachmentIDsFor(mmsMessageId: Long): List<Long>
4645
fun getLinkPreviewAttachmentIDFor(mmsMessageId: Long): Long?
4746
}

app/src/main/java/org/session/libsession/database/StorageProtocol.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ interface StorageProtocol {
9292
fun addReceivedMessageTimestamp(timestamp: Long)
9393
fun removeReceivedMessageTimestamps(timestamps: Set<Long>)
9494
fun getAttachmentsForMessage(mmsMessageId: Long): List<DatabaseAttachment>
95-
fun getMessageBy(timestamp: Long, author: String): MessageRecord?
95+
fun getMessageBy(threadId: Long, timestamp: Long, author: String): MessageRecord?
9696
fun updateSentTimestamp(messageId: MessageId, newTimestamp: Long)
9797
fun markAsResyncing(messageId: MessageId)
9898
fun markAsSyncing(messageId: MessageId)

app/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ import org.thoughtcrime.securesms.database.model.MessageId
7171
import org.thoughtcrime.securesms.database.model.ReactionRecord
7272
import org.thoughtcrime.securesms.dependencies.ManagerScope
7373
import org.thoughtcrime.securesms.pro.ProStatusManager
74-
import org.thoughtcrime.securesms.repository.ConversationRepository
7574
import org.thoughtcrime.securesms.sskenvironment.ReadReceiptManager
7675
import java.security.SignatureException
7776
import javax.inject.Inject
@@ -244,7 +243,8 @@ class ReceivedMessageHandler @Inject constructor(
244243

245244
val timestamp = message.timestamp ?: return null
246245
val author = message.author ?: return null
247-
val messageToDelete = storage.getMessageBy(timestamp, author) ?: return null
246+
val threadId = message.threadID ?: return null
247+
val messageToDelete = storage.getMessageBy(threadId, timestamp, author) ?: return null
248248
val messageIdToDelete = messageToDelete.messageId
249249
val messageType = messageToDelete.individualRecipient?.getType()
250250

@@ -326,7 +326,7 @@ class ReceivedMessageHandler @Inject constructor(
326326
Address.fromSerialized(quote.author)
327327
}
328328

329-
val messageInfo = messageDataProvider.getMessageForQuote(quote.id, author)
329+
val messageInfo = messageDataProvider.getMessageForQuote(context.threadId, quote.id, author)
330330
quoteMessageBody = messageInfo?.third
331331
quoteModel = if (messageInfo != null) {
332332
val attachments = if (messageInfo.second) messageDataProvider.getAttachmentsAndLinkPreviewFor(messageInfo.first) else ArrayList()

app/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ object OnionRequestAPI {
6060
.map { it.isNotEmpty() }
6161
.stateIn(GlobalScope, SharingStarted.Eagerly, paths.value.isNotEmpty())
6262

63+
private val NON_PENALIZING_STATUSES = setOf(403, 404, 406, 425)
64+
6365
init {
6466
// Listen for the changes in paths and persist it to the db
6567
GlobalScope.launch {
@@ -410,12 +412,20 @@ object OnionRequestAPI {
410412
} else {
411413
handleUnspecificError()
412414
}
413-
} else if (destination is Destination.Server && exception.statusCode == 400) {
414-
Log.d("Loki","Destination server returned code ${exception.statusCode} with message: $message")
415+
} else if(exception.statusCode in NON_PENALIZING_STATUSES){
416+
// error codes that shouldn't penalize our path or drop snodes
417+
// 404 is probably file server missing a file, don't rebuild path or mark a snode as bad here
418+
Log.d("Loki","Request returned a non penalizing code ${exception.statusCode} with message: $message")
419+
}
420+
// we do not want to penalize the path/nodes when:
421+
// - the exit node reached the server but the destination returned 5xx or 400
422+
// - the exit node couldn't reach its destination with a 5xx or 400, but the destination was a community (which we can know from the server's name being in the error message)
423+
else if (destination is Destination.Server &&
424+
(exception.statusCode in 500..504 || exception.statusCode == 400) &&
425+
(exception is HTTPRequestFailedAtDestinationException || exception.body?.contains(destination.host) == true)) {
426+
Log.d("Loki","Destination server error - Non path penalizing. Request returned code ${exception.statusCode} with message: $message")
415427
} else if (message == "Loki Server error") {
416428
Log.d("Loki", "message was $message")
417-
} else if (exception.statusCode == 404) {
418-
// 404 is probably file server missing a file, don't rebuild path or mark a snode as bad here
419429
} else { // Only drop snode/path if not receiving above two exception cases
420430
handleUnspecificError()
421431
}

app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -938,12 +938,6 @@ interface TextSecurePreferences {
938938
setBooleanPreference(context, FINGERPRINT_KEY_GENERATED, true)
939939
}
940940

941-
@JvmStatic
942-
fun clearAll(context: Context) {
943-
getDefaultSharedPreferences(context).edit().clear().commit()
944-
}
945-
946-
947941
// ----- Get / set methods for if we have already warned the user that saving attachments will allow other apps to access them -----
948942
// Note: We only ever show the warning dialog about this ONCE - when the user accepts this fact we write true to the flag & never show again.
949943
@JvmStatic
@@ -1680,8 +1674,16 @@ class AppTextSecurePreferences @Inject constructor(
16801674
return getBooleanPreference(AUTOPLAY_AUDIO_MESSAGES, false)
16811675
}
16821676

1677+
/**
1678+
* Clear all prefs and reset our observables
1679+
*/
16831680
override fun clearAll() {
1684-
getDefaultSharedPreferences(context).edit().clear().commit()
1681+
pushEnabled.update { false }
1682+
localNumberState.update { null }
1683+
postProLaunchState.update { false }
1684+
hiddenPasswordState.update { false }
1685+
1686+
getDefaultSharedPreferences(context).edit(commit = true) { clear() }
16851687
}
16861688

16871689
override fun getHidePassword() = getBooleanPreference(HIDE_PASSWORD, false)

app/src/main/java/org/session/libsignal/utilities/HTTP.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ object HTTP {
7373

7474
open class HTTPRequestFailedException(
7575
val statusCode: Int,
76-
val json: Map<*, *>?,
76+
val json: Map<*, *>? = null,
77+
val body: String? = null,
7778
message: String = "HTTP request failed with status code $statusCode"
7879
) : kotlin.Exception(message)
7980
class HTTPNoNetworkException : HTTPRequestFailedException(0, null, "No network connection")
@@ -131,10 +132,10 @@ object HTTP {
131132
else -> defaultConnection
132133
}.newCall(request.build()).await().use { response ->
133134
when (val statusCode = response.code) {
134-
200 -> response.body!!.bytes()
135+
in 200..299 -> response.body.bytes()
135136
else -> {
136137
Log.d("Loki", "${verb.rawValue} request to $url failed with status code: $statusCode.")
137-
throw HTTPRequestFailedException(statusCode, null)
138+
throw HTTPRequestFailedException(statusCode, body = response.body.string())
138139
}
139140
}
140141
}
@@ -143,8 +144,16 @@ object HTTP {
143144

144145
if (!isConnectedToNetwork()) { throw HTTPNoNetworkException() }
145146

146-
// Override the actual error so that we can correctly catch failed requests in OnionRequestAPI
147-
throw HTTPRequestFailedException(0, null, "HTTP request failed due to: ${exception.message}")
147+
if (exception !is HTTPRequestFailedException) {
148+
149+
// Override the actual error so that we can correctly catch failed requests in OnionRequestAPI
150+
throw HTTPRequestFailedException(
151+
statusCode = 0,
152+
message = "HTTP request failed due to: ${exception.message}"
153+
)
154+
} else {
155+
throw exception
156+
}
148157
}
149158
}
150159

app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.kt

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ class MediaPreviewActivity : ScreenLockActionBarActivity(),
143143
private var albumRailAdapter: MediaRailAdapter? = null
144144

145145
private var windowInsetBottom = 0
146-
private var railHeight = 0
147146

148147
@OptIn(ExperimentalCoroutinesApi::class)
149148
override fun onCreate(bundle: Bundle?, ready: Boolean) {
@@ -172,7 +171,7 @@ class MediaPreviewActivity : ScreenLockActionBarActivity(),
172171
windowInsetBottom = insets.bottom
173172

174173
binding.toolbar.updatePadding(top = insets.top)
175-
binding.mediaPreviewAlbumRailContainer.updatePadding(bottom = max(insets.bottom, binding.mediaPreviewAlbumRailContainer.paddingBottom))
174+
binding.mediaPreviewAlbumRailContainer.updatePadding(bottom = insets.bottom)
176175

177176
updateControlsPosition()
178177

@@ -213,12 +212,9 @@ class MediaPreviewActivity : ScreenLockActionBarActivity(),
213212
* Updates the media controls' position based on the rail's position
214213
*/
215214
private fun updateControlsPosition() {
216-
// the ypos of the controls is either the window bottom inset, or the rail height if there is a rail
217-
// since the rail height takes the window inset into account with its padding
218-
val totalBottomPadding = max(
219-
windowInsetBottom,
220-
railHeight + resources.getDimensionPixelSize(R.dimen.medium_spacing)
221-
)
215+
val totalBottomPadding = windowInsetBottom +
216+
binding.mediaPreviewAlbumRail.height+
217+
resources.getDimensionPixelSize(R.dimen.medium_spacing)
222218

223219
adapter?.setControlsYPosition(totalBottomPadding)
224220
}
@@ -431,7 +427,7 @@ class MediaPreviewActivity : ScreenLockActionBarActivity(),
431427
binding.mediaPreviewAlbumRailContainer.viewTreeObserver.removeOnGlobalLayoutListener(
432428
this
433429
)
434-
railHeight = binding.mediaPreviewAlbumRailContainer.height
430+
435431
updateControlsPosition()
436432
}
437433
}

app/src/main/java/org/thoughtcrime/securesms/ShareScreen.kt

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import org.thoughtcrime.securesms.groups.compose.MemberItem
3131
import org.thoughtcrime.securesms.ui.SearchBar
3232
import org.thoughtcrime.securesms.ui.components.BackAppBar
3333
import org.thoughtcrime.securesms.ui.components.CircularProgressIndicator
34+
import org.thoughtcrime.securesms.ui.components.SmallCircularProgressIndicator
3435
import org.thoughtcrime.securesms.ui.qaTag
3536
import org.thoughtcrime.securesms.ui.theme.LocalColors
3637
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
@@ -66,7 +67,7 @@ fun ShareScreen(
6667
fun ShareList(
6768
state: ShareViewModel.UIState,
6869
contacts: List<ConversationItem>,
69-
hasConversations: Boolean,
70+
hasConversations: Boolean?,
7071
onContactItemClicked: (address: Address) -> Unit,
7172
searchQuery: String,
7273
onSearchQueryChanged: (String) -> Unit,
@@ -116,29 +117,41 @@ fun ShareList(
116117

117118
Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing))
118119

119-
if (!hasConversations) {
120-
Text(
121-
text = stringResource(id = R.string.conversationsNone),
122-
modifier = Modifier.padding(top = LocalDimensions.current.spacing)
123-
.align(Alignment.CenterHorizontally),
124-
style = LocalType.current.base.copy(color = LocalColors.current.textSecondary)
125-
)
126-
} else {
127-
LazyColumn(
128-
state = scrollState,
129-
contentPadding = PaddingValues(bottom = paddings.calculateBottomPadding()),
130-
) {
131-
132-
items(contacts) { contacts ->
133-
// Each member's view
134-
MemberItem(
135-
address = contacts.address,
136-
onClick = onContactItemClicked,
137-
title = contacts.name,
138-
showProBadge = contacts.showProBadge,
139-
showAsAdmin = false,
140-
avatarUIData = contacts.avatarUIData
141-
)
120+
when(hasConversations){
121+
// null means we don't yet have a result, so show a loader
122+
null -> {
123+
SmallCircularProgressIndicator(
124+
modifier = Modifier.padding(top = LocalDimensions.current.spacing)
125+
.align(Alignment.CenterHorizontally),
126+
)
127+
}
128+
129+
false -> {
130+
Text(
131+
text = stringResource(id = R.string.conversationsNone),
132+
modifier = Modifier.padding(top = LocalDimensions.current.spacing)
133+
.align(Alignment.CenterHorizontally),
134+
style = LocalType.current.base.copy(color = LocalColors.current.textSecondary)
135+
)
136+
}
137+
138+
true -> {
139+
LazyColumn(
140+
state = scrollState,
141+
contentPadding = PaddingValues(bottom = paddings.calculateBottomPadding()),
142+
) {
143+
144+
items(contacts) { contacts ->
145+
// Each member's view
146+
MemberItem(
147+
address = contacts.address,
148+
onClick = onContactItemClicked,
149+
title = contacts.name,
150+
showProBadge = contacts.showProBadge,
151+
showAsAdmin = false,
152+
avatarUIData = contacts.avatarUIData
153+
)
154+
}
142155
}
143156
}
144157
}
@@ -201,6 +214,25 @@ private fun PreviewSelectEmptyContacts() {
201214
}
202215
}
203216

217+
@Preview
218+
@Composable
219+
private fun PreviewSelectFetchingContacts() {
220+
val contacts = emptyList<ConversationItem>()
221+
222+
PreviewTheme {
223+
ShareList(
224+
state = ShareViewModel.UIState(false),
225+
contacts = contacts,
226+
hasConversations = null,
227+
onContactItemClicked = {},
228+
searchQuery = "",
229+
onSearchQueryChanged = {},
230+
onSearchQueryClear = {},
231+
onBack = {},
232+
)
233+
}
234+
}
235+
204236
@Preview
205237
@Composable
206238
private fun PreviewSelectEmptyContactsWithSearch() {

app/src/main/java/org/thoughtcrime/securesms/ShareViewModel.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ class ShareViewModel @Inject constructor(
7171
::filterContacts
7272
).stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
7373

74-
val hasAnyConversations: StateFlow<Boolean> =
74+
val hasAnyConversations: StateFlow<Boolean?> =
7575
conversationRepository.observeConversationList()
7676
.map { it.isNotEmpty() }
77-
.stateIn(viewModelScope, SharingStarted.Eagerly, false)
77+
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
7878

7979
private val _uiEvents = MutableSharedFlow<ShareUIEvent>(extraBufferCapacity = 1)
8080
val uiEvents: SharedFlow<ShareUIEvent> get() = _uiEvents

0 commit comments

Comments
 (0)