forked from Ivasoft/mattermost-mobile
Merge branch 'gekidou' into gekidou_account_screen
This commit is contained in:
@@ -8,7 +8,8 @@
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": [
|
||||
"@typescript-eslint",
|
||||
"mattermost"
|
||||
"mattermost",
|
||||
"import"
|
||||
],
|
||||
"settings": {
|
||||
"react": {
|
||||
@@ -58,7 +59,32 @@
|
||||
"singleLine": {
|
||||
"beforeColon": false,
|
||||
"afterColon": true
|
||||
}}]
|
||||
}}],
|
||||
"@typescript-eslint/member-delimiter-style": 2,
|
||||
"import/order": [
|
||||
2,
|
||||
{
|
||||
"groups": ["builtin", "external", "parent", "sibling", "index", "type"],
|
||||
"newlines-between": "always",
|
||||
"pathGroups": [
|
||||
{
|
||||
"pattern": "{@(@actions|@app|@assets|@client|@components|@constants|@context|@database|@helpers|@hooks|@init|@queries|@screens|@selectors|@share|@store|@telemetry|@typings|@test|@utils)/**,@(@constants|@i18n|@notifications|@store|@websocket)}",
|
||||
"group": "external",
|
||||
"position": "after"
|
||||
},
|
||||
{
|
||||
"pattern": "app/**",
|
||||
"group": "parent",
|
||||
"position": "before"
|
||||
}
|
||||
],
|
||||
"alphabetize": {
|
||||
"order": "asc",
|
||||
"caseInsensitive": true
|
||||
},
|
||||
"pathGroupsExcludedImportTypes": ["type"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
|
||||
@@ -224,6 +224,7 @@ configurations.all {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
|
||||
|
||||
//noinspection GradleDynamicVersio
|
||||
implementation "com.facebook.react:react-native:+" // From node_modules
|
||||
|
||||
@@ -89,10 +89,6 @@ public class CustomPushNotificationHelper {
|
||||
}
|
||||
}
|
||||
|
||||
// if (serverUrl == null) {
|
||||
message = "Unknown Server\n" + message;
|
||||
// }
|
||||
|
||||
messagingStyle.addMessage(message, timestamp, sender.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.mattermost.helpers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.nozbe.watermelondb.Database;
|
||||
|
||||
public class DatabaseHelper {
|
||||
private static final String DEFAULT_DATABASE_NAME = "app.db";
|
||||
private static Database defaultDatabase;
|
||||
|
||||
private static void setDefaultDatabase(Context context) {
|
||||
String databaseName = Uri.fromFile(context.getFilesDir()).toString() + "/" + DEFAULT_DATABASE_NAME;
|
||||
defaultDatabase = new Database(databaseName, context);
|
||||
}
|
||||
|
||||
public static String getOnlyServerUrl(Context context) {
|
||||
if (defaultDatabase == null) {
|
||||
setDefaultDatabase(context);
|
||||
}
|
||||
|
||||
String emptyArray[] = {};
|
||||
String query = "SELECT url FROM Servers";
|
||||
Cursor cursor = defaultDatabase.rawQuery(query, emptyArray);
|
||||
|
||||
if (cursor.getCount() == 1) {
|
||||
cursor.moveToFirst();
|
||||
return cursor.getString(0);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,525 @@
|
||||
package com.mattermost.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import com.facebook.react.bridge.Arguments
|
||||
import com.facebook.react.bridge.NoSuchKeyException
|
||||
import com.facebook.react.bridge.ReadableArray
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
import com.nozbe.watermelondb.Database
|
||||
import com.nozbe.watermelondb.mapCursor
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.lang.Exception
|
||||
import java.util.*
|
||||
|
||||
class DatabaseHelper {
|
||||
var defaultDatabase: Database? = null
|
||||
private set
|
||||
|
||||
val onlyServerUrl: String?
|
||||
get() {
|
||||
val query = "SELECT url FROM Servers WHERE last_active_at != 0"
|
||||
val cursor = defaultDatabase!!.rawQuery(query)
|
||||
if (cursor.count == 1) {
|
||||
cursor.moveToFirst()
|
||||
val url = cursor.getString(0)
|
||||
cursor.close()
|
||||
return url
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun init(context: Context) {
|
||||
if (defaultDatabase == null) {
|
||||
setDefaultDatabase(context)
|
||||
}
|
||||
}
|
||||
|
||||
fun find(db: Database, tableName: String, id: String?): ReadableMap? {
|
||||
val args: Array<Any?> = arrayOf(id)
|
||||
try {
|
||||
db.rawQuery("select * from $tableName where id == ? limit 1", args).use { cursor ->
|
||||
if (cursor.count <= 0) {
|
||||
return null
|
||||
}
|
||||
val resultMap = Arguments.createMap()
|
||||
cursor.moveToFirst()
|
||||
resultMap.mapCursor(cursor)
|
||||
return resultMap
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun getDatabaseForServer(context: Context?, serverUrl: String): Database? {
|
||||
val args: Array<Any?> = arrayOf(serverUrl)
|
||||
val query = "SELECT db_path FROM Servers WHERE url=?"
|
||||
val cursor = defaultDatabase!!.rawQuery(query, args)
|
||||
if (cursor.count == 1) {
|
||||
cursor.moveToFirst()
|
||||
val databasePath = cursor.getString(0)
|
||||
cursor.close()
|
||||
return Database(databasePath, context!!)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun queryIds(db: Database, tableName: String, ids: Array<String>): List<String> {
|
||||
val list: MutableList<String> = ArrayList()
|
||||
val args = TextUtils.join(",", Arrays.stream(ids).map { value: String? -> "?" }.toArray())
|
||||
try {
|
||||
db.rawQuery("select distinct id from $tableName where id IN ($args)", ids as Array<Any?>).use { cursor ->
|
||||
if (cursor.count > 0) {
|
||||
while (cursor.moveToNext()) {
|
||||
list.add(cursor.getString(cursor.getColumnIndex("id")))
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
fun queryByColumn(db: Database, tableName: String, columnName: String, values: Array<Any?>): List<String> {
|
||||
val list: MutableList<String> = ArrayList()
|
||||
val args = TextUtils.join(",", Arrays.stream(values).map { value: Any? -> "?" }.toArray())
|
||||
try {
|
||||
db.rawQuery("select distinct $columnName from $tableName where $columnName IN ($args)", values).use { cursor ->
|
||||
if (cursor.count > 0) {
|
||||
while (cursor.moveToNext()) {
|
||||
list.add(cursor.getString(cursor.getColumnIndex(columnName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
fun queryCurrentUserId(db: Database): String? {
|
||||
val result = find(db, "System", "currentUserId")!!
|
||||
return result.getString("value")
|
||||
}
|
||||
|
||||
fun queryPostSinceForChannel(db: Database?, channelId: String): Double? {
|
||||
if (db != null) {
|
||||
val postsInChannelQuery = "SELECT earliest, latest FROM PostsInChannel WHERE channel_id=? ORDER BY latest DESC LIMIT 1"
|
||||
val cursor1 = db.rawQuery(postsInChannelQuery, arrayOf(channelId))
|
||||
if (cursor1.count == 1) {
|
||||
cursor1.moveToFirst()
|
||||
val earliest = cursor1.getDouble(0)
|
||||
val latest = cursor1.getDouble(1)
|
||||
cursor1.close()
|
||||
val postQuery = "SELECT create_at FROM POST WHERE channel_id= ? AND delete_at=0 AND create_at BETWEEN ? AND ? ORDER BY create_at DESC"
|
||||
val cursor2 = db.rawQuery(postQuery, arrayOf(channelId, earliest, latest))
|
||||
if (cursor2.count >= 60) {
|
||||
cursor2.moveToFirst()
|
||||
val createAt = cursor2.getDouble(0)
|
||||
cursor2.close()
|
||||
return createAt
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun handlePosts(db: Database, postsData: ReadableMap?, channelId: String) {
|
||||
// Posts, PostInChannel, PostInThread, Reactions, Files, CustomEmojis, Users
|
||||
if (postsData != null) {
|
||||
val ordered = postsData.getArray("order")?.toArrayList()
|
||||
val posts = ReadableMapUtils.toJSONObject(postsData.getMap("posts")).toMap()
|
||||
val previousPostId = postsData.getString("prev_post_id")
|
||||
val postsInThread = hashMapOf<String, List<JSONObject>>()
|
||||
var earliest = 0.0
|
||||
var latest = 0.0
|
||||
|
||||
if (ordered != null && posts.isNotEmpty()) {
|
||||
val firstId = ordered.first()
|
||||
val lastId = ordered.last()
|
||||
var prevPostId = ""
|
||||
|
||||
val sortedPosts = posts.toList().sortedBy { (_, value) ->
|
||||
((value as Map<*, *>).get("create_at") as Double)
|
||||
}
|
||||
|
||||
sortedPosts.forEachIndexed { index, it ->
|
||||
val key = it.first
|
||||
if (it.second != null) {
|
||||
val post = (it.second as MutableMap<String, Any?>)
|
||||
|
||||
if (index == 0) {
|
||||
post.putIfAbsent("prev_post_id", previousPostId)
|
||||
} else if (!prevPostId.isNullOrEmpty()) {
|
||||
post.putIfAbsent("prev_post_id", prevPostId)
|
||||
}
|
||||
|
||||
if (lastId == key) {
|
||||
earliest = post.get("create_at") as Double
|
||||
} else if (firstId == key) {
|
||||
latest = post.get("create_at") as Double
|
||||
}
|
||||
|
||||
val jsonPost = JSONObject(post)
|
||||
val rootId = post.get("root_id") as? String
|
||||
|
||||
if (!rootId.isNullOrEmpty()) {
|
||||
var thread = postsInThread.get(rootId)?.toMutableList()
|
||||
if (thread == null) {
|
||||
thread = mutableListOf()
|
||||
}
|
||||
|
||||
thread.add(jsonPost)
|
||||
postsInThread.put(rootId, thread.toList())
|
||||
}
|
||||
|
||||
if (find(db, "Post", key) == null) {
|
||||
insertPost(db, jsonPost)
|
||||
} else {
|
||||
updatePost(db, jsonPost)
|
||||
}
|
||||
|
||||
if (ordered.contains(key)) {
|
||||
prevPostId = key
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handlePostsInChannel(db, channelId, earliest, latest)
|
||||
handlePostsInThread(db, postsInThread)
|
||||
}
|
||||
}
|
||||
|
||||
fun handleUsers(db: Database, users: ReadableArray) {
|
||||
for (i in 0 until users.size()) {
|
||||
val user = users.getMap(i)
|
||||
val roles = user.getString("roles") ?: ""
|
||||
val isBot = try {
|
||||
user.getBoolean("is_bot")
|
||||
} catch (e: NoSuchKeyException) {
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
db.execute(
|
||||
"insert into User (id, auth_service, update_at, delete_at, email, first_name, is_bot, is_guest, " +
|
||||
"last_name, last_picture_update, locale, nickname, position, roles, status, username, notify_props, " +
|
||||
"props, timezone, _status) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'created')",
|
||||
arrayOf(
|
||||
user.getString("id"),
|
||||
user.getString("auth_service"),
|
||||
user.getDouble("update_at"),
|
||||
user.getDouble("delete_at"),
|
||||
user.getString("email"),
|
||||
user.getString("first_name"),
|
||||
isBot,
|
||||
roles.contains("system_guest"),
|
||||
user.getString("last_name"),
|
||||
user.getDouble("last_picture_update"),
|
||||
user.getString("locale"),
|
||||
user.getString("nickname"),
|
||||
user.getString("position"),
|
||||
roles,
|
||||
"",
|
||||
user.getString("username"),
|
||||
"{}",
|
||||
ReadableMapUtils.toJSONObject(user.getMap("props") ?: Arguments.createMap()).toString(),
|
||||
ReadableMapUtils.toJSONObject(user.getMap("timezone") ?: Arguments.createMap()).toString(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setDefaultDatabase(context: Context) {
|
||||
val databaseName = "app.db"
|
||||
val databasePath = Uri.fromFile(context.filesDir).toString() + "/" + databaseName
|
||||
defaultDatabase = Database(databasePath, context)
|
||||
}
|
||||
|
||||
private fun insertPost(db: Database, post: JSONObject) {
|
||||
var metadata: JSONObject? = null
|
||||
var reactions: JSONArray? = null
|
||||
var customEmojis: JSONArray? = null
|
||||
var files: JSONArray? = null
|
||||
|
||||
try {
|
||||
metadata = post.getJSONObject("metadata")
|
||||
reactions = metadata.remove("reactions") as JSONArray?
|
||||
customEmojis = metadata.remove("emojis") as JSONArray?
|
||||
files = metadata.remove("files") as JSONArray?
|
||||
} catch (e: Exception) {
|
||||
// no metadata found
|
||||
metadata = JSONObject()
|
||||
}
|
||||
|
||||
db.execute(
|
||||
"insert into Post " +
|
||||
"(id, channel_id, create_at, delete_at, update_at, edit_at, is_pinned, message, metadata, original_id, pending_post_id, " +
|
||||
"previous_post_id, root_id, type, user_id, props, _status)" +
|
||||
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'created')",
|
||||
arrayOf(
|
||||
post.getString("id"),
|
||||
post.getString("channel_id"),
|
||||
post.getDouble("create_at"),
|
||||
post.getDouble("delete_at"),
|
||||
post.getDouble("update_at"),
|
||||
post.getDouble("edit_at"),
|
||||
post.getBoolean("is_pinned"),
|
||||
post.getString("message"),
|
||||
metadata.toString(),
|
||||
post.getString("original_id"),
|
||||
post.getString("pending_post_id"),
|
||||
post.getString("prev_post_id"),
|
||||
post.getString("root_id"),
|
||||
post.getString("type"),
|
||||
post.getString("user_id"),
|
||||
post.getJSONObject("props").toString()
|
||||
)
|
||||
)
|
||||
|
||||
if (reactions != null && reactions.length() > 0) {
|
||||
insertReactions(db, reactions)
|
||||
}
|
||||
|
||||
if (customEmojis != null && customEmojis.length() > 0) {
|
||||
insertCustomEmojis(db, customEmojis)
|
||||
}
|
||||
|
||||
if (files != null && files.length() > 0) {
|
||||
insertFiles(db, files)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePost(db: Database, post: JSONObject) {
|
||||
var metadata: JSONObject? = null
|
||||
var reactions: JSONArray? = null
|
||||
var customEmojis: JSONArray? = null
|
||||
|
||||
try {
|
||||
metadata = post.getJSONObject("metadata")
|
||||
reactions = metadata.remove("reactions") as JSONArray?
|
||||
customEmojis = metadata.remove("emojis") as JSONArray?
|
||||
metadata.remove("files")
|
||||
} catch (e: Exception) {
|
||||
// no metadata found
|
||||
metadata = JSONObject()
|
||||
}
|
||||
|
||||
db.execute(
|
||||
"update Post SET channel_id = ?, create_at = ?, delete_at = ?, update_at =?, edit_at =?, " +
|
||||
"is_pinned = ?, message = ?, metadata = ?, original_id = ?, pending_post_id = ?, previous_post_id = ?, " +
|
||||
"root_id = ?, type = ?, user_id = ?, props = ?, _status = 'updated' " +
|
||||
"where id = ?",
|
||||
arrayOf(
|
||||
post.getString("channel_id"),
|
||||
post.getDouble("create_at"),
|
||||
post.getDouble("delete_at"),
|
||||
post.getDouble("update_at"),
|
||||
post.getDouble("edit_at"),
|
||||
post.getBoolean("is_pinned"),
|
||||
post.getString("message"),
|
||||
metadata.toString(),
|
||||
post.getString("original_id"),
|
||||
post.getString("pending_post_id"),
|
||||
post.getString("prev_post_id"),
|
||||
post.getString("root_id"),
|
||||
post.getString("type"),
|
||||
post.getString("user_id"),
|
||||
post.getJSONObject("props").toString(),
|
||||
post.getString("id"),
|
||||
)
|
||||
)
|
||||
|
||||
if (reactions != null && reactions.length() > 0) {
|
||||
db.execute("delete from Reaction where post_id = ?", arrayOf(post.getString("id")))
|
||||
insertReactions(db, reactions)
|
||||
}
|
||||
|
||||
if (customEmojis != null && customEmojis.length() > 0) {
|
||||
insertCustomEmojis(db, customEmojis)
|
||||
}
|
||||
}
|
||||
|
||||
private fun insertCustomEmojis(db: Database, customEmojis: JSONArray) {
|
||||
for (i in 0 until customEmojis.length()) {
|
||||
val emoji = customEmojis.getJSONObject(i)
|
||||
if(find(db, "CustomEmoji", emoji.getString("id")) == null) {
|
||||
db.execute(
|
||||
"insert into CustomEmoji (id, name, _status) values (?, ?, 'created')",
|
||||
arrayOf(
|
||||
emoji.getString("id"),
|
||||
emoji.getString("name"),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun insertFiles(db: Database, files: JSONArray) {
|
||||
for (i in 0 until files.length()) {
|
||||
val file = files.getJSONObject(i)
|
||||
db.execute(
|
||||
"insert into File (id, extension, height, image_thumbnail, local_path, mime_type, name, post_id, size, width, _status) " +
|
||||
"values (?, ?, ?, ?, '', ?, ?, ?, ?, ?, 'created')",
|
||||
arrayOf(
|
||||
file.getString("id"),
|
||||
file.getString("extension"),
|
||||
file.getInt("height"),
|
||||
file.getString("mini_preview"),
|
||||
file.getString("mime_type"),
|
||||
file.getString("name"),
|
||||
file.getString("post_id"),
|
||||
file.getDouble("size"),
|
||||
file.getInt("width")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun insertReactions(db: Database, reactions: JSONArray) {
|
||||
for (i in 0 until reactions.length()) {
|
||||
val reaction = reactions.getJSONObject(i)
|
||||
val id = RandomId.generate()
|
||||
db.execute(
|
||||
"insert into Reaction (id, create_at, emoji_name, post_id, user_id, _status) " +
|
||||
"values (?, ?, ?, ?, ?, 'created')",
|
||||
arrayOf(
|
||||
id,
|
||||
reaction.getDouble("create_at"),
|
||||
reaction.getString("emoji_name"),
|
||||
reaction.getString("post_id"),
|
||||
reaction.getString("user_id")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePostsInChannel(db: Database, channelId: String, earliest: Double, latest: Double) {
|
||||
db.rawQuery("select id, channel_id, earliest, latest from PostsInChannel where channel_id = ?", arrayOf(channelId)).use { cursor ->
|
||||
if (cursor.count == 0) {
|
||||
// create new post in channel
|
||||
insertPostInChannel(db, channelId, earliest, latest)
|
||||
return
|
||||
}
|
||||
|
||||
val resultArray = Arguments.createArray()
|
||||
while (cursor.moveToNext()) {
|
||||
val cursorMap = Arguments.createMap()
|
||||
cursorMap.mapCursor(cursor)
|
||||
resultArray.pushMap(cursorMap)
|
||||
}
|
||||
|
||||
val chunk = findPostInChannel(resultArray, earliest, latest)
|
||||
if (chunk != null) {
|
||||
db.execute(
|
||||
"update PostsInChannel set earliest = ?, latest = ?, _status = 'updated' where id = ?",
|
||||
arrayOf(
|
||||
minOf(earliest, chunk.getDouble("earliest")),
|
||||
maxOf(latest, chunk.getDouble("latest")),
|
||||
chunk.getString("id")
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val newChunk = insertPostInChannel(db, channelId, earliest, latest)
|
||||
mergePostsInChannel(db, resultArray, newChunk)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findPostInChannel(chunks: ReadableArray, earliest: Double, latest: Double): ReadableMap? {
|
||||
for (i in 0 until chunks.size()) {
|
||||
val chunk = chunks.getMap(i)
|
||||
if (earliest >= chunk.getDouble("earliest") || latest <= chunk.getDouble("latest")) {
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private fun insertPostInChannel(db: Database, channelId: String, earliest: Double, latest: Double): ReadableMap {
|
||||
val id = RandomId.generate()
|
||||
db.execute("insert into PostsInChannel (id, channel_id, earliest, latest, _status) values (?, ?, ?, ?, 'created')",
|
||||
arrayOf(id, channelId, earliest, latest))
|
||||
|
||||
val map = Arguments.createMap()
|
||||
map.putString("id", id)
|
||||
map.putString("channel_id", channelId)
|
||||
map.putDouble("earliest", earliest)
|
||||
map.putDouble("latest", latest)
|
||||
return map
|
||||
}
|
||||
|
||||
private fun mergePostsInChannel(db: Database, existingChunks: ReadableArray, newChunk: ReadableMap) {
|
||||
for (i in 0 until existingChunks.size()) {
|
||||
val chunk = existingChunks.getMap(i)
|
||||
if (newChunk.getDouble("earliest") <= chunk.getDouble("earliest") &&
|
||||
newChunk.getDouble("latest") >= chunk.getDouble("latest")) {
|
||||
db.execute("delete from PostsInChannel where id = ?", arrayOf(chunk.getString("id")))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePostsInThread(db: Database, postsInThread: Map<String, List<JSONObject>>) {
|
||||
postsInThread.forEach { (key, list) ->
|
||||
val sorted = list.sortedBy { it.getDouble("create_at") }
|
||||
val earliest = sorted.first().getDouble("create_at")
|
||||
val latest = sorted.last().getDouble("create_at")
|
||||
db.rawQuery("select * from PostsInThread where root_id = ? order by latest desc", arrayOf(key)).use { cursor ->
|
||||
if (cursor.count > 0) {
|
||||
cursor.moveToFirst()
|
||||
val cursorMap = Arguments.createMap()
|
||||
cursorMap.mapCursor(cursor)
|
||||
db.execute(
|
||||
"update PostsInThread set earliest = ?, latest = ?, _status = 'updated' where id = ?",
|
||||
arrayOf(
|
||||
minOf(earliest, cursorMap.getDouble("earliest")),
|
||||
maxOf(latest, cursorMap.getDouble("latest")),
|
||||
key
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val id = RandomId.generate()
|
||||
db.execute(
|
||||
"insert into PostsInThread (id, root_id, earliest, latest, _status) " +
|
||||
"values (?, ?, ?, ?, 'created')",
|
||||
arrayOf(id, key, earliest, latest)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun JSONObject.toMap(): Map<String, *> = keys().asSequence().associateWith {
|
||||
when (val value = this[it])
|
||||
{
|
||||
is JSONArray ->
|
||||
{
|
||||
val map = (0 until value.length()).associate { Pair(it.toString(), value[it]) }
|
||||
JSONObject(map).toMap().values.toList()
|
||||
}
|
||||
is JSONObject -> value.toMap()
|
||||
JSONObject.NULL -> null
|
||||
else -> value
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var instance: DatabaseHelper? = null
|
||||
get() {
|
||||
if (field == null) {
|
||||
field = DatabaseHelper()
|
||||
}
|
||||
return field
|
||||
}
|
||||
private set
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.mattermost.helpers;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
import com.mattermost.networkclient.APIClientModule;
|
||||
import com.mattermost.networkclient.enums.RetryTypes;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
|
||||
public class Network {
|
||||
private static APIClientModule clientModule;
|
||||
private static final WritableMap clientOptions = Arguments.createMap();
|
||||
private static final Promise emptyPromise = new ResolvePromise();
|
||||
|
||||
public static void init(Context context) {
|
||||
final ReactApplicationContext reactContext = new ReactApplicationContext(context);
|
||||
clientModule = new APIClientModule(reactContext);
|
||||
createClientOptions();
|
||||
}
|
||||
|
||||
public static void get(String baseUrl, String endpoint, ReadableMap options, Promise promise) {
|
||||
createClientIfNeeded(baseUrl);
|
||||
clientModule.get(baseUrl, endpoint, options, promise);
|
||||
}
|
||||
|
||||
public static void post(String baseUrl, String endpoint, ReadableMap options, Promise promise) {
|
||||
createClientIfNeeded(baseUrl);
|
||||
clientModule.post(baseUrl, endpoint, options, promise);
|
||||
}
|
||||
|
||||
private static void createClientOptions() {
|
||||
WritableMap headers = Arguments.createMap();
|
||||
headers.putString("X-Requested-With", "XMLHttpRequest");
|
||||
clientOptions.putMap("headers", headers);
|
||||
|
||||
WritableMap retryPolicyConfiguration = Arguments.createMap();
|
||||
retryPolicyConfiguration.putString("type", RetryTypes.EXPONENTIAL_RETRY.getType());
|
||||
retryPolicyConfiguration.putDouble("retryLimit", 2);
|
||||
retryPolicyConfiguration.putDouble("exponentialBackoffBase", 2);
|
||||
retryPolicyConfiguration.putDouble("exponentialBackoffScale", 0.5);
|
||||
clientOptions.putMap("retryPolicyConfiguration", retryPolicyConfiguration);
|
||||
|
||||
WritableMap requestAdapterConfiguration = Arguments.createMap();
|
||||
requestAdapterConfiguration.putString("bearerAuthTokenResponseHeader", "token");
|
||||
clientOptions.putMap("requestAdapterConfiguration", requestAdapterConfiguration);
|
||||
|
||||
WritableMap sessionConfiguration = Arguments.createMap();
|
||||
sessionConfiguration.putInt("httpMaximumConnectionsPerHost", 10);
|
||||
sessionConfiguration.putDouble("timeoutIntervalForRequest", 30000);
|
||||
sessionConfiguration.putDouble("timeoutIntervalForResource", 30000);
|
||||
clientOptions.putMap("sessionConfiguration", sessionConfiguration);
|
||||
}
|
||||
|
||||
private static void createClientIfNeeded(String baseUrl) {
|
||||
HttpUrl url = HttpUrl.parse(baseUrl);
|
||||
if (url != null && !clientModule.hasClientFor(url)) {
|
||||
clientModule.createClientFor(baseUrl, clientOptions, emptyPromise);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package com.mattermost.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import com.facebook.react.bridge.Arguments
|
||||
import com.facebook.react.bridge.ReadableArray
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
import com.nozbe.watermelondb.Database
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.coroutines.*
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
class PushNotificationDataHelper(private val context: Context) {
|
||||
private var scope = Executors.newSingleThreadExecutor()
|
||||
fun fetchAndStoreDataForPushNotification(initialData: Bundle) {
|
||||
scope.execute(Runnable {
|
||||
runBlocking {
|
||||
PushNotificationDataRunnable.start(context, initialData)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class PushNotificationDataRunnable {
|
||||
companion object {
|
||||
private val specialMentions = listOf<String>("all", "here", "channel")
|
||||
@Synchronized
|
||||
suspend fun start(context: Context, initialData: Bundle) {
|
||||
try {
|
||||
val serverUrl: String = initialData.getString("server_url") ?: return
|
||||
val channelId = initialData.getString("channel_id")
|
||||
val db = DatabaseHelper.instance!!.getDatabaseForServer(context, serverUrl)
|
||||
|
||||
if (db != null) {
|
||||
var postData: ReadableMap?
|
||||
var posts: ReadableMap? = null
|
||||
var userIdsToLoad: ReadableArray? = null
|
||||
var usernamesToLoad: ReadableArray? = null
|
||||
|
||||
coroutineScope {
|
||||
if (channelId != null) {
|
||||
postData = fetchPosts(db, serverUrl, channelId)
|
||||
posts = postData?.getMap("posts")
|
||||
userIdsToLoad = postData?.getArray("userIdsToLoad")
|
||||
usernamesToLoad = postData?.getArray("usernamesToLoad")
|
||||
|
||||
if (userIdsToLoad != null && userIdsToLoad!!.size() > 0) {
|
||||
val users = fetchUsersById(serverUrl, userIdsToLoad!!)
|
||||
userIdsToLoad = users?.getArray("data")
|
||||
}
|
||||
|
||||
if (usernamesToLoad != null && usernamesToLoad!!.size() > 0) {
|
||||
val users = fetchUsersByUsernames(serverUrl, usernamesToLoad!!)
|
||||
usernamesToLoad = users?.getArray("data")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db.transaction {
|
||||
if (posts != null && channelId != null) {
|
||||
DatabaseHelper.instance!!.handlePosts(db, posts!!.getMap("data"), channelId)
|
||||
}
|
||||
|
||||
if (userIdsToLoad != null && userIdsToLoad!!.size() > 0) {
|
||||
DatabaseHelper.instance!!.handleUsers(db, userIdsToLoad!!)
|
||||
}
|
||||
|
||||
if (usernamesToLoad != null && usernamesToLoad!!.size() > 0) {
|
||||
DatabaseHelper.instance!!.handleUsers(db, usernamesToLoad!!)
|
||||
}
|
||||
}
|
||||
|
||||
db.close()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchPosts(db: Database, serverUrl: String, channelId: String): ReadableMap? {
|
||||
val regex = Regex("""\B@(([a-z0-9-._]*[a-z0-9_])[.-]*)""", setOf(RegexOption.IGNORE_CASE))
|
||||
val since = DatabaseHelper.instance!!.queryPostSinceForChannel(db, channelId)
|
||||
val currentUserId = DatabaseHelper.instance!!.queryCurrentUserId(db)?.removeSurrounding("\"")
|
||||
val currentUser = DatabaseHelper.instance!!.find(db, "User", currentUserId)
|
||||
val currentUsername = currentUser?.getString("username")
|
||||
val queryParams = if (since == null) "?page=0&per_page=60" else "?since=${since.toLong()}"
|
||||
val endpoint = "/api/v4/channels/$channelId/posts$queryParams"
|
||||
val postsResponse = fetch(serverUrl, endpoint)
|
||||
val results = Arguments.createMap()
|
||||
|
||||
if (postsResponse != null) {
|
||||
val data = ReadableMapUtils.toMap(postsResponse)
|
||||
results.putMap("posts", postsResponse)
|
||||
val postsData = data.get("data") as? Map<*, *>
|
||||
if (postsData != null) {
|
||||
val postsMap = postsData.get("posts")
|
||||
if (postsMap != null) {
|
||||
val posts = ReadableMapUtils.toWritableMap(postsMap as? Map<String, Object>)
|
||||
val iterator = posts.keySetIterator()
|
||||
val userIds = mutableListOf<String>()
|
||||
val usernames = mutableListOf<String>()
|
||||
while(iterator.hasNextKey()) {
|
||||
val key = iterator.nextKey()
|
||||
val post = posts.getMap(key)
|
||||
val userId = post?.getString("user_id")
|
||||
if (userId != null && userId != currentUserId && !userIds.contains(userId)) {
|
||||
userIds.add(userId)
|
||||
}
|
||||
val message = post?.getString("message")
|
||||
if (message != null) {
|
||||
val matchResults = regex.findAll(message)
|
||||
matchResults.iterator().forEach {
|
||||
val username = it.value.removePrefix("@")
|
||||
if (!usernames.contains(username) && currentUsername != username && !specialMentions.contains(username)) {
|
||||
usernames.add(username)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val existingUserIds = DatabaseHelper.instance!!.queryIds(db, "User", userIds.toTypedArray())
|
||||
val existingUsernames = DatabaseHelper.instance!!.queryByColumn(db, "User", "username", usernames.toTypedArray())
|
||||
userIds.removeAll { it in existingUserIds }
|
||||
usernames.removeAll { it in existingUsernames }
|
||||
|
||||
if (userIds.size > 0) {
|
||||
results.putArray("userIdsToLoad", ReadableArrayUtils.toWritableArray(userIds.toTypedArray()))
|
||||
}
|
||||
|
||||
if (usernames.size > 0) {
|
||||
results.putArray("usernamesToLoad", ReadableArrayUtils.toWritableArray(usernames.toTypedArray()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
private suspend fun fetchUsersById(serverUrl: String, userIds: ReadableArray): ReadableMap? {
|
||||
val endpoint = "api/v4/users/ids"
|
||||
val options = Arguments.createMap()
|
||||
options.putArray("body", ReadableArrayUtils.toWritableArray(ReadableArrayUtils.toArray(userIds)))
|
||||
return fetchWithPost(serverUrl, endpoint, options);
|
||||
}
|
||||
|
||||
private suspend fun fetchUsersByUsernames(serverUrl: String, usernames: ReadableArray): ReadableMap? {
|
||||
val endpoint = "api/v4/users/usernames"
|
||||
val options = Arguments.createMap()
|
||||
options.putArray("body", ReadableArrayUtils.toWritableArray(ReadableArrayUtils.toArray(usernames)))
|
||||
return fetchWithPost(serverUrl, endpoint, options);
|
||||
}
|
||||
|
||||
private suspend fun fetch(serverUrl: String, endpoint: String): ReadableMap? {
|
||||
return suspendCoroutine { cont ->
|
||||
Network.get(serverUrl, endpoint, null, object : ResolvePromise() {
|
||||
override fun resolve(value: Any?) {
|
||||
val response = value as ReadableMap?
|
||||
if (response != null && !response.getBoolean("ok")) {
|
||||
val error = response.getMap("data")
|
||||
cont.resumeWith(Result.failure((IOException("Unexpected code ${error?.getInt("status_code")} ${error?.getString("message")}"))))
|
||||
} else {
|
||||
cont.resumeWith(Result.success(response))
|
||||
}
|
||||
}
|
||||
|
||||
override fun reject(code: String, message: String) {
|
||||
cont.resumeWith(Result.failure(IOException("Unexpected code $code $message")))
|
||||
}
|
||||
|
||||
override fun reject(reason: Throwable?) {
|
||||
cont.resumeWith(Result.failure(IOException("Unexpected code $reason")))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchWithPost(serverUrl: String, endpoint: String, options: ReadableMap?) : ReadableMap? {
|
||||
return suspendCoroutine { cont ->
|
||||
Network.post(serverUrl, endpoint, options, object : ResolvePromise() {
|
||||
override fun resolve(value: Any?) {
|
||||
val response = value as ReadableMap?
|
||||
cont.resumeWith(Result.success(response))
|
||||
}
|
||||
|
||||
override fun reject(code: String, message: String) {
|
||||
cont.resumeWith(Result.failure(IOException("Unexpected code $code $message")))
|
||||
}
|
||||
|
||||
override fun reject(reason: Throwable?) {
|
||||
cont.resumeWith(Result.failure(IOException("Unexpected code $reason")))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
android/app/src/main/java/com/mattermost/helpers/RandomId.kt
Normal file
22
android/app/src/main/java/com/mattermost/helpers/RandomId.kt
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.mattermost.helpers
|
||||
|
||||
import kotlin.math.floor
|
||||
|
||||
class RandomId {
|
||||
companion object {
|
||||
private const val alphabet = "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||
private const val alphabetLenght = alphabet.length
|
||||
private const val idLenght = 16
|
||||
|
||||
fun generate(): String {
|
||||
var id = ""
|
||||
for (i in 1.rangeTo((idLenght / 2))) {
|
||||
val random = floor(Math.random() * alphabetLenght * alphabetLenght)
|
||||
id += alphabet[floor(random / alphabetLenght).toInt()]
|
||||
id += alphabet[(random % alphabetLenght).toInt()]
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.mattermost.helpers;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableType;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONException;
|
||||
|
||||
public class ReadableArrayUtils {
|
||||
public static JSONArray toJSONArray(ReadableArray readableArray) throws JSONException {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
|
||||
for (int i = 0; i < readableArray.size(); i++) {
|
||||
ReadableType type = readableArray.getType(i);
|
||||
|
||||
switch (type) {
|
||||
case Null:
|
||||
jsonArray.put(i, null);
|
||||
break;
|
||||
case Boolean:
|
||||
jsonArray.put(i, readableArray.getBoolean(i));
|
||||
break;
|
||||
case Number:
|
||||
jsonArray.put(i, readableArray.getDouble(i));
|
||||
break;
|
||||
case String:
|
||||
jsonArray.put(i, readableArray.getString(i));
|
||||
break;
|
||||
case Map:
|
||||
jsonArray.put(i, ReadableMapUtils.toJSONObject(readableArray.getMap(i)));
|
||||
break;
|
||||
case Array:
|
||||
jsonArray.put(i, ReadableArrayUtils.toJSONArray(readableArray.getArray(i)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
public static Object[] toArray(JSONArray jsonArray) throws JSONException {
|
||||
Object[] array = new Object[jsonArray.length()];
|
||||
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
Object value = jsonArray.get(i);
|
||||
|
||||
if (value instanceof JSONObject) {
|
||||
value = ReadableMapUtils.toMap((JSONObject) value);
|
||||
}
|
||||
if (value instanceof JSONArray) {
|
||||
value = ReadableArrayUtils.toArray((JSONArray) value);
|
||||
}
|
||||
|
||||
array[i] = value;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public static Object[] toArray(ReadableArray readableArray) {
|
||||
Object[] array = new Object[readableArray.size()];
|
||||
|
||||
for (int i = 0; i < readableArray.size(); i++) {
|
||||
ReadableType type = readableArray.getType(i);
|
||||
|
||||
switch (type) {
|
||||
case Null:
|
||||
array[i] = null;
|
||||
break;
|
||||
case Boolean:
|
||||
array[i] = readableArray.getBoolean(i);
|
||||
break;
|
||||
case Number:
|
||||
array[i] = readableArray.getDouble(i);
|
||||
break;
|
||||
case String:
|
||||
array[i] = readableArray.getString(i);
|
||||
break;
|
||||
case Map:
|
||||
array[i] = ReadableMapUtils.toMap(readableArray.getMap(i));
|
||||
break;
|
||||
case Array:
|
||||
array[i] = ReadableArrayUtils.toArray(readableArray.getArray(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public static WritableArray toWritableArray(Object[] array) {
|
||||
WritableArray writableArray = Arguments.createArray();
|
||||
|
||||
for (Object value : array) {
|
||||
if (value == null) {
|
||||
writableArray.pushNull();
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
writableArray.pushBoolean((Boolean) value);
|
||||
}
|
||||
if (value instanceof Double) {
|
||||
writableArray.pushDouble((Double) value);
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
writableArray.pushInt((Integer) value);
|
||||
}
|
||||
if (value instanceof String) {
|
||||
writableArray.pushString((String) value);
|
||||
}
|
||||
if (value instanceof Map) {
|
||||
writableArray.pushMap(ReadableMapUtils.toWritableMap((Map<String, Object>) value));
|
||||
}
|
||||
if (value.getClass().isArray()) {
|
||||
writableArray.pushArray(ReadableArrayUtils.toWritableArray((Object[]) value));
|
||||
}
|
||||
}
|
||||
|
||||
return writableArray;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.mattermost.helpers;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
||||
import com.facebook.react.bridge.ReadableType;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
public class ReadableMapUtils {
|
||||
public static JSONObject toJSONObject(ReadableMap readableMap) throws JSONException {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
|
||||
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
|
||||
|
||||
while (iterator.hasNextKey()) {
|
||||
String key = iterator.nextKey();
|
||||
ReadableType type = readableMap.getType(key);
|
||||
|
||||
switch (type) {
|
||||
case Null:
|
||||
jsonObject.put(key, null);
|
||||
break;
|
||||
case Boolean:
|
||||
jsonObject.put(key, readableMap.getBoolean(key));
|
||||
break;
|
||||
case Number:
|
||||
jsonObject.put(key, readableMap.getDouble(key));
|
||||
break;
|
||||
case String:
|
||||
jsonObject.put(key, readableMap.getString(key));
|
||||
break;
|
||||
case Map:
|
||||
jsonObject.put(key, ReadableMapUtils.toJSONObject(readableMap.getMap(key)));
|
||||
break;
|
||||
case Array:
|
||||
jsonObject.put(key, ReadableArrayUtils.toJSONArray(readableMap.getArray(key)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
public static Map<String, Object> toMap(JSONObject jsonObject) throws JSONException {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
Iterator<String> iterator = jsonObject.keys();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
String key = iterator.next();
|
||||
Object value = jsonObject.get(key);
|
||||
|
||||
if (value instanceof JSONObject) {
|
||||
value = ReadableMapUtils.toMap((JSONObject) value);
|
||||
}
|
||||
if (value instanceof JSONArray) {
|
||||
value = ReadableArrayUtils.toArray((JSONArray) value);
|
||||
}
|
||||
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public static Map<String, Object> toMap(ReadableMap readableMap) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
|
||||
|
||||
while (iterator.hasNextKey()) {
|
||||
String key = iterator.nextKey();
|
||||
ReadableType type = readableMap.getType(key);
|
||||
|
||||
switch (type) {
|
||||
case Null:
|
||||
map.put(key, null);
|
||||
break;
|
||||
case Boolean:
|
||||
map.put(key, readableMap.getBoolean(key));
|
||||
break;
|
||||
case Number:
|
||||
map.put(key, readableMap.getDouble(key));
|
||||
break;
|
||||
case String:
|
||||
map.put(key, readableMap.getString(key));
|
||||
break;
|
||||
case Map:
|
||||
map.put(key, ReadableMapUtils.toMap(readableMap.getMap(key)));
|
||||
break;
|
||||
case Array:
|
||||
map.put(key, ReadableArrayUtils.toArray(readableMap.getArray(key)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public static WritableMap toWritableMap(Map<String, Object> map) {
|
||||
WritableMap writableMap = Arguments.createMap();
|
||||
Iterator iterator = map.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry pair = (Map.Entry)iterator.next();
|
||||
Object value = pair.getValue();
|
||||
|
||||
if (value == null) {
|
||||
writableMap.putNull((String) pair.getKey());
|
||||
} else if (value instanceof Boolean) {
|
||||
writableMap.putBoolean((String) pair.getKey(), (Boolean) value);
|
||||
} else if (value instanceof Double) {
|
||||
writableMap.putDouble((String) pair.getKey(), (Double) value);
|
||||
} else if (value instanceof Integer) {
|
||||
writableMap.putInt((String) pair.getKey(), (Integer) value);
|
||||
} else if (value instanceof String) {
|
||||
writableMap.putString((String) pair.getKey(), (String) value);
|
||||
} else if (value instanceof Map) {
|
||||
writableMap.putMap((String) pair.getKey(), ReadableMapUtils.toWritableMap((Map<String, Object>) value));
|
||||
} else if (value.getClass() != null && value.getClass().isArray()) {
|
||||
writableMap.putArray((String) pair.getKey(), ReadableArrayUtils.toWritableArray((Object[]) value));
|
||||
}
|
||||
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
return writableMap;
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,13 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.mattermost.helpers.CustomPushNotificationHelper;
|
||||
import com.mattermost.helpers.DatabaseHelper;
|
||||
import com.mattermost.helpers.Network;
|
||||
import com.mattermost.helpers.PushNotificationDataHelper;
|
||||
import com.mattermost.helpers.ResolvePromise;
|
||||
import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
|
||||
import com.wix.reactnativenotifications.core.ProxyService;
|
||||
import com.wix.reactnativenotifications.core.notification.PushNotification;
|
||||
import com.wix.reactnativenotifications.core.AppLaunchHelper;
|
||||
import com.wix.reactnativenotifications.core.AppLifecycleFacade;
|
||||
@@ -43,12 +44,16 @@ public class CustomPushNotification extends PushNotification {
|
||||
private static final String PUSH_TYPE_CLEAR = "clear";
|
||||
private static final String PUSH_TYPE_SESSION = "session";
|
||||
private static final String NOTIFICATIONS_IN_CHANNEL = "notificationsInChannel";
|
||||
private final PushNotificationDataHelper dataHelper;
|
||||
|
||||
public CustomPushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper jsIoHelper) {
|
||||
super(context, bundle, appLifecycleFacade, appLaunchHelper, jsIoHelper);
|
||||
CustomPushNotificationHelper.createNotificationChannels(context);
|
||||
dataHelper = new PushNotificationDataHelper(context);
|
||||
|
||||
try {
|
||||
Objects.requireNonNull(DatabaseHelper.Companion.getInstance()).init(context);
|
||||
Network.init(context);
|
||||
PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||
String version = String.valueOf(pInfo.versionCode);
|
||||
String storedVersion = null;
|
||||
@@ -151,7 +156,9 @@ public class CustomPushNotification extends PushNotification {
|
||||
public void resolve(@Nullable Object value) {
|
||||
if (isIdLoaded) {
|
||||
Bundle response = (Bundle) value;
|
||||
addServerUrlToBundle(response);
|
||||
if (value != null) {
|
||||
addServerUrlToBundle(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,10 +176,14 @@ public class CustomPushNotification extends PushNotification {
|
||||
if (!mAppLifecycleFacade.isAppVisible()) {
|
||||
if (type.equals(PUSH_TYPE_MESSAGE)) {
|
||||
if (channelId != null) {
|
||||
if (serverUrl != null) {
|
||||
dataHelper.fetchAndStoreDataForPushNotification(mNotificationProps.asBundle());
|
||||
}
|
||||
|
||||
Map<String, List<Integer>> notificationsInChannel = loadNotificationsMap(mContext);
|
||||
List<Integer> list = notificationsInChannel.get(channelId);
|
||||
if (list == null) {
|
||||
list = Collections.synchronizedList(new ArrayList(0));
|
||||
list = Collections.synchronizedList(new ArrayList<>(0));
|
||||
}
|
||||
|
||||
list.add(0, notificationId);
|
||||
@@ -259,7 +270,7 @@ public class CustomPushNotification extends PushNotification {
|
||||
private String addServerUrlToBundle(Bundle bundle) {
|
||||
String serverUrl = bundle.getString("server_url");
|
||||
if (serverUrl == null) {
|
||||
serverUrl = DatabaseHelper.getOnlyServerUrl(mContext);
|
||||
serverUrl = Objects.requireNonNull(DatabaseHelper.Companion.getInstance()).getOnlyServerUrl();
|
||||
bundle.putString("server_url", serverUrl);
|
||||
mNotificationProps = createProps(bundle);
|
||||
}
|
||||
@@ -269,13 +280,13 @@ public class CustomPushNotification extends PushNotification {
|
||||
|
||||
private static void saveNotificationsMap(Context context, Map<String, List<Integer>> inputMap) {
|
||||
SharedPreferences pSharedPref = context.getSharedPreferences(PUSH_NOTIFICATIONS, Context.MODE_PRIVATE);
|
||||
if (pSharedPref != null && context != null) {
|
||||
if (pSharedPref != null) {
|
||||
JSONObject json = new JSONObject(inputMap);
|
||||
String jsonString = json.toString();
|
||||
SharedPreferences.Editor editor = pSharedPref.edit();
|
||||
editor.remove(NOTIFICATIONS_IN_CHANNEL).commit();
|
||||
editor.remove(NOTIFICATIONS_IN_CHANNEL).apply();
|
||||
editor.putString(NOTIFICATIONS_IN_CHANNEL, jsonString);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,8 +126,10 @@ public class MainApplication extends NavigationApplication implements INotificat
|
||||
super.onCreate();
|
||||
instance = this;
|
||||
|
||||
Context context = getApplicationContext();
|
||||
|
||||
// Delete any previous temp files created by the app
|
||||
File tempFolder = new File(getApplicationContext().getCacheDir(), RealPathUtil.CACHE_DIR_NAME);
|
||||
File tempFolder = new File(context.getCacheDir(), RealPathUtil.CACHE_DIR_NAME);
|
||||
RealPathUtil.deleteTempFiles(tempFolder);
|
||||
Log.i("ReactNative", "Cleaning temp cache " + tempFolder.getAbsolutePath());
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ buildscript {
|
||||
targetSdkVersion = 29
|
||||
ndkVersion = "20.1.5948944"
|
||||
supportLibVersion = "28.0.0"
|
||||
kotlinVersion = "1.4.30"
|
||||
kotlin_version = "1.4.30"
|
||||
kotlinVersion = "1.5.30"
|
||||
kotlin_version = "1.5.30"
|
||||
firebaseVersion = "21.0.0"
|
||||
RNNKotlinVersion = kotlinVersion
|
||||
}
|
||||
|
||||
@@ -11,16 +11,15 @@ import {General} from '@constants';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {privateChannelJoinPrompt} from '@helpers/api/channel';
|
||||
import {prepareMyChannelsForTeam, queryMyChannel} from '@queries/servers/channel';
|
||||
import {addChannelToTeamHistory, prepareMyTeams, queryMyTeamById, queryTeamById, queryTeamByName} from '@queries/servers/team';
|
||||
import {queryCommonSystemValues, setCurrentChannelId, setCurrentTeamAndChannelId} from '@queries/servers/system';
|
||||
import {addChannelToTeamHistory, prepareMyTeams, queryMyTeamById, queryTeamById, queryTeamByName} from '@queries/servers/team';
|
||||
import {PERMALINK_GENERIC_TEAM_NAME_REDIRECT} from '@utils/url';
|
||||
|
||||
import type {IntlShape} from 'react-intl';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type MyChannelModel from '@typings/database/models/servers/my_channel';
|
||||
import type MyTeamModel from '@typings/database/models/servers/my_team';
|
||||
import type TeamModel from '@typings/database/models/servers/team';
|
||||
import type {IntlShape} from 'react-intl';
|
||||
|
||||
export const switchToChannel = async (serverUrl: string, channelId: string) => {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl]?.database;
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
import {Keyboard} from 'react-native';
|
||||
|
||||
import type {IntlShape} from 'react-intl';
|
||||
|
||||
import {fetchMyChannelsForTeam} from '@actions/remote/channel';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {queryCommonSystemValues} from '@queries/servers/system';
|
||||
@@ -15,6 +13,7 @@ import {changeOpacity} from '@utils/theme';
|
||||
import {PERMALINK_GENERIC_TEAM_NAME_REDIRECT} from '@utils/url';
|
||||
|
||||
import type TeamModel from '@typings/database/models/servers/team';
|
||||
import type {IntlShape} from 'react-intl';
|
||||
|
||||
let showingPermalink = false;
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import {queryPostById} from '@queries/servers/post';
|
||||
import {queryCurrentUserId} from '@queries/servers/system';
|
||||
import {generateId} from '@utils/general';
|
||||
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
export const sendAddToChannelEphemeralPost = async (serverUrl: string, user: UserModel, addedUsernames: string[], messages: string[], channeId: string, postRootId = '') => {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import moment from 'moment-timezone';
|
||||
import {createIntl} from 'react-intl';
|
||||
|
||||
import {getSessions} from '@actions/remote/session';
|
||||
import {DEFAULT_LOCALE, getTranslations} from '@i18n';
|
||||
import PushNotifications from '@init/push_notifications';
|
||||
import {sortByNewest} from '@utils/general';
|
||||
import {createIntl} from 'react-intl';
|
||||
|
||||
export const scheduleExpiredNotification = async (serverUrl: string, config: Partial<ClientConfig>, userId: string, locale = DEFAULT_LOCALE) => {
|
||||
if (config.ExtendSessionLengthWithActivity === 'true') {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
import {getTimeZone} from 'react-native-localize';
|
||||
|
||||
import {updateMe} from '@actions/remote/user';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {queryUserById} from '@queries/servers/user';
|
||||
import {updateMe} from '@actions/remote/user';
|
||||
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
|
||||
@@ -11,9 +11,8 @@ import {fetchRolesIfNeeded} from './role';
|
||||
import {forceLogoutIfNecessary} from './session';
|
||||
import {fetchProfilesPerChannels, fetchUsersByIds} from './user';
|
||||
|
||||
import type {Model} from '@nozbe/watermelondb';
|
||||
|
||||
import type {Client} from '@client/rest';
|
||||
import type {Model} from '@nozbe/watermelondb';
|
||||
|
||||
export type MyChannelsRequest = {
|
||||
channels?: Channel[];
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {ClientResponse} from '@mattermost/react-native-network-client';
|
||||
|
||||
import {SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import NetworkManager from '@init/network_manager';
|
||||
@@ -11,6 +9,7 @@ import {queryExpandedLinks} from '@queries/servers/system';
|
||||
import {forceLogoutIfNecessary} from './session';
|
||||
|
||||
import type {Client} from '@client/rest';
|
||||
import type {ClientResponse} from '@mattermost/react-native-network-client';
|
||||
|
||||
export const doPing = async (serverUrl: string) => {
|
||||
const client = await NetworkManager.createClient(serverUrl);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Q} from '@nozbe/watermelondb';
|
||||
|
||||
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
|
||||
@@ -11,12 +11,12 @@ import {queryDeviceToken} from '@queries/app/global';
|
||||
import {queryCurrentUserId, queryCommonSystemValues} from '@queries/servers/system';
|
||||
import {getCSRFFromCookie} from '@utils/security';
|
||||
|
||||
import type {LoginArgs} from '@typings/database/database';
|
||||
|
||||
import {logError} from './error';
|
||||
import {loginEntry} from './entry';
|
||||
import {logError} from './error';
|
||||
import {fetchDataRetentionPolicy} from './systems';
|
||||
|
||||
import type {LoginArgs} from '@typings/database/database';
|
||||
|
||||
const HTTP_UNAUTHORIZED = 401;
|
||||
|
||||
export const completeLogin = async (serverUrl: string, user: UserProfile) => {
|
||||
|
||||
@@ -12,8 +12,9 @@ import {fetchMyChannelsForTeam} from './channel';
|
||||
import {fetchPostsForUnreadChannels} from './post';
|
||||
import {fetchRolesIfNeeded} from './role';
|
||||
import {forceLogoutIfNecessary} from './session';
|
||||
import TeamModel from '@typings/database/models/servers/team';
|
||||
import TeamMembershipModel from '@typings/database/models/servers/team_membership';
|
||||
|
||||
import type TeamModel from '@typings/database/models/servers/team';
|
||||
import type TeamMembershipModel from '@typings/database/models/servers/team_membership';
|
||||
|
||||
export type MyTeamsRequest = {
|
||||
teams?: Team[];
|
||||
|
||||
@@ -2,22 +2,23 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Q} from '@nozbe/watermelondb';
|
||||
|
||||
import {fetchRolesIfNeeded} from '@actions/remote/role';
|
||||
import {Database, General} from '@constants';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {debounce} from '@helpers/api/general';
|
||||
import analytics from '@init/analytics';
|
||||
import NetworkManager from '@init/network_manager';
|
||||
import {prepareUsers, queryCurrentUser, queryUsersById, queryUsersByUsername} from '@queries/servers/user';
|
||||
import {queryCurrentUserId} from '@queries/servers/system';
|
||||
import {prepareUsers, queryCurrentUser, queryUsersById, queryUsersByUsername} from '@queries/servers/user';
|
||||
|
||||
import {forceLogoutIfNecessary} from './session';
|
||||
|
||||
import type {Client} from '@client/rest';
|
||||
import type {LoadMeArgs} from '@typings/database/database';
|
||||
import type RoleModel from '@typings/database/models/servers/role';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
import {forceLogoutIfNecessary} from './session';
|
||||
|
||||
export type ProfilesPerChannelRequest = {
|
||||
data?: ProfilesInChannelRequest[];
|
||||
error?: never;
|
||||
|
||||
@@ -8,6 +8,9 @@ import {t} from '@i18n';
|
||||
import {Analytics, create} from '@init/analytics';
|
||||
import {setServerCredentials} from '@init/credentials';
|
||||
|
||||
import * as ClientConstants from './constants';
|
||||
import ClientError from './error';
|
||||
|
||||
import type {
|
||||
APIClientInterface,
|
||||
ClientHeaders,
|
||||
@@ -15,9 +18,6 @@ import type {
|
||||
RequestOptions,
|
||||
} from '@mattermost/react-native-network-client';
|
||||
|
||||
import * as ClientConstants from './constants';
|
||||
import ClientError from './error';
|
||||
|
||||
export default class ClientBase {
|
||||
analytics: Analytics|undefined;
|
||||
apiClient: APIClientInterface;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import assert from 'assert';
|
||||
|
||||
import nock from 'nock';
|
||||
|
||||
import {HEADER_X_VERSION_ID} from '@client/rest/constants';
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
import mix from '@utils/mix';
|
||||
|
||||
import {DEFAULT_LIMIT_AFTER, DEFAULT_LIMIT_BEFORE, HEADER_X_VERSION_ID} from './constants';
|
||||
import ClientApps, {ClientAppsMix} from './apps';
|
||||
import ClientBase from './base';
|
||||
import ClientChannels, {ClientChannelsMix} from './channels';
|
||||
import {DEFAULT_LIMIT_AFTER, DEFAULT_LIMIT_BEFORE, HEADER_X_VERSION_ID} from './constants';
|
||||
import ClientEmojis, {ClientEmojisMix} from './emojis';
|
||||
import ClientFiles, {ClientFilesMix} from './files';
|
||||
import ClientGeneral, {ClientGeneralMix} from './general';
|
||||
|
||||
@@ -5,8 +5,8 @@ import React from 'react';
|
||||
import {StyleSheet, TextStyle, View} from 'react-native';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
|
||||
import {t} from '@i18n';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import {t} from '@i18n';
|
||||
|
||||
const style = StyleSheet.create({
|
||||
info: {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import Database from '@nozbe/watermelondb/Database';
|
||||
import React from 'react';
|
||||
|
||||
import CustomStatusEmoji from '@components/custom_status/custom_status_emoji';
|
||||
import {renderWithEverything} from '@test/intl-test-helper';
|
||||
import TestHelper from '@test/test_helper';
|
||||
import Database from '@nozbe/watermelondb/Database';
|
||||
|
||||
describe('components/custom_status/custom_status_emoji', () => {
|
||||
let database: Database | undefined;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import CustomStatusText from '@components/custom_status/custom_status_text';
|
||||
|
||||
@@ -23,8 +23,8 @@ import NetworkManager from '@init/network_manager';
|
||||
import {EmojiIndicesByAlias, Emojis} from '@utils/emoji';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
|
||||
const assetImages = new Map([['mattermost.png', require('@assets/images/emojis/mattermost.png')]]);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {render} from '@testing-library/react-native';
|
||||
import React from 'react';
|
||||
|
||||
import {Preferences} from '@constants';
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import AtMention from '@components/markdown/at_mention';
|
||||
import MarkdownLink from '@components/markdown/markdown_link';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {getMarkdownTextStyles} from '@utils/markdown';
|
||||
import {concatStyles, changeOpacity, makeStyleSheetFromTheme} from '@app/utils/theme';
|
||||
import {concatStyles, changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import type {PrimitiveType} from 'intl-messageformat';
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {createElement, isValidElement} from 'react';
|
||||
import {StyleProp, Text, TextProps, TextStyle, ViewStyle} from 'react-native';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {StyleProp, Text, TextProps, TextStyle, ViewStyle} from 'react-native';
|
||||
|
||||
type FormattedTextProps = TextProps & {
|
||||
id: string;
|
||||
|
||||
@@ -11,13 +11,13 @@ import {useIntl} from 'react-intl';
|
||||
import {DeviceEventEmitter, GestureResponderEvent, StyleProp, StyleSheet, Text, TextStyle, View} from 'react-native';
|
||||
import {of as of$} from 'rxjs';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {Navigation, Preferences} from '@constants';
|
||||
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import {useTheme} from '@context/theme';
|
||||
import UserModel from '@database/models/server/user';
|
||||
import {getTeammateNameDisplaySetting} from '@helpers/api/preference';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import {showModal, showModalOverCurrentContext} from '@screens/navigation';
|
||||
import {displayUsername, getUserMentionKeys, getUsersByUsername} from '@utils/user';
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ import MarkdownLink from './markdown_link';
|
||||
import MarkdownList from './markdown_list';
|
||||
import MarkdownListItem from './markdown_list_item';
|
||||
import MarkdownTable from './markdown_table';
|
||||
import MarkdownTableCell, {MarkdownTableCellProps} from './markdown_table_cell';
|
||||
import MarkdownTableImage from './markdown_table_image';
|
||||
import MarkdownTableRow, {MarkdownTableRowProps} from './markdown_table_row';
|
||||
import MarkdownTableCell, {MarkdownTableCellProps} from './markdown_table_cell';
|
||||
import {addListItemIndices, combineTextNodes, highlightMentions, pullOutImages} from './transform';
|
||||
|
||||
import type {MarkdownBlockStyles, MarkdownTextStyles, UserMentionKey} from '@typings/global/markdown';
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {ReactNode} from 'react';
|
||||
|
||||
import {StyleSheet, TextStyle, View, ViewStyle} from 'react-native';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
|
||||
@@ -8,10 +8,10 @@ import {useIntl} from 'react-intl';
|
||||
import {DeviceEventEmitter, Keyboard, StyleSheet, Text, TextStyle, View} from 'react-native';
|
||||
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import {useTheme} from '@context/theme';
|
||||
import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
|
||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||
import {Navigation} from '@constants';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {goToScreen, showModalOverCurrentContext} from '@screens/navigation';
|
||||
import {getDisplayNameForLanguage} from '@utils/markdown';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {useManagedConfig} from '@mattermost/react-native-emm';
|
||||
import Clipboard from '@react-native-community/clipboard';
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import Clipboard from '@react-native-community/clipboard';
|
||||
import React, {Children, ReactElement, useCallback} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Alert, DeviceEventEmitter, StyleSheet, Text, View} from 'react-native';
|
||||
@@ -20,8 +20,8 @@ import DeepLinkTypes from '@constants/deep_linking';
|
||||
import {useServerUrl} from '@context/server_url';
|
||||
import {dismissAllModals, popToRoot, showModalOverCurrentContext} from '@screens/navigation';
|
||||
import {errorBadChannel} from '@utils/draft';
|
||||
import {matchDeepLink, normalizeProtocol, tryOpenURL} from '@utils/url';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
import {matchDeepLink, normalizeProtocol, tryOpenURL} from '@utils/url';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {useServerUrl} from '@context/server_url';
|
||||
import {generateId} from '@utils/general';
|
||||
import React, {memo, useCallback, useRef, useState} from 'react';
|
||||
import {StyleSheet, View} from 'react-native';
|
||||
import parseUrl from 'url-parse';
|
||||
@@ -10,7 +8,9 @@ import parseUrl from 'url-parse';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import ProgressiveImage from '@components/progressive_image';
|
||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||
import {useServerUrl} from '@context/server_url';
|
||||
import {openGallerWithMockFile} from '@utils/gallery';
|
||||
import {generateId} from '@utils/general';
|
||||
import {calculateDimensions, isGifTooLarge} from '@utils/images';
|
||||
|
||||
type MarkdownTableImageProps = {
|
||||
|
||||
@@ -7,8 +7,8 @@ import {Keyboard, StyleProp, View, ViewStyle} from 'react-native';
|
||||
|
||||
import {fetchMissingProfilesByIds, fetchMissingProfilesByUsernames} from '@actions/remote/user';
|
||||
import Markdown from '@components/markdown';
|
||||
import SystemAvatar from '@app/components/system_avatar';
|
||||
import SystemHeader from '@app/components/system_header';
|
||||
import SystemAvatar from '@components/system_avatar';
|
||||
import SystemHeader from '@components/system_header';
|
||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||
import {Post as PostConstants} from '@constants';
|
||||
import {useServerUrl} from '@context/server_url';
|
||||
|
||||
@@ -9,10 +9,10 @@ import {DeviceEventEmitter, FlatList, Platform, RefreshControl, StyleSheet, View
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import Post from '@components/post_list/post';
|
||||
import CombinedUserActivity from '@app/components/post_list/combined_user_activity';
|
||||
import CombinedUserActivity from '@components/post_list/combined_user_activity';
|
||||
import DateSeparator from '@components/post_list/date_separator';
|
||||
import NewMessagesLine from '@components/post_list/new_message_line';
|
||||
import Post from '@components/post_list/post';
|
||||
import {Preferences} from '@constants';
|
||||
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import {useTheme} from '@context/theme';
|
||||
@@ -26,7 +26,7 @@ import type PostModel from '@typings/database/models/servers/post';
|
||||
import type PostsInChannelModel from '@typings/database/models/servers/posts_in_channel';
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import UserModel from '@typings/database/models/servers/user';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
type RefreshProps = {
|
||||
children: ReactElement;
|
||||
|
||||
@@ -11,8 +11,8 @@ import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import SystemAvatar from '@components/system_avatar';
|
||||
import ProfilePicture from '@components/profile_picture';
|
||||
import SystemAvatar from '@components/system_avatar';
|
||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||
import {View as ViewConstant} from '@constants';
|
||||
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
@@ -22,13 +22,12 @@ import NetworkManager from '@init/network_manager';
|
||||
import {showModal} from '@screens/navigation';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
import type {ImageSource} from 'react-native-vector-icons/Icon';
|
||||
|
||||
import type {Client} from '@client/rest';
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
import type {ImageSource} from 'react-native-vector-icons/Icon';
|
||||
|
||||
type AvatarProps = {
|
||||
author: UserModel;
|
||||
|
||||
@@ -11,8 +11,8 @@ import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {removePost, sendAddToChannelEphemeralPost} from '@actions/local/post';
|
||||
import {addMembersToChannel} from '@actions/remote/channel';
|
||||
import AtMention from '@components/markdown/at_mention';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import AtMention from '@components/markdown/at_mention';
|
||||
import {General} from '@constants';
|
||||
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import {useServerUrl} from '@context/server_url';
|
||||
@@ -23,8 +23,8 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
import SystemModel from '@typings/database/models/servers/system';
|
||||
|
||||
type AddMembersProps = {
|
||||
channelType: string | null;
|
||||
|
||||
@@ -6,7 +6,7 @@ import {LayoutChangeEvent, useWindowDimensions, ScrollView, View} from 'react-na
|
||||
import Animated from 'react-native-reanimated';
|
||||
|
||||
import Markdown from '@components/markdown';
|
||||
import ShowMoreButton from '@app/components/post_list/post/body/message/show_more_button';
|
||||
import ShowMoreButton from '@components/post_list/post/body/message/show_more_button';
|
||||
import {useShowMoreAnimatedStyle} from '@hooks/show_more';
|
||||
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
@@ -10,16 +10,16 @@ import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {getRedirectLocation} from '@actions/remote/general';
|
||||
import FileIcon from '@app/components/post_list/post/body/files/file_icon';
|
||||
import FileIcon from '@components/post_list/post/body/files/file_icon';
|
||||
import ProgressiveImage from '@components/progressive_image';
|
||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||
import {Device} from '@constants';
|
||||
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import {useServerUrl} from '@context/server_url';
|
||||
import useDidUpdate from '@hooks/did_update';
|
||||
import {useSplitView} from '@hooks/device';
|
||||
import {generateId} from '@utils/general';
|
||||
import useDidUpdate from '@hooks/did_update';
|
||||
import {openGallerWithMockFile} from '@utils/gallery';
|
||||
import {generateId} from '@utils/general';
|
||||
import {calculateDimensions, getViewPortWidth, isGifTooLarge} from '@utils/images';
|
||||
import {changeOpacity} from '@utils/theme';
|
||||
import {isImageLink, isValidUrl} from '@utils/url';
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
import React, {useCallback, useState} from 'react';
|
||||
|
||||
import {selectAttachmentMenuAction} from '@actions/local/post';
|
||||
import {useServerUrl} from '@context/server_url';
|
||||
|
||||
import AutocompleteSelector from '@components/autocomplete_selector';
|
||||
import {useServerUrl} from '@context/server_url';
|
||||
|
||||
type Props = {
|
||||
dataSource?: string;
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
import React, {useCallback, useRef, useState} from 'react';
|
||||
import {View} from 'react-native';
|
||||
|
||||
import FileIcon from '@app/components/post_list/post/body/files/file_icon';
|
||||
import FileIcon from '@components/post_list/post/body/files/file_icon';
|
||||
import ProgressiveImage from '@components/progressive_image';
|
||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||
import {Device} from '@constants';
|
||||
import {useSplitView} from '@hooks/device';
|
||||
import {generateId} from '@utils/general';
|
||||
import {openGallerWithMockFile} from '@utils/gallery';
|
||||
import {generateId} from '@utils/general';
|
||||
import {isGifTooLarge, calculateDimensions, getViewPortWidth} from '@utils/images';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {isValidUrl} from '@utils/url';
|
||||
|
||||
@@ -6,7 +6,7 @@ import {LayoutChangeEvent, useWindowDimensions, ScrollView, StyleProp, StyleShee
|
||||
import Animated from 'react-native-reanimated';
|
||||
|
||||
import Markdown from '@components/markdown';
|
||||
import ShowMoreButton from '@app/components/post_list/post/body/message/show_more_button';
|
||||
import ShowMoreButton from '@components/post_list/post/body/message/show_more_button';
|
||||
import {useShowMoreAnimatedStyle} from '@hooks/show_more';
|
||||
|
||||
import type {MarkdownBlockStyles, MarkdownTextStyles} from '@typings/global/markdown';
|
||||
|
||||
@@ -12,9 +12,8 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import FileIcon from './file_icon';
|
||||
|
||||
import type {ResizeMode} from 'react-native-fast-image';
|
||||
|
||||
import type {Client} from '@client/rest';
|
||||
import type {ResizeMode} from 'react-native-fast-image';
|
||||
|
||||
type ImageFileProps = {
|
||||
backgroundColor?: string;
|
||||
|
||||
@@ -17,8 +17,8 @@ import Files from './files';
|
||||
import Message from './message';
|
||||
import Reactions from './reactions';
|
||||
|
||||
import type FileModel from '@typings/database/models/servers/file';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import FileModel from '@typings/database/models/servers/file';
|
||||
|
||||
type BodyProps = {
|
||||
appsEnabled: boolean;
|
||||
|
||||
@@ -8,15 +8,14 @@ import Animated from 'react-native-reanimated';
|
||||
import Markdown from '@components/markdown';
|
||||
import {SEARCH} from '@constants/screens';
|
||||
import {useShowMoreAnimatedStyle} from '@hooks/show_more';
|
||||
import {getMentionKeysForPost} from '@utils/post';
|
||||
import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown';
|
||||
|
||||
import {getMentionKeysForPost} from '@utils/post';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import ShowMoreButton from './show_more_button';
|
||||
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
type MessageProps = {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {from as from$, of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ import FormattedTime from '@components/formatted_time';
|
||||
import {CHANNEL, THREAD} from '@constants/screens';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {postUserDisplayName} from '@utils/post';
|
||||
import {displayUsername, getUserCustomStatus, getUserTimezone, isCustomStatusExpired} from '@utils/user';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {displayUsername, getUserCustomStatus, getUserTimezone, isCustomStatusExpired} from '@utils/user';
|
||||
|
||||
import HeaderCommentedOn from './commented_on';
|
||||
import HeaderDisplayName from './display_name';
|
||||
|
||||
@@ -16,8 +16,8 @@ import Header from './header';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
|
||||
type HeaderInputProps = {
|
||||
config: ClientConfig;
|
||||
|
||||
@@ -17,12 +17,12 @@ import {canManageChannelMembers, hasPermissionForPost} from '@utils/role';
|
||||
import Post from './post';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type PostsInThreadModel from '@typings/database/models/servers/posts_in_thread';
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
import PostsInThreadModel from '@typings/database/models/servers/posts_in_thread';
|
||||
import CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
|
||||
const {SERVER: {CUSTOM_EMOJI, POST, PREFERENCE, SYSTEM, USER}} = MM_TABLES;
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ import {DeviceEventEmitter, Keyboard, StyleProp, View, ViewStyle} from 'react-na
|
||||
|
||||
import {showPermalink} from '@actions/local/permalink';
|
||||
import {removePost} from '@actions/local/post';
|
||||
import SystemAvatar from '@app/components/system_avatar';
|
||||
import SystemHeader from '@app/components/system_header';
|
||||
import SystemAvatar from '@components/system_avatar';
|
||||
import SystemHeader from '@components/system_header';
|
||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||
import * as Screens from '@constants/screens';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {useServerUrl} from '@context/server_url';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {showModalOverCurrentContext} from '@screens/navigation';
|
||||
import {fromAutoResponder, isFromWebhook, isPostPendingOrFailed, isSystemMessage} from '@utils/post';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
@@ -24,9 +24,9 @@ import Header from './header';
|
||||
import PreHeader from './pre_header';
|
||||
import SystemMessage from './system_message';
|
||||
|
||||
import type FileModel from '@typings/database/models/servers/file';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
import FileModel from '@typings/database/models/servers/file';
|
||||
|
||||
type PostProps = {
|
||||
appsEnabled: boolean;
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
|
||||
import SystemMessage from './system_message';
|
||||
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
|
||||
const withPost = withObservables(['post'], ({post}: {post: PostModel}) => ({
|
||||
author: post.author.observe(),
|
||||
}));
|
||||
|
||||
@@ -12,10 +12,9 @@ import {t} from '@i18n';
|
||||
import {getMarkdownTextStyles} from '@utils/markdown';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import type {PrimitiveType} from 'intl-messageformat';
|
||||
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
import type {PrimitiveType} from 'intl-messageformat';
|
||||
|
||||
type SystemMessageProps = {
|
||||
author?: UserModel;
|
||||
|
||||
@@ -9,7 +9,7 @@ import {useIntl} from 'react-intl';
|
||||
import {View} from '@constants';
|
||||
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import {isMinimumServerVersion} from '@utils/helpers';
|
||||
import {unsupportedServer} from '@app/utils/supported_server';
|
||||
import {unsupportedServer} from '@utils/supported_server';
|
||||
import {isSystemAdmin} from '@utils/user';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
@@ -17,10 +17,9 @@ import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {getUserTimezone} from '@utils/user';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
|
||||
type withUserInputProps = {
|
||||
config: SystemModel;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
import React from 'react';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {General} from '@constants';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {changeOpacity} from '@utils/theme';
|
||||
|
||||
type UserStatusProps = {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Platform} from 'react-native';
|
||||
import {FileSystem} from 'react-native-unimodules';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import {FileSystem} from 'react-native-unimodules';
|
||||
|
||||
import keyMirror from '@utils/key_mirror';
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ import Network from './network';
|
||||
import Permissions from './permissions';
|
||||
import Post from './post';
|
||||
import Preferences from './preferences';
|
||||
import SSO, {REDIRECT_URL_SCHEME, REDIRECT_URL_SCHEME_DEV} from './sso';
|
||||
import Screens from './screens';
|
||||
import SSO, {REDIRECT_URL_SCHEME, REDIRECT_URL_SCHEME_DEV} from './sso';
|
||||
import View, {Upgrade} from './view';
|
||||
import WebsocketEvents from './websocket';
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
import {setNavigationStackStyles} from '@utils/theme';
|
||||
|
||||
import type Database from '@nozbe/watermelondb/Database';
|
||||
import type {PreferenceModel, SystemModel} from '@database/models/server';
|
||||
import type Database from '@nozbe/watermelondb/Database';
|
||||
|
||||
type Props = {
|
||||
currentTeamId: SystemModel[];
|
||||
|
||||
@@ -3,33 +3,31 @@
|
||||
|
||||
import {Database, Q} from '@nozbe/watermelondb';
|
||||
import LokiJSAdapter from '@nozbe/watermelondb/adapters/lokijs';
|
||||
|
||||
import logger from '@nozbe/watermelondb/utils/common/logger';
|
||||
import {DeviceEventEmitter, Platform} from 'react-native';
|
||||
import {FileSystem} from 'react-native-unimodules';
|
||||
import urlParse from 'url-parse';
|
||||
|
||||
import {MIGRATION_EVENTS, MM_TABLES} from '@constants/database';
|
||||
import AppDataOperator from '@database/operator/app_data_operator';
|
||||
import AppDatabaseMigrations from '@app/database/migration/app';
|
||||
import {InfoModel, GlobalModel, ServersModel} from '@database/models/app';
|
||||
import {schema as appSchema} from '@app/database/schema/app';
|
||||
import AppDatabaseMigrations from '@database/migration/app';
|
||||
import ServerDatabaseMigrations from '@database/migration/server';
|
||||
import {InfoModel, GlobalModel, ServersModel} from '@database/models/app';
|
||||
import {ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
GroupModel, GroupMembershipModel, GroupsChannelModel, GroupsTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
TermsOfServiceModel, UserModel,
|
||||
} from '@database/models/server';
|
||||
import AppDataOperator from '@database/operator/app_data_operator';
|
||||
import ServerDataOperator from '@database/operator/server_data_operator';
|
||||
import {schema as appSchema} from '@database/schema/app';
|
||||
import {serverSchema} from '@database/schema/server';
|
||||
import {queryActiveServer, queryServer} from '@queries/app/servers';
|
||||
import {DatabaseType} from '@typings/database/enums';
|
||||
import {deleteIOSDatabase} from '@utils/mattermost_managed';
|
||||
import {hashCode} from '@utils/security';
|
||||
|
||||
import type {AppDatabase, CreateServerDatabaseArgs, Models, RegisterServerDatabaseArgs, ServerDatabase, ServerDatabases} from '@typings/database/database';
|
||||
import {DatabaseType} from '@typings/database/enums';
|
||||
|
||||
import ServerDataOperator from '../../operator/server_data_operator';
|
||||
|
||||
const {SERVERS} = MM_TABLES.APP;
|
||||
const APP_DATABASE = 'app';
|
||||
|
||||
@@ -10,26 +10,25 @@ import {FileSystem} from 'react-native-unimodules';
|
||||
import urlParse from 'url-parse';
|
||||
|
||||
import {MIGRATION_EVENTS, MM_TABLES} from '@constants/database';
|
||||
import AppDataOperator from '@database/operator/app_data_operator';
|
||||
import AppDatabaseMigrations from '@database/migration/app';
|
||||
import {InfoModel, GlobalModel, ServersModel} from '@database/models/app';
|
||||
import {schema as appSchema} from '@database/schema/app';
|
||||
import ServerDatabaseMigrations from '@database/migration/server';
|
||||
import {InfoModel, GlobalModel, ServersModel} from '@database/models/app';
|
||||
import {ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
GroupModel, GroupMembershipModel, GroupsChannelModel, GroupsTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
TermsOfServiceModel, UserModel,
|
||||
} from '@database/models/server';
|
||||
import AppDataOperator from '@database/operator/app_data_operator';
|
||||
import ServerDataOperator from '@database/operator/server_data_operator';
|
||||
import {schema as appSchema} from '@database/schema/app';
|
||||
import {serverSchema} from '@database/schema/server';
|
||||
import {queryActiveServer, queryServer} from '@queries/app/servers';
|
||||
import {DatabaseType} from '@typings/database/enums';
|
||||
import {deleteIOSDatabase, getIOSAppGroupDetails} from '@utils/mattermost_managed';
|
||||
import {hashCode} from '@utils/security';
|
||||
|
||||
import type {AppDatabase, CreateServerDatabaseArgs, RegisterServerDatabaseArgs, Models, ServerDatabase, ServerDatabases} from '@typings/database/database';
|
||||
import {DatabaseType} from '@typings/database/enums';
|
||||
|
||||
import ServerDataOperator from '../operator/server_data_operator';
|
||||
|
||||
const {SERVERS} = MM_TABLES.APP;
|
||||
const APP_DATABASE = 'app';
|
||||
|
||||
@@ -5,11 +5,11 @@ import {Q} from '@nozbe/watermelondb';
|
||||
import {Platform} from 'react-native';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {DatabaseType} from '@typings/database/enums';
|
||||
import {getIOSAppGroupDetails} from '@utils/mattermost_managed';
|
||||
|
||||
import DatabaseManager from './index';
|
||||
|
||||
import {DatabaseType} from '@typings/database/enums';
|
||||
import type ServersModel from '@typings/database/models/app/servers';
|
||||
|
||||
export default async () => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
import {field, json} from '@nozbe/watermelondb/decorators';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {safeParseJSON} from '@utils/helpers';
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Relation} from '@nozbe/watermelondb';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
import {field, immutableRelation} from '@nozbe/watermelondb/decorators';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
import {children, field} from '@nozbe/watermelondb/decorators';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Relation} from '@nozbe/watermelondb';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
import {field, immutableRelation} from '@nozbe/watermelondb/decorators';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type InfoModel from '@typings/database/models/app/info';
|
||||
import type GlobalModel from '@typings/database/models/app/global';
|
||||
import type InfoModel from '@typings/database/models/app/info';
|
||||
|
||||
export const isRecordInfoEqualToRaw = (record: InfoModel, raw: AppInfo) => {
|
||||
return (raw.build_number === record.buildNumber && raw.version_number === record.versionNumber);
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
import type {Model} from '@nozbe/watermelondb';
|
||||
|
||||
import type InfoModel from '@typings/database/models/app/info';
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
import type GlobalModel from '@typings/database/models/app/global';
|
||||
import type InfoModel from '@typings/database/models/app/info';
|
||||
|
||||
const {INFO, GLOBAL} = MM_TABLES.APP;
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ import {
|
||||
getValidRecordsForUpdate,
|
||||
retrieveRecords,
|
||||
} from '@database/operator/utils/general';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
import type {WriterInterface} from '@nozbe/watermelondb/Database';
|
||||
import type Model from '@nozbe/watermelondb/Model';
|
||||
|
||||
import type {
|
||||
HandleRecordsArgs,
|
||||
OperationArgs,
|
||||
@@ -20,7 +20,6 @@ import type {
|
||||
ProcessRecordsArgs,
|
||||
RecordPair,
|
||||
} from '@typings/database/database';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
export interface BaseDataOperatorType {
|
||||
database: Database;
|
||||
|
||||
@@ -17,9 +17,9 @@ import {
|
||||
} from '@database/operator/server_data_operator/transformers/channel';
|
||||
import {getUniqueRawsBy} from '@database/operator/utils/general';
|
||||
|
||||
import type {HandleChannelArgs, HandleChannelInfoArgs, HandleMyChannelArgs, HandleMyChannelSettingsArgs} from '@typings/database/database';
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type ChannelInfoModel from '@typings/database/models/servers/channel_info';
|
||||
import type {HandleChannelArgs, HandleChannelInfoArgs, HandleMyChannelArgs, HandleMyChannelSettingsArgs} from '@typings/database/database';
|
||||
import type MyChannelModel from '@typings/database/models/servers/my_channel';
|
||||
import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings';
|
||||
|
||||
|
||||
@@ -16,9 +16,8 @@ import {
|
||||
transformTermsOfServiceRecord,
|
||||
} from '@database/operator/server_data_operator/transformers/general';
|
||||
|
||||
import type {Model} from '@nozbe/watermelondb';
|
||||
|
||||
import type ServerDataOperator from '..';
|
||||
import type {Model} from '@nozbe/watermelondb';
|
||||
|
||||
describe('*** DataOperator: Base Handlers tests ***', () => {
|
||||
let operator: ServerDataOperator;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import BaseDataOperator from '@database/operator/base_data_operator';
|
||||
import DataOperatorException from '@database/exceptions/data_operator_exception';
|
||||
import BaseDataOperator from '@database/operator/base_data_operator';
|
||||
import {
|
||||
isRecordCustomEmojiEqualToRaw,
|
||||
isRecordRoleEqualToRaw,
|
||||
@@ -19,10 +19,9 @@ import {
|
||||
import {getUniqueRawsBy} from '@database/operator/utils/general';
|
||||
|
||||
import type {Model} from '@nozbe/watermelondb';
|
||||
|
||||
import type {HandleCustomEmojiArgs, HandleRoleArgs, HandleSystemArgs, HandleTOSArgs, OperationArgs} from '@typings/database/database';
|
||||
import type RoleModel from '@typings/database/models/servers/role';
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type RoleModel from '@typings/database/models/servers/role';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import type TermsOfServiceModel from '@typings/database/models/servers/terms_of_service';
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
import {Q} from '@nozbe/watermelondb';
|
||||
|
||||
import {Database} from '@constants';
|
||||
import {transformPostsInChannelRecord} from '@database/operator/server_data_operator/transformers/post';
|
||||
import {getPostListEdges} from '@database//operator/utils/post';
|
||||
import {transformPostsInChannelRecord} from '@database/operator/server_data_operator/transformers/post';
|
||||
|
||||
import type PostsInChannelModel from '@typings/database/models/servers/posts_in_channel';
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
import {Q} from '@nozbe/watermelondb';
|
||||
|
||||
import {Database} from '@constants';
|
||||
import {getRawRecordPairs, getValidRecordsForUpdate} from '@database/operator/utils/general';
|
||||
import {transformPostInThreadRecord} from '@database/operator/server_data_operator/transformers/post';
|
||||
import {getPostListEdges} from '@database//operator/utils/post';
|
||||
import {transformPostInThreadRecord} from '@database/operator/server_data_operator/transformers/post';
|
||||
import {getRawRecordPairs, getValidRecordsForUpdate} from '@database/operator/utils/general';
|
||||
|
||||
import type {RecordPair} from '@typings/database/database';
|
||||
import type PostsInThreadModel from '@typings/database/models/servers/posts_in_thread';
|
||||
|
||||
@@ -17,14 +17,14 @@ import {
|
||||
import {getUniqueRawsBy} from '@database/operator/utils/general';
|
||||
import {sanitizeReactions} from '@database/operator/utils/reaction';
|
||||
|
||||
import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership';
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type {
|
||||
HandleChannelMembershipArgs,
|
||||
HandlePreferencesArgs,
|
||||
HandleReactionsArgs,
|
||||
HandleUsersArgs,
|
||||
} from '@typings/database/database';
|
||||
import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership';
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
import type ReactionModel from '@typings/database/models/servers/reaction';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type ChannelInfoModel from '@typings/database/models/servers/channel_info';
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
import type MyChannelModel from '@typings/database/models/servers/my_channel';
|
||||
import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings';
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index';
|
||||
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type RoleModel from '@typings/database/models/servers/role';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import type TermsOfServiceModel from '@typings/database/models/servers/terms_of_service';
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
import type GroupsChannelModel from '@typings/database/models/servers/groups_channel';
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import Model from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {TransformerArgs} from '@typings/database/database';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
import type{TransformerArgs} from '@typings/database/database';
|
||||
import type DraftModel from '@typings/database/models/servers/draft';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
import type FileModel from '@typings/database/models/servers/file';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type PostsInChannelModel from '@typings/database/models/servers/posts_in_channel';
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index';
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import type MyTeamModel from '@typings/database/models/servers/my_team';
|
||||
import type SlashCommandModel from '@typings/database/models/servers/slash_command';
|
||||
import type TeamModel from '@typings/database/models/servers/team';
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {
|
||||
transformChannelMembershipRecord,
|
||||
transformPreferenceRecord,
|
||||
transformReactionRecord,
|
||||
transformUserRecord,
|
||||
} from '@database/operator/server_data_operator/transformers/user';
|
||||
|
||||
// See LICENSE.txt for license information.
|
||||
import {createTestConnection} from '@database/operator/utils/create_test_connection';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index';
|
||||
|
||||
import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership';
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership';
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
import type ReactionModel from '@typings/database/models/servers/reaction';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type {IdenticalRecordArgs, RangeOfValueArgs, RecordPair, RetrieveRecordsArgs} from '@typings/database/database';
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type SlashCommandModel from '@typings/database/models/servers/slash_command';
|
||||
import type TeamModel from '@typings/database/models/servers/team';
|
||||
|
||||
@@ -5,12 +5,11 @@ import DatabaseManager from '@database/manager';
|
||||
import {createPostsChain, sanitizePosts} from '@database/operator/utils/post';
|
||||
import {sanitizeReactions} from '@database/operator/utils/reaction';
|
||||
|
||||
import type {WriterInterface} from '@nozbe/watermelondb/Database';
|
||||
|
||||
import type ReactionModel from '@typings/database/models/servers/reaction';
|
||||
|
||||
import {mockedPosts, mockedReactions} from './mock';
|
||||
|
||||
import type {WriterInterface} from '@nozbe/watermelondb/Database';
|
||||
import type ReactionModel from '@typings/database/models/servers/reaction';
|
||||
|
||||
describe('DataOperator: Utils tests', () => {
|
||||
it('=> sanitizePosts: should filter between ordered and unordered posts', () => {
|
||||
const {postsOrdered, postsUnordered} = sanitizePosts({
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {AppSchema, appSchema, tableSchema} from '@nozbe/watermelondb';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
const {INFO, GLOBAL, SERVERS} = MM_TABLES.APP;
|
||||
|
||||
@@ -5,9 +5,9 @@ import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
import type GroupsChannelModel from '@typings/database/models/servers/groups_channel';
|
||||
import type GroupsTeamModel from '@typings/database/models/servers/groups_team';
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type TeamModel from '@typings/database/models/servers/team';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import {Dimensions} from 'react-native';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
|
||||
import LocalConfig from '@assets/config.json';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Alert, DeviceEventEmitter, Linking, Platform} from 'react-native';
|
||||
import CookieManager, {Cookie} from '@react-native-cookies/cookies';
|
||||
import {Alert, DeviceEventEmitter, Linking, Platform} from 'react-native';
|
||||
import semver from 'semver';
|
||||
|
||||
import {fetchConfigAndLicense} from '@actions/remote/systems';
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import Emm, {ManagedConfig} from '@mattermost/react-native-emm';
|
||||
import {Alert, AlertButton, AppState, AppStateStatus, Platform} from 'react-native';
|
||||
import JailMonkey from 'jail-monkey';
|
||||
import {Alert, AlertButton, AppState, AppStateStatus, Platform} from 'react-native';
|
||||
|
||||
import {DEFAULT_LOCALE, getTranslations, t} from '@i18n';
|
||||
import {getIOSAppGroupDetails} from '@utils/mattermost_managed';
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {DeviceEventEmitter} from 'react-native';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
|
||||
import Emm from '@mattermost/react-native-emm';
|
||||
import {
|
||||
APIClientErrorEvent,
|
||||
@@ -11,6 +8,8 @@ import {
|
||||
getOrCreateAPIClient,
|
||||
RetryTypes,
|
||||
} from '@mattermost/react-native-network-client';
|
||||
import {DeviceEventEmitter} from 'react-native';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
|
||||
import LocalConfig from '@assets/config.json';
|
||||
import {Client} from '@client/rest';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {DEFAULT_LOCALE, getLocalizedMessage, t} from '@i18n';
|
||||
import {AppState, DeviceEventEmitter, Platform} from 'react-native';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import {
|
||||
@@ -18,6 +17,7 @@ import {
|
||||
import {Device, General, Navigation} from '@constants';
|
||||
import {GLOBAL_IDENTIFIERS} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {DEFAULT_LOCALE, getLocalizedMessage, t} from '@i18n';
|
||||
import {getLaunchPropsFromNotification, relaunchApp} from '@init/launch';
|
||||
import NativeNotifications from '@notifications';
|
||||
import {queryMentionCount} from '@queries/app/global';
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {GLOBAL_IDENTIFIERS, MM_TABLES} from '@constants/database';
|
||||
import {Database} from '@nozbe/watermelondb';
|
||||
|
||||
import {GLOBAL_IDENTIFIERS, MM_TABLES} from '@constants/database';
|
||||
|
||||
import type Global from '@typings/database/models/app/global';
|
||||
|
||||
const {APP: {GLOBAL}} = MM_TABLES;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {Database, Q} from '@nozbe/watermelondb';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import type Servers from '@typings/database/models/app/servers';
|
||||
|
||||
const {APP: {SERVERS}} = MM_TABLES;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user