forked from melod1n/fast-messenger
api refactored and cleaned
This commit is contained in:
@@ -1,160 +0,0 @@
|
||||
package com.meloda.fast
|
||||
|
||||
import android.util.Log
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.meloda.fast.concurrent.EventInfo
|
||||
import com.meloda.fast.concurrent.TaskManager
|
||||
import com.meloda.fast.api.VKApiKeys
|
||||
import com.meloda.fast.api.model.VKMessage
|
||||
import com.meloda.fast.api.VKUtil
|
||||
import org.json.JSONArray
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
object VKLongPollParser {
|
||||
|
||||
|
||||
@WorkerThread
|
||||
fun parse(updates: JSONArray) {
|
||||
if (updates.length() == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
for (i in 0 until updates.length()) {
|
||||
val item = updates.optJSONArray(i)
|
||||
when (item.optInt(0)) {
|
||||
2 -> messageSetFlags(item)
|
||||
3 -> messageClearFlags(item)
|
||||
4 -> messageEvent(item)
|
||||
5 -> messageEdit(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun parseEvent(eventInfo: EventInfo<*>, onMessagesListener: OnMessagesListener) {
|
||||
when (eventInfo.key) {
|
||||
VKApiKeys.NEW_MESSAGE.value -> onMessagesListener.onNewMessage(eventInfo.data as VKMessage)
|
||||
VKApiKeys.EDIT_MESSAGE.value -> onMessagesListener.onEditMessage(eventInfo.data as VKMessage)
|
||||
VKApiKeys.RESTORE_MESSAGE.value -> onMessagesListener.onRestoredMessage(eventInfo.data as VKMessage)
|
||||
VKApiKeys.DELETE_MESSAGE.value -> {
|
||||
val array = eventInfo.data as Array<Int>
|
||||
onMessagesListener.onDeleteMessage(array[0], array[1])
|
||||
}
|
||||
VKApiKeys.READ_MESSAGE.value -> {
|
||||
val array = eventInfo.data as Array<Int>
|
||||
onMessagesListener.onReadMessage(array[0], array[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val TAG = "VKLongPollParser"
|
||||
|
||||
private fun messageEvent(item: JSONArray) {
|
||||
val message = VKUtil.parseLongPollMessage(item)
|
||||
|
||||
TaskManager.execute {
|
||||
if (message.isFromUser()) {
|
||||
// VKUtil.searchUser(message.fromId)?.let { message.fromUser = it }
|
||||
} else {
|
||||
// VKUtil.searchGroup(message.fromId)?.let { message.fromGroup = it }
|
||||
}
|
||||
|
||||
// MemoryCache.getConversationById(message.peerId)?.let {
|
||||
// it.lastMessage = message
|
||||
// it.lastMessageId = message.messageId
|
||||
//
|
||||
// MemoryCache.put(it)
|
||||
// }
|
||||
//
|
||||
// MemoryCache.put(message)
|
||||
|
||||
val info = EventInfo(VKApiKeys.NEW_MESSAGE.name, message)
|
||||
|
||||
sendEvent(info)
|
||||
}
|
||||
}
|
||||
|
||||
private fun messageEdit(item: JSONArray) {
|
||||
val message = VKUtil.parseLongPollMessage(item)
|
||||
val info = EventInfo(VKApiKeys.EDIT_MESSAGE.name, message)
|
||||
|
||||
// MemoryCache.put(message)
|
||||
|
||||
sendEvent(info)
|
||||
}
|
||||
|
||||
private fun messageDelete(item: JSONArray) {
|
||||
val messageId = item.optInt(1)
|
||||
val peerId = item.optInt(3)
|
||||
val info = EventInfo(VKApiKeys.DELETE_MESSAGE.name, arrayOf(peerId, messageId))
|
||||
|
||||
// MemoryCache.deleteMessage(messageId)
|
||||
|
||||
sendEvent(info)
|
||||
}
|
||||
|
||||
private fun messageRestored(item: JSONArray) {
|
||||
val message = VKUtil.parseLongPollMessage(item)
|
||||
val info = EventInfo(VKApiKeys.RESTORE_MESSAGE.name, message)
|
||||
|
||||
// MemoryCache.put(message)
|
||||
|
||||
sendEvent(info)
|
||||
}
|
||||
|
||||
private fun messageRead(item: JSONArray) {
|
||||
val messageId = item.optInt(1)
|
||||
val peerId = item.optInt(3)
|
||||
val info = EventInfo(VKApiKeys.READ_MESSAGE.name, arrayOf(peerId, messageId))
|
||||
|
||||
// MemoryCache.edit(MemoryCache.getMessageById(messageId)?.apply { isRead = true })
|
||||
|
||||
sendEvent(info)
|
||||
}
|
||||
|
||||
private fun messageClearFlags(item: JSONArray) {
|
||||
val id = item.optInt(1)
|
||||
val flags = item.optInt(2)
|
||||
if (VKUtil.isMessageHasFlag(flags, "cancel_spam")) {
|
||||
Log.i(TAG, "Message with id $id: Not spam")
|
||||
}
|
||||
if (VKUtil.isMessageHasFlag(flags, "deleted")) {
|
||||
messageRestored(item)
|
||||
}
|
||||
if (VKUtil.isMessageHasFlag(flags, "important")) {
|
||||
Log.i(TAG, "Message with id $id: Not Important")
|
||||
}
|
||||
if (VKUtil.isMessageHasFlag(flags, "unread")) {
|
||||
messageRead(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun messageSetFlags(item: JSONArray) {
|
||||
val id = item.optInt(1)
|
||||
val flags = item.optInt(2)
|
||||
if (VKUtil.isMessageHasFlag(flags, "delete_for_all")) {
|
||||
messageDelete(item)
|
||||
}
|
||||
if (VKUtil.isMessageHasFlag(flags, "deleted")) {
|
||||
messageDelete(item)
|
||||
}
|
||||
if (VKUtil.isMessageHasFlag(flags, "spam")) {
|
||||
Log.i(TAG, "Message with id $id: Spam")
|
||||
}
|
||||
if (VKUtil.isMessageHasFlag(flags, "important")) {
|
||||
Log.i(TAG, "Message with id $id: Important")
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendEvent(eventInfo: EventInfo<*>) {
|
||||
TaskManager.sendEvent(eventInfo)
|
||||
}
|
||||
|
||||
interface OnMessagesListener {
|
||||
fun onNewMessage(message: VKMessage)
|
||||
fun onEditMessage(message: VKMessage)
|
||||
fun onRestoredMessage(message: VKMessage)
|
||||
fun onDeleteMessage(peerId: Int, messageId: Int)
|
||||
fun onReadMessage(peerId: Int, messageId: Int)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.meloda.fast.api
|
||||
|
||||
interface OnResponseListener<T> {
|
||||
|
||||
fun onResponse(response: T)
|
||||
|
||||
fun onError(t: Throwable)
|
||||
|
||||
}
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
package com.meloda.fast
|
||||
package com.meloda.fast.api
|
||||
|
||||
import android.text.TextUtils
|
||||
import com.meloda.fast.common.AppGlobal
|
||||
|
||||
object UserConfig {
|
||||
@@ -1,506 +0,0 @@
|
||||
package com.meloda.fast.api
|
||||
|
||||
import android.os.Handler
|
||||
import android.util.Log
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.meloda.fast.BuildConfig
|
||||
import com.meloda.fast.api.method.MessageMethodSetter
|
||||
import com.meloda.fast.api.method.MethodSetter
|
||||
import com.meloda.fast.api.method.UserMethodSetter
|
||||
import com.meloda.fast.api.network.ErrorCodes
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
@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 = com.meloda.fast.net.HttpRequest[url].asString()
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.i(TAG, "response: $buffer")
|
||||
}
|
||||
|
||||
val json = JSONObject(buffer)
|
||||
|
||||
try {
|
||||
checkError(json, url)
|
||||
} catch (ex: VKException) {
|
||||
throw ex
|
||||
// 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
|
||||
|
||||
com.meloda.fast.api.model.VKLongPollServer::class.java -> {
|
||||
json.optJSONObject("response")?.let {
|
||||
return arrayListOf(com.meloda.fast.api.model.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) {
|
||||
com.meloda.fast.api.model.VKUser::class.java -> {
|
||||
json.optJSONObject("response")?.let { r ->
|
||||
com.meloda.fast.api.model.VKUser.friendsCount = r.optInt("count")
|
||||
}
|
||||
|
||||
for (i in 0 until array.length()) {
|
||||
models.add(com.meloda.fast.api.model.VKUser(array.optJSONObject(i)) as T)
|
||||
}
|
||||
}
|
||||
|
||||
com.meloda.fast.api.model.VKMessage::class.java -> {
|
||||
response as JSONObject
|
||||
|
||||
if (url.contains("messages.getHistory")) {
|
||||
com.meloda.fast.api.model.VKMessage.lastHistoryCount = response.optInt("count")
|
||||
|
||||
response.optJSONArray("profiles")?.let {
|
||||
val profiles = arrayListOf<com.meloda.fast.api.model.VKUser>()
|
||||
|
||||
for (j in 0 until it.length()) {
|
||||
profiles.add(com.meloda.fast.api.model.VKUser(it.optJSONObject(j)))
|
||||
}
|
||||
|
||||
com.meloda.fast.api.model.VKMessage.profiles = profiles
|
||||
}
|
||||
|
||||
response.optJSONArray("groups")?.let {
|
||||
val groups = arrayListOf<com.meloda.fast.api.model.VKGroup>()
|
||||
|
||||
for (j in 0 until it.length()) {
|
||||
groups.add(com.meloda.fast.api.model.VKGroup(it.optJSONObject(j)))
|
||||
}
|
||||
|
||||
com.meloda.fast.api.model.VKMessage.groups = groups
|
||||
}
|
||||
|
||||
response.optJSONArray("conversations")?.let {
|
||||
val conversations = arrayListOf<com.meloda.fast.api.model.VKConversation>()
|
||||
|
||||
for (j in 0 until it.length()) {
|
||||
conversations.add(
|
||||
com.meloda.fast.api.model.VKConversation(
|
||||
it.optJSONObject(
|
||||
j
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
com.meloda.fast.api.model.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 = com.meloda.fast.api.model.VKMessage(source)
|
||||
models.add(message as T)
|
||||
}
|
||||
}
|
||||
|
||||
com.meloda.fast.api.model.VKGroup::class.java -> {
|
||||
for (i in 0 until array.length()) {
|
||||
models.add(com.meloda.fast.api.model.VKGroup(array.optJSONObject(i)) as T)
|
||||
}
|
||||
}
|
||||
|
||||
com.meloda.fast.api.model.VKModel::class.java -> {
|
||||
if (url.contains("messages.getHistoryAttachments")) {
|
||||
return com.meloda.fast.api.model.VKAttachments.parse(array) as ArrayList<T>
|
||||
}
|
||||
}
|
||||
|
||||
com.meloda.fast.api.model.VKConversation::class.java -> {
|
||||
if (url.contains("getConversationsById")) {
|
||||
for (i in 0 until array.length()) {
|
||||
val source = array.optJSONObject(i)
|
||||
models.add(com.meloda.fast.api.model.VKConversation(source) as T)
|
||||
}
|
||||
|
||||
return models
|
||||
}
|
||||
|
||||
json.optJSONObject("response")?.let { r ->
|
||||
com.meloda.fast.api.model.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 = com.meloda.fast.api.model.VKConversation(oConversation).also {
|
||||
it.lastMessage = com.meloda.fast.api.model.VKMessage(oLastMessage)
|
||||
}
|
||||
|
||||
response.optJSONArray("profiles")?.let {
|
||||
val profiles = arrayListOf<com.meloda.fast.api.model.VKUser>()
|
||||
|
||||
for (j in 0 until it.length()) {
|
||||
profiles.add(com.meloda.fast.api.model.VKUser(it.optJSONObject(j)))
|
||||
}
|
||||
|
||||
com.meloda.fast.api.model.VKConversation.profiles = profiles
|
||||
}
|
||||
|
||||
response.optJSONArray("groups")?.let {
|
||||
val groups = arrayListOf<com.meloda.fast.api.model.VKGroup>()
|
||||
|
||||
for (j in 0 until it.length()) {
|
||||
groups.add(com.meloda.fast.api.model.VKGroup(it.optJSONObject(j)))
|
||||
}
|
||||
|
||||
com.meloda.fast.api.model.VKConversation.groups = groups
|
||||
}
|
||||
|
||||
models.add(conversation as T)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return models
|
||||
}
|
||||
|
||||
fun <E> execute(url: String, cls: Class<E>, listener: OnResponseListener<E>?) {
|
||||
com.meloda.fast.concurrent.TaskManager.execute {
|
||||
try {
|
||||
val models = execute(url, cls) ?: return@execute
|
||||
|
||||
// listener?.onResponse(models)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
listener?.onError(e)
|
||||
// it.resumeWithException(e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
suspend fun <E> suspendExecute(url: String, cls: Class<E>): Flow<E> {
|
||||
return suspendCoroutine {
|
||||
try {
|
||||
val models = execute(url, cls)?.asFlow() ?: return@suspendCoroutine
|
||||
|
||||
it.resume(models)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
it.resumeWithException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <E> executeArray(url: String, cls: Class<E>, listener: OnResponseListener<ArrayList<E>>) {
|
||||
com.meloda.fast.concurrent.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.meloda.fast.api
|
||||
|
||||
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")
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package com.meloda.fast.api
|
||||
|
||||
import android.util.Log
|
||||
import com.meloda.fast.BuildConfig
|
||||
import com.meloda.fast.UserConfig
|
||||
import java.net.URLEncoder
|
||||
|
||||
object VKAuth {
|
||||
|
||||
private const val TAG = "VKM.VKAuth"
|
||||
|
||||
object GrantType {
|
||||
const val PASSWORD = "password"
|
||||
}
|
||||
|
||||
const val scope = "notify," +
|
||||
"friends," +
|
||||
"photos," +
|
||||
"audio," +
|
||||
"video," +
|
||||
"docs," +
|
||||
"status," +
|
||||
"notes," +
|
||||
"pages," +
|
||||
"wall," +
|
||||
"groups," +
|
||||
"messages," +
|
||||
"offline," +
|
||||
"notifications"
|
||||
|
||||
private const val redirectUrl = "https://oauth.vk.com/blank.html"
|
||||
|
||||
fun getDirectAuthUrl(
|
||||
login: String,
|
||||
password: String,
|
||||
twoFa: Boolean = false,
|
||||
twoFaCode: String = "",
|
||||
captcha: Pair<String, String>? = null
|
||||
) = "https://oauth.vk.com/token?" +
|
||||
"grant_type=password&" +
|
||||
"client_id=${VKConstants.VK_APP_ID}&" +
|
||||
"client_secret=${VKConstants.VK_SECRET}&" +
|
||||
"username=$login&" +
|
||||
"password=$password&" +
|
||||
"scope=$scope&" +
|
||||
"2fa_supported=1&" +
|
||||
"force_sms=${if (twoFa) "1" else "0"}" +
|
||||
(if (twoFa) "code=$twoFaCode" else "") +
|
||||
(if (captcha == null) "" else "&captcha_sid=${captcha.first}&captcha_key=${captcha.second}") +
|
||||
"&v=${URLEncoder.encode(VKApi.API_VERSION, "utf-8")}"
|
||||
|
||||
fun getSendSmsCodeUrl(sid: String) = "https://api.vk.com/method/auth.validatePhone?" +
|
||||
"sid=$sid&" +
|
||||
"&v=${URLEncoder.encode(VKApi.API_VERSION, "utf-8")}"
|
||||
|
||||
fun getOAuthUrl(settings: String) = "https://oauth.vk.com/authorize?" +
|
||||
"client_id=${UserConfig.FAST_APP_ID}&" +
|
||||
"display=mobile&" +
|
||||
"scope=$settings&" +
|
||||
"redirect_uri=${
|
||||
URLEncoder.encode(
|
||||
redirectUrl,
|
||||
"utf-8"
|
||||
)
|
||||
}&" +
|
||||
"response_type=token&" +
|
||||
"v=${URLEncoder.encode(VKApi.API_VERSION, "utf-8")}"
|
||||
|
||||
fun parseRedirectUrl(url: String): Pair<String, Int> {
|
||||
val accessToken = VKUtil.extractPattern(url, "access_token=(.*?)&") ?: ""
|
||||
val userId = VKUtil.extractPattern(url, "user_id=(\\d*)")?.toIntOrNull() ?: -1
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.i(TAG, "access_token=$accessToken")
|
||||
Log.i(TAG, "user_id=$userId")
|
||||
}
|
||||
|
||||
if (accessToken.isEmpty() || userId == -1) throw Exception(
|
||||
"Failed to parse redirect url: $url"
|
||||
)
|
||||
|
||||
return accessToken to userId
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,30 @@ object VKConstants {
|
||||
const val USER_FIELDS =
|
||||
"photo_50,photo_100,photo_200,status,screen_name,online,online_mobile,last_seen,verified,sex"
|
||||
|
||||
|
||||
const val API_VERSION = "5.132"
|
||||
const val VK_APP_ID = "2274003"
|
||||
const val VK_SECRET = "hHbZxrka2uZ6jB1inYsH"
|
||||
|
||||
|
||||
object Auth {
|
||||
const val SCOPE = "notify," +
|
||||
"friends," +
|
||||
"photos," +
|
||||
"audio," +
|
||||
"video," +
|
||||
"docs," +
|
||||
"status," +
|
||||
"notes," +
|
||||
"pages," +
|
||||
"wall," +
|
||||
"groups," +
|
||||
"messages," +
|
||||
"offline," +
|
||||
"notifications"
|
||||
|
||||
object GrantType {
|
||||
const val PASSWORD = "password"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
// TODO: 8/31/2021 review
|
||||
object VKUtil {
|
||||
|
||||
private const val TAG = "VKUtil"
|
||||
@@ -23,26 +23,6 @@ object VKUtil {
|
||||
return throwable.error == VKErrors.NEED_CAPTCHA
|
||||
}
|
||||
|
||||
fun extractValidationSid(throwable: Throwable): String? {
|
||||
if (throwable !is VKException) return null
|
||||
return throwable.json?.optString("validation_sid")
|
||||
}
|
||||
|
||||
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
|
||||
@@ -292,7 +272,7 @@ object VKUtil {
|
||||
message.text = text
|
||||
|
||||
// val fromId =
|
||||
// if (isMessageHasFlag(flags, "outbox")) com.meloda.fast.UserConfig.userId
|
||||
// if (isMessageHasFlag(flags, "outbox")) com.meloda.fast.api.UserConfig.userId
|
||||
// else peerId
|
||||
|
||||
message.fromId = peerId
|
||||
@@ -357,7 +337,7 @@ object VKUtil {
|
||||
val editTime = array.optInt(10)
|
||||
message.editTime = editTime
|
||||
|
||||
// val out = fromId == com.meloda.fast.UserConfig.userId
|
||||
// val out = fromId == com.meloda.fast.api.UserConfig.userId
|
||||
// message.isOut = out
|
||||
//
|
||||
// if (message.isFromUser()) {
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
package com.meloda.fast.api.method
|
||||
|
||||
import com.meloda.fast.util.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", com.meloda.fast.util.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", com.meloda.fast.util.ArrayUtils.asString(attachments))
|
||||
return this
|
||||
}
|
||||
|
||||
fun attachment(vararg attachments: String): MessageMethodSetter {
|
||||
put("attachment", com.meloda.fast.util.ArrayUtils.asString(*attachments))
|
||||
return this
|
||||
}
|
||||
|
||||
fun forwardMessages(ids: Collection<String>): MessageMethodSetter {
|
||||
put("forward_messages", com.meloda.fast.util.ArrayUtils.asString(ids))
|
||||
return this
|
||||
}
|
||||
|
||||
fun forwardMessages(vararg ids: Int): MessageMethodSetter {
|
||||
put("forward_messages", com.meloda.fast.util.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", com.meloda.fast.util.ArrayUtils.asString(ids))
|
||||
return this
|
||||
}
|
||||
|
||||
fun chatIds(ids: Collection<Int>): MessageMethodSetter {
|
||||
put("max_msg_id", com.meloda.fast.util.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
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package com.meloda.fast.api.method
|
||||
|
||||
import android.util.ArrayMap
|
||||
import android.util.Log
|
||||
import com.meloda.fast.BuildConfig
|
||||
import com.meloda.fast.api.OnResponseListener
|
||||
import com.meloda.fast.api.VKApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
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
|
||||
}
|
||||
|
||||
suspend fun <E> executeSuspend(cls: Class<E>): Flow<E> {
|
||||
return VKApi.suspendExecute(getSignedUrl(), cls)
|
||||
}
|
||||
|
||||
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", com.meloda.fast.util.ArrayUtils.asString(ids))
|
||||
}
|
||||
|
||||
fun userIds(ids: ArrayList<Int>): MethodSetter {
|
||||
return put("user_ids", com.meloda.fast.util.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", com.meloda.fast.util.ArrayUtils.asString(ids))
|
||||
}
|
||||
|
||||
fun groupIds(ids: ArrayList<Int>): MethodSetter {
|
||||
return put("group_ids", com.meloda.fast.util.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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.meloda.fast.api.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
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.meloda.fast.api.network
|
||||
|
||||
import com.meloda.fast.api.VKApi
|
||||
import com.meloda.fast.api.VKConstants
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import java.net.URLEncoder
|
||||
@@ -9,7 +9,7 @@ class AuthInterceptor : Interceptor {
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val builder = chain.request().url.newBuilder()
|
||||
.addQueryParameter("v", URLEncoder.encode(VKApi.API_VERSION, "utf-8"))
|
||||
.addQueryParameter("v", URLEncoder.encode(VKConstants.API_VERSION, "utf-8"))
|
||||
return chain.proceed(chain.request().newBuilder().apply { url(builder.build()) }.build())
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import com.meloda.fast.base.viewmodel.VKEvent
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
abstract class BaseVMFragment<VM : BaseViewModel> : BaseFragment {
|
||||
abstract class BaseViewModelFragment<VM : BaseViewModel> : BaseFragment {
|
||||
|
||||
constructor() : super()
|
||||
|
||||
@@ -9,3 +9,5 @@ data class ShowDialogInfoEvent(
|
||||
|
||||
object StartProgressEvent : VKEvent()
|
||||
object StopProgressEvent : VKEvent()
|
||||
|
||||
abstract class VKEvent
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.meloda.fast.base.viewmodel
|
||||
|
||||
abstract class VKEvent
|
||||
@@ -1,105 +0,0 @@
|
||||
package com.meloda.fast.common
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.meloda.fast.R
|
||||
|
||||
object FragmentSwitcher {
|
||||
|
||||
fun getCurrentFragment(fragmentManager: FragmentManager): Fragment? {
|
||||
val fragments = fragmentManager.fragments
|
||||
|
||||
if (fragments.isEmpty()) throw RuntimeException("FragmentManager's fragments is empty")
|
||||
|
||||
for (fragment in fragments) {
|
||||
if (fragment.isVisible) {
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun addFragments(
|
||||
fragmentManager: FragmentManager,
|
||||
containerId: Int,
|
||||
fragments: Collection<Fragment>
|
||||
) {
|
||||
val transaction = fragmentManager.beginTransaction()
|
||||
|
||||
for (fragment in fragments) {
|
||||
transaction.add(containerId, fragment, fragment.javaClass.simpleName)
|
||||
}
|
||||
|
||||
transaction.commitNow()
|
||||
}
|
||||
|
||||
fun showFragment(fragmentManager: FragmentManager, tag: String) {
|
||||
showFragment(fragmentManager, tag, false)
|
||||
}
|
||||
|
||||
fun showFragment(
|
||||
fragmentManager: FragmentManager,
|
||||
tag: String,
|
||||
hideOthers: Boolean,
|
||||
containerId: Int = R.id.fragmentContainer
|
||||
) {
|
||||
val fragments = fragmentManager.fragments
|
||||
|
||||
if (fragments.isEmpty()) throw RuntimeException("FragmentManager's fragments is empty")
|
||||
|
||||
var fragmentToShow: Fragment? = null
|
||||
|
||||
for (fragment in fragments) {
|
||||
if (fragment.tag != null && fragment.tag == tag) {
|
||||
fragmentToShow = fragment
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
val transaction = fragmentManager.beginTransaction()
|
||||
|
||||
if (fragmentToShow == null) {
|
||||
throw NullPointerException("Required fragment is null")
|
||||
} else {
|
||||
transaction.show(fragmentToShow)
|
||||
}
|
||||
|
||||
if (hideOthers) {
|
||||
for (fragment in fragments) {
|
||||
if (fragment.tag != null && fragment.tag == tag) continue
|
||||
transaction.hide(fragment)
|
||||
}
|
||||
}
|
||||
|
||||
transaction.commit()
|
||||
}
|
||||
|
||||
fun clearFragments(fragmentManager: FragmentManager) {
|
||||
val fragments = fragmentManager.fragments
|
||||
|
||||
if (fragments.isEmpty()) throw RuntimeException("FragmentManager's fragments is empty")
|
||||
|
||||
val transaction = fragmentManager.beginTransaction()
|
||||
|
||||
for (fragment in fragments) {
|
||||
transaction.remove(fragment)
|
||||
}
|
||||
|
||||
transaction.commitNow()
|
||||
}
|
||||
|
||||
fun hideFragments(fragmentManager: FragmentManager) {
|
||||
val fragments = fragmentManager.fragments
|
||||
|
||||
if (fragments.isEmpty()) throw RuntimeException("FragmentManager's fragments is empty")
|
||||
|
||||
val transaction = fragmentManager.beginTransaction()
|
||||
|
||||
for (fragment in fragments) {
|
||||
transaction.hide(fragment)
|
||||
}
|
||||
|
||||
transaction.commitNow()
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.meloda.fast.common
|
||||
|
||||
import android.util.Log
|
||||
import androidx.collection.arrayMapOf
|
||||
import com.meloda.fast.concurrent.TaskManager
|
||||
import com.meloda.fast.BuildConfig
|
||||
import com.meloda.fast.model.NewUpdateInfo
|
||||
import com.meloda.fast.net.HttpRequest
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
object UpdateManager {
|
||||
|
||||
interface OnUpdateListener {
|
||||
fun onNewUpdate(updateInfo: NewUpdateInfo)
|
||||
|
||||
fun onNoUpdates()
|
||||
}
|
||||
|
||||
private const val checkLink = "https://melodev.procsec.top/vkm/project_vkm_ota.json"
|
||||
|
||||
private const val PRODUCT_NAME = "project_vkm"
|
||||
private const val BRANCH = "alpha"
|
||||
private const val OFFSET = 0
|
||||
|
||||
private const val TAG = "UpdateManager"
|
||||
|
||||
fun checkUpdates(onUpdateListener: OnUpdateListener) {
|
||||
TaskManager.execute {
|
||||
val newLink = "https://temply.procsec.top/prop/deploy/api/method/getOTA"
|
||||
|
||||
val params = arrayMapOf<String, String>()
|
||||
params["product"] = PRODUCT_NAME
|
||||
params["branch"] = BRANCH
|
||||
params["offset"] = OFFSET.toString()
|
||||
params["code"] = AppGlobal.versionCode.toString()
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(TAG, "Request started")
|
||||
}
|
||||
|
||||
HttpRequest[newLink, params].asString().let {
|
||||
AppGlobal.post {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(TAG, "response: $it")
|
||||
}
|
||||
|
||||
val response: Any = if (it == "[]") JSONArray(it) else JSONObject(it)
|
||||
|
||||
val newUpdateInfo: NewUpdateInfo? =
|
||||
if (response is JSONArray) null else NewUpdateInfo(response as JSONObject)
|
||||
|
||||
if (response is JSONArray || newUpdateInfo?.version?.isEmpty() == true || newUpdateInfo?.version == AppGlobal.versionName) {
|
||||
onUpdateListener.onNoUpdates()
|
||||
return@post
|
||||
} else {
|
||||
newUpdateInfo?.let { onUpdateListener.onNewUpdate(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HttpRequest[checkLink].asString().let {
|
||||
// val response = JSONObject(it)
|
||||
//
|
||||
// val updateInfo = UpdateInfo(response)
|
||||
//
|
||||
// AppGlobal.handler.post {
|
||||
// if (updateInfo.version.isEmpty() || updateInfo.version == AppGlobal.versionName) {
|
||||
// onUpdateListener.onNoUpdates()
|
||||
// return@post
|
||||
// }
|
||||
//
|
||||
// if (AppGlobal.versionName != updateInfo.version) {
|
||||
// onUpdateListener.onNewUpdate(updateInfo)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.meloda.fast.concurrent
|
||||
|
||||
class EventInfo<T> constructor(var key: String, var data: T? = null)
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.meloda.fast.concurrent
|
||||
|
||||
import android.os.Process
|
||||
|
||||
class LowThread(runnable: Runnable?) : Thread(runnable) {
|
||||
|
||||
override fun run() {
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)
|
||||
super.run()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.meloda.fast.concurrent
|
||||
|
||||
object TaskManager {
|
||||
|
||||
private const val TAG = "TaskManager"
|
||||
|
||||
private val listeners = arrayListOf<OnEventListener>()
|
||||
|
||||
fun addOnEventListener(listener: OnEventListener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
fun removeOnEventListener(listener: OnEventListener?) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
fun execute(runnable: Runnable?) {
|
||||
LowThread(runnable).start()
|
||||
}
|
||||
|
||||
fun sendEvent(eventInfo: EventInfo<*>) {
|
||||
for (listener in listeners) {
|
||||
listener.onNewEvent(eventInfo)
|
||||
}
|
||||
}
|
||||
|
||||
interface OnEventListener {
|
||||
fun onNewEvent(info: EventInfo<*>)
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,10 @@ 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.api.UserConfig
|
||||
import com.meloda.fast.api.VKUtil
|
||||
import com.meloda.fast.api.model.VKUser
|
||||
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
|
||||
@@ -25,8 +26,6 @@ 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.VKUtil
|
||||
import org.json.JSONObject
|
||||
|
||||
@WorkerThread
|
||||
@@ -78,7 +77,7 @@ class UsersStorage : Storage<VKUser>() {
|
||||
}
|
||||
|
||||
override fun getAllValues(): ArrayList<VKUser> {
|
||||
val cursor = selectCursor(TABLE_USERS)
|
||||
val cursor = CacheStorage.selectCursor(TABLE_USERS)
|
||||
val users = ArrayList<VKUser>()
|
||||
|
||||
while (cursor.moveToNext()) users.add(parseValue(cursor))
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.meloda.fast.extensions
|
||||
|
||||
import android.content.Intent
|
||||
import android.util.SparseArray
|
||||
import androidx.core.util.forEach
|
||||
import androidx.collection.SparseArrayCompat
|
||||
import androidx.collection.forEach
|
||||
import androidx.collection.set
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.LiveData
|
||||
@@ -11,7 +12,7 @@ import androidx.navigation.NavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.meloda.fast.R
|
||||
import com.meloda.fast.UserConfig
|
||||
import com.meloda.fast.api.UserConfig
|
||||
|
||||
/**
|
||||
* Manages the various graphs needed for a [BottomNavigationView].
|
||||
@@ -28,7 +29,7 @@ object NavigationExtensions {
|
||||
): LiveData<NavController> {
|
||||
|
||||
// Map of tags
|
||||
val graphIdToTagMap = SparseArray<String>()
|
||||
val graphIdToTagMap = SparseArrayCompat<String>()
|
||||
// Result. Mutable live data with the selected controlled
|
||||
val selectedNavController = MutableLiveData<NavController>()
|
||||
|
||||
@@ -68,7 +69,7 @@ object NavigationExtensions {
|
||||
|
||||
// Now connect selecting an item with swapping Fragments
|
||||
var selectedItemTag = graphIdToTagMap[this.selectedItemId]
|
||||
val firstFragmentTag = graphIdToTagMap[firstFragmentGraphId]
|
||||
val firstFragmentTag = graphIdToTagMap[firstFragmentGraphId] ?: ""
|
||||
var isOnFirstFragment = selectedItemTag == firstFragmentTag
|
||||
|
||||
setOnItemSelectedListener { item ->
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.meloda.fast.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class NewUpdateInfo() {
|
||||
|
||||
var id: Int = 0
|
||||
var version: String = ""
|
||||
var code: Int = 0
|
||||
var time: Int = 0
|
||||
var changelog: String = ""
|
||||
|
||||
// var branchId: Int = 0
|
||||
// var branchName: String = ""
|
||||
|
||||
var downloadLink: String = ""
|
||||
|
||||
// var state: Boolean = true
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
id = o.optInt("id")
|
||||
version = o.optString("version")
|
||||
code = o.optInt("code")
|
||||
time = o.optInt("time")
|
||||
changelog = o.optString("changelog")
|
||||
|
||||
downloadLink = o.optString("download")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.meloda.fast.model
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
class UpdateInfo() {
|
||||
|
||||
var version: String = ""
|
||||
var code: Int = 0
|
||||
var changelog: String = ""
|
||||
var downloadLink: String = ""
|
||||
var date: Int = 0
|
||||
|
||||
constructor(o: JSONObject) : this() {
|
||||
version = o.optString("lastVersionName")
|
||||
code = o.optInt("lastVersionCode")
|
||||
changelog = o.optString("changelog")
|
||||
downloadLink = o.optString("downloadLink")
|
||||
date = o.optInt("buildDate")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package com.meloda.fast.net
|
||||
|
||||
import androidx.collection.ArrayMap
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.UnsupportedEncodingException
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.net.URLEncoder
|
||||
|
||||
class HttpRequest(
|
||||
private val url: String,
|
||||
private val method: String,
|
||||
private val params: ArrayMap<String, String> = ArrayMap<String, String>()
|
||||
) {
|
||||
companion object {
|
||||
const val GET = "GET"
|
||||
const val POST = "POST"
|
||||
|
||||
operator fun get(
|
||||
url: String,
|
||||
params: ArrayMap<String, String> = ArrayMap()
|
||||
): HttpRequest {
|
||||
return HttpRequest(url, GET, params)
|
||||
}
|
||||
|
||||
operator fun get(url: String): HttpRequest {
|
||||
return Companion[url, ArrayMap()]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private var connection: HttpURLConnection? = null
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun asString(): String {
|
||||
val input = getStream()
|
||||
|
||||
val content = com.meloda.fast.io.EasyStreams.read(input)
|
||||
|
||||
connection?.disconnect()
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun asBytes(): ByteArray {
|
||||
val input = getStream()
|
||||
val content = com.meloda.fast.io.EasyStreams.readBytes(input)
|
||||
|
||||
connection?.disconnect()
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun getStream(): InputStream {
|
||||
if (connection == null) {
|
||||
connection = createConnection()
|
||||
}
|
||||
|
||||
var input = connection!!.inputStream
|
||||
val encoding = connection!!.getHeaderField("Content-Encoding")
|
||||
if ("gzip".equals(encoding, ignoreCase = true)) {
|
||||
input = com.meloda.fast.io.EasyStreams.gzip(input)
|
||||
}
|
||||
|
||||
return input
|
||||
}
|
||||
|
||||
@Throws(UnsupportedEncodingException::class)
|
||||
private fun getParams(): String {
|
||||
val buffer = StringBuilder()
|
||||
|
||||
for (i in 0 until params.size) {
|
||||
val key = params.keyAt(i)
|
||||
val value = params.valueAt(i)
|
||||
buffer.append(key).append("=")
|
||||
buffer.append(URLEncoder.encode(value, "UTF-8"))
|
||||
buffer.append("&")
|
||||
}
|
||||
return buffer.toString()
|
||||
}
|
||||
|
||||
@Throws(UnsupportedEncodingException::class)
|
||||
private fun getUrl(): String {
|
||||
return if (params.isNotEmpty() && "GET".equals(method, ignoreCase = true)) {
|
||||
url + "?" + getParams()
|
||||
} else url
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun createConnection(): HttpURLConnection? {
|
||||
connection = URL(getUrl()).openConnection() as HttpURLConnection
|
||||
connection!!.readTimeout = 60000
|
||||
connection!!.connectTimeout = 60000
|
||||
connection!!.useCaches = true
|
||||
connection!!.doInput = true
|
||||
connection!!.doOutput =
|
||||
!GET.equals(method, ignoreCase = true)
|
||||
connection!!.requestMethod = method
|
||||
connection!!.setRequestProperty("Accept-Encoding", "gzip")
|
||||
return connection
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
try {
|
||||
return asString()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.meloda.fast.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.meloda.fast.api.OnResponseListener
|
||||
|
||||
open class DownloadUpdateReceiver : BroadcastReceiver() {
|
||||
|
||||
var listener: OnResponseListener<Any?>? = null
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
listener?.onResponse(null)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.meloda.fast.BuildConfig
|
||||
import com.meloda.fast.R
|
||||
import com.meloda.fast.base.BaseVMFragment
|
||||
import com.meloda.fast.base.BaseViewModelFragment
|
||||
import com.meloda.fast.base.viewmodel.StartProgressEvent
|
||||
import com.meloda.fast.base.viewmodel.StopProgressEvent
|
||||
import com.meloda.fast.base.viewmodel.VKEvent
|
||||
@@ -36,7 +36,7 @@ import java.util.*
|
||||
import kotlin.concurrent.schedule
|
||||
|
||||
@AndroidEntryPoint
|
||||
class LoginFragment : BaseVMFragment<LoginViewModel>(R.layout.fragment_login) {
|
||||
class LoginFragment : BaseViewModelFragment<LoginViewModel>(R.layout.fragment_login) {
|
||||
|
||||
override val viewModel: LoginViewModel by viewModels()
|
||||
private val binding: FragmentLoginBinding by viewBinding()
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.meloda.fast.screens.login
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.meloda.fast.UserConfig
|
||||
import com.meloda.fast.api.VKAuth
|
||||
import com.meloda.fast.api.UserConfig
|
||||
import com.meloda.fast.api.VKConstants
|
||||
import com.meloda.fast.api.VKException
|
||||
import com.meloda.fast.api.VKUtil
|
||||
@@ -15,10 +13,7 @@ import com.meloda.fast.base.viewmodel.StartProgressEvent
|
||||
import com.meloda.fast.base.viewmodel.StopProgressEvent
|
||||
import com.meloda.fast.base.viewmodel.VKEvent
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@@ -36,12 +31,12 @@ class LoginViewModel @Inject constructor(
|
||||
{
|
||||
repo.auth(
|
||||
RequestAuthDirect(
|
||||
grantType = VKAuth.GrantType.PASSWORD,
|
||||
grantType = VKConstants.Auth.GrantType.PASSWORD,
|
||||
clientId = VKConstants.VK_APP_ID,
|
||||
clientSecret = VKConstants.VK_SECRET,
|
||||
username = login,
|
||||
password = password,
|
||||
scope = VKAuth.scope,
|
||||
scope = VKConstants.Auth.SCOPE,
|
||||
twoFaForceSms = true,
|
||||
twoFaCode = twoFaCode,
|
||||
captchaSid = captcha?.first,
|
||||
@@ -64,6 +59,8 @@ class LoginViewModel @Inject constructor(
|
||||
checkErrors(it)
|
||||
if (it !is VKException) return@makeJob
|
||||
|
||||
twoFaCode?.let { sendEvent(CodeSent) }
|
||||
|
||||
if (VKUtil.isValidationRequired(it)) {
|
||||
it.validationSid?.let { sid ->
|
||||
sendEvent(ValidationRequired(validationSid = sid))
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
package com.meloda.fast.screens.login
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.viewbinding.library.fragment.viewBinding
|
||||
import android.webkit.CookieManager
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.meloda.fast.R
|
||||
import com.meloda.fast.api.VKAuth
|
||||
import com.meloda.fast.base.BaseFragment
|
||||
import com.meloda.fast.databinding.FragmentValidationBinding
|
||||
|
||||
class ValidationFragment : BaseFragment(R.layout.fragment_validation) {
|
||||
|
||||
private val binding: FragmentValidationBinding by viewBinding()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val redirectUrl = getRedirectUrl()
|
||||
|
||||
binding.webView.webViewClient = object : WebViewClient() {
|
||||
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
|
||||
Log.d("Fast::Validation", "onPageStarted: url: $url")
|
||||
parseUrl(url ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
binding.webView.settings.domStorageEnabled = true
|
||||
binding.webView.clearCache(true)
|
||||
binding.webView.layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
|
||||
val manager = CookieManager.getInstance()
|
||||
manager.removeAllCookies(null)
|
||||
manager.flush()
|
||||
manager.setAcceptCookie(true)
|
||||
|
||||
binding.webView.loadUrl(redirectUrl)
|
||||
}
|
||||
|
||||
private fun getRedirectUrl() = requireArguments().getString("redirectUrl", "")
|
||||
|
||||
private fun parseUrl(url: String) {
|
||||
if (url.startsWith("https://oauth.vk.com/blank.html#success=1")) {
|
||||
if (!url.contains("error=")) {
|
||||
val data = VKAuth.parseRedirectUrl(url)
|
||||
|
||||
val accessToken = data.first
|
||||
val userId = data.second
|
||||
|
||||
parentFragmentManager.setFragmentResult(
|
||||
"validation",
|
||||
bundleOf(
|
||||
"accessToken" to accessToken,
|
||||
"userId" to userId
|
||||
)
|
||||
)
|
||||
|
||||
findNavController().navigate(R.id.toLogin)
|
||||
}
|
||||
} else {
|
||||
Log.d("Fast::Validation", "parseUrl: $url")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,14 +6,14 @@ import android.viewbinding.library.fragment.viewBinding
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.meloda.fast.R
|
||||
import com.meloda.fast.UserConfig
|
||||
import com.meloda.fast.base.BaseVMFragment
|
||||
import com.meloda.fast.api.UserConfig
|
||||
import com.meloda.fast.base.BaseViewModelFragment
|
||||
import com.meloda.fast.databinding.FragmentMainBinding
|
||||
import com.meloda.fast.extensions.NavigationExtensions.setupWithNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainFragment : BaseVMFragment<MainViewModel>(R.layout.fragment_main) {
|
||||
class MainFragment : BaseViewModelFragment<MainViewModel>(R.layout.fragment_main) {
|
||||
|
||||
override val viewModel: MainViewModel by viewModels()
|
||||
private val binding: FragmentMainBinding by viewBinding()
|
||||
|
||||
@@ -6,7 +6,7 @@ import android.viewbinding.library.fragment.viewBinding
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.meloda.fast.R
|
||||
import com.meloda.fast.base.BaseVMFragment
|
||||
import com.meloda.fast.base.BaseViewModelFragment
|
||||
import com.meloda.fast.base.viewmodel.StartProgressEvent
|
||||
import com.meloda.fast.base.viewmodel.StopProgressEvent
|
||||
import com.meloda.fast.base.viewmodel.VKEvent
|
||||
@@ -16,7 +16,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ConversationsFragment : BaseVMFragment<ConversationsViewModel>(R.layout.fragment_conversations) {
|
||||
class ConversationsFragment : BaseViewModelFragment<ConversationsViewModel>(R.layout.fragment_conversations) {
|
||||
|
||||
override val viewModel: ConversationsViewModel by viewModels()
|
||||
private val binding: FragmentConversationsBinding by viewBinding()
|
||||
|
||||
@@ -5,17 +5,13 @@ import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.collection.arrayMapOf
|
||||
import com.meloda.fast.UserConfig
|
||||
import com.meloda.fast.VKLongPollParser
|
||||
import com.meloda.fast.api.VKApi
|
||||
import com.meloda.fast.api.UserConfig
|
||||
import com.meloda.fast.api.model.VKLongPollServer
|
||||
import com.meloda.fast.concurrent.LowThread
|
||||
import com.meloda.fast.net.HttpRequest
|
||||
import com.meloda.fast.util.AndroidUtils
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
// TODO: 8/31/2021 rewrite
|
||||
@Deprecated("Absolutely obsolete")
|
||||
class LongPollService : Service() {
|
||||
private var thread: Thread? = null
|
||||
@@ -26,7 +22,7 @@ class LongPollService : Service() {
|
||||
|
||||
running = false
|
||||
|
||||
thread = LowThread(Updater())
|
||||
// thread = LowThread(Updater())
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
@@ -75,8 +71,9 @@ class LongPollService : Service() {
|
||||
}
|
||||
try {
|
||||
if (server == null) {
|
||||
server = VKApi.messages().getLongPollServer()
|
||||
.execute(VKLongPollServer::class.java)!![0]
|
||||
server = null
|
||||
// server = VKApi.messages().getLongPollServer()
|
||||
// .execute(VKLongPollServer::class.java)!![0]
|
||||
}
|
||||
|
||||
val response = getResponse(server)
|
||||
@@ -92,7 +89,7 @@ class LongPollService : Service() {
|
||||
|
||||
Log.i(TAG, "updates: $updates")
|
||||
|
||||
server.ts = tsResponse
|
||||
server?.ts = tsResponse
|
||||
|
||||
if (updates.length() != 0) {
|
||||
process(updates)
|
||||
@@ -110,23 +107,23 @@ class LongPollService : Service() {
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
private fun getResponse(server: VKLongPollServer): JSONObject {
|
||||
val params = arrayMapOf<String, String>()
|
||||
params["act"] = "a_check"
|
||||
params["key"] = server.key
|
||||
params["ts"] = server.ts.toString()
|
||||
params["wait"] = "10"
|
||||
params["mode"] = "490"
|
||||
params["version"] = "9"
|
||||
|
||||
val buffer = HttpRequest["https://" + server.server, params].asString()
|
||||
|
||||
return JSONObject(buffer)
|
||||
private fun getResponse(server: VKLongPollServer?): JSONObject {
|
||||
return JSONObject("")
|
||||
// val params = arrayMapOf<String, String>()
|
||||
// params["act"] = "a_check"
|
||||
// params["key"] = server.key
|
||||
// params["ts"] = server.ts.toString()
|
||||
// params["wait"] = "10"
|
||||
// params["mode"] = "490"
|
||||
// params["version"] = "9"
|
||||
//
|
||||
// val buffer = HttpRequest["https://" + server.server, params].asString()
|
||||
//
|
||||
// return JSONObject(buffer)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun process(updates: JSONArray) {
|
||||
VKLongPollParser.parse(updates)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,18 +2,15 @@ package com.meloda.fast.util
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.meloda.fast.concurrent.TaskManager
|
||||
import com.meloda.fast.R
|
||||
import com.meloda.fast.api.VKUtil
|
||||
import com.meloda.fast.api.model.*
|
||||
import com.meloda.fast.common.AppGlobal
|
||||
import com.meloda.fast.extensions.ContextExtensions.color
|
||||
import com.meloda.fast.extensions.ContextExtensions.drawable
|
||||
import com.meloda.fast.extensions.DrawableExtensions.tint
|
||||
import com.meloda.fast.extensions.StringExtensions.lowerCase
|
||||
import com.meloda.fast.R
|
||||
import com.meloda.fast.api.model.*
|
||||
import com.meloda.fast.common.AppGlobal
|
||||
import com.meloda.fast.api.OnResponseListener
|
||||
import com.meloda.fast.api.VKUtil
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
@@ -81,41 +78,6 @@ object VKUtils {
|
||||
// )
|
||||
// }
|
||||
|
||||
@Deprecated("")
|
||||
@WorkerThread
|
||||
fun searchUser(id: Int, onResponseListener: OnResponseListener<VKUser>? = null): VKUser? {
|
||||
return if (VKUtil.isGroupId(id) || VKUtil.isChatId(id)) {
|
||||
null
|
||||
} else {
|
||||
// MemoryCache.getUserById(id)?.let { return it }
|
||||
//
|
||||
// if (BuildConfig.DEBUG) {
|
||||
// Log.d(VKUtil.TAG, "User with id $id not found")
|
||||
// }
|
||||
//
|
||||
// TaskManager.loadUser(VKApiKeys.UPDATE_USER, id, onResponseListener)
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("")
|
||||
@WorkerThread
|
||||
fun searchGroup(id: Int, onResponseListener: OnResponseListener<VKGroup>? = null): VKGroup? {
|
||||
return if (!VKUtil.isGroupId(id) || VKUtil.isChatId(id)) {
|
||||
null
|
||||
} else {
|
||||
// MemoryCache.getGroupById(abs(id))?.let { return it }
|
||||
//
|
||||
// if (BuildConfig.DEBUG) {
|
||||
// Log.d(VKUtil.TAG, "Group with id $id not found")
|
||||
// }
|
||||
//
|
||||
// TaskManager.loadGroup(VKApiKeys.UPDATE_GROUP, abs(id), onResponseListener)
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun getAttachmentText(context: Context, attachments: List<VKModel>): String {
|
||||
val resId: Int
|
||||
@@ -158,7 +120,7 @@ object VKUtils {
|
||||
if (resId == -1) "Unknown attachments" else context.getString(
|
||||
resId,
|
||||
attachments.size
|
||||
).toLowerCase(Locale.getDefault())
|
||||
).lowerCase()
|
||||
} else {
|
||||
context.getString(R.string.message_attachments_many)
|
||||
}
|
||||
@@ -226,62 +188,60 @@ object VKUtils {
|
||||
@Deprecated("need to rewrite")
|
||||
fun getActionText(
|
||||
context: Context,
|
||||
lastMessage: VKMessage,
|
||||
onResponseListener: OnResponseListener<String>
|
||||
lastMessage: VKMessage
|
||||
) {
|
||||
TaskManager.execute {
|
||||
lastMessage.action?.let {
|
||||
var result = ""
|
||||
|
||||
when (it.type) {
|
||||
VKMessageAction.Type.CHAT_CREATE -> result = context.getString(
|
||||
R.string.message_action_created_chat,
|
||||
lastMessage.action?.let {
|
||||
var result = ""
|
||||
|
||||
when (it.type) {
|
||||
VKMessageAction.Type.CHAT_CREATE -> result = context.getString(
|
||||
R.string.message_action_created_chat,
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.INVITE_USER -> result =
|
||||
if (lastMessage.fromId == lastMessage.action!!.memberId) {
|
||||
context.getString(R.string.message_action_returned_to_chat, "")
|
||||
} else {
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.INVITE_USER -> result =
|
||||
if (lastMessage.fromId == lastMessage.action!!.memberId) {
|
||||
context.getString(R.string.message_action_returned_to_chat, "")
|
||||
} else {
|
||||
""
|
||||
// val invited = MemoryCache.getUserById(lastMessage.action!!.memberId)
|
||||
// context.getString(R.string.message_action_invited_user, invited)
|
||||
}
|
||||
VKMessageAction.Type.INVITE_USER_BY_LINK -> result = context.getString(
|
||||
R.string.message_action_invited_by_link,
|
||||
}
|
||||
VKMessageAction.Type.INVITE_USER_BY_LINK -> result = context.getString(
|
||||
R.string.message_action_invited_by_link,
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.KICK_USER -> result =
|
||||
if (lastMessage.fromId == lastMessage.action!!.memberId) {
|
||||
context.getString(R.string.message_action_left_from_chat, "")
|
||||
} else {
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.KICK_USER -> result =
|
||||
if (lastMessage.fromId == lastMessage.action!!.memberId) {
|
||||
context.getString(R.string.message_action_left_from_chat, "")
|
||||
} else {
|
||||
""
|
||||
// val kicked = MemoryCache.getUserById(lastMessage.action!!.memberId)
|
||||
// context.getString(R.string.message_action_kicked_user, kicked)
|
||||
}
|
||||
VKMessageAction.Type.PHOTO_REMOVE -> result = context.getString(
|
||||
R.string.message_action_removed_photo,
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.PHOTO_UPDATE -> result = context.getString(
|
||||
R.string.message_action_updated_photo,
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.PIN_MESSAGE -> result = context.getString(
|
||||
R.string.message_action_pinned_message,
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.UNPIN_MESSAGE -> result = context.getString(
|
||||
R.string.message_action_unpinned_message,
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.TITLE_UPDATE -> result = context.getString(
|
||||
R.string.message_action_updated_title,
|
||||
""
|
||||
)
|
||||
}
|
||||
|
||||
AppGlobal.post { onResponseListener.onResponse(result) }
|
||||
}
|
||||
VKMessageAction.Type.PHOTO_REMOVE -> result = context.getString(
|
||||
R.string.message_action_removed_photo,
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.PHOTO_UPDATE -> result = context.getString(
|
||||
R.string.message_action_updated_photo,
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.PIN_MESSAGE -> result = context.getString(
|
||||
R.string.message_action_pinned_message,
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.UNPIN_MESSAGE -> result = context.getString(
|
||||
R.string.message_action_unpinned_message,
|
||||
""
|
||||
)
|
||||
VKMessageAction.Type.TITLE_UPDATE -> result = context.getString(
|
||||
R.string.message_action_updated_title,
|
||||
""
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.meloda.fast.viewmodel
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.meloda.fast.database.CacheStorage
|
||||
import com.meloda.fast.api.VKApi
|
||||
import com.meloda.fast.api.VKConstants
|
||||
import com.meloda.fast.api.model.VKConversation
|
||||
import com.meloda.fast.api.model.VKMessage
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class ChatsViewModel : ViewModel() {
|
||||
|
||||
val chatsAnswer = MutableLiveData<ChatsAnswer?>()
|
||||
|
||||
data class ChatsAnswer(var status: Status, var message: String? = "") {
|
||||
companion object {
|
||||
val SUCCESS get() = ChatsAnswer(Status.SUCCESS)
|
||||
val FAIL get() = ChatsAnswer(Status.FAIL)
|
||||
val LOADING get() = ChatsAnswer(Status.LOADING)
|
||||
}
|
||||
|
||||
enum class Status {
|
||||
SUCCESS, FAIL, LOADING
|
||||
}
|
||||
}
|
||||
|
||||
fun loadChats() = viewModelScope.launch(Dispatchers.IO) {
|
||||
chatsAnswer.postValue(ChatsAnswer.LOADING)
|
||||
|
||||
try {
|
||||
val chats = VKApi.messages()
|
||||
.getConversations()
|
||||
.filter("all")
|
||||
.extended(true)
|
||||
.fields(VKConstants.USER_FIELDS + ',' + VKConstants.GROUP_FIELDS)
|
||||
.offset(0)
|
||||
.count(30)
|
||||
.executeSuspend(VKConversation::class.java)
|
||||
|
||||
// CacheStorage.chatsStorage.insertValues(chats)
|
||||
|
||||
val lastMessages = arrayListOf<VKMessage>()
|
||||
chats.collect {
|
||||
lastMessages.add(it.lastMessage)
|
||||
}
|
||||
|
||||
CacheStorage.messagesStorage.insertValues(lastMessages)
|
||||
CacheStorage.usersStorage.insertValues(VKConversation.profiles)
|
||||
CacheStorage.groupsStorage.insertValues(VKConversation.groups)
|
||||
//
|
||||
// chatsAnswer.value = ChatsAnswer.SUCCESS
|
||||
|
||||
chatsAnswer.postValue(ChatsAnswer.SUCCESS)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
// adapter.updateValues(chats.toList())
|
||||
// adapter.notifyDataSetChanged()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
chatsAnswer.postValue(ChatsAnswer.FAIL.also { it.message = e.message })
|
||||
// chatsAnswer.value = ChatsAnswer.FAIL.also { it.message = e.message }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import android.util.AttributeSet
|
||||
import android.view.ViewTreeObserver
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
|
||||
// TODO: 8/31/2021 extend ShapeableImageView and set corners for half of size
|
||||
class CircleImageView : AppCompatImageView {
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
package com.meloda.fast.widget
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.theme.overlay.MaterialThemeOverlay
|
||||
import com.meloda.fast.R
|
||||
import com.meloda.fast.util.AndroidUtils
|
||||
|
||||
class Toolbar : MaterialToolbar {
|
||||
|
||||
constructor(context: Context) : this(context, null)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
MaterialThemeOverlay.wrap(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr,
|
||||
com.google.android.material.R.style.Widget_MaterialComponents_Toolbar
|
||||
),
|
||||
attrs,
|
||||
defStyleAttr
|
||||
)
|
||||
|
||||
private fun init() {
|
||||
//...
|
||||
}
|
||||
|
||||
override fun setTitle(resId: Int) {
|
||||
title = context.getString(resId)
|
||||
}
|
||||
|
||||
override fun setTitle(title: CharSequence?) {
|
||||
findViewById<TextView>(R.id.toolbarTitle).text = title
|
||||
}
|
||||
|
||||
override fun setTitleTextColor(color: Int) {
|
||||
findViewById<TextView>(R.id.toolbarTitle).setTextColor(color)
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
super.onDraw(canvas)
|
||||
init()
|
||||
}
|
||||
|
||||
override fun setNavigationIcon(icon: Drawable?) {
|
||||
findViewById<ImageButton>(R.id.toolbarNavigationIcon).setImageDrawable(icon)
|
||||
}
|
||||
|
||||
override fun setNavigationIcon(@DrawableRes resId: Int) {
|
||||
findViewById<ImageButton>(R.id.toolbarNavigationIcon).setImageResource(resId)
|
||||
}
|
||||
|
||||
// fun setNavigationIconTintList(tintList: ColorStateList?) {
|
||||
// findViewById<ImageButton>(R.id.toolbarNavigationIcon).drawable?.setTintList(tintList)
|
||||
// }
|
||||
//
|
||||
// fun setNavigationIconTint(@ColorInt tintColor: Int) {
|
||||
// findViewById<ImageButton>(R.id.toolbarNavigationIcon).drawable?.setTint(tintColor)
|
||||
// }
|
||||
|
||||
fun setNavigationClickListener(listener: OnClickListener?) {
|
||||
findViewById<View>(R.id.toolbarNavigation).setOnClickListener(listener)
|
||||
}
|
||||
|
||||
fun setNavigationOnBackClickListener(activity: Activity) {
|
||||
findViewById<View>(R.id.toolbarNavigation).setOnClickListener { activity.onBackPressed() }
|
||||
}
|
||||
|
||||
fun setNavigationVisibility(visible: Boolean) {
|
||||
findViewById<View>(R.id.toolbarNavigation).visibility = if (visible) VISIBLE else GONE
|
||||
}
|
||||
|
||||
fun tintNavigationIcon(@ColorInt color: Int) {
|
||||
findViewById<ImageButton>(R.id.toolbarNavigationIcon).imageTintList =
|
||||
ColorStateList.valueOf(color)
|
||||
}
|
||||
|
||||
fun setAvatarIcon(icon: Drawable?) {
|
||||
findViewById<ImageView>(R.id.toolbarAvatar).setImageDrawable(icon)
|
||||
}
|
||||
|
||||
fun setAvatarIcon(@DrawableRes resId: Int) {
|
||||
// findViewById<SimpleDraweeView>(R.id.toolbarAvatar).setActualImageResource(resId)
|
||||
}
|
||||
|
||||
fun setAvatarClickListener(listener: OnClickListener?) {
|
||||
findViewById<View>(R.id.toolbarAvatar).setOnClickListener(listener)
|
||||
}
|
||||
|
||||
fun setAvatarVisibility(visible: Boolean) {
|
||||
findViewById<View>(R.id.toolbarAvatar).visibility = if (visible) VISIBLE else GONE
|
||||
}
|
||||
|
||||
// fun getAvatar(): SimpleDraweeView {
|
||||
// return findViewById(R.id.toolbarAvatar)
|
||||
// }
|
||||
|
||||
fun setTitleMode(titleMode: TitleMode) {
|
||||
val title = findViewById<TextView>(R.id.toolbarTitle)
|
||||
|
||||
when (titleMode) {
|
||||
TitleMode.SIMPLE -> {
|
||||
title.gravity = Gravity.CENTER
|
||||
title.typeface = ResourcesCompat.getFont(context, R.font.google_sans_medium)
|
||||
title.setTextColor(AndroidUtils.getThemeAttrColor(context, R.attr.colorAccent))
|
||||
title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 22f)
|
||||
}
|
||||
TitleMode.HINT -> {
|
||||
title.gravity = Gravity.CENTER_VERTICAL and Gravity.START
|
||||
title.typeface = ResourcesCompat.getFont(context, R.font.google_sans_regular)
|
||||
title.setTextColor(
|
||||
AndroidUtils.getThemeAttrColor(
|
||||
context,
|
||||
R.attr.textColorSecondary
|
||||
)
|
||||
)
|
||||
title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class TitleMode {
|
||||
SIMPLE, HINT
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</layout>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.meloda.fast.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<com.google.android.material.appbar.MaterialToolbar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/toolbar"
|
||||
@@ -63,4 +63,4 @@
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</com.meloda.fast.widget.Toolbar>
|
||||
</com.google.android.material.appbar.MaterialToolbar>
|
||||
@@ -17,24 +17,6 @@
|
||||
app:popUpTo="@id/loginFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
|
||||
<action
|
||||
android:id="@+id/toValidation"
|
||||
app:destination="@id/validationFragment" />
|
||||
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/validationFragment"
|
||||
android:name="com.meloda.fast.screens.login.ValidationFragment"
|
||||
android:label="ValidationFragment"
|
||||
tools:layout="@layout/fragment_validation">
|
||||
|
||||
<action
|
||||
android:id="@+id/toLogin"
|
||||
app:destination="@id/loginFragment"
|
||||
app:popUpTo="@id/validationFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
|
||||
</fragment>
|
||||
|
||||
|
||||
|
||||
@@ -29,24 +29,6 @@
|
||||
app:popUpTo="@id/loginFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
|
||||
<action
|
||||
android:id="@+id/toValidation"
|
||||
app:destination="@id/validationFragment" />
|
||||
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/validationFragment"
|
||||
android:name="com.meloda.fast.screens.login.ValidationFragment"
|
||||
android:label="ValidationFragment"
|
||||
tools:layout="@layout/fragment_validation">
|
||||
|
||||
<action
|
||||
android:id="@+id/toLogin"
|
||||
app:destination="@id/loginFragment"
|
||||
app:popUpTo="@id/validationFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
|
||||
</fragment>
|
||||
|
||||
</navigation>
|
||||
Reference in New Issue
Block a user