forked from melod1n/fast-messenger
New cache system
Refactoring Separation into libraries
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.meloda.vksdk">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.meloda.vksdk
|
||||
|
||||
object ErrorCodes {
|
||||
const val UNKNOWN_ERROR = 1
|
||||
const val APP_DISABLED = 2
|
||||
const val UNKNOWN_METHOD = 3
|
||||
const val INVALID_SIGNATURE = 4
|
||||
const val USER_AUTHORIZATION_FAILED = 5
|
||||
const val TOO_MANY_REQUESTS = 6
|
||||
const val NO_RIGHTS = 7
|
||||
const val BAD_REQUEST = 8
|
||||
const val TOO_MANY_SIMILAR_ACTIONS = 9
|
||||
const val INTERNAL_SERVER_ERROR = 10
|
||||
const val IN_TEST_MODE = 11
|
||||
const val EXECUTE_CODE_COMPILE_ERROR = 12
|
||||
const val EXECUTE_CODE_RUNTIME_ERROR = 13
|
||||
const val CAPTCHA_NEEDED = 14
|
||||
const val ACCESS_DENIED = 15
|
||||
const val REQUIRES_REQUESTS_OVER_HTTPS = 16
|
||||
const val VALIDATION_REQUIRED = 17
|
||||
const val USER_BANNED_OR_DELETED = 18
|
||||
const val ACTION_PROHIBITED = 20
|
||||
const val ACTION_ALLOWED_ONLY_FOR_STANDALONE = 21
|
||||
const val METHOD_OFF = 23
|
||||
const val CONFIRMATION_REQUIRED = 24
|
||||
const val PARAMETER_IS_NOT_SPECIFIED = 100
|
||||
const val INCORRECT_APP_ID = 101
|
||||
const val OUT_OF_LIMITS = 103
|
||||
const val INCORRECT_USER_ID = 113
|
||||
const val INCORRECT_TIMESTAMP = 150
|
||||
const val ACCESS_TO_ALBUM_DENIED = 200
|
||||
const val ACCESS_TO_AUDIO_DENIED = 201
|
||||
const val ACCESS_TO_GROUP_DENIED = 203
|
||||
const val ALBUM_IS_FULL = 300
|
||||
const val ACTION_DENIED = 500
|
||||
const val PERMISSION_DENIED = 600
|
||||
const val CANNOT_SEND_MESSAGE_BLACK_LIST = 900
|
||||
const val CANNOT_SEND_MESSAGE_GROUP = 901
|
||||
const val INVALID_DOC_ID = 1150
|
||||
const val INVALID_DOC_TITLE = 1152
|
||||
const val ACCESS_TO_DOC_DENIED = 1153
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.meloda.vksdk
|
||||
|
||||
interface OnResponseListener<T> {
|
||||
|
||||
fun onResponse(response: T)
|
||||
|
||||
fun onError(t: Throwable)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,480 @@
|
||||
package com.meloda.vksdk
|
||||
|
||||
import android.os.Handler
|
||||
import android.util.Log
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.meloda.concurrent.TaskManager
|
||||
import com.meloda.netservices.HttpRequest
|
||||
import com.meloda.vksdk.method.MessageMethodSetter
|
||||
import com.meloda.vksdk.method.MethodSetter
|
||||
import com.meloda.vksdk.method.UserMethodSetter
|
||||
import com.meloda.vksdk.model.*
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
object VKApi {
|
||||
|
||||
private const val TAG = "VKM:VKApi"
|
||||
|
||||
const val BASE_URL = "https://api.vk.com/method/"
|
||||
|
||||
const val API_VERSION = "5.132"
|
||||
|
||||
var language: String = ""
|
||||
var token: String = ""
|
||||
|
||||
private lateinit var handler: Handler
|
||||
|
||||
fun init(language: String, token: String, handler: Handler) {
|
||||
VKApi.language = language
|
||||
VKApi.token = token
|
||||
VKApi.handler = handler
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> execute(url: String, cls: Class<T>?): ArrayList<T>? {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.w(TAG, "url: $url")
|
||||
}
|
||||
|
||||
val buffer = HttpRequest[url].asString()
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.i(TAG, "response: $buffer")
|
||||
}
|
||||
|
||||
val json = JSONObject(buffer)
|
||||
|
||||
try {
|
||||
checkError(json, url)
|
||||
} catch (ex: VKException) {
|
||||
if (ex.code == ErrorCodes.TOO_MANY_REQUESTS) {
|
||||
Timer().schedule(object : TimerTask() {
|
||||
override fun run() {
|
||||
execute(url, cls)
|
||||
}
|
||||
}, 1000)
|
||||
} else throw ex
|
||||
}
|
||||
|
||||
when (cls) {
|
||||
null -> return null
|
||||
|
||||
VKLongPollServer::class.java -> {
|
||||
json.optJSONObject("response")?.let {
|
||||
return arrayListOf(VKLongPollServer(it)) as ArrayList<T>?
|
||||
}
|
||||
}
|
||||
|
||||
Boolean::class.java -> {
|
||||
val value = json.optInt("response") == 1
|
||||
return arrayListOf(value) as ArrayList<T>?
|
||||
}
|
||||
|
||||
Long::class.java -> {
|
||||
val value = json.optLong("response")
|
||||
return arrayListOf(value) as ArrayList<T>?
|
||||
}
|
||||
|
||||
Int::class.java -> {
|
||||
val value = json.optInt("response")
|
||||
return arrayListOf(value) as ArrayList<T>?
|
||||
}
|
||||
}
|
||||
|
||||
val response = json.opt("response") ?: return null
|
||||
|
||||
val array = optItems(json) ?: return null
|
||||
val models = ArrayList<T>(array.length())
|
||||
|
||||
when (cls) {
|
||||
VKUser::class.java -> {
|
||||
json.optJSONObject("response")?.let { r ->
|
||||
VKUser.friendsCount = r.optInt("count")
|
||||
}
|
||||
|
||||
for (i in 0 until array.length()) {
|
||||
models.add(VKUser(array.optJSONObject(i)) as T)
|
||||
}
|
||||
}
|
||||
|
||||
VKMessage::class.java -> {
|
||||
response as JSONObject
|
||||
|
||||
if (url.contains("messages.getHistory")) {
|
||||
VKMessage.lastHistoryCount = response.optInt("count")
|
||||
|
||||
response.optJSONArray("profiles")?.let {
|
||||
val profiles = arrayListOf<VKUser>()
|
||||
|
||||
for (j in 0 until it.length()) {
|
||||
profiles.add(VKUser(it.optJSONObject(j)))
|
||||
}
|
||||
|
||||
VKMessage.profiles = profiles
|
||||
}
|
||||
|
||||
response.optJSONArray("groups")?.let {
|
||||
val groups = arrayListOf<VKGroup>()
|
||||
|
||||
for (j in 0 until it.length()) {
|
||||
groups.add(VKGroup(it.optJSONObject(j)))
|
||||
}
|
||||
|
||||
VKMessage.groups = groups
|
||||
}
|
||||
|
||||
response.optJSONArray("conversations")?.let {
|
||||
val conversations = arrayListOf<VKConversation>()
|
||||
|
||||
for (j in 0 until it.length()) {
|
||||
conversations.add(VKConversation(it.optJSONObject(j)))
|
||||
}
|
||||
|
||||
VKMessage.conversations = conversations
|
||||
}
|
||||
}
|
||||
|
||||
for (i in 0 until array.length()) {
|
||||
var source = array.optJSONObject(i)
|
||||
if (source.has("message")) {
|
||||
source = source.optJSONObject("message")
|
||||
}
|
||||
|
||||
val message = VKMessage(source)
|
||||
models.add(message as T)
|
||||
}
|
||||
}
|
||||
|
||||
VKGroup::class.java -> {
|
||||
for (i in 0 until array.length()) {
|
||||
models.add(VKGroup(array.optJSONObject(i)) as T)
|
||||
}
|
||||
}
|
||||
|
||||
VKModel::class.java -> {
|
||||
if (url.contains("messages.getHistoryAttachments")) {
|
||||
return VKAttachments.parse(array) as ArrayList<T>
|
||||
}
|
||||
}
|
||||
|
||||
VKConversation::class.java -> {
|
||||
if (url.contains("getConversationsById")) {
|
||||
for (i in 0 until array.length()) {
|
||||
val source = array.optJSONObject(i)
|
||||
models.add(VKConversation(source) as T)
|
||||
}
|
||||
|
||||
return models
|
||||
}
|
||||
|
||||
json.optJSONObject("response")?.let { r ->
|
||||
VKConversation.conversationsCount = r.optInt("count")
|
||||
}
|
||||
|
||||
for (i in 0 until array.length()) {
|
||||
response as JSONObject
|
||||
|
||||
val source = array.optJSONObject(i)
|
||||
val oConversation = source.optJSONObject("conversation") ?: return null
|
||||
val oLastMessage = source.optJSONObject("last_message") ?: return null
|
||||
|
||||
val conversation = VKConversation(oConversation).also {
|
||||
it.lastMessage = VKMessage(oLastMessage)
|
||||
}
|
||||
|
||||
response.optJSONArray("profiles")?.let {
|
||||
val profiles = arrayListOf<VKUser>()
|
||||
|
||||
for (j in 0 until it.length()) {
|
||||
profiles.add(VKUser(it.optJSONObject(j)))
|
||||
}
|
||||
|
||||
VKConversation.profiles = profiles
|
||||
}
|
||||
|
||||
response.optJSONArray("groups")?.let {
|
||||
val groups = arrayListOf<VKGroup>()
|
||||
|
||||
for (j in 0 until it.length()) {
|
||||
groups.add(VKGroup(it.optJSONObject(j)))
|
||||
}
|
||||
|
||||
VKConversation.groups = groups
|
||||
}
|
||||
|
||||
models.add(conversation as T)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return models
|
||||
}
|
||||
|
||||
fun <E> execute(url: String, cls: Class<E>, listener: OnResponseListener<E>?) {
|
||||
TaskManager.execute {
|
||||
try {
|
||||
val models = execute(url, cls)
|
||||
|
||||
listener?.let { SuccessCallback(listener, models as E) }
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
|
||||
listener?.let { ErrorCallback(listener, e) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <E> executeArray(url: String, cls: Class<E>, listener: OnResponseListener<ArrayList<E>>) {
|
||||
TaskManager.execute {
|
||||
try {
|
||||
val models = execute(url, cls)
|
||||
|
||||
handler.post { listener.onResponse(models as ArrayList<E>) }
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
|
||||
listener.onError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun optItems(source: JSONObject): JSONArray? {
|
||||
val response = source.opt("response")
|
||||
|
||||
return when (response) {
|
||||
is JSONArray -> response
|
||||
is JSONObject -> response.optJSONArray("items")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkError(json: JSONObject, url: String) {
|
||||
if (json.has("error")) {
|
||||
val error = json.optJSONObject("error") ?: return
|
||||
|
||||
val code = error.optInt("error_code", -1)
|
||||
val message = error.optString("error_msg", "")
|
||||
val e = VKException(url, message, code)
|
||||
|
||||
//TODO: add checking invalid session
|
||||
if (code == 5 && message.contains("invalid session")) {
|
||||
// context?.startActivity(Intent(context, DropUserDataActivity::class.java).apply {
|
||||
// addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
// })
|
||||
}
|
||||
|
||||
if (code == ErrorCodes.CAPTCHA_NEEDED) {
|
||||
e.captchaImg = error.optString("captcha_img")
|
||||
e.captchaSid = error.optString("captcha_sid")
|
||||
}
|
||||
|
||||
if (code == ErrorCodes.VALIDATION_REQUIRED) {
|
||||
e.redirectUri = error.optString("redirect_uri")
|
||||
}
|
||||
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
fun users(): VKUsers {
|
||||
return VKUsers()
|
||||
}
|
||||
|
||||
fun friends(): VKFriends {
|
||||
return VKFriends()
|
||||
}
|
||||
|
||||
fun messages(): VKMessages {
|
||||
return VKMessages()
|
||||
}
|
||||
|
||||
fun groups(): VKGroups {
|
||||
return VKGroups()
|
||||
}
|
||||
|
||||
fun account(): VKAccounts {
|
||||
return VKAccounts()
|
||||
}
|
||||
|
||||
class VKFriends {
|
||||
fun get(): MethodSetter {
|
||||
return MethodSetter("friends.get")
|
||||
}
|
||||
}
|
||||
|
||||
class VKUsers {
|
||||
fun get(): UserMethodSetter {
|
||||
return UserMethodSetter("users.get")
|
||||
}
|
||||
}
|
||||
|
||||
class VKMessages {
|
||||
fun get(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.get")
|
||||
}
|
||||
|
||||
fun getConversations(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.getConversations")
|
||||
}
|
||||
|
||||
fun getConversationsById(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.getConversationsById")
|
||||
}
|
||||
|
||||
fun getById(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.getById")
|
||||
}
|
||||
|
||||
fun search(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.search")
|
||||
}
|
||||
|
||||
fun getHistory(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.getHistory")
|
||||
}
|
||||
|
||||
fun getHistoryAttachments(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.getHistoryAttachments")
|
||||
}
|
||||
|
||||
fun send(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.send")
|
||||
}
|
||||
|
||||
fun sendSticker(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.sendSticker")
|
||||
}
|
||||
|
||||
fun delete(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.delete")
|
||||
}
|
||||
|
||||
fun deleteDialog(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.deleteDialog")
|
||||
}
|
||||
|
||||
fun restore(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.restore")
|
||||
}
|
||||
|
||||
fun markAsRead(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.markAsRead")
|
||||
}
|
||||
|
||||
fun markAsImportant(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.markAsImportant")
|
||||
}
|
||||
|
||||
fun getLongPollServer(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.getLongPollServer")
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns updates in user's private messages.
|
||||
* To speed up handling of private messages,
|
||||
* it can be useful to cache previously loaded messages on
|
||||
* a user's mobile device/desktop, to prevent re-receipt at each call.
|
||||
* With this method, you can synchronize a local copy of
|
||||
* the message list with the actual version.
|
||||
*
|
||||
*
|
||||
* Result:
|
||||
* Returns an object that contains the following fields:
|
||||
* 1 — history: An array similar to updates field returned
|
||||
* from the Long Poll server,
|
||||
* with these exceptions:
|
||||
* - For events with code 4 (addition of a new message),
|
||||
* there are no fields except the first three.
|
||||
* - There are no events with codes 8, 9 (friend goes online/offline)
|
||||
* or with codes 61, 62 (typing during conversation/chat).
|
||||
*
|
||||
*
|
||||
* 2 — messages: An array of private message objects that were found
|
||||
* among events with code 4 (addition of a new message)
|
||||
* from the history field.
|
||||
* Each object of message contains a set of fields described here.
|
||||
* The first array element is the total number of messages
|
||||
*/
|
||||
fun getLongPollHistory(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.getLongPollHistory")
|
||||
}
|
||||
|
||||
fun getChat(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.getChat")
|
||||
}
|
||||
|
||||
fun createChat(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.createChat")
|
||||
}
|
||||
|
||||
fun editChat(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.editChat")
|
||||
}
|
||||
|
||||
val chatUsers: MessageMethodSetter
|
||||
get() = MessageMethodSetter("messages.getChatUsers")
|
||||
|
||||
fun setActivity(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.setActivity").type(true)
|
||||
}
|
||||
|
||||
fun addChatUser(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.addChatUser")
|
||||
}
|
||||
|
||||
fun removeChatUser(): MessageMethodSetter {
|
||||
return MessageMethodSetter("messages.removeChatUser")
|
||||
}
|
||||
}
|
||||
|
||||
class VKGroups {
|
||||
fun getById(): MethodSetter {
|
||||
return MethodSetter("groups.getById")
|
||||
}
|
||||
|
||||
fun join(): MethodSetter {
|
||||
return MethodSetter("groups.join")
|
||||
}
|
||||
}
|
||||
|
||||
class VKAccounts {
|
||||
fun setOffline(): MethodSetter {
|
||||
return MethodSetter("account.setOffline")
|
||||
}
|
||||
|
||||
fun setOnline(): MethodSetter {
|
||||
return MethodSetter("account.setOnline")
|
||||
}
|
||||
}
|
||||
|
||||
class SuccessCallback<E>(
|
||||
private val listener: OnResponseListener<E>?,
|
||||
private val response: E
|
||||
) : Runnable {
|
||||
override fun run() {
|
||||
listener?.onResponse(response)
|
||||
}
|
||||
}
|
||||
|
||||
class SuccessArrayCallback<E>(
|
||||
private val listener: OnResponseListener<ArrayList<E>>?,
|
||||
private val response: ArrayList<E>
|
||||
) : Runnable {
|
||||
override fun run() {
|
||||
listener?.onResponse(response)
|
||||
}
|
||||
}
|
||||
|
||||
class ErrorCallback<E>(
|
||||
private val listener: OnResponseListener<E>?,
|
||||
private val exception: Exception
|
||||
) : Runnable {
|
||||
override fun run() {
|
||||
listener?.onError(exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.meloda.vksdk
|
||||
|
||||
enum class VKApiKeys(val value: String) {
|
||||
READ_MESSAGE("_read_message"),
|
||||
RESTORE_MESSAGE("_restore_message"),
|
||||
NEW_MESSAGE("_new_message"),
|
||||
EDIT_MESSAGE("_edit_message"),
|
||||
DELETE_MESSAGE("_delete_message"),
|
||||
|
||||
UPDATE_MESSAGE("_update_message"),
|
||||
UPDATE_CONVERSATION("_update_conversation"),
|
||||
UPDATE_USER("_update_user"),
|
||||
UPDATE_GROUP("_update_group")
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.meloda.vksdk
|
||||
|
||||
import android.util.Log
|
||||
import com.meloda.vksdk.util.VKUtil
|
||||
import java.net.URLEncoder
|
||||
|
||||
object VKAuth {
|
||||
|
||||
private const val TAG = "VKM.VKAuth"
|
||||
|
||||
const val settings =
|
||||
"notify," +
|
||||
"friends," +
|
||||
"photos," +
|
||||
"audio," +
|
||||
"video," +
|
||||
"docs," +
|
||||
"status," +
|
||||
"notes," +
|
||||
"pages," +
|
||||
"wall," +
|
||||
"groups," +
|
||||
"messages," +
|
||||
"offline," +
|
||||
"notifications"
|
||||
|
||||
const val redirectUrl = "https://oauth.vk.com/blank.html"
|
||||
|
||||
fun getDirectAuthUrl(login: String, password: String, captcha: String = ""): String {
|
||||
return "https://oauth.vk.com/token?grant_type=password&" +
|
||||
"client_id=6146827&" +
|
||||
"scope=$settings&" +
|
||||
"client_secret=qVxWRF1CwHERuIrKBnqe&" +
|
||||
"username=$login&" +
|
||||
"password=$password" +
|
||||
(if (captcha.isEmpty()) "" else "&$captcha") +
|
||||
"&v=${VKApi.API_VERSION}"
|
||||
// return "https://oauth.vk.com/token?grant_type=password&" +
|
||||
// "client_id=2274003&" +
|
||||
// "scope=notify,friends,photos,audio,video,docs,notes,pages,status,offers,questions,wall,groups,messages,email,notifications,stats,ads,market,offline&" +
|
||||
// "client_secret=hHbZxrka2uZ6jB1inYsH&" +
|
||||
// "username=$login&" +
|
||||
// "password=$password" +
|
||||
// (if (captcha.isEmpty()) "" else "&$captcha") +
|
||||
// "&v=${VKApi.API_VERSION}"
|
||||
}
|
||||
|
||||
fun getUrl(api_id: String, settings: String): String {
|
||||
return "https://oauth.vk.com/authorize?" +
|
||||
"client_id=$api_id&" +
|
||||
"display=mobile&" +
|
||||
"scope=$settings&" +
|
||||
"redirect_uri=${
|
||||
URLEncoder.encode(
|
||||
redirectUrl,
|
||||
"utf-8"
|
||||
)
|
||||
}&" +
|
||||
"response_type=token&" +
|
||||
"v=${URLEncoder.encode(VKApi.API_VERSION, "utf-8")}"
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun parseRedirectUrl(url: String): Array<String> {
|
||||
val accessToken = VKUtil.extractPattern(url, "access_token=(.*?)&")
|
||||
val userId = VKUtil.extractPattern(url, "user_id=(\\d*)")
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.i(TAG, "access_token=$accessToken")
|
||||
Log.i(TAG, "user_id=$userId")
|
||||
}
|
||||
|
||||
if (userId == null || userId.isEmpty() || accessToken == null || accessToken.isEmpty()) throw Exception(
|
||||
"Failed to parse redirect url $url"
|
||||
)
|
||||
|
||||
return arrayOf(accessToken, userId)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.meloda.vksdk
|
||||
|
||||
object VKConstants {
|
||||
|
||||
|
||||
const val GROUP_FIELDS = "description,members_count,counters,status,verified"
|
||||
|
||||
const val USER_FIELDS =
|
||||
"photo_50,photo_100,photo_200,status,screen_name,online,online_mobile,last_seen,verified,sex"
|
||||
|
||||
/*
|
||||
|
||||
const val ACTION_CHAT_CREATE = "chat_create"
|
||||
const val ACTION_PHOTO_UPDATE = "chat_photo_update"
|
||||
const val ACTION_PHOTO_REMOVE = "chat_photo_remove"
|
||||
const val ACTION_TITLE_UPDATE = "chat_title_update"
|
||||
const val ACTION_PIN_MESSAGE = "chat_pin_message"
|
||||
const val ACTION_UNPIN_MESSAGE = "chat_unpin_message"
|
||||
const val ACTION_INVITE_USER = "chat_invite_user"
|
||||
const val ACTION_INVITE_USER_BY_LINK = "chat_invite_user_by_link"
|
||||
const val ACTION_KICK_USER = "chat_kick_user"
|
||||
const val ACTION_SCREENSHOT = "chat_screenshot"
|
||||
const val ACTION_INVITE_USER_BY_CALL = "chat_invite_user_by_call"
|
||||
const val ACTION_INVITE_USER_BY_CALL_JOIN_LINK = "chat_invite_user_by_call_link"
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.meloda.vksdk
|
||||
|
||||
import java.io.IOException
|
||||
|
||||
class VKException(var url: String, override var message: String, var code: Int) :
|
||||
IOException(message) {
|
||||
var captchaSid: String? = null
|
||||
var captchaImg: String? = null
|
||||
var redirectUri: String? = null
|
||||
|
||||
override fun toString(): String {
|
||||
return "code: $code, message: $message"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package com.meloda.vksdk.method
|
||||
|
||||
import com.meloda.arrayutils.ArrayUtils
|
||||
|
||||
class MessageMethodSetter(name: String) : MethodSetter(name) {
|
||||
|
||||
fun out(value: Boolean): MessageMethodSetter {
|
||||
put("out", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun timeOffset(value: Int): MessageMethodSetter {
|
||||
put("time_offset", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun filters(value: Int): MessageMethodSetter {
|
||||
put("filters", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun previewLength(value: Int): MessageMethodSetter {
|
||||
put("preview_length", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun lastMessageId(value: Int): MessageMethodSetter {
|
||||
put("last_message_id", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun unread(value: Boolean): MessageMethodSetter {
|
||||
put("unread", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun messageIds(vararg ids: Int): MessageMethodSetter {
|
||||
put("message_ids", ArrayUtils.asString(ids))
|
||||
return this
|
||||
}
|
||||
|
||||
fun messageIds(ids: ArrayList<Int>): MessageMethodSetter {
|
||||
put("message_ids", ArrayUtils.asString(ids))
|
||||
return this
|
||||
}
|
||||
|
||||
fun q(query: String): MessageMethodSetter {
|
||||
put("q", query)
|
||||
return this
|
||||
}
|
||||
|
||||
fun startMessageId(id: Int): MessageMethodSetter {
|
||||
put("start_message_id", id)
|
||||
return this
|
||||
}
|
||||
|
||||
fun peerId(value: Int): MessageMethodSetter {
|
||||
put("peer_id", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun peerIds(vararg values: Int): MessageMethodSetter {
|
||||
put("peer_ids", ArrayUtils.asString(values))
|
||||
return this
|
||||
}
|
||||
|
||||
fun reversed(value: Boolean): MessageMethodSetter {
|
||||
put("rev", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun domain(value: String): MessageMethodSetter {
|
||||
put("domain", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun chatId(value: Int): MessageMethodSetter {
|
||||
put("chat_id", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun message(message: String): MessageMethodSetter {
|
||||
put("message", message)
|
||||
return this
|
||||
}
|
||||
|
||||
fun randomId(value: Int): MessageMethodSetter {
|
||||
put("random_id", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun lat(lat: Double): MessageMethodSetter {
|
||||
put("lat", lat)
|
||||
return this
|
||||
}
|
||||
|
||||
fun longitude(value: Long): MessageMethodSetter {
|
||||
put("LONG", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun attachment(attachments: Collection<String>): MessageMethodSetter {
|
||||
put("attachment", ArrayUtils.asString(attachments))
|
||||
return this
|
||||
}
|
||||
|
||||
fun attachment(vararg attachments: String): MessageMethodSetter {
|
||||
put("attachment", ArrayUtils.asString(*attachments))
|
||||
return this
|
||||
}
|
||||
|
||||
fun forwardMessages(ids: Collection<String>): MessageMethodSetter {
|
||||
put("forward_messages", ArrayUtils.asString(ids))
|
||||
return this
|
||||
}
|
||||
|
||||
fun forwardMessages(vararg ids: Int): MessageMethodSetter {
|
||||
put("forward_messages", ArrayUtils.asString(ids))
|
||||
return this
|
||||
}
|
||||
|
||||
fun stickerId(value: Int): MessageMethodSetter {
|
||||
put("sticker_id", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun messageId(value: Int): MessageMethodSetter {
|
||||
put("message_id", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun important(value: Boolean): MessageMethodSetter {
|
||||
put("important", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun ts(value: Long): MessageMethodSetter {
|
||||
put("ts", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun pts(value: Int): MessageMethodSetter {
|
||||
put("pts", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun msgsLimit(limit: Int): MessageMethodSetter {
|
||||
put("msgs_limit", limit)
|
||||
return this
|
||||
}
|
||||
|
||||
fun onlines(onlines: Boolean): MessageMethodSetter {
|
||||
put("onlines", onlines)
|
||||
return this
|
||||
}
|
||||
|
||||
fun maxMsgId(id: Int): MessageMethodSetter {
|
||||
put("max_msg_id", id)
|
||||
return this
|
||||
}
|
||||
|
||||
fun chatIds(vararg ids: Int): MessageMethodSetter {
|
||||
put("max_msg_id", ArrayUtils.asString(ids))
|
||||
return this
|
||||
}
|
||||
|
||||
fun chatIds(ids: Collection<Int>): MessageMethodSetter {
|
||||
put("max_msg_id", ArrayUtils.asString(ids))
|
||||
return this
|
||||
}
|
||||
|
||||
fun title(title: String): MessageMethodSetter {
|
||||
put("title", title)
|
||||
return this
|
||||
}
|
||||
|
||||
fun type(typing: Boolean): MessageMethodSetter {
|
||||
if (typing) {
|
||||
put("type", "typing")
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun mediaType(type: String): MessageMethodSetter {
|
||||
put("media_type", type)
|
||||
return this
|
||||
}
|
||||
|
||||
fun photoSizes(value: Boolean): MessageMethodSetter {
|
||||
return put("photo_sizes", value) as MessageMethodSetter
|
||||
}
|
||||
|
||||
fun filter(value: String): MessageMethodSetter {
|
||||
return put("filter", value) as MessageMethodSetter
|
||||
}
|
||||
|
||||
fun extended(value: Boolean): MessageMethodSetter {
|
||||
return put("extended", value) as MessageMethodSetter
|
||||
}
|
||||
|
||||
fun markConversationAsRead(asRead: Boolean): MessageMethodSetter {
|
||||
put("mark_conversation_as_read", asRead)
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package com.meloda.vksdk.method
|
||||
|
||||
import android.util.ArrayMap
|
||||
import android.util.Log
|
||||
import com.meloda.arrayutils.ArrayUtils
|
||||
import com.meloda.vksdk.BuildConfig
|
||||
import com.meloda.vksdk.OnResponseListener
|
||||
import com.meloda.vksdk.VKApi
|
||||
import java.net.URLEncoder
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
open class MethodSetter(private val name: String) {
|
||||
|
||||
private val params: ArrayMap<String, String> = ArrayMap()
|
||||
|
||||
fun put(key: String, value: Any): MethodSetter {
|
||||
params[key] = value.toString()
|
||||
return this
|
||||
}
|
||||
|
||||
fun put(key: String, value: String): MethodSetter {
|
||||
params[key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
fun put(key: String, value: Int): MethodSetter {
|
||||
params[key] = value.toString()
|
||||
return this
|
||||
}
|
||||
|
||||
fun put(key: String, value: Long): MethodSetter {
|
||||
params[key] = value.toString()
|
||||
return this
|
||||
}
|
||||
|
||||
fun put(key: String, value: Boolean): MethodSetter {
|
||||
params[key] = if (value) "1" else "0"
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getSignedUrl(): String {
|
||||
if (!params.containsKey("access_token")) {
|
||||
params["access_token"] = VKApi.token
|
||||
}
|
||||
|
||||
if (!params.containsKey("v")) {
|
||||
params["v"] = VKApi.API_VERSION
|
||||
}
|
||||
|
||||
if (!params.containsKey("lang")) {
|
||||
params["lang"] = VKApi.language
|
||||
}
|
||||
|
||||
return "${VKApi.BASE_URL}$name?${retrieveParams()}"
|
||||
}
|
||||
|
||||
private fun retrieveParams(): String {
|
||||
val builder = StringBuilder()
|
||||
|
||||
for (i in 0 until params.size) {
|
||||
val key = params.keyAt(i)
|
||||
val value = params.valueAt(i)
|
||||
|
||||
if (builder.isNotEmpty()) {
|
||||
builder.append("&")
|
||||
}
|
||||
|
||||
builder.append(key)
|
||||
builder.append("=")
|
||||
builder.append(URLEncoder.encode(value, "UTF-8"))
|
||||
}
|
||||
|
||||
val params = builder.toString()
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.i("MethodSetter", "retrieved params: $params")
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
fun <E> execute(cls: Class<E>): ArrayList<E>? {
|
||||
return VKApi.execute(getSignedUrl(), cls)
|
||||
}
|
||||
|
||||
fun <E> executeArray(cls: Class<E>, listener: OnResponseListener<ArrayList<E>>) {
|
||||
VKApi.executeArray(getSignedUrl(), cls, listener)
|
||||
}
|
||||
|
||||
fun <E> execute(cls: Class<E>, listener: OnResponseListener<E>?) {
|
||||
VKApi.execute(getSignedUrl(), cls, listener)
|
||||
}
|
||||
|
||||
fun userId(value: Int): MethodSetter {
|
||||
return put("user_id", value)
|
||||
}
|
||||
|
||||
fun userIds(vararg ids: Int): MethodSetter {
|
||||
return put("user_ids", ArrayUtils.asString(ids))
|
||||
}
|
||||
|
||||
fun userIds(ids: ArrayList<Int>): MethodSetter {
|
||||
return put("user_ids", ArrayUtils.asString(ids))
|
||||
}
|
||||
|
||||
fun ownerId(value: Int): MethodSetter {
|
||||
return put("owner_id", value)
|
||||
}
|
||||
|
||||
fun groupId(value: Int): MethodSetter {
|
||||
return put("group_id", value)
|
||||
}
|
||||
|
||||
fun groupIds(vararg ids: Int): MethodSetter {
|
||||
return put("group_ids", ArrayUtils.asString(ids))
|
||||
}
|
||||
|
||||
fun groupIds(ids: ArrayList<Int>): MethodSetter {
|
||||
return put("group_ids", ArrayUtils.asString(ids))
|
||||
}
|
||||
|
||||
fun fields(values: String): MethodSetter {
|
||||
return put("fields", values)
|
||||
}
|
||||
|
||||
fun count(value: Int): MethodSetter {
|
||||
return put("count", value)
|
||||
}
|
||||
|
||||
fun sort(value: Int): MethodSetter {
|
||||
put("sort", value)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* hints — сортировать по рейтингу, аналогично тому, как друзья сортируются в разделе Мои друзья
|
||||
* random — возвращает друзей в случайном порядке.
|
||||
* mobile — возвращает выше тех друзей, у которых установлены мобильные приложения.
|
||||
* name — сортировать по имени (долго)
|
||||
*
|
||||
*/
|
||||
|
||||
fun order(value: String): MethodSetter {
|
||||
put("order", value)
|
||||
return this
|
||||
}
|
||||
|
||||
fun offset(value: Int = 0): MethodSetter {
|
||||
return put("offset", value)
|
||||
}
|
||||
|
||||
fun nameCase(value: String): MethodSetter {
|
||||
return put("name_case", value)
|
||||
}
|
||||
|
||||
fun captchaSid(value: String): MethodSetter {
|
||||
return put("captcha_sid", value)
|
||||
}
|
||||
|
||||
fun captchaKey(value: String): MethodSetter {
|
||||
return put("captcha_key", value)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.meloda.vksdk.method
|
||||
|
||||
class UserMethodSetter(name: String) : MethodSetter(name) {
|
||||
|
||||
fun extended(extended: Boolean): UserMethodSetter {
|
||||
put("extended", extended)
|
||||
return this
|
||||
}
|
||||
|
||||
fun type(type: String): UserMethodSetter {
|
||||
put("type", type)
|
||||
return this
|
||||
}
|
||||
|
||||
fun comment(comment: String): UserMethodSetter {
|
||||
put("comment", comment)
|
||||
return this
|
||||
}
|
||||
|
||||
fun latitude(latitude: Float): UserMethodSetter {
|
||||
put("latitude", latitude)
|
||||
return this
|
||||
}
|
||||
|
||||
fun longitude(longitude: Float): UserMethodSetter {
|
||||
put("longitude", longitude)
|
||||
return this
|
||||
}
|
||||
|
||||
fun accuracy(accuracy: Int): UserMethodSetter {
|
||||
put("accuracy", accuracy)
|
||||
return this
|
||||
}
|
||||
|
||||
fun timeout(timeout: Int): UserMethodSetter {
|
||||
put("timeout", timeout)
|
||||
return this
|
||||
}
|
||||
|
||||
fun radius(radius: Int): UserMethodSetter {
|
||||
put("radius", radius)
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONArray
|
||||
import java.util.*
|
||||
|
||||
object VKAttachments {
|
||||
|
||||
fun parse(array: JSONArray): ArrayList<VKModel> {
|
||||
val attachments = ArrayList<VKModel>(array.length())
|
||||
|
||||
for (i in 0 until array.length()) {
|
||||
var attachment = array.optJSONObject(i) ?: continue
|
||||
if (attachment.has("attachment")) {
|
||||
attachment = attachment.optJSONObject("attachment") ?: continue
|
||||
}
|
||||
|
||||
val type = Type.fromString(attachment.optString("type"))
|
||||
val jsonObject = attachment.optJSONObject(type.value) ?: continue
|
||||
|
||||
when (type) {
|
||||
Type.PHOTO -> attachments.add(VKPhoto(jsonObject))
|
||||
Type.AUDIO -> attachments.add(VKAudio(jsonObject))
|
||||
Type.VIDEO -> attachments.add(VKVideo(jsonObject))
|
||||
Type.DOCUMENT -> attachments.add(VKDocument(jsonObject))
|
||||
Type.STICKER -> attachments.add(VKSticker(jsonObject))
|
||||
Type.LINK -> attachments.add(VKLink(jsonObject))
|
||||
Type.GIFT -> attachments.add(VKGift(jsonObject))
|
||||
Type.VOICE_MESSAGE -> attachments.add(VKAudioMessage(jsonObject))
|
||||
Type.GRAFFITI -> attachments.add(VKGraffiti(jsonObject))
|
||||
Type.POLL -> attachments.add(VKPoll(jsonObject))
|
||||
Type.CALL -> attachments.add(VKCall(jsonObject))
|
||||
Type.WALL_POST -> attachments.add(VKWall(jsonObject))
|
||||
Type.WALL_REPLY -> attachments.add(VKComment(jsonObject))
|
||||
Type.GEOLOCATION -> attachments.add(VKGeolocation(jsonObject))
|
||||
else -> continue
|
||||
}
|
||||
}
|
||||
|
||||
return attachments
|
||||
}
|
||||
|
||||
enum class Type(val value: String) {
|
||||
NONE("none"),
|
||||
PHOTO("photo"),
|
||||
VIDEO("video"),
|
||||
AUDIO("audio"),
|
||||
AUDIO_PLAYLIST("audio_playlist"),
|
||||
DOCUMENT("doc"),
|
||||
LINK("link"),
|
||||
STICKER("sticker"),
|
||||
GIFT("gift"),
|
||||
VOICE_MESSAGE("audio_message"),
|
||||
GRAFFITI("graffiti"),
|
||||
POLL("poll"),
|
||||
GEOLOCATION("geo"),
|
||||
WALL_POST("wall"),
|
||||
WALL_REPLY("wall_reply"),
|
||||
CALL("call"),
|
||||
STORY("story"),
|
||||
POINT("point"),
|
||||
MARKET("market"),
|
||||
ARTICLE("article"),
|
||||
PODCAST("podcast"),
|
||||
MONEY_REQUEST("money_request");
|
||||
|
||||
companion object {
|
||||
fun fromString(value: String): Type {
|
||||
for (v in values()) {
|
||||
if (v.value == value) return v
|
||||
}
|
||||
|
||||
return NONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKAudio() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.AUDIO
|
||||
|
||||
var id: Int = 0
|
||||
var ownerId: Int = 0
|
||||
var artist: String = ""
|
||||
var title: String = ""
|
||||
var duration: Int = 0
|
||||
var url: String = ""
|
||||
var date: Int = 0
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
id = o.optInt("id", -1)
|
||||
ownerId = o.optInt("owner_id", -1)
|
||||
artist = o.optString("artist")
|
||||
title = o.optString("title")
|
||||
duration = o.optInt("duration")
|
||||
url = o.optString("url")
|
||||
date = o.optInt("date")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKAudioMessage() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.VOICE_MESSAGE
|
||||
|
||||
var duration: Int = 0
|
||||
var waveform: ArrayList<Int> = arrayListOf()
|
||||
var linkOgg: String = ""
|
||||
var linkMp3: String = ""
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
duration = o.optInt("duration")
|
||||
linkOgg = o.optString("link_ogg")
|
||||
linkMp3 = o.optString("link_mp3")
|
||||
|
||||
o.optJSONArray("waveform")?.let {
|
||||
val waveform = ArrayList<Int>()
|
||||
for (i in 0 until it.length()) {
|
||||
waveform.add(it.optInt(i))
|
||||
}
|
||||
this.waveform = waveform
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKCall() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.CALL
|
||||
|
||||
var initiatorId: Int = 0
|
||||
var receiverId: Int = 0
|
||||
var state: State = State.NONE
|
||||
var time: Int = 0
|
||||
var duration: Int = 0
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
initiatorId = o.optInt("initiator_id", -1)
|
||||
receiverId = o.optInt("receiver_id", -1)
|
||||
state = State.fromString(o.optString("state"))
|
||||
time = o.optInt("time")
|
||||
duration = o.optInt("duration")
|
||||
}
|
||||
|
||||
enum class State(val value: String) {
|
||||
NONE("none"),
|
||||
REACHED("reached"),
|
||||
CANCELLED_INITIATOR("canceled_by_initiator"),
|
||||
CANCELLED_RECEIVER("canceled_by_receiver");
|
||||
|
||||
companion object {
|
||||
fun fromString(value: String) = values().first { it.value == value }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKComment() : VKModel() { //https://vk.com/dev/objects/comment
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.WALL_REPLY
|
||||
|
||||
constructor(o: JSONObject) : this() {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKConversation() : VKModel(), Cloneable {
|
||||
|
||||
override val attachmentType = VKAttachments.Type.NONE
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
|
||||
var profiles = arrayListOf<VKUser>()
|
||||
var groups = arrayListOf<VKGroup>()
|
||||
|
||||
var conversationsCount: Int = 0
|
||||
|
||||
var count: Int = 0
|
||||
}
|
||||
|
||||
var isAllowed: Boolean = false
|
||||
var notAllowedReason: Reason = Reason.NULL
|
||||
|
||||
var inReadMessageId: Int = 0
|
||||
var outReadMessageId: Int = 0
|
||||
var lastMessageId: Int = 0
|
||||
var unreadCount: Int = 0
|
||||
|
||||
var id: Int = 0
|
||||
|
||||
var intType: Int = 0
|
||||
var type: Type = Type.NULL
|
||||
|
||||
var localId: Int = 0
|
||||
|
||||
var notificationsEnabled: Boolean = false
|
||||
|
||||
var disabledUntil: Int = 0
|
||||
var isDisabledForever: Boolean = false
|
||||
var isNoSound: Boolean = false
|
||||
|
||||
var membersCount: Int = 0
|
||||
var title: String = ""
|
||||
|
||||
var pinnedMessage: VKMessage? = null
|
||||
|
||||
var intState: Int = 0
|
||||
var state: State = State.IN
|
||||
|
||||
var lastMessage: VKMessage = VKMessage()
|
||||
|
||||
var isGroupChannel: Boolean = false
|
||||
|
||||
var photo50: String = ""
|
||||
var photo100: String = ""
|
||||
var photo200: String = ""
|
||||
|
||||
var peerUser: VKUser? = null
|
||||
|
||||
var peerGroup: VKGroup? = null
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
inReadMessageId = o.optInt("in_read")
|
||||
outReadMessageId = o.optInt("out_read")
|
||||
lastMessageId = o.optInt("last_message_id", -1)
|
||||
unreadCount = o.optInt("unread_count", 0)
|
||||
|
||||
o.optJSONObject("peer")?.let {
|
||||
id = it.optInt("id", -1)
|
||||
type = Type.fromString(it.optString("type"))
|
||||
localId = it.optInt("local_id")
|
||||
}
|
||||
|
||||
o.optJSONObject("push_settings")?.let {
|
||||
disabledUntil = it.optInt("disabled_until")
|
||||
isDisabledForever = it.optBoolean("disabled_forever")
|
||||
isNoSound = it.optBoolean("no_sound")
|
||||
}
|
||||
|
||||
o.optJSONObject("can_write")?.let {
|
||||
isAllowed = it.optBoolean("allowed")
|
||||
notAllowedReason = Reason.fromInt(it.optInt("reason", -1))
|
||||
}
|
||||
|
||||
o.optJSONObject("chat_settings")?.let {
|
||||
membersCount = it.optInt("members_count")
|
||||
title = it.optString("title")
|
||||
|
||||
it.optJSONObject("pinned_message")?.let { pinned ->
|
||||
pinnedMessage = VKMessage(pinned)
|
||||
}
|
||||
|
||||
state = State.fromString(it.optString("state"))
|
||||
|
||||
it.optJSONObject("photo")?.let { photo ->
|
||||
photo50 = photo.optString("photo_50")
|
||||
photo100 = photo.optString("photo_100")
|
||||
photo200 = photo.optString("photo_200")
|
||||
}
|
||||
|
||||
isGroupChannel = it.optBoolean("is_group_channel")
|
||||
}
|
||||
}
|
||||
|
||||
fun isNotificationsDisabled() = (isDisabledForever || disabledUntil > 0 || isNoSound)
|
||||
|
||||
fun isChat() = type == Type.CHAT
|
||||
|
||||
fun isUser() = type == Type.USER
|
||||
|
||||
fun isGroup() = type == Type.GROUP
|
||||
|
||||
override fun toString(): String {
|
||||
return title
|
||||
}
|
||||
|
||||
public override fun clone(): VKConversation {
|
||||
return super.clone() as VKConversation
|
||||
}
|
||||
|
||||
enum class Type(val value: String) {
|
||||
NULL("null"),
|
||||
USER("user"),
|
||||
CHAT("chat"),
|
||||
GROUP("group");
|
||||
|
||||
companion object {
|
||||
fun fromString(value: String) = values().first { it.value == value }
|
||||
}
|
||||
}
|
||||
|
||||
enum class State(val value: String) {
|
||||
IN("in"),
|
||||
KICKED("kicked"),
|
||||
LEFT("left");
|
||||
|
||||
companion object {
|
||||
fun fromString(value: String) = values().first { it.value == value }
|
||||
}
|
||||
}
|
||||
|
||||
enum class Reason(val value: Int) {
|
||||
NULL(-1),
|
||||
U(0),
|
||||
BLOCKED_DELETED(18),
|
||||
BLACKLISTED(900),
|
||||
BLOCKED_GROUP_MESSAGES(901),
|
||||
PRIVACY_SETTINGS(902),
|
||||
GROUP_DISABLED_MESSAGES(915),
|
||||
GROUP_BLOCKED_MESSAGES(916),
|
||||
NO_ACCESS_CHAT(917),
|
||||
NO_ACCESS_EMAIL(918),
|
||||
U1(925),
|
||||
NO_ACCESS_COMMUNITY(203);
|
||||
|
||||
companion object {
|
||||
fun fromInt(value: Int) = values().first { it.value == value }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
|
||||
class VKDocument() : VKModel() {
|
||||
|
||||
override val attachmentType = VKAttachments.Type.DOCUMENT
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
var id: Int = 0
|
||||
var ownerId: Int = 0
|
||||
var title: String = ""
|
||||
var size: Int = 0
|
||||
var ext: String = ""
|
||||
var url: String = ""
|
||||
var date: Int = 0
|
||||
var type: Type = Type.UNKNOWN
|
||||
var preview: Preview? = null
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
id = o.optInt("id", -1)
|
||||
ownerId = o.optInt("owner_id", -1)
|
||||
title = o.optString("title")
|
||||
size = o.optInt("size")
|
||||
ext = o.optString("ext")
|
||||
url = o.optString("url")
|
||||
date = o.optInt("date")
|
||||
type = Type.fromInt(o.optInt("type"))
|
||||
|
||||
o.optJSONObject("preview")?.let {
|
||||
preview = Preview(it)
|
||||
}
|
||||
}
|
||||
|
||||
class Preview(o: JSONObject) : Serializable {
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
var photo: Photo? = null
|
||||
var graffiti: Graffiti? = null
|
||||
|
||||
inner class Photo(o: JSONObject) : Serializable {
|
||||
|
||||
var sizes: ArrayList<VKPhotoSize>? = null
|
||||
|
||||
init {
|
||||
o.optJSONArray("sizes")?.let {
|
||||
val sizes = ArrayList<VKPhotoSize>()
|
||||
for (i in 0 until it.length()) {
|
||||
sizes.add(VKPhotoSize(it.optJSONObject(i)))
|
||||
}
|
||||
this.sizes = sizes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Graffiti(o: JSONObject) : Serializable {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
var src: String = o.optString("src")
|
||||
var width: Int = o.optInt("width")
|
||||
var height: Int = o.optInt("height")
|
||||
}
|
||||
|
||||
init {
|
||||
o.optJSONObject("photo")?.let {
|
||||
photo = Photo(it)
|
||||
}
|
||||
|
||||
o.optJSONObject("graffiti")?.let {
|
||||
graffiti = Graffiti(it)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
enum class Type(val value: Int) {
|
||||
NONE(0),
|
||||
TEXT(1),
|
||||
ARCHIVE(2),
|
||||
GIF(3),
|
||||
IMAGE(4),
|
||||
AUDIO(5),
|
||||
VIDEO(6),
|
||||
BOOK(7),
|
||||
UNKNOWN(8);
|
||||
|
||||
companion object {
|
||||
fun fromInt(value: Int) = values().first { it.value == value }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKGeolocation() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.GEOLOCATION
|
||||
|
||||
constructor(o: JSONObject) : this() {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKGift() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.GIFT
|
||||
|
||||
var id: Int = 0
|
||||
var thumb256: String = ""
|
||||
var thumb96: String = ""
|
||||
var thumb48: String = ""
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
id = o.optInt("id", -1)
|
||||
thumb256 = o.optString("thumb_256")
|
||||
thumb96 = o.optString("thumb_96")
|
||||
thumb48 = o.optString("thumb_48")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKGraffiti() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.GRAFFITI
|
||||
|
||||
var id: Int = 0
|
||||
var ownerId: Int = 0
|
||||
var url: String = ""
|
||||
var width: Int = 0
|
||||
var height: Int = 0
|
||||
var accessKey: String = ""
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
id = o.optInt("id", -1)
|
||||
ownerId = o.optInt("owner_id", -1)
|
||||
url = o.optString("url")
|
||||
width = o.optInt("width")
|
||||
height = o.optInt("height")
|
||||
accessKey = o.optString("access_key")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
open class VKGroup() : VKModel() {
|
||||
|
||||
override val attachmentType = VKAttachments.Type.NONE
|
||||
|
||||
companion object {
|
||||
|
||||
const val serialVersionUID: Long = 1L
|
||||
|
||||
fun parse(array: JSONArray): ArrayList<VKGroup> {
|
||||
val groups = ArrayList<VKGroup>()
|
||||
|
||||
for (i in 0 until array.length()) {
|
||||
groups.add(VKGroup(array.optJSONObject(i)))
|
||||
}
|
||||
return groups
|
||||
}
|
||||
}
|
||||
|
||||
var id: Int = 0
|
||||
var name: String = ""
|
||||
var screenName: String = ""
|
||||
var isClosed: Boolean = false
|
||||
var deactivated: String = ""
|
||||
var type: Type = Type.NULL
|
||||
var photo50: String = ""
|
||||
var photo100: String = ""
|
||||
var photo200: String = ""
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
id = o.optInt("id", -1)
|
||||
name = o.optString("name")
|
||||
screenName = o.optString("screen_name")
|
||||
isClosed = o.optInt("is_closed") == 1
|
||||
deactivated = o.optString("deactivated")
|
||||
type = Type.fromString(o.optString("type"))
|
||||
photo50 = o.optString("photo_50")
|
||||
photo100 = o.optString("photo_100")
|
||||
photo200 = o.optString("photo_200")
|
||||
}
|
||||
|
||||
enum class Type(val value: String) {
|
||||
NULL("null"),
|
||||
GROUP("group"),
|
||||
PAGE("page"),
|
||||
EVENT("event");
|
||||
|
||||
companion object {
|
||||
fun fromString(value: String) = values().first { it.value == value }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
import java.io.Serializable
|
||||
|
||||
class VKLink() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.LINK
|
||||
|
||||
var url: String = ""
|
||||
var title: String = ""
|
||||
var caption: String = ""
|
||||
var description: String = ""
|
||||
var previewPage: String = ""
|
||||
var previewUrl: String = ""
|
||||
var photo: VKPhoto? = null
|
||||
var button: Button? = null
|
||||
|
||||
constructor(o: JSONObject): this() {
|
||||
url = o.optString("url")
|
||||
title = o.optString("title")
|
||||
caption = o.optString("caption")
|
||||
description = o.optString("description")
|
||||
previewPage = o.optString("preview_page")
|
||||
previewUrl = o.optString("preview_url")
|
||||
|
||||
o.optJSONObject("photo")?.let {
|
||||
photo = VKPhoto(it)
|
||||
}
|
||||
|
||||
o.optJSONObject("button")?.let {
|
||||
button = Button(it)
|
||||
}
|
||||
}
|
||||
|
||||
class Button(o: JSONObject) : Serializable {
|
||||
var title: String = o.optString("title")
|
||||
var action: Action? = null
|
||||
|
||||
init {
|
||||
o.optJSONObject("action")?.let {
|
||||
action = Action(it)
|
||||
}
|
||||
}
|
||||
|
||||
class Action(o: JSONObject) : Serializable {
|
||||
|
||||
var type: String = o.optString("type")
|
||||
var url: String = o.optString("url")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import java.util.*
|
||||
|
||||
class VKLongPollHistory : VKModel() {
|
||||
|
||||
override val attachmentType = VKAttachments.Type.NONE
|
||||
|
||||
private val lpMessages: ArrayList<VKMessage>? = null
|
||||
private val messages: ArrayList<VKMessage>? = null
|
||||
private val profiles: ArrayList<VKUser>? = null
|
||||
private val groups: ArrayList<VKGroup>? = null //TODO: использовать
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKLongPollServer() : VKModel() {
|
||||
|
||||
override val attachmentType = VKAttachments.Type.NONE
|
||||
|
||||
var key: String = ""
|
||||
var server: String = ""
|
||||
var ts: Long = 0
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
key = o.optString("key")
|
||||
server = o.optString("server").replace("\\", "")
|
||||
ts = o.optLong("ts")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import android.util.ArrayMap
|
||||
import com.meloda.vksdk.util.VKUtil
|
||||
import org.json.JSONObject
|
||||
|
||||
open class VKMessage() : VKModel() {
|
||||
|
||||
override val attachmentType = VKAttachments.Type.NONE
|
||||
|
||||
companion object {
|
||||
|
||||
var profiles = arrayListOf<VKUser>()
|
||||
var groups = arrayListOf<VKGroup>()
|
||||
var conversations = arrayListOf<VKConversation>()
|
||||
|
||||
const val serialVersionUID: Long = 1L
|
||||
|
||||
var lastHistoryCount: Int = 0
|
||||
|
||||
const val UNREAD = 1 // Оно просто есть
|
||||
const val OUTBOX = 1 shl 1 // Исходящее сообщение
|
||||
const val REPLIED = 1 shl 2 // На сообщение был создан ответ
|
||||
const val IMPORTANT = 1 shl 3 // Важное сообщение
|
||||
const val FRIENDS = 1 shl 5 // Сообщение в чат друга
|
||||
const val SPAM = 1 shl 6 // Сообщение помечено как спам
|
||||
const val DELETED = 1 shl 7 // Удаление сообщения
|
||||
const val AUDIO_LISTENED = 1 shl 12 // ГС прослушано
|
||||
const val CHAT = 1 shl 13 // Сообщение отправлено в беседу
|
||||
const val CANCEL_SPAM = 1 shl 15 // Отмена пометки спама
|
||||
const val HIDDEN = 1 shl 16 // Приветственное сообщение сообщества
|
||||
const val DELETE_FOR_ALL = 1 shl 17 // Сообщение удалено для всех
|
||||
const val CHAT_IN = 1 shl 19 // Входящее сообщение в беседе
|
||||
const val REPLY_MSG = 1 shl 21 // Ответ на сообщение
|
||||
|
||||
val flags = ArrayMap<String, Int>()
|
||||
|
||||
fun isOut(flags: Int): Boolean {
|
||||
return OUTBOX and flags > 0
|
||||
}
|
||||
|
||||
fun isDeleted(flags: Int): Boolean {
|
||||
return DELETED and flags > 0
|
||||
}
|
||||
|
||||
fun isUnread(flags: Int): Boolean {
|
||||
return UNREAD and flags > 0
|
||||
}
|
||||
|
||||
fun isSpam(flags: Int): Boolean {
|
||||
return SPAM and flags > 0
|
||||
}
|
||||
|
||||
fun isCanceledSpam(flags: Int): Boolean {
|
||||
return CANCEL_SPAM and flags > 0
|
||||
}
|
||||
|
||||
fun isImportant(flags: Int): Boolean {
|
||||
return IMPORTANT and flags > 0
|
||||
}
|
||||
|
||||
fun isDeletedForAll(flags: Int): Boolean {
|
||||
return DELETE_FOR_ALL and flags > 0
|
||||
}
|
||||
|
||||
init {
|
||||
flags["unread"] = UNREAD
|
||||
flags["outbox"] = OUTBOX
|
||||
flags["replied"] = REPLIED
|
||||
flags["important"] = IMPORTANT
|
||||
flags["friends"] = FRIENDS
|
||||
flags["spam"] = SPAM
|
||||
flags["deleted"] = DELETED
|
||||
flags["audio_listened"] = AUDIO_LISTENED
|
||||
flags["chat"] = CHAT
|
||||
flags["cancel_spam"] = CANCEL_SPAM
|
||||
flags["hidden"] = HIDDEN
|
||||
flags["delete_for_all"] = DELETE_FOR_ALL
|
||||
flags["chat_in"] = CHAT_IN
|
||||
flags["reply_msg"] = REPLY_MSG
|
||||
}
|
||||
}
|
||||
|
||||
var id: Int = 0
|
||||
var date: Int = 0
|
||||
var peerId: Int = 0
|
||||
var fromId: Int = 0
|
||||
var editTime: Int = 0
|
||||
var isOut: Boolean = false
|
||||
var text: String = ""
|
||||
var randomId: Int = 0
|
||||
var conversationMessageId: Int = 0
|
||||
|
||||
var hasEmoji: Boolean = false
|
||||
var isImportant: Boolean = false
|
||||
var isRead: Boolean = false
|
||||
|
||||
var attachments: ArrayList<VKModel> = arrayListOf()
|
||||
|
||||
var fwdMessages: ArrayList<VKMessage> = arrayListOf()
|
||||
|
||||
var replyMessage: VKMessage? = null
|
||||
|
||||
var action: VKMessageAction? = null
|
||||
|
||||
var fromUser: VKUser? = null
|
||||
|
||||
var fromGroup: VKGroup? = null
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
id = o.optInt("id", -1)
|
||||
date = o.optInt("date")
|
||||
peerId = o.optInt("peer_id", -1)
|
||||
fromId = o.optInt("from_id", -1)
|
||||
editTime = o.optInt("edit_time", -1)
|
||||
isOut = o.optInt("out") == 1
|
||||
|
||||
text = VKUtil.prepareMessageText(o.optString("text"))
|
||||
|
||||
randomId = o.optInt("random_id", -1)
|
||||
conversationMessageId = o.optInt("conversation_message_id", -1)
|
||||
isImportant = o.optBoolean("important")
|
||||
|
||||
o.optJSONArray("attachments")?.let {
|
||||
attachments = VKAttachments.parse(it)
|
||||
}
|
||||
|
||||
o.optJSONArray("fwd_messages")?.let {
|
||||
val fwdMessages = ArrayList<VKMessage>(it.length())
|
||||
for (i in 0 until it.length()) {
|
||||
fwdMessages.add(VKMessage(it.optJSONObject(i)))
|
||||
}
|
||||
this.fwdMessages = fwdMessages
|
||||
}
|
||||
|
||||
o.optJSONObject("reply_message")?.let {
|
||||
replyMessage = VKMessage(it)
|
||||
}
|
||||
|
||||
o.optJSONObject("action")?.let {
|
||||
action = VKMessageAction(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun getForwardedMessages() = ArrayList<VKMessage>().apply {
|
||||
for (model in fwdMessages) add(model)
|
||||
}
|
||||
|
||||
fun isFromUser() = fromId > 0
|
||||
|
||||
fun isFromGroup() = fromId < 0
|
||||
|
||||
fun isOutbox() = isOut
|
||||
|
||||
fun isInbox() = !isOutbox()
|
||||
|
||||
override fun toString(): String {
|
||||
return if (text.isNotEmpty()) {
|
||||
text
|
||||
} else {
|
||||
super.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKMessageAction() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.NONE
|
||||
|
||||
var type: Type = Type.NONE
|
||||
var memberId = 0
|
||||
var message: VKMessage? = null
|
||||
var conversationMessageId: Int = 0
|
||||
var text: String = ""
|
||||
var oldText: String = ""
|
||||
|
||||
//TODO: add photo
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
type = Type.fromString(o.optString("type"))
|
||||
memberId = o.optInt("member_id", -1)
|
||||
text = o.optString("text")
|
||||
}
|
||||
|
||||
enum class Type(val value: String) {
|
||||
NONE("none"),
|
||||
CHAT_CREATE("chat_create"),
|
||||
PHOTO_UPDATE("chat_photo_update"),
|
||||
PHOTO_REMOVE("chat_photo_remove"),
|
||||
TITLE_UPDATE("chat_title_update"),
|
||||
PIN_MESSAGE("chat_pin_message"),
|
||||
UNPIN_MESSAGE("chat_unpin_message"),
|
||||
INVITE_USER("chat_invite_user"),
|
||||
INVITE_USER_BY_LINK("chat_invite_user_by_link"),
|
||||
KICK_USER("chat_kick_user"),
|
||||
SCREENSHOT("chat_screenshot"),
|
||||
INVITE_USER_BY_CALL("chat_invite_user_by_call"),
|
||||
INVITE_USER_BY_CALL_LINK("chat_invite_user_by_call_link");
|
||||
|
||||
companion object {
|
||||
fun fromString(value: String) = values().first { it.value == value }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
abstract class VKModel : Serializable {
|
||||
|
||||
abstract val attachmentType: VKAttachments.Type
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID = 1L
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
|
||||
class VKPhoto() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.PHOTO
|
||||
|
||||
var id: Int = 0
|
||||
var albumId: Int = 0
|
||||
var ownerId: Int = 0
|
||||
var text: String = ""
|
||||
var date: Int = 0
|
||||
var width: Int = 0
|
||||
var height: Int = 0
|
||||
var sizes: ArrayList<VKPhotoSize>? = null
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
id = o.optInt("id", -1)
|
||||
albumId = o.optInt("album_id", -1)
|
||||
ownerId = o.optInt("owner_id", -1)
|
||||
text = o.optString("text")
|
||||
date = o.optInt("date")
|
||||
width = o.optInt("width")
|
||||
height = o.optInt("height")
|
||||
|
||||
o.optJSONArray("sizes")?.let {
|
||||
val sizes = ArrayList<VKPhotoSize>()
|
||||
for (i in 0 until it.length()) {
|
||||
sizes.add(VKPhotoSize(it.optJSONObject(i)))
|
||||
}
|
||||
this.sizes = sizes
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKPhotoSize(o: JSONObject) : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.NONE
|
||||
|
||||
var type: String = o.optString("type")
|
||||
var url: String = o.optString("url")
|
||||
var height: Int = o.optInt("height")
|
||||
var width: Int = o.optInt("width")
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKPoll() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.POLL
|
||||
|
||||
constructor(o: JSONObject): this() {}
|
||||
|
||||
// var id = o.optInt("id", -1)
|
||||
// var ownerId = o.optInt("owner_id", -1)
|
||||
// var created = o.optInt("created")
|
||||
// var question: String = o.optString("question")
|
||||
// var votes = o.optInt("votes")
|
||||
// var answers = ArrayList<Answer>()
|
||||
// var isAnonymous = o.optBoolean("anonymous")
|
||||
// var isMultiple = o.optBoolean("multiple")
|
||||
// var answerIds = ArrayList<Int>()
|
||||
// var endDate = o.optInt("end_date")
|
||||
// var isClosed = o.optBoolean("closed")
|
||||
// var isBoard = o.optBoolean("is_board")
|
||||
// var isCanEdit = o.optBoolean("can_edit")
|
||||
// var isCanVote = false
|
||||
// var isCanReport = false
|
||||
// var isCanShare = false
|
||||
// var authorId = 0
|
||||
// var background = Color.WHITE
|
||||
|
||||
//TODO: private ArrayList friends
|
||||
|
||||
// init {
|
||||
// o.optJSONArray("answers")?.let {
|
||||
// val answers = ArrayList<Answer>()
|
||||
// for (i in 0 until it.length()) {
|
||||
// answers.add(Answer(it.optJSONObject(i)))
|
||||
// }
|
||||
// this.answers = answers
|
||||
// }
|
||||
|
||||
// //setAnswerIds();
|
||||
|
||||
// // ...
|
||||
// }
|
||||
|
||||
// class Answer(o: JSONObject) : Serializable {
|
||||
|
||||
// var id = o.optInt("id", -1)
|
||||
// var text: String = o.optString("text")
|
||||
// var votes = o.optInt("votes")
|
||||
// var rate = o.optInt("rate")
|
||||
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
|
||||
class VKSticker() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.STICKER
|
||||
|
||||
var productId: Int = 0
|
||||
var stickerId: Int = 0
|
||||
var images: ArrayList<Image>? = null
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
productId = o.optInt("product_id", -1)
|
||||
stickerId = o.optInt("sticker_id", -1)
|
||||
|
||||
o.optJSONArray("images")?.let {
|
||||
val images = ArrayList<Image>()
|
||||
for (i in 0 until it.length()) {
|
||||
images.add(Image(it.optJSONObject(i)))
|
||||
}
|
||||
this.images = images
|
||||
}
|
||||
}
|
||||
|
||||
class Image(o: JSONObject) : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.NONE
|
||||
|
||||
var url: String = o.optString("url")
|
||||
var width = o.optInt("width")
|
||||
var height = o.optInt("height")
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
open class VKUser() : VKModel() {
|
||||
|
||||
override val attachmentType = VKAttachments.Type.NONE
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
|
||||
var friendsCount: Int = 0
|
||||
|
||||
fun parse(array: JSONArray): ArrayList<VKUser> {
|
||||
val users = ArrayList<VKUser>()
|
||||
|
||||
for (i in 0 until array.length()) {
|
||||
users.add(VKUser(array.optJSONObject(i)))
|
||||
}
|
||||
|
||||
return users
|
||||
}
|
||||
}
|
||||
|
||||
var sortId: Int = 0
|
||||
|
||||
var userId: Int = 0
|
||||
var firstName: String = ""
|
||||
var lastName: String = ""
|
||||
var deactivated: String = ""
|
||||
var isClosed: Boolean = false
|
||||
var isCanAccessClosed: Boolean = true
|
||||
var sex: Int = 0
|
||||
var screenName: String = ""
|
||||
var photo50: String = ""
|
||||
var photo100: String = ""
|
||||
var photo200: String = ""
|
||||
var isOnline: Boolean = false
|
||||
var isOnlineMobile: Boolean = false
|
||||
var status: String = ""
|
||||
|
||||
var lastSeen: Int = 0
|
||||
var lastSeenPlatform: Int = 0
|
||||
|
||||
var isVerified: Boolean = false
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
sortId = 0
|
||||
userId = o.optInt("id", -1)
|
||||
firstName = o.optString("first_name")
|
||||
lastName = o.optString("last_name")
|
||||
deactivated = o.optString("deactivated", "")
|
||||
isClosed = o.optBoolean("is_closed")
|
||||
isCanAccessClosed = o.optBoolean("can_access_closed")
|
||||
sex = o.optInt("sex")
|
||||
screenName = o.optString("screen_name")
|
||||
photo50 = o.optString("photo_50")
|
||||
photo100 = o.optString("photo_100")
|
||||
photo200 = o.optString("photo_200")
|
||||
isOnline = o.optInt("online") == 1
|
||||
isOnlineMobile = isOnline && o.optInt("online_mobile") == 1
|
||||
status = o.optString("status")
|
||||
lastSeen = 0
|
||||
lastSeenPlatform = 0
|
||||
isVerified = o.optInt("verified") == 1
|
||||
|
||||
o.optJSONObject("last_seen")?.let {
|
||||
lastSeen = it.optInt("time")
|
||||
lastSeenPlatform = it.optInt("platform")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun isDeactivated() = deactivated.isNotEmpty()
|
||||
|
||||
override fun toString(): String {
|
||||
return "$firstName $lastName"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKVideo() : VKModel() {
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.VIDEO
|
||||
|
||||
// var id = o.optInt("id", -1)
|
||||
// var ownerId = o.optInt("owner_id", -1)
|
||||
// var title: String = o.optString("title")
|
||||
// var description: String = o.optString("description")
|
||||
// var duration = o.optInt("duration", -1)
|
||||
// var photo130: String = o.optString("photo_130")
|
||||
// var photo320: String = o.optString("photo_320")
|
||||
// var photo640: String = o.optString("photo_640")
|
||||
// var photo800: String = o.optString("photo_800")
|
||||
// var photo1280: String = o.optString("photo_1280")
|
||||
// var firstFrame130: String = o.optString("first_frame_130")
|
||||
// var firstFrame320: String = o.optString("first_frame_320")
|
||||
// var firstFrame640: String = o.optString("first_frame_640")
|
||||
// var firstFrame800: String = o.optString("first_frame_800")
|
||||
// var firstFrame1280: String = o.optString("first_frame_1280")
|
||||
// var date = o.optInt("date")
|
||||
// var views = o.optInt("views")
|
||||
// var comments = o.optInt("comments")
|
||||
// var player: String = o.optString("player")
|
||||
// var isCanEdit = o.optInt("can_edit", 0) == 1
|
||||
// var isCanAdd = o.optInt("can_add") == 1
|
||||
// var isPrivate = o.optInt("is_private", 0) == 1
|
||||
// var accessKey: String = o.optString("access_key")
|
||||
// var isProcessing = o.optInt("processing", 0) == 1
|
||||
// var isLive = o.optInt("live", 0) == 1
|
||||
// var isUpcoming = o.optInt("upcoming", 0) == 1
|
||||
// var isFavorite = o.optBoolean("favorite")
|
||||
|
||||
constructor(o: JSONObject) : this() {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.meloda.vksdk.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class VKWall() : VKModel() { //https://vk.com/dev/objects/post
|
||||
|
||||
companion object {
|
||||
const val serialVersionUID: Long = 1L
|
||||
}
|
||||
|
||||
override val attachmentType = VKAttachments.Type.WALL_POST
|
||||
|
||||
constructor(o: JSONObject) : this() {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,369 @@
|
||||
package com.meloda.vksdk.util
|
||||
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.meloda.vksdk.model.*
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
object VKUtil {
|
||||
|
||||
private const val TAG = "VKUtil"
|
||||
|
||||
fun extractPattern(string: String, pattern: String): String? {
|
||||
val p = Pattern.compile(pattern)
|
||||
val m = p.matcher(string)
|
||||
return if (!m.find()) null else m.toMatchResult().group(1)
|
||||
}
|
||||
|
||||
private const val pattern_string_profile_id = "^(id)?(\\d{1,10})$"
|
||||
|
||||
private val pattern_profile_id = Pattern.compile(pattern_string_profile_id)
|
||||
|
||||
fun parseProfileId(text: String): String? {
|
||||
val m = pattern_profile_id.matcher(text)
|
||||
return if (!m.find()) null else m.group(2)
|
||||
}
|
||||
|
||||
fun sortMessagesByDate(
|
||||
values: ArrayList<VKMessage>,
|
||||
firstOnTop: Boolean
|
||||
): ArrayList<VKMessage> {
|
||||
values.sortWith { m1, m2 ->
|
||||
val d1 = m1.date
|
||||
val d2 = m2.date
|
||||
|
||||
if (firstOnTop) {
|
||||
d2 - d1
|
||||
} else {
|
||||
d1 - d2
|
||||
}
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
fun sortConversationsByDate(
|
||||
values: ArrayList<VKConversation>,
|
||||
firstOnTop: Boolean
|
||||
): ArrayList<VKConversation> {
|
||||
values.sortWith { c1, c2 ->
|
||||
val d1 = c1.lastMessage.date
|
||||
val d2 = c2.lastMessage.date
|
||||
|
||||
return@sortWith if (firstOnTop) {
|
||||
d2 - d1
|
||||
} else {
|
||||
d1 - d2
|
||||
}
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
fun prepareMessageText(message: String): String {
|
||||
if (message.isEmpty()) return message
|
||||
|
||||
var newText = message
|
||||
|
||||
val mentions = hashMapOf<String, String>()
|
||||
|
||||
var startFrom = 0
|
||||
|
||||
while (true) {
|
||||
val leftBracketIndex = newText.indexOf('[', startFrom)
|
||||
val verticalLineIndex = newText.indexOf('|', startFrom)
|
||||
val rightBracketIndex = newText.indexOf(']', startFrom)
|
||||
|
||||
if (leftBracketIndex == -1 ||
|
||||
verticalLineIndex == -1 ||
|
||||
rightBracketIndex == -1
|
||||
) {
|
||||
break
|
||||
}
|
||||
|
||||
val id = newText.substring(leftBracketIndex + 1, verticalLineIndex)
|
||||
|
||||
if (!id.matches(Regex("^id(\\d+)\$")) || rightBracketIndex - verticalLineIndex < 2) {
|
||||
break
|
||||
}
|
||||
|
||||
val text = newText.substring(verticalLineIndex + 1, rightBracketIndex)
|
||||
|
||||
val str = "[$id|$text]"
|
||||
|
||||
mentions[str] = text
|
||||
startFrom = rightBracketIndex + 1
|
||||
}
|
||||
|
||||
mentions.forEach {
|
||||
newText = newText.replace(it.key, it.value)
|
||||
}
|
||||
|
||||
return newText
|
||||
}
|
||||
|
||||
// fun removeTime(date: Date): Long {
|
||||
// return Calendar.getInstance().apply {
|
||||
// time = date
|
||||
// this[Calendar.HOUR_OF_DAY] = 0
|
||||
// this[Calendar.MINUTE] = 0
|
||||
// this[Calendar.SECOND] = 0
|
||||
// this[Calendar.MILLISECOND] = 0
|
||||
// }.timeInMillis
|
||||
// }
|
||||
|
||||
|
||||
//TODO: нормальное время
|
||||
fun getLastSeenTime(date: Long): String {
|
||||
return SimpleDateFormat("HH:mm", Locale.getDefault()).format(date)
|
||||
}
|
||||
|
||||
|
||||
fun getTitle(conversation: VKConversation, peerUser: VKUser?, peerGroup: VKGroup?): String {
|
||||
return when {
|
||||
conversation.isUser() -> {
|
||||
peerUser?.let { return it.toString() } ?: ""
|
||||
}
|
||||
|
||||
conversation.isGroup() -> {
|
||||
peerGroup?.let { return it.name } ?: ""
|
||||
}
|
||||
|
||||
conversation.isChat() -> {
|
||||
conversation.title
|
||||
}
|
||||
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
fun getMessageTitle(message: VKMessage, fromUser: VKUser?, fromGroup: VKGroup?): String {
|
||||
return when {
|
||||
message.isFromUser() -> {
|
||||
fromUser?.let { return it.toString() } ?: ""
|
||||
}
|
||||
|
||||
message.isFromGroup() -> {
|
||||
fromGroup?.let { return it.name } ?: ""
|
||||
}
|
||||
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
fun getAvatar(conversation: VKConversation, peerUser: VKUser?, peerGroup: VKGroup?): String {
|
||||
return when {
|
||||
conversation.isUser() -> {
|
||||
peerUser?.let { return it.photo200 } ?: ""
|
||||
}
|
||||
|
||||
conversation.isGroup() -> {
|
||||
peerGroup?.let { return it.photo200 } ?: ""
|
||||
}
|
||||
|
||||
conversation.isChat() -> {
|
||||
conversation.photo200
|
||||
}
|
||||
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
fun getUserAvatar(message: VKMessage, fromUser: VKUser?, fromGroup: VKGroup?): String {
|
||||
return when {
|
||||
message.isFromUser() -> {
|
||||
fromUser?.let { return it.photo100 } ?: ""
|
||||
}
|
||||
|
||||
message.isFromGroup() -> {
|
||||
fromGroup?.let { return it.photo100 } ?: ""
|
||||
}
|
||||
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
fun getUserPhoto(user: VKUser): String {
|
||||
if (user.photo200.isEmpty()) {
|
||||
if (user.photo100.isEmpty()) {
|
||||
if (user.photo50.isEmpty()) {
|
||||
return ""
|
||||
}
|
||||
} else {
|
||||
return user.photo100
|
||||
}
|
||||
} else {
|
||||
return user.photo200
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
fun getGroupPhoto(group: VKGroup): String {
|
||||
if (group.photo200.isEmpty()) {
|
||||
if (group.photo100.isEmpty()) {
|
||||
if (group.photo50.isEmpty()) {
|
||||
return ""
|
||||
}
|
||||
} else {
|
||||
return group.photo100
|
||||
}
|
||||
} else {
|
||||
return group.photo200
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
fun parseConversations(array: JSONArray): ArrayList<VKConversation> {
|
||||
val conversations = arrayListOf<VKConversation>()
|
||||
for (i in 0 until array.length()) {
|
||||
conversations.add(VKConversation(array.optJSONObject(i)))
|
||||
}
|
||||
|
||||
return conversations
|
||||
}
|
||||
|
||||
fun parseMessages(array: JSONArray): ArrayList<VKMessage> {
|
||||
val messages = arrayListOf<VKMessage>()
|
||||
for (i in 0 until array.length()) {
|
||||
messages.add(VKMessage(array.optJSONObject(i)))
|
||||
}
|
||||
|
||||
return messages
|
||||
}
|
||||
|
||||
fun isMessageHasFlag(mask: Int, flagName: String): Boolean {
|
||||
val o: Any? = VKMessage.flags[flagName]
|
||||
return if (o != null) { //has flag
|
||||
val flag = o as Int
|
||||
flag and mask > 0
|
||||
} else false
|
||||
}
|
||||
|
||||
//TODO: rewrite parsing
|
||||
//fromUser and fromGroup are null
|
||||
@Deprecated("need to rewrite")
|
||||
@WorkerThread
|
||||
fun parseLongPollMessage(array: JSONArray): VKMessage {
|
||||
val message = VKMessage()
|
||||
|
||||
val id = array.optInt(1)
|
||||
val flags = array.optInt(2)
|
||||
val peerId = array.optInt(3)
|
||||
val date = array.optInt(4)
|
||||
val text = array.optString(5)
|
||||
|
||||
message.id = id
|
||||
message.peerId = peerId
|
||||
message.date = date
|
||||
message.text = text
|
||||
|
||||
// val fromId =
|
||||
// if (isMessageHasFlag(flags, "outbox")) com.meloda.fast.UserConfig.userId
|
||||
// else peerId
|
||||
|
||||
message.fromId = peerId
|
||||
|
||||
array.optJSONObject(6)?.let {
|
||||
if (it.has("emoji")) message.hasEmoji = true
|
||||
|
||||
if (it.has("from")) {
|
||||
message.fromId = it.optInt("from", -1)
|
||||
}
|
||||
|
||||
if (it.has("source_act")) {
|
||||
message.action = VKMessageAction().also { action ->
|
||||
action.type = VKMessageAction.Type.fromString(it.optString("source_act"))
|
||||
|
||||
when (action.type) {
|
||||
VKMessageAction.Type.CHAT_CREATE -> {
|
||||
action.text = it.optString("source_text")
|
||||
}
|
||||
VKMessageAction.Type.TITLE_UPDATE -> {
|
||||
action.oldText = it.optString("source_old_text")
|
||||
action.text = it.optString("source_text")
|
||||
}
|
||||
VKMessageAction.Type.PIN_MESSAGE -> {
|
||||
action.memberId = it.optInt("source_mid")
|
||||
action.conversationMessageId = it.optInt("source_chat_local_id")
|
||||
|
||||
it.optJSONObject("source_message")?.let { message ->
|
||||
action.message = VKMessage(message)
|
||||
}
|
||||
}
|
||||
VKMessageAction.Type.UNPIN_MESSAGE -> {
|
||||
action.memberId = it.optInt("source_mid")
|
||||
action.conversationMessageId = it.optInt("source_chat_local_id")
|
||||
}
|
||||
VKMessageAction.Type.INVITE_USER,
|
||||
VKMessageAction.Type.KICK_USER,
|
||||
VKMessageAction.Type.SCREENSHOT,
|
||||
VKMessageAction.Type.INVITE_USER_BY_CALL -> {
|
||||
action.memberId = it.optInt("source_mid")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
array.optJSONObject(7)?.let {
|
||||
/**
|
||||
*
|
||||
* fwd? reply? attachments_count? attachments?
|
||||
*
|
||||
*/
|
||||
}
|
||||
|
||||
val randomId = array.optInt(8)
|
||||
message.randomId = randomId
|
||||
|
||||
val conversationMessageId = array.optInt(9)
|
||||
message.conversationMessageId = conversationMessageId
|
||||
|
||||
val editTime = array.optInt(10)
|
||||
message.editTime = editTime
|
||||
|
||||
// val out = fromId == com.meloda.fast.UserConfig.userId
|
||||
// message.isOut = out
|
||||
//
|
||||
// if (message.isFromUser()) {
|
||||
// message.fromUser = MemoryCache.getUserById(fromId)
|
||||
// } else {
|
||||
// message.fromGroup = MemoryCache.getGroupById(abs(fromId))
|
||||
// }
|
||||
|
||||
return message
|
||||
}
|
||||
|
||||
fun parseJsonPhotos(jsonPhotos: JSONObject): List<String> {
|
||||
val photos = arrayListOf<String>()
|
||||
|
||||
for (key in jsonPhotos.keys()) {
|
||||
photos.add(jsonPhotos.getString(key))
|
||||
}
|
||||
|
||||
return photos
|
||||
}
|
||||
|
||||
fun putPhotosToJson(photo50: String, photo100: String, photo200: String): JSONObject {
|
||||
val json = JSONObject()
|
||||
|
||||
json.put("photo_50", photo50)
|
||||
json.put("photo_100", photo100)
|
||||
json.put("photo_200", photo200)
|
||||
|
||||
return json
|
||||
}
|
||||
|
||||
fun isGroupId(id: Int) = id < 0
|
||||
|
||||
fun isUserId(id: Int) = id in 1..1999999999
|
||||
|
||||
fun isChatId(id: Int) = id > 2_000_000_000
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user