Move from java/ to kotlin/ directory

Android 12 dynamic color usage on login screen
This commit is contained in:
2021-08-31 02:18:29 +03:00
parent 2453e534ae
commit 1209c37e24
135 changed files with 140 additions and 57 deletions
@@ -0,0 +1,115 @@
package com.meloda.fast.database
import android.content.ContentValues
import android.database.Cursor
import android.os.Bundle
import com.meloda.fast.common.AppGlobal.Companion.database
import com.meloda.fast.database.DatabaseUtils.TABLE_CHATS
import com.meloda.fast.database.DatabaseUtils.TABLE_FRIENDS
import com.meloda.fast.database.DatabaseUtils.TABLE_MESSAGES
import com.meloda.fast.database.DatabaseUtils.TABLE_USERS
import com.meloda.fast.database.storage.ChatsStorage
import com.meloda.fast.database.storage.GroupsStorage
import com.meloda.fast.database.storage.MessagesStorage
import com.meloda.fast.database.storage.UsersStorage
import com.meloda.fast.api.model.VKConversation
import com.meloda.fast.api.model.VKMessage
import com.meloda.fast.api.model.VKUser
import java.util.*
object CacheStorage {
val usersStorage = UsersStorage()
val messagesStorage = MessagesStorage()
val chatsStorage = ChatsStorage()
val groupsStorage = GroupsStorage()
fun selectCursor(tableName: String): Cursor {
return QueryBuilder.query()
.select("*").from(tableName)
.asCursor(database)
}
fun selectCursor(tableName: String, where: String): Cursor {
return QueryBuilder.query()
.select("*").from(tableName)
.where(where)
.asCursor(database)
}
fun selectCursor(tableName: String, columnName: String, value: Any): Cursor {
return QueryBuilder.query()
.select("*").from(tableName)
.where("$columnName=$value")
.asCursor(database)
}
fun selectCursor(tableName: String, columnName: String, ids: IntArray): Cursor {
val where = StringBuilder(5 * ids.size)
where.append("$columnName=${ids[0]}")
for (i in 1 until ids.size) {
where.append(" OR ")
where.append("$columnName=${ids[i]}")
}
return selectCursor(tableName, where.toString())
}
fun getInt(cursor: Cursor, columnName: String) =
cursor.getInt(cursor.getColumnIndexOrThrow(columnName))
fun getString(cursor: Cursor, columnName: String) =
cursor.getString(cursor.getColumnIndexOrThrow(columnName))
fun getBlob(cursor: Cursor, columnName: String) =
cursor.getBlob(cursor.getColumnIndexOrThrow(columnName))
fun <T> insert(tableName: String, values: ArrayList<T>) {
database.beginTransaction()
val contentValues = ContentValues()
for (value in values) {
when (tableName) {
TABLE_USERS -> {
usersStorage.cacheValue(contentValues, value as VKUser)
break
}
TABLE_FRIENDS -> {
usersStorage.cacheValue(
contentValues,
value as VKUser,
Bundle().apply { putBoolean("toFriends", true) })
break
}
TABLE_MESSAGES -> {
messagesStorage.cacheValue(contentValues, value as VKMessage)
break
}
TABLE_CHATS -> {
chatsStorage.cacheValue(contentValues, value as VKConversation)
break
}
}
database.insert(tableName, null, contentValues)
contentValues.clear()
}
database.setTransactionSuccessful()
database.endTransaction()
}
fun delete(tableName: String, whereClause: String, vararg whereArgs: String) {
database.delete(tableName, whereClause, whereArgs)
}
fun delete(tableName: String) {
database.delete(tableName, null, null)
}
}
@@ -0,0 +1,29 @@
package com.meloda.fast.database
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
class DatabaseHelper constructor(context: Context) : SQLiteOpenHelper(
context,
DB_NAME,
null,
DB_VERSION
) {
companion object {
private const val DB_NAME = "cache.db"
private const val DB_VERSION = 1
}
override fun onCreate(db: SQLiteDatabase) {
db.execSQL(DatabaseUtils.createUsersTable())
db.execSQL(DatabaseUtils.createGroupsTable())
db.execSQL(DatabaseUtils.createFriendsTable())
db.execSQL(DatabaseUtils.createMessagesTable())
db.execSQL(DatabaseUtils.createChatsTable())
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
}
}
@@ -0,0 +1,95 @@
package com.meloda.fast.database
object DatabaseKeys {
const val ID = "_id"
const val SORT_ID = "_sort_id"
const val USER_ID = "_user_id"
const val FIRST_NAME = "_first_name"
const val LAST_NAME = "_last_name"
const val DEACTIVATED = "_deactivated"
const val GENDER = "_gender"
const val SCREEN_NAME = "_screen_name"
const val PHOTOS = "_photos"
const val IS_ONLINE = "_is_online"
const val IS_ONLINE_MOBILE = "_is_online_mobile"
const val STATUS = "_status"
const val LAST_SEEN = "_last_seen"
const val MESSAGE_ID = "_message_id"
const val DATE = "_date"
const val PEER_ID = "_peer_id"
const val FROM_ID = "_from_id"
const val EDIT_TIME = "_edit_time"
const val IS_OUT = "_is_out"
const val TEXT = "_text"
const val RANDOM_ID = "_random_id"
const val CONVERSATION_MESSAGE_ID = "_conversation_message_id"
const val ATTACHMENTS = "_attachments"
const val FWD_MESSAGES = "_fwd_messages"
const val REPLY_MESSAGE_ID = "_reply_message_id"
const val ACTION = "_action"
const val IS_ALLOWED = "_is_allowed"
const val NOT_ALLOWED_REASON = "_not_allowed_reason"
const val IN_READ_MESSAGE_ID = "_in_read_message_id"
const val OUT_READ_MESSAGE_ID = "_out_read_message_id"
const val LAST_MESSAGE_ID = "_last_message_id"
const val UNREAD_COUNT = "_unread_count"
const val CONVERSATION_ID = "_conversation_id"
const val TYPE = "_type"
const val LOCAL_ID = "_local_id"
const val IS_NOTIFICATIONS_DISABLED = "_is_notifications_disabled"
const val MEMBERS_COUNT = "_members_count"
const val TITLE = "_title"
const val PINNED_MESSAGE_ID = "_pinned_message_id"
const val CHAT_STATE = "_chat_state"
const val IS_GROUP_CHANNEL = "_is_group_channel"
const val FRIEND_ID = "_friend_id"
const val GROUP_ID = "_group_id"
const val NAME = "_name"
const val IS_CLOSED = "_is_closed"
}
@@ -0,0 +1,153 @@
package com.meloda.fast.database
import com.meloda.fast.database.DatabaseKeys.ACTION
import com.meloda.fast.database.DatabaseKeys.ATTACHMENTS
import com.meloda.fast.database.DatabaseKeys.CHAT_STATE
import com.meloda.fast.database.DatabaseKeys.CONVERSATION_ID
import com.meloda.fast.database.DatabaseKeys.CONVERSATION_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.DATE
import com.meloda.fast.database.DatabaseKeys.DEACTIVATED
import com.meloda.fast.database.DatabaseKeys.EDIT_TIME
import com.meloda.fast.database.DatabaseKeys.FIRST_NAME
import com.meloda.fast.database.DatabaseKeys.FRIEND_ID
import com.meloda.fast.database.DatabaseKeys.FROM_ID
import com.meloda.fast.database.DatabaseKeys.FWD_MESSAGES
import com.meloda.fast.database.DatabaseKeys.GENDER
import com.meloda.fast.database.DatabaseKeys.GROUP_ID
import com.meloda.fast.database.DatabaseKeys.IN_READ_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.IS_ALLOWED
import com.meloda.fast.database.DatabaseKeys.IS_CLOSED
import com.meloda.fast.database.DatabaseKeys.IS_GROUP_CHANNEL
import com.meloda.fast.database.DatabaseKeys.IS_NOTIFICATIONS_DISABLED
import com.meloda.fast.database.DatabaseKeys.IS_ONLINE
import com.meloda.fast.database.DatabaseKeys.IS_ONLINE_MOBILE
import com.meloda.fast.database.DatabaseKeys.IS_OUT
import com.meloda.fast.database.DatabaseKeys.LAST_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.LAST_NAME
import com.meloda.fast.database.DatabaseKeys.LAST_SEEN
import com.meloda.fast.database.DatabaseKeys.LOCAL_ID
import com.meloda.fast.database.DatabaseKeys.MEMBERS_COUNT
import com.meloda.fast.database.DatabaseKeys.MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.NAME
import com.meloda.fast.database.DatabaseKeys.NOT_ALLOWED_REASON
import com.meloda.fast.database.DatabaseKeys.OUT_READ_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.PEER_ID
import com.meloda.fast.database.DatabaseKeys.PHOTOS
import com.meloda.fast.database.DatabaseKeys.PINNED_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.RANDOM_ID
import com.meloda.fast.database.DatabaseKeys.REPLY_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.SCREEN_NAME
import com.meloda.fast.database.DatabaseKeys.SORT_ID
import com.meloda.fast.database.DatabaseKeys.STATUS
import com.meloda.fast.database.DatabaseKeys.TEXT
import com.meloda.fast.database.DatabaseKeys.TITLE
import com.meloda.fast.database.DatabaseKeys.TYPE
import com.meloda.fast.database.DatabaseKeys.UNREAD_COUNT
import com.meloda.fast.database.DatabaseKeys.USER_ID
object DatabaseUtils {
const val TABLE_USERS = "users"
const val TABLE_MESSAGES = "messages"
const val TABLE_CHATS = "chats"
const val TABLE_FRIENDS = "friends"
const val TABLE_GROUPS = "groups"
private val usersTableMap = HashMap<String, String>().apply {
this[USER_ID] = "integer primary key on conflict replace"
this[FIRST_NAME] = "varchar(255)"
this[LAST_NAME] = "varchar(255)"
this[DEACTIVATED] = "varchar(255)"
this[GENDER] = "integer default 0"
this[SCREEN_NAME] = "varchar(255)"
this[PHOTOS] = "text"
this[IS_ONLINE] = "integer default 0"
this[IS_ONLINE_MOBILE] = "integer default 0"
this[STATUS] = "varchar(255)"
this[LAST_SEEN] = "integer"
}
private val groupsTableMap = HashMap<String, String>().apply {
this[GROUP_ID] = "integer primary key on conflict replace"
this[NAME] = "varchar(255)"
this[SCREEN_NAME] = "varchar(255)"
this[IS_CLOSED] = "integer default 0"
this[DEACTIVATED] = "varchar(255)"
this[TYPE] = "varchar(255)"
this[PHOTOS] = "text"
}
private val messagesTableMap = HashMap<String, String>().apply {
this[MESSAGE_ID] = "integer primary key on conflict replace"
this[DATE] = "integer"
this[PEER_ID] = "integer"
this[FROM_ID] = "integer"
this[EDIT_TIME] = "integer"
this[IS_OUT] = "integer default 0"
this[TEXT] = "text"
this[RANDOM_ID] = "integer"
this[CONVERSATION_MESSAGE_ID] = "integer"
this[ATTACHMENTS] = "blob"
this[REPLY_MESSAGE_ID] = "integer"
this[ACTION] = "blob"
//2,3,4,5 - message_ids
this[FWD_MESSAGES] = "text"
}
private val chatsTableMap = HashMap<String, String>().apply {
this[CONVERSATION_ID] = "integer primary key on conflict replace"
this[IS_ALLOWED] = "integer default 1"
this[NOT_ALLOWED_REASON] = "integer"
this[IN_READ_MESSAGE_ID] = "integer"
this[OUT_READ_MESSAGE_ID] = "integer"
this[LAST_MESSAGE_ID] = "integer"
this[UNREAD_COUNT] = "integer"
this[LOCAL_ID] = "integer"
this[IS_NOTIFICATIONS_DISABLED] = "integer default 0"
this[MEMBERS_COUNT] = "integer"
this[TITLE] = "varchar(255)"
this[IS_GROUP_CHANNEL] = "integer default 0"
this[TYPE] = "integer"
this[CHAT_STATE] = "integer"
this[PHOTOS] = "text"
this[PINNED_MESSAGE_ID] = "integer"
}
private val friendsTableMap = HashMap<String, String>().apply {
this[FRIEND_ID] = "integer primary key on conflict replace"
this[SORT_ID] = "integer"
//id which user friend
this[USER_ID] = "integer"
}
fun createUsersTable() = createTableQuery(TABLE_USERS, usersTableMap)
fun createGroupsTable() = createTableQuery(TABLE_GROUPS, groupsTableMap)
fun createMessagesTable() = createTableQuery(TABLE_MESSAGES, messagesTableMap)
fun createChatsTable() = createTableQuery(TABLE_CHATS, chatsTableMap)
fun createFriendsTable() = createTableQuery(TABLE_FRIENDS, friendsTableMap)
private fun createTableQuery(tableName: String, tableData: HashMap<String, String>): String {
val builder = StringBuilder("create table $tableName (")
val entry: Map.Entry<String, String> = tableData.entries.first()
builder.append(entry.key)
builder.append(" ")
builder.append(entry.value)
tableData.forEach {
if (it == entry) return@forEach
builder.append(", ")
builder.append(it.key)
builder.append(" ")
builder.append(it.value)
}
builder.append(");")
return builder.toString();
}
}
@@ -0,0 +1,71 @@
package com.meloda.fast.database
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
class QueryBuilder private constructor() {
companion object {
fun query(): QueryBuilder {
return QueryBuilder()
}
}
private val builder: StringBuilder = StringBuilder()
fun select(column: String): QueryBuilder {
builder.append("SELECT ")
.append(column)
.append(" ")
return this
}
fun from(table: String): QueryBuilder {
builder.append("FROM ")
.append(table)
.append(" ")
return this
}
fun where(clause: String): QueryBuilder {
builder.append("WHERE ")
.append(clause)
.append(" ")
return this
}
fun leftJoin(table: String): QueryBuilder {
builder.append("LEFT JOIN ")
.append(table)
.append(" ")
return this
}
fun on(where: String): QueryBuilder {
builder.append("ON ")
.append(where)
.append(" ")
return this
}
fun and(): QueryBuilder {
builder.append("AND ")
return this
}
fun or(): QueryBuilder {
builder.append("OR ")
return this
}
fun asCursor(db: SQLiteDatabase): Cursor {
return db.rawQuery(toString(), null)
}
override fun toString(): String {
return builder.toString().trim()
}
}
@@ -0,0 +1,32 @@
package com.meloda.fast.database.base
import android.content.ContentValues
import android.database.Cursor
import android.os.Bundle
import androidx.annotation.WorkerThread
import com.meloda.fast.common.AppGlobal
abstract class Storage<T> {
abstract val tag: String
protected var database = AppGlobal.database
@WorkerThread
abstract fun getAllValues(): ArrayList<T>
@WorkerThread
abstract fun insertValues(values: ArrayList<T>, params: Bundle? = null)
@WorkerThread
fun insertValue(value: T, params: Bundle? = null) {
insertValues(arrayListOf(value), params)
}
@WorkerThread
abstract fun cacheValue(values: ContentValues, value: T, params: Bundle? = null)
@WorkerThread
abstract fun parseValue(cursor: Cursor): T
}
@@ -0,0 +1,141 @@
package com.meloda.fast.database.storage
import android.content.ContentValues
import android.database.Cursor
import android.os.Bundle
import android.util.Log
import androidx.annotation.WorkerThread
import com.meloda.fast.database.CacheStorage
import com.meloda.fast.database.CacheStorage.messagesStorage
import com.meloda.fast.database.DatabaseKeys.CHAT_STATE
import com.meloda.fast.database.DatabaseKeys.CONVERSATION_ID
import com.meloda.fast.database.DatabaseKeys.IN_READ_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.IS_ALLOWED
import com.meloda.fast.database.DatabaseKeys.IS_GROUP_CHANNEL
import com.meloda.fast.database.DatabaseKeys.IS_NOTIFICATIONS_DISABLED
import com.meloda.fast.database.DatabaseKeys.LAST_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.LOCAL_ID
import com.meloda.fast.database.DatabaseKeys.MEMBERS_COUNT
import com.meloda.fast.database.DatabaseKeys.NOT_ALLOWED_REASON
import com.meloda.fast.database.DatabaseKeys.OUT_READ_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.PHOTOS
import com.meloda.fast.database.DatabaseKeys.PINNED_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.TITLE
import com.meloda.fast.database.DatabaseKeys.TYPE
import com.meloda.fast.database.DatabaseKeys.UNREAD_COUNT
import com.meloda.fast.database.DatabaseUtils.TABLE_CHATS
import com.meloda.fast.database.base.Storage
import com.meloda.fast.api.model.VKConversation
import com.meloda.fast.api.util.VKUtil
import org.json.JSONObject
@WorkerThread
class ChatsStorage : Storage<VKConversation>() {
override val tag = "ChatsStorage"
override fun getAllValues(): ArrayList<VKConversation> {
val cursor = CacheStorage.selectCursor(TABLE_CHATS)
val conversations = ArrayList<VKConversation>()
while (cursor.moveToNext()) conversations.add(parseValue(cursor))
cursor.close()
return conversations
}
@WorkerThread
override fun insertValues(values: ArrayList<VKConversation>, params: Bundle?) {
if (values.isEmpty()) return
database.beginTransaction()
val contentValues = ContentValues()
for (value in values) {
cacheValue(contentValues, value, params)
database.insert(TABLE_CHATS, null, contentValues)
contentValues.clear()
}
database.setTransactionSuccessful()
database.endTransaction()
Log.d(tag, "Successful cached chats")
}
@WorkerThread
override fun cacheValue(values: ContentValues, value: VKConversation, params: Bundle?) {
values.put(CONVERSATION_ID, value.id)
values.put(IS_ALLOWED, value.isAllowed)
values.put(NOT_ALLOWED_REASON, value.notAllowedReason.value)
values.put(IN_READ_MESSAGE_ID, value.inReadMessageId)
values.put(OUT_READ_MESSAGE_ID, value.outReadMessageId)
values.put(LAST_MESSAGE_ID, value.lastMessageId)
values.put(UNREAD_COUNT, value.unreadCount)
values.put(LOCAL_ID, value.localId)
values.put(IS_NOTIFICATIONS_DISABLED, value.notificationsEnabled)
values.put(MEMBERS_COUNT, value.membersCount)
values.put(TITLE, value.title)
values.put(IS_GROUP_CHANNEL, value.isGroupChannel)
values.put(TYPE, value.intType)
values.put(CHAT_STATE, value.intState)
values.put(
PHOTOS,
VKUtil.putPhotosToJson(
value.photo50,
value.photo100,
value.photo200
).toString()
)
value.pinnedMessage?.let {
values.put(PINNED_MESSAGE_ID, it.id)
}
}
@WorkerThread
override fun parseValue(cursor: Cursor): VKConversation {
val conversation = VKConversation()
conversation.id = CacheStorage.getInt(cursor, CONVERSATION_ID)
conversation.isAllowed = CacheStorage.getInt(cursor, IS_ALLOWED) == 1
conversation.notAllowedReason = VKConversation.Reason.fromInt(
CacheStorage.getInt(cursor, NOT_ALLOWED_REASON)
)
conversation.inReadMessageId = CacheStorage.getInt(cursor, IN_READ_MESSAGE_ID)
conversation.outReadMessageId = CacheStorage.getInt(cursor, OUT_READ_MESSAGE_ID)
conversation.unreadCount = CacheStorage.getInt(cursor, UNREAD_COUNT)
conversation.localId = CacheStorage.getInt(cursor, LOCAL_ID)
conversation.notificationsEnabled =
CacheStorage.getInt(cursor, IS_NOTIFICATIONS_DISABLED) == 1
conversation.membersCount = CacheStorage.getInt(cursor, MEMBERS_COUNT)
conversation.title = CacheStorage.getString(cursor, TITLE)
conversation.isGroupChannel = CacheStorage.getInt(cursor, IS_GROUP_CHANNEL) == 1
val pinnedMessageId = CacheStorage.getInt(cursor, PINNED_MESSAGE_ID)
if (pinnedMessageId != -1) {
val pinnedMessage = messagesStorage.getMessageById(pinnedMessageId)
if (pinnedMessage != null) conversation.pinnedMessage = pinnedMessage
}
conversation.intType = CacheStorage.getInt(cursor, TYPE)
conversation.intState = CacheStorage.getInt(cursor, CHAT_STATE)
conversation.lastMessageId = CacheStorage.getInt(cursor, LAST_MESSAGE_ID)
val lastMessage = messagesStorage.getMessageById(conversation.lastMessageId)
if (lastMessage != null) conversation.lastMessage = lastMessage
val photos = VKUtil.parseJsonPhotos(JSONObject(CacheStorage.getString(cursor, PHOTOS)))
conversation.photo50 = photos[0]
conversation.photo100 = photos[1]
conversation.photo200 = photos[2]
return conversation
}
}
@@ -0,0 +1,111 @@
package com.meloda.fast.database.storage
import android.content.ContentValues
import android.database.Cursor
import android.os.Bundle
import android.util.Log
import androidx.annotation.WorkerThread
import com.meloda.fast.database.CacheStorage
import com.meloda.fast.database.CacheStorage.getInt
import com.meloda.fast.database.CacheStorage.getString
import com.meloda.fast.database.DatabaseKeys.DEACTIVATED
import com.meloda.fast.database.DatabaseKeys.GROUP_ID
import com.meloda.fast.database.DatabaseKeys.IS_CLOSED
import com.meloda.fast.database.DatabaseKeys.NAME
import com.meloda.fast.database.DatabaseKeys.PHOTOS
import com.meloda.fast.database.DatabaseKeys.SCREEN_NAME
import com.meloda.fast.database.DatabaseKeys.TYPE
import com.meloda.fast.database.DatabaseUtils.TABLE_GROUPS
import com.meloda.fast.database.base.Storage
import com.meloda.fast.api.model.VKGroup
import com.meloda.fast.api.util.VKUtil
import org.json.JSONObject
class GroupsStorage : Storage<VKGroup>() {
override val tag = "GroupsStorage"
@WorkerThread
fun getGroups(ids: IntArray): ArrayList<VKGroup> {
val cursor = CacheStorage.selectCursor(TABLE_GROUPS, GROUP_ID, ids)
val groups = ArrayList<VKGroup>(cursor.count)
while (cursor.moveToNext()) groups.add(parseValue(cursor))
cursor.close()
return groups
}
@WorkerThread
fun getGroup(userId: Int): VKGroup? {
val group = getGroups(intArrayOf(userId))
return if (group.isNotEmpty()) group[0] else null
}
override fun getAllValues(): ArrayList<VKGroup> {
val cursor = CacheStorage.selectCursor(TABLE_GROUPS)
val groups = ArrayList<VKGroup>()
while (cursor.moveToNext()) groups.add(parseValue(cursor))
cursor.close()
return groups
}
override fun insertValues(values: ArrayList<VKGroup>, params: Bundle?) {
if (values.isEmpty()) return
database.beginTransaction()
val contentValues = ContentValues()
for (value in values) {
cacheValue(contentValues, value, params)
database.insert(TABLE_GROUPS, null, contentValues)
contentValues.clear()
}
database.setTransactionSuccessful()
database.endTransaction()
Log.d(tag, "Successful cached groups")
}
override fun cacheValue(values: ContentValues, value: VKGroup, params: Bundle?) {
values.put(GROUP_ID, value.id)
values.put(NAME, value.name)
values.put(SCREEN_NAME, value.screenName)
values.put(IS_CLOSED, value.isClosed)
values.put(DEACTIVATED, value.deactivated)
values.put(TYPE, value.type.value)
val photos =
VKUtil.putPhotosToJson(value.photo50, value.photo100, value.photo200).toString()
values.put(PHOTOS, photos)
}
override fun parseValue(cursor: Cursor): VKGroup {
val group = VKGroup()
group.id = getInt(cursor, GROUP_ID)
group.name = getString(cursor, NAME)
group.screenName = getString(cursor, SCREEN_NAME)
group.isClosed = getInt(cursor, IS_CLOSED) == 1
group.deactivated = getString(cursor, DEACTIVATED)
group.type = VKGroup.Type.fromString(getString(cursor, TYPE))
val photos = VKUtil.parseJsonPhotos(JSONObject(getString(cursor, PHOTOS)))
group.photo50 = photos[0]
group.photo100 = photos[1]
group.photo200 = photos[2]
return group
}
}
@@ -0,0 +1,178 @@
package com.meloda.fast.database.storage
import android.content.ContentValues
import android.database.Cursor
import android.os.Bundle
import android.util.Log
import androidx.annotation.WorkerThread
import com.meloda.fast.database.CacheStorage
import com.meloda.fast.database.CacheStorage.selectCursor
import com.meloda.fast.database.DatabaseKeys.ACTION
import com.meloda.fast.database.DatabaseKeys.ATTACHMENTS
import com.meloda.fast.database.DatabaseKeys.CONVERSATION_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.DATE
import com.meloda.fast.database.DatabaseKeys.EDIT_TIME
import com.meloda.fast.database.DatabaseKeys.FROM_ID
import com.meloda.fast.database.DatabaseKeys.FWD_MESSAGES
import com.meloda.fast.database.DatabaseKeys.IS_OUT
import com.meloda.fast.database.DatabaseKeys.MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.PEER_ID
import com.meloda.fast.database.DatabaseKeys.RANDOM_ID
import com.meloda.fast.database.DatabaseKeys.REPLY_MESSAGE_ID
import com.meloda.fast.database.DatabaseKeys.TEXT
import com.meloda.fast.database.DatabaseUtils.TABLE_MESSAGES
import com.meloda.fast.database.base.Storage
import com.meloda.fast.util.Utils
import com.meloda.fast.api.model.VKMessage
import com.meloda.fast.api.model.VKMessageAction
import com.meloda.fast.api.model.VKModel
import java.util.stream.Collectors
@WorkerThread
@Suppress("UNCHECKED_CAST")
class MessagesStorage : Storage<VKMessage>() {
override val tag = "MessagesStorage"
@WorkerThread
fun getMessagesHistory(peerId: Int): ArrayList<VKMessage> {
val cursor = CacheStorage.selectCursor(TABLE_MESSAGES, PEER_ID, peerId)
val messages = ArrayList<VKMessage>(cursor.count)
while (cursor.moveToNext()) messages.add(parseValue(cursor))
cursor.close()
return messages
}
@WorkerThread
fun getMessageById(messageId: Int): VKMessage? {
val cursor = CacheStorage.selectCursor(TABLE_MESSAGES, MESSAGE_ID, messageId)
if (cursor.moveToFirst()) {
val message = parseValue(cursor)
cursor.close()
return message
}
return null
}
override fun getAllValues(): ArrayList<VKMessage> {
val cursor = selectCursor(TABLE_MESSAGES)
val messages = ArrayList<VKMessage>()
while (cursor.moveToNext()) messages.add(parseValue(cursor))
cursor.close()
return messages
}
@WorkerThread
override fun insertValues(values: ArrayList<VKMessage>, params: Bundle?) {
if (values.isEmpty()) return
database.beginTransaction()
val contentValues = ContentValues()
for (value in values) {
cacheValue(contentValues, value)
database.insert(TABLE_MESSAGES, null, contentValues)
contentValues.clear()
}
database.setTransactionSuccessful()
database.endTransaction()
Log.d(tag, "Successful cached messages")
}
@WorkerThread
override fun cacheValue(values: ContentValues, value: VKMessage, params: Bundle?) {
values.put(MESSAGE_ID, value.id)
values.put(DATE, value.date)
values.put(PEER_ID, value.peerId)
values.put(FROM_ID, value.fromId)
values.put(EDIT_TIME, value.editTime)
values.put(TEXT, value.text)
values.put(RANDOM_ID, value.randomId)
values.put(CONVERSATION_MESSAGE_ID, value.conversationMessageId)
value.replyMessage?.let {
values.put(REPLY_MESSAGE_ID, it.id)
}
value.action?.let {
values.put(ACTION, Utils.serialize(it))
}
value.attachments.let {
if (it.isNotEmpty()) {
values.put(ATTACHMENTS, Utils.serialize(it))
}
}
value.fwdMessages.let {
if (it.isNotEmpty()) {
val ids = arrayListOf<String>()
it.forEach { message -> ids.add(message.id.toString()) }
ids.stream().collect(Collectors.joining(",")).let { str ->
values.put(FWD_MESSAGES, str)
}
}
}
}
@WorkerThread
override fun parseValue(cursor: Cursor): VKMessage {
val message = VKMessage()
message.id = CacheStorage.getInt(cursor, MESSAGE_ID)
message.date = CacheStorage.getInt(cursor, DATE)
message.peerId = CacheStorage.getInt(cursor, PEER_ID)
message.fromId = CacheStorage.getInt(cursor, FROM_ID)
message.editTime = CacheStorage.getInt(cursor, EDIT_TIME)
message.isOut = CacheStorage.getInt(cursor, IS_OUT) == 1
message.text = CacheStorage.getString(cursor, TEXT)
message.randomId = CacheStorage.getInt(cursor, RANDOM_ID)
message.conversationMessageId = CacheStorage.getInt(cursor, CONVERSATION_MESSAGE_ID)
val blobAttachments = Utils.deserialize(CacheStorage.getBlob(cursor, ATTACHMENTS))
if (blobAttachments != null) message.attachments = blobAttachments as ArrayList<VKModel>
else message.attachments = arrayListOf()
val replyMessageId = CacheStorage.getInt(cursor, REPLY_MESSAGE_ID)
val replyMessage = getMessageById(replyMessageId)
if (replyMessage != null) message.replyMessage = replyMessage
val blobAction = Utils.deserialize(CacheStorage.getBlob(cursor, ACTION))
if (blobAction != null) message.action = blobAction as VKMessageAction
val stringFwdMessages = CacheStorage.getString(cursor, FWD_MESSAGES)
if (stringFwdMessages != null) {
val split = stringFwdMessages.split(',')
val ids = arrayListOf<Int>()
for (s in split) ids.add(s.toInt())
val fwdMessages = arrayListOf<VKMessage>()
ids.forEach {
val fwdMessage = getMessageById(it)
if (fwdMessage != null) fwdMessages.add(fwdMessage)
}
message.fwdMessages = fwdMessages
} else message.fwdMessages = arrayListOf()
return message
}
}
@@ -0,0 +1,172 @@
package com.meloda.fast.database.storage
import android.content.ContentValues
import android.database.Cursor
import android.os.Bundle
import android.util.Log
import androidx.annotation.WorkerThread
import com.meloda.fast.UserConfig
import com.meloda.fast.database.CacheStorage
import com.meloda.fast.database.CacheStorage.selectCursor
import com.meloda.fast.database.DatabaseKeys.DEACTIVATED
import com.meloda.fast.database.DatabaseKeys.FIRST_NAME
import com.meloda.fast.database.DatabaseKeys.FRIEND_ID
import com.meloda.fast.database.DatabaseKeys.GENDER
import com.meloda.fast.database.DatabaseKeys.IS_ONLINE
import com.meloda.fast.database.DatabaseKeys.IS_ONLINE_MOBILE
import com.meloda.fast.database.DatabaseKeys.LAST_NAME
import com.meloda.fast.database.DatabaseKeys.LAST_SEEN
import com.meloda.fast.database.DatabaseKeys.PHOTOS
import com.meloda.fast.database.DatabaseKeys.SCREEN_NAME
import com.meloda.fast.database.DatabaseKeys.SORT_ID
import com.meloda.fast.database.DatabaseKeys.STATUS
import com.meloda.fast.database.DatabaseKeys.USER_ID
import com.meloda.fast.database.DatabaseUtils.TABLE_FRIENDS
import com.meloda.fast.database.DatabaseUtils.TABLE_USERS
import com.meloda.fast.database.QueryBuilder
import com.meloda.fast.database.base.Storage
import com.meloda.fast.api.model.VKUser
import com.meloda.fast.api.util.VKUtil
import org.json.JSONObject
@WorkerThread
class UsersStorage : Storage<VKUser>() {
override val tag = "UsersStorage"
@WorkerThread
fun getUsers(ids: IntArray): ArrayList<VKUser> {
val cursor = CacheStorage.selectCursor(TABLE_USERS, USER_ID, ids)
val users = ArrayList<VKUser>(cursor.count)
while (cursor.moveToNext()) users.add(parseValue(cursor))
cursor.close()
return users
}
@WorkerThread
fun getUser(userId: Int): VKUser? {
val user = getUsers(intArrayOf(userId))
return if (user.isNotEmpty()) user[0] else null
}
@WorkerThread
fun getFriends(userId: Int, onlyOnline: Boolean = false): ArrayList<VKUser> {
val cursor = QueryBuilder.query()
.select("*")
.from(TABLE_FRIENDS)
.leftJoin(TABLE_USERS)
.on("friends.${FRIEND_ID} = users.$USER_ID")
.where("friends.${USER_ID} = $userId")
.asCursor(database)
val users = ArrayList<VKUser>(cursor.count)
while (cursor.moveToNext()) {
val userOnline = CacheStorage.getInt(cursor, IS_ONLINE) == 1
if (onlyOnline && !userOnline) continue
val user = parseValue(cursor)
users.add(user)
}
cursor.close()
return users
}
override fun getAllValues(): ArrayList<VKUser> {
val cursor = selectCursor(TABLE_USERS)
val users = ArrayList<VKUser>()
while (cursor.moveToNext()) users.add(parseValue(cursor))
cursor.close()
return users
}
@WorkerThread
override fun insertValues(values: ArrayList<VKUser>, params: Bundle?) {
if (values.isEmpty()) return
val toFriends = params?.getBoolean("toFriends") ?: false
database.beginTransaction()
val contentValues = ContentValues()
for (user in values) {
cacheValue(contentValues, user, params)
database.insert(if (toFriends) TABLE_FRIENDS else TABLE_USERS, null, contentValues)
contentValues.clear()
}
database.setTransactionSuccessful()
database.endTransaction()
Log.d(tag, "Successful cached users. toFriends: $toFriends")
}
@WorkerThread
override fun cacheValue(values: ContentValues, value: VKUser, params: Bundle?) {
val toFriends = params?.getBoolean("toFriends") ?: false
if (toFriends) {
values.put(USER_ID, UserConfig.userId)
values.put(FRIEND_ID, value.userId)
values.put(SORT_ID, value.sortId)
return
}
values.put(USER_ID, value.userId)
values.put(FIRST_NAME, value.firstName)
values.put(LAST_NAME, value.lastName)
values.put(DEACTIVATED, value.deactivated)
values.put(GENDER, value.sex)
values.put(SCREEN_NAME, value.screenName)
values.put(IS_ONLINE, value.isOnline)
values.put(IS_ONLINE_MOBILE, value.isOnlineMobile)
values.put(STATUS, value.status)
values.put(LAST_SEEN, value.lastSeen)
values.put(
PHOTOS,
VKUtil.putPhotosToJson(
value.photo50,
value.photo100,
value.photo200
).toString()
)
}
@WorkerThread
override fun parseValue(cursor: Cursor): VKUser {
val user = VKUser()
user.userId = CacheStorage.getInt(cursor, USER_ID)
user.firstName = CacheStorage.getString(cursor, FIRST_NAME)
user.lastName = CacheStorage.getString(cursor, LAST_NAME)
user.deactivated = CacheStorage.getString(cursor, DEACTIVATED)
user.sex = CacheStorage.getInt(cursor, GENDER)
user.screenName = CacheStorage.getString(cursor, SCREEN_NAME)
user.isOnline = CacheStorage.getInt(cursor, IS_ONLINE) == 1
user.isOnlineMobile = CacheStorage.getInt(cursor, IS_ONLINE_MOBILE) == 1
user.status = CacheStorage.getString(cursor, STATUS)
user.lastSeen = CacheStorage.getInt(cursor, LAST_SEEN)
val photos =
VKUtil.parseJsonPhotos(JSONObject(CacheStorage.getString(cursor, PHOTOS)))
user.photo50 = photos[0]
user.photo100 = photos[1]
user.photo200 = photos[2]
return user
}
}