mirror of
https://github.com/oxen-io/session-android.git
synced 2023-12-14 02:53:01 +01:00
16ca97d2d3
* feat: Add emoji reacts support * Remove message multi-selection * Add emoji reaction model * Add emoji reaction panel * Blur reacts panel background * Show emoji keyboard * Add emoji sprites * Update reaction proto * Emoji database updates * Emoji database refactor * Emoji reaction persistence * Optimize reactions retrieval * Fix emoji group query * Display emojis * Fix emoji persistence * Cleanup * Persistence refactor * Add reactions bottom sheet * Cleanup * Ui tweaks * React with any emoji * Show emoji react notifications * Remove reaction * Show reactions modal on long press * Click to react (+1) with an emoji * Click to react with an emoji * Enable emoji expand/collapse * fix: some compile issues from merge conflicts * fix: compile issues merging quote and media message UI * fix: xml IDs and adding in legacy is selected for future inclusion * Fix view constraints * Fix merge issue * Add message selection option in conversation context menu * Add sogs emoji integration * Handle sogs emoji reactions * Enable sending/deleting sogs emojis * fix: improve the visible message layout * fix: add file IDs to request parameters for message send (#940) * Fix open group polling from seqno instead of last hash (#939) * fix: reset seqno to get recent messages from open groups * build: upgrade build numbers * fix: actually run the migration * Using StringBuilder to construct request url * Fix reaction filter * fix: is_mms added in second projection query * Update default emojis * fix: include legacy and new open groups in server ID tracking (#941) * feat: add hidden moderator and admin roles, separated as they may be used independently in future (#942) * Cleanup * Fix view constraints * Add reactions capability check * Fix reactions alignment * Ui fixes * Display reactions list * feat: add formatted count strings * fix: account for negatives and add tests * Migrate old official open group locations for polling and adding (#932) * feat: adding in first part of open group migrations and tests for migration logic / helpers * feat: test code and migration logic for open groups in the case of no conflicts * feat: add in extra test cases and refactor code for migrator * refactor: migrate open group join URLs and references to server in adding new open groups to catch legacy and re-write it * refactor: joining open groups using OpenGroupUrlParser.kt now * fix: add in compile issues for renamed OpenGroupApi.kt from OpenGroupV2 * fix: prevent duplicates of http/https for new open group DNS and prevent adding new groups based on public key * fix: room and server swapped parameters * fix: replace default server for config messages * fix: actually using public key to de-dupe didn't work for rooms * build: bump version code and name * Display reactions list on open groups for moderators * Ui tweaks * Ui tweaks for moderation * Refactor * fix: compile issue * fix: de-duping joined queries in the get X from cursor * Restore import * fix: colouring the reaction overlay scrubber * fix: highlight colour, show reaction count if 1 or above * Cleanup * fix: light mode accent * fix: light / dark mode themeing in reactions dialog fragment * Emoji notification blinded id check * fix: show reaction list correctly and pass isUserModerator to bind methods * fix: remove unnecessary places for the moderator * fix: X button for removing own react not showing up properly * feat: add clear all header view * fix: migrate the clear all to the correct location * fix: use display instead of base * Truncate emoji sender ids * feat: add notify thread function in thread db * Notify threads on reaction received * fix: design fixes for the reaction list * fix: emoji reactions bottom sheet dialog UI designs * feat: add unsupported emoji reaction * fix: crash and doing vector properly * Fix reaction database queries * Fix background open group adder job * Show new open group reactions * Fetch a maximum of 5 reactors * Handle open group reactions polling conflicts * Add count to user reaction * Show number of additional reactors * fix: unreads set same as the unread query * fix: design changes * fix: update dependency to improve flexboxlayout behaviour, design consistencies * Add select message icon and update long press menu items order and wording * Fix crash on reactors dialog * fix: colours and backgrounds to match designs * fix: add header in recipient item * fix: margins * fix: alignments and layout issues for emoji reactions view * feat: add overflow previews and logic for overflow * Dim action bar * Add emoji search * Search index fix * Set count for 1:1 and closed group reactions when inserting in local database * Use on screen toolbar to allow overlaying * Show/hide scroll to bottom button * feat: add extended properties so it doesn't collapse on re-bind * Cleanup * feat: prevent keeping extended on rebinding if we get a new message ID * fix: long press works on devices now, fix release lint issue and crash for emoji search DBs from emoji builds * Display message timestamp * Fix modal items alignment * fix: sort order and emoji count in compareTo * Scale down really large messages to fit * Prevent closed group crash * Fix reaction author Co-authored-by: charles <charles@oxen.io> Co-authored-by: jubb <hjubb@users.noreply.github.com>
101 lines
3.3 KiB
Kotlin
101 lines
3.3 KiB
Kotlin
package org.thoughtcrime.securesms.database
|
|
|
|
import android.content.Context
|
|
import androidx.core.content.contentValuesOf
|
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
|
import org.thoughtcrime.securesms.database.model.EmojiSearchData
|
|
import org.thoughtcrime.securesms.util.CursorUtil
|
|
import kotlin.math.max
|
|
import kotlin.math.roundToInt
|
|
|
|
/**
|
|
* Contains all info necessary for full-text search of emoji tags.
|
|
*/
|
|
class EmojiSearchDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper) {
|
|
|
|
companion object {
|
|
const val TABLE_NAME = "emoji_search"
|
|
const val LABEL = "label"
|
|
const val EMOJI = "emoji"
|
|
const val CREATE_EMOJI_SEARCH_TABLE_COMMAND = "CREATE VIRTUAL TABLE $TABLE_NAME USING fts5($LABEL, $EMOJI UNINDEXED)"
|
|
}
|
|
|
|
/**
|
|
* @param query A search query. Doesn't need any special formatted -- it'll be sanitized.
|
|
* @return A list of emoji that are related to the search term, ordered by relevance.
|
|
*/
|
|
fun query(originalQuery: String, originalLimit: Int): List<String> {
|
|
val query: String = originalQuery.trim()
|
|
|
|
if (query.isEmpty()) {
|
|
return emptyList()
|
|
}
|
|
|
|
val limit: Int = max(originalLimit, 100)
|
|
val entries = mutableListOf<Entry>()
|
|
|
|
readableDatabase.query(TABLE_NAME, arrayOf(LABEL, EMOJI), "$LABEL LIKE ?", arrayOf("%$query%"), null, null, null, "$limit")
|
|
.use { cursor ->
|
|
while (cursor.moveToNext()) {
|
|
entries += Entry(
|
|
label = CursorUtil.requireString(cursor, LABEL),
|
|
emoji = CursorUtil.requireString(cursor, EMOJI)
|
|
)
|
|
}
|
|
}
|
|
|
|
return entries
|
|
.sortedWith { lhs, rhs ->
|
|
similarityScore(query, lhs.label) - similarityScore(query, rhs.label)
|
|
}
|
|
.distinctBy { it.emoji }
|
|
.take(originalLimit)
|
|
.map { it.emoji }
|
|
}
|
|
|
|
/**
|
|
* Deletes the content of the current search index and replaces it with the new one.
|
|
*/
|
|
fun setSearchIndex(searchIndex: List<EmojiSearchData>) {
|
|
writableDatabase.beginTransaction()
|
|
writableDatabase.delete(TABLE_NAME, null, null)
|
|
|
|
for (searchData in searchIndex) {
|
|
for (label in searchData.tags) {
|
|
val values = contentValuesOf(
|
|
LABEL to label,
|
|
EMOJI to searchData.emoji
|
|
)
|
|
writableDatabase.insert(TABLE_NAME, null, values)
|
|
}
|
|
}
|
|
writableDatabase.setTransactionSuccessful()
|
|
writableDatabase.endTransaction()
|
|
}
|
|
|
|
/**
|
|
* Ranks how "similar" a match is to the original search term.
|
|
* A lower score means more similar, with 0 being a perfect match.
|
|
*
|
|
* We know that the `searchTerm` must be a substring of the `match`.
|
|
* We determine similarity by how many letters appear before or after the `searchTerm` in the `match`.
|
|
* We give letters that come before the term a bigger weight than those that come after as a way to prefer matches that are prefixed by the `searchTerm`.
|
|
*/
|
|
private fun similarityScore(searchTerm: String, match: String): Int {
|
|
if (searchTerm == match) {
|
|
return 0
|
|
}
|
|
|
|
val startIndex = match.indexOf(searchTerm)
|
|
|
|
val prefixCount = startIndex
|
|
val suffixCount = match.length - (startIndex + searchTerm.length)
|
|
|
|
val prefixRankWeight = 1.5f
|
|
val suffixRankWeight = 1f
|
|
|
|
return ((prefixCount * prefixRankWeight) + (suffixCount * suffixRankWeight)).roundToInt()
|
|
}
|
|
|
|
private data class Entry(val label: String, val emoji: String)
|
|
}
|