Skip to content

Commit b45a066

Browse files
Merge pull request #1730 from session-foundation/feature/pro-stats
Pro Stats
2 parents 000522e + c0121fd commit b45a066

File tree

16 files changed

+210
-72
lines changed

16 files changed

+210
-72
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ interface StorageProtocol {
146146
fun trimThreadBefore(threadID: Long, timestamp: Long)
147147
fun getMessageCount(threadID: Long): Long
148148
fun getTotalPinned(): Int
149+
suspend fun getTotalSentProBadges(): Int
150+
suspend fun getTotalSentLongMessages(): Int
149151
fun setPinned(address: Address, isPinned: Boolean)
150152
fun isRead(threadId: Long) : Boolean
151153
fun setThreadCreationDate(threadId: Long, newDate: Long)

app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ import androidx.recyclerview.widget.RecyclerView
5858
import com.annimon.stream.Stream
5959
import com.bumptech.glide.Glide
6060
import com.squareup.phrase.Phrase
61-
import dagger.Lazy
6261
import dagger.hilt.android.AndroidEntryPoint
6362
import dagger.hilt.android.lifecycle.withCreationCallback
6463
import kotlinx.coroutines.CancellationException
@@ -119,7 +118,6 @@ import org.session.libsignal.crypto.MnemonicCodec
119118
import org.session.libsignal.utilities.ListenableFuture
120119
import org.session.libsignal.utilities.Log
121120
import org.session.libsignal.utilities.toHexString
122-
import org.thoughtcrime.securesms.ApplicationContext
123121
import org.thoughtcrime.securesms.FullComposeActivity.Companion.applyCommonPropertiesForCompose
124122
import org.thoughtcrime.securesms.ScreenLockActionBarActivity
125123
import org.thoughtcrime.securesms.audio.AudioRecorderHandle
@@ -135,7 +133,6 @@ import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companio
135133
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_REPLY
136134
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_RESEND
137135
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_SAVE
138-
import org.thoughtcrime.securesms.conversation.v2.dialogs.BlockedDialog
139136
import org.thoughtcrime.securesms.conversation.v2.dialogs.LinkPreviewDialog
140137
import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarButton
141138
import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarDelegate
@@ -158,7 +155,6 @@ import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager
158155
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities
159156
import org.thoughtcrime.securesms.conversation.v2.utilities.ResendMessageUtilities
160157
import org.thoughtcrime.securesms.crypto.MnemonicUtilities
161-
import org.thoughtcrime.securesms.database.AttachmentDatabase
162158
import org.thoughtcrime.securesms.database.GroupDatabase
163159
import org.thoughtcrime.securesms.database.LokiMessageDatabase
164160
import org.thoughtcrime.securesms.database.MmsDatabase
@@ -2076,9 +2072,11 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
20762072
override fun sendMessage() {
20772073
val recipient = viewModel.recipient
20782074

2075+
// It shouldn't be possible to send a message to a blocked user anymore.
2076+
// But as a safety net:
20792077
// show the unblock dialog when trying to send a message to a blocked contact
20802078
if (recipient.isStandardRecipient && recipient.blocked) {
2081-
BlockedDialog(recipient.address, recipient.displayName()).show(supportFragmentManager, "Blocked Dialog")
2079+
unblock()
20822080
return
20832081
}
20842082

app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/BlockedDialog.kt

Lines changed: 0 additions & 36 deletions
This file was deleted.

app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ class InputBar @JvmOverloads constructor(
365365
fun setCharLimitState(state: InputbarViewModel.InputBarCharLimitState?) {
366366
// handle char limit
367367
if(state != null){
368-
binding.characterLimitText.text = state.count.toString()
368+
binding.characterLimitText.text = state.countFormatted
369369
binding.characterLimitText.setTextColor(if(state.danger) dangerColor else textColor)
370370
binding.characterLimitContainer.setOnClickListener {
371371
delegate?.onCharLimitTapped()

app/src/main/java/org/thoughtcrime/securesms/conversation/v2/settings/ConversationSettingsDialogs.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ fun ConversationSettingsDialogs(
263263
iconRes = R.drawable.ic_pro_badge,
264264
iconSize = 40.sp to 18.sp,
265265
style = LocalType.current.large,
266+
textQaTag = stringResource(R.string.qa_cta_body)
266267
)
267268
},
268269
content = { CTAImage(heroImage = R.drawable.cta_hero_group) },

app/src/main/java/org/thoughtcrime/securesms/conversation/v2/settings/ConversationSettingsViewModel.kt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import androidx.annotation.StringRes
1111
import androidx.appcompat.app.AppCompatActivity.CLIPBOARD_SERVICE
1212
import androidx.lifecycle.ViewModel
1313
import androidx.lifecycle.viewModelScope
14+
import androidx.lifecycle.viewmodel.compose.viewModel
1415
import com.squareup.phrase.Phrase
1516
import dagger.assisted.Assisted
1617
import dagger.assisted.AssistedFactory
@@ -713,14 +714,17 @@ class ConversationSettingsViewModel @AssistedInject constructor(
713714
private fun pinConversation(){
714715
// check the pin limit before continuing
715716
val totalPins = storage.getTotalPinned()
716-
val maxPins = proStatusManager.getPinnedConversationLimit(recipientRepository.getSelf().isPro)
717-
if(totalPins >= maxPins){
717+
val maxPins =
718+
proStatusManager.getPinnedConversationLimit(recipientRepository.getSelf().isPro)
719+
if (totalPins >= maxPins) {
718720
// the user has reached the pin limit, show the CTA
719721
_dialogState.update {
720-
it.copy(pinCTA = PinProCTA(
721-
overTheLimit = totalPins > maxPins,
722-
proSubscription = proStatusManager.proDataState.value.type
723-
))
722+
it.copy(
723+
pinCTA = PinProCTA(
724+
overTheLimit = totalPins > maxPins,
725+
proSubscription = proStatusManager.proDataState.value.type
726+
)
727+
)
724728
}
725729
} else {
726730
viewModelScope.launch {

app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,32 @@ class MmsDatabase @Inject constructor(
117117
.any { MmsSmsColumns.Types.isOutgoingMessageType(it) }
118118
}
119119

120+
fun getOutgoingMessageProFeatureCount(featureMask: Long): Int {
121+
return getOutgoingProFeatureCountInternal(PRO_MESSAGE_FEATURES, featureMask)
122+
}
123+
124+
fun getOutgoingProfileProFeatureCount(featureMask: Long): Int {
125+
return getOutgoingProFeatureCountInternal(PRO_PROFILE_FEATURES, featureMask)
126+
}
127+
128+
private fun getOutgoingProFeatureCountInternal(column: String, featureMask: Long): Int {
129+
val db = readableDatabase
130+
val outgoingTypes = MmsSmsColumns.Types.OUTGOING_MESSAGE_TYPES.joinToString(",")
131+
132+
// outgoing clause
133+
val outgoingSelection =
134+
"($MESSAGE_BOX & ${MmsSmsColumns.Types.BASE_TYPE_MASK}) IN ($outgoingTypes)"
135+
136+
val where = "($column & $featureMask) != 0 AND $outgoingSelection"
137+
138+
db.query(TABLE_NAME, arrayOf("COUNT(*)"), where, null, null, null, null).use { cursor ->
139+
if (cursor.moveToFirst()) {
140+
return cursor.getInt(0)
141+
}
142+
}
143+
return 0
144+
}
145+
120146
fun isDeletedMessage(id: Long): Boolean =
121147
writableDatabase.query(
122148
TABLE_NAME,
@@ -703,7 +729,7 @@ class MmsDatabase @Inject constructor(
703729
val deletedMessageIDs: MutableList<Long>
704730
val deletedMessagesThreadIDs = hashSetOf<Long>()
705731

706-
writableDatabase.rawQuery(
732+
writableDatabase.rawQuery(
707733
"DELETE FROM $TABLE_NAME WHERE $where RETURNING $ID, $THREAD_ID",
708734
*whereArgs
709735
).use { cursor ->
@@ -1055,12 +1081,12 @@ class MmsDatabase @Inject constructor(
10551081
val quoteText = retrievedQuote?.body
10561082
val quoteMissing = retrievedQuote == null
10571083
val quoteDeck = (
1058-
(retrievedQuote as? MmsMessageRecord)?.slideDeck ?:
1059-
Stream.of(attachmentDatabase.getAttachment(cursor))
1060-
.filter { obj: DatabaseAttachment? -> obj!!.isQuote }
1061-
.toList()
1062-
.let { SlideDeck(context, it) }
1063-
)
1084+
(retrievedQuote as? MmsMessageRecord)?.slideDeck ?:
1085+
Stream.of(attachmentDatabase.getAttachment(cursor))
1086+
.filter { obj: DatabaseAttachment? -> obj!!.isQuote }
1087+
.toList()
1088+
.let { SlideDeck(context, it) }
1089+
)
10641090
return Quote(
10651091
quoteId,
10661092
recipientRepository.getRecipientSync(quoteAuthor.toAddress()),

app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
import dagger.hilt.android.qualifiers.ApplicationContext;
5656
import kotlin.Pair;
5757
import kotlin.Triple;
58+
import network.loki.messenger.libsession_util.protocol.ProFeature;
59+
import network.loki.messenger.libsession_util.protocol.ProMessageFeature;
5860

5961
@Singleton
6062
public class MmsSmsDatabase extends Database {
@@ -427,6 +429,17 @@ public long getConversationCount(long threadId) {
427429
return count;
428430
}
429431

432+
public int getOutgoingMessageProFeatureCount(long featureMask) {
433+
return smsDatabase.get().getOutgoingMessageProFeatureCount(featureMask) +
434+
mmsDatabase.get().getOutgoingMessageProFeatureCount(featureMask);
435+
}
436+
437+
public int getOutgoingProfileProFeatureCount(long featureMask) {
438+
return smsDatabase.get().getOutgoingProfileProFeatureCount(featureMask) +
439+
mmsDatabase.get().getOutgoingProfileProFeatureCount(featureMask);
440+
}
441+
442+
430443
public void incrementReadReceiptCount(SyncMessageId syncMessageId, long timestamp) {
431444
smsDatabase.get().incrementReceiptCount(syncMessageId, false, true);
432445
mmsDatabase.get().incrementReceiptCount(syncMessageId, timestamp, false, true);

app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,39 @@ public boolean isOutgoingMessage(long id) {
294294
return isOutgoing;
295295
}
296296

297+
public int getOutgoingMessageProFeatureCount(long featureMask) {
298+
return getOutgoingProFeatureCountInternal(PRO_MESSAGE_FEATURES, featureMask);
299+
}
300+
301+
public int getOutgoingProfileProFeatureCount(long featureMask) {
302+
return getOutgoingProFeatureCountInternal(PRO_PROFILE_FEATURES, featureMask);
303+
}
304+
305+
private int getOutgoingProFeatureCountInternal(@NonNull String columnName, long featureMask) {
306+
SQLiteDatabase db = getReadableDatabase();
307+
308+
// outgoing clause
309+
StringBuilder outgoingTypes = new StringBuilder();
310+
long[] types = MmsSmsColumns.Types.OUTGOING_MESSAGE_TYPES;
311+
for (int i = 0; i < types.length; i++) {
312+
if (i > 0) outgoingTypes.append(",");
313+
outgoingTypes.append(types[i]);
314+
}
315+
316+
String outgoingSelection =
317+
"(" + TYPE + " & " + MmsSmsColumns.Types.BASE_TYPE_MASK + ") IN (" + outgoingTypes + ")";
318+
319+
String where = "(" + columnName + " & " + featureMask + ") != 0 AND " + outgoingSelection;
320+
321+
try (Cursor cursor = db.query(TABLE_NAME, new String[]{"COUNT(*)"}, where, null, null, null, null)) {
322+
if (cursor != null && cursor.moveToFirst()) {
323+
return cursor.getInt(0);
324+
}
325+
}
326+
327+
return 0;
328+
}
329+
297330
public boolean isDeletedMessage(long id) {
298331
SQLiteDatabase database = getWritableDatabase();
299332
Cursor cursor = null;

app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ import android.content.Context
44
import android.net.Uri
55
import dagger.Lazy
66
import dagger.hilt.android.qualifiers.ApplicationContext
7+
import kotlinx.coroutines.Dispatchers
8+
import kotlinx.coroutines.withContext
79
import network.loki.messenger.libsession_util.MutableConversationVolatileConfig
810
import network.loki.messenger.libsession_util.PRIORITY_PINNED
911
import network.loki.messenger.libsession_util.PRIORITY_VISIBLE
1012
import network.loki.messenger.libsession_util.ReadableUserGroupsConfig
13+
import network.loki.messenger.libsession_util.protocol.ProFeature
14+
import network.loki.messenger.libsession_util.protocol.ProMessageFeature
15+
import network.loki.messenger.libsession_util.protocol.ProProfileFeature
1116
import network.loki.messenger.libsession_util.util.BlindKeyAPI
1217
import network.loki.messenger.libsession_util.util.Bytes
1318
import network.loki.messenger.libsession_util.util.Conversation
@@ -945,6 +950,24 @@ open class Storage @Inject constructor(
945950
}
946951
}
947952

953+
override suspend fun getTotalSentProBadges(): Int =
954+
getTotalSentForFeature(ProProfileFeature.PRO_BADGE)
955+
956+
override suspend fun getTotalSentLongMessages(): Int =
957+
getTotalSentForFeature(ProMessageFeature.HIGHER_CHARACTER_LIMIT)
958+
959+
suspend fun getTotalSentForFeature(feature: ProFeature): Int = withContext(Dispatchers.IO) {
960+
val mask = 1L shl feature.bitIndex
961+
962+
when (feature) {
963+
is ProMessageFeature ->
964+
mmsSmsDatabase.getOutgoingMessageProFeatureCount(mask)
965+
966+
is ProProfileFeature ->
967+
mmsSmsDatabase.getOutgoingProfileProFeatureCount(mask)
968+
}
969+
}
970+
948971
override fun setPinned(address: Address, isPinned: Boolean) {
949972
val isLocalNumber = address.address == getUserPublicKey()
950973
configFactory.withMutableUserConfigs { configs ->

0 commit comments

Comments
 (0)