From b09ae2049ce2889d21bd4913329713f552adaa9e Mon Sep 17 00:00:00 2001 From: Danil Nikolaev Date: Tue, 31 Aug 2021 16:20:09 +0300 Subject: [PATCH 1/2] api refactored and cleaned --- .../com/meloda/fast/VKLongPollParser.kt | 160 ------ .../com/meloda/fast/api/OnResponseListener.kt | 9 - .../com/meloda/fast/{ => api}/UserConfig.kt | 3 +- .../main/kotlin/com/meloda/fast/api/VKApi.kt | 506 ------------------ .../kotlin/com/meloda/fast/api/VKApiKeys.kt | 14 - .../main/kotlin/com/meloda/fast/api/VKAuth.kt | 84 --- .../kotlin/com/meloda/fast/api/VKConstants.kt | 24 + .../main/kotlin/com/meloda/fast/api/VKUtil.kt | 26 +- .../fast/api/method/MessageMethodSetter.kt | 205 ------- .../meloda/fast/api/method/MethodSetter.kt | 169 ------ .../fast/api/method/UserMethodSetter.kt | 44 -- .../fast/api/network/AuthInterceptor.kt | 4 +- ...VMFragment.kt => BaseViewModelFragment.kt} | 2 +- .../com/meloda/fast/base/viewmodel/Events.kt | 4 +- .../com/meloda/fast/base/viewmodel/VKEvent.kt | 3 - .../meloda/fast/common/FragmentSwitcher.kt | 105 ---- .../com/meloda/fast/common/UpdateManager.kt | 81 --- .../com/meloda/fast/concurrent/EventInfo.kt | 3 - .../com/meloda/fast/concurrent/LowThread.kt | 12 - .../com/meloda/fast/concurrent/TaskManager.kt | 30 -- .../fast/database/storage/UsersStorage.kt | 9 +- .../fast/extensions/NavigationExtensions.kt | 11 +- .../com/meloda/fast/model/NewUpdateInfo.kt | 30 -- .../com/meloda/fast/model/UpdateInfo.kt | 21 - .../kotlin/com/meloda/fast/net/HttpRequest.kt | 114 ---- .../fast/receiver/DownloadUpdateReceiver.kt | 17 - .../fast/screens/login/LoginFragment.kt | 4 +- .../fast/screens/login/LoginViewModel.kt | 13 +- .../fast/screens/login/ValidationFragment.kt | 75 --- .../meloda/fast/screens/main/MainFragment.kt | 6 +- .../screens/messages/ConversationsFragment.kt | 4 +- .../meloda/fast/service/LongPollService.kt | 43 +- .../kotlin/com/meloda/fast/util/VKUtils.kt | 140 ++--- .../meloda/fast/viewmodel/ChatsViewModel.kt | 70 --- .../com/meloda/fast/widget/CircleImageView.kt | 1 + .../kotlin/com/meloda/fast/widget/Toolbar.kt | 141 ----- .../main/res/layout/fragment_validation.xml | 9 - app/src/main/res/layout/toolbar.xml | 4 +- app/src/main/res/navigation/login.xml | 18 - app/src/main/res/navigation/main.xml | 18 - 40 files changed, 129 insertions(+), 2107 deletions(-) delete mode 100644 app/src/main/kotlin/com/meloda/fast/VKLongPollParser.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/api/OnResponseListener.kt rename app/src/main/kotlin/com/meloda/fast/{ => api}/UserConfig.kt (93%) delete mode 100644 app/src/main/kotlin/com/meloda/fast/api/VKApi.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/api/VKApiKeys.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/api/VKAuth.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/api/method/MessageMethodSetter.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/api/method/MethodSetter.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/api/method/UserMethodSetter.kt rename app/src/main/kotlin/com/meloda/fast/base/{BaseVMFragment.kt => BaseViewModelFragment.kt} (91%) delete mode 100644 app/src/main/kotlin/com/meloda/fast/base/viewmodel/VKEvent.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/common/FragmentSwitcher.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/common/UpdateManager.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/concurrent/EventInfo.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/concurrent/LowThread.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/concurrent/TaskManager.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/model/NewUpdateInfo.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/model/UpdateInfo.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/net/HttpRequest.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/receiver/DownloadUpdateReceiver.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/screens/login/ValidationFragment.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/viewmodel/ChatsViewModel.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/widget/Toolbar.kt delete mode 100644 app/src/main/res/layout/fragment_validation.xml diff --git a/app/src/main/kotlin/com/meloda/fast/VKLongPollParser.kt b/app/src/main/kotlin/com/meloda/fast/VKLongPollParser.kt deleted file mode 100644 index f203d761..00000000 --- a/app/src/main/kotlin/com/meloda/fast/VKLongPollParser.kt +++ /dev/null @@ -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 - onMessagesListener.onDeleteMessage(array[0], array[1]) - } - VKApiKeys.READ_MESSAGE.value -> { - val array = eventInfo.data as Array - 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) - } - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/OnResponseListener.kt b/app/src/main/kotlin/com/meloda/fast/api/OnResponseListener.kt deleted file mode 100644 index 57e036bb..00000000 --- a/app/src/main/kotlin/com/meloda/fast/api/OnResponseListener.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.meloda.fast.api - -interface OnResponseListener { - - fun onResponse(response: T) - - fun onError(t: Throwable) - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/UserConfig.kt b/app/src/main/kotlin/com/meloda/fast/api/UserConfig.kt similarity index 93% rename from app/src/main/kotlin/com/meloda/fast/UserConfig.kt rename to app/src/main/kotlin/com/meloda/fast/api/UserConfig.kt index 2e3e40d7..3d882c2c 100644 --- a/app/src/main/kotlin/com/meloda/fast/UserConfig.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/UserConfig.kt @@ -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 { diff --git a/app/src/main/kotlin/com/meloda/fast/api/VKApi.kt b/app/src/main/kotlin/com/meloda/fast/api/VKApi.kt deleted file mode 100644 index 33d23cc1..00000000 --- a/app/src/main/kotlin/com/meloda/fast/api/VKApi.kt +++ /dev/null @@ -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 execute(url: String, cls: Class?): ArrayList? { - 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? - } - } - - Boolean::class.java -> { - val value = json.optInt("response") == 1 - return arrayListOf(value) as ArrayList? - } - - Long::class.java -> { - val value = json.optLong("response") - return arrayListOf(value) as ArrayList? - } - - Int::class.java -> { - val value = json.optInt("response") - return arrayListOf(value) as ArrayList? - } - } - - val response = json.opt("response") ?: return null - - val array = optItems(json) ?: return null - val models = ArrayList(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() - - 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() - - 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() - - 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 - } - } - - 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() - - 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() - - 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 execute(url: String, cls: Class, listener: OnResponseListener?) { - 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 suspendExecute(url: String, cls: Class): Flow { - return suspendCoroutine { - try { - val models = execute(url, cls)?.asFlow() ?: return@suspendCoroutine - - it.resume(models) - } catch (e: Exception) { - e.printStackTrace() - it.resumeWithException(e) - } - } - } - - fun executeArray(url: String, cls: Class, listener: OnResponseListener>) { - com.meloda.fast.concurrent.TaskManager.execute { - try { - val models = execute(url, cls) - - handler.post { listener.onResponse(models as ArrayList) } - } 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( - private val listener: OnResponseListener?, - private val response: E - ) : Runnable { - override fun run() { - listener?.onResponse(response) - } - } - - class SuccessArrayCallback( - private val listener: OnResponseListener>?, - private val response: ArrayList - ) : Runnable { - override fun run() { - listener?.onResponse(response) - } - } - - class ErrorCallback( - private val listener: OnResponseListener?, - private val exception: Exception - ) : Runnable { - override fun run() { - listener?.onError(exception) - } - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/VKApiKeys.kt b/app/src/main/kotlin/com/meloda/fast/api/VKApiKeys.kt deleted file mode 100644 index 91ac7211..00000000 --- a/app/src/main/kotlin/com/meloda/fast/api/VKApiKeys.kt +++ /dev/null @@ -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") -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/VKAuth.kt b/app/src/main/kotlin/com/meloda/fast/api/VKAuth.kt deleted file mode 100644 index f67a5338..00000000 --- a/app/src/main/kotlin/com/meloda/fast/api/VKAuth.kt +++ /dev/null @@ -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? = 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 { - 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 - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/VKConstants.kt b/app/src/main/kotlin/com/meloda/fast/api/VKConstants.kt index b91d785e..5c4843c9 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/VKConstants.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/VKConstants.kt @@ -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" + } + } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/VKUtil.kt b/app/src/main/kotlin/com/meloda/fast/api/VKUtil.kt index ca604ea2..8361dddc 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/VKUtil.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/VKUtil.kt @@ -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, 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()) { diff --git a/app/src/main/kotlin/com/meloda/fast/api/method/MessageMethodSetter.kt b/app/src/main/kotlin/com/meloda/fast/api/method/MessageMethodSetter.kt deleted file mode 100644 index d8c5e2d5..00000000 --- a/app/src/main/kotlin/com/meloda/fast/api/method/MessageMethodSetter.kt +++ /dev/null @@ -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): 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): 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): 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): 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 - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/method/MethodSetter.kt b/app/src/main/kotlin/com/meloda/fast/api/method/MethodSetter.kt deleted file mode 100644 index dbebf7eb..00000000 --- a/app/src/main/kotlin/com/meloda/fast/api/method/MethodSetter.kt +++ /dev/null @@ -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 = 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 executeSuspend(cls: Class): Flow { - return VKApi.suspendExecute(getSignedUrl(), cls) - } - - fun execute(cls: Class): ArrayList? { - return VKApi.execute(getSignedUrl(), cls) - } - - fun executeArray(cls: Class, listener: OnResponseListener>) { - VKApi.executeArray(getSignedUrl(), cls, listener) - } - - fun execute(cls: Class, listener: OnResponseListener?) { - 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): 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): 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) - } - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/method/UserMethodSetter.kt b/app/src/main/kotlin/com/meloda/fast/api/method/UserMethodSetter.kt deleted file mode 100644 index 5a8daa90..00000000 --- a/app/src/main/kotlin/com/meloda/fast/api/method/UserMethodSetter.kt +++ /dev/null @@ -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 - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/AuthInterceptor.kt b/app/src/main/kotlin/com/meloda/fast/api/network/AuthInterceptor.kt index a3f3274c..b97282a4 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/AuthInterceptor.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/network/AuthInterceptor.kt @@ -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()) } diff --git a/app/src/main/kotlin/com/meloda/fast/base/BaseVMFragment.kt b/app/src/main/kotlin/com/meloda/fast/base/BaseViewModelFragment.kt similarity index 91% rename from app/src/main/kotlin/com/meloda/fast/base/BaseVMFragment.kt rename to app/src/main/kotlin/com/meloda/fast/base/BaseViewModelFragment.kt index be8aac75..a9f7eb55 100644 --- a/app/src/main/kotlin/com/meloda/fast/base/BaseVMFragment.kt +++ b/app/src/main/kotlin/com/meloda/fast/base/BaseViewModelFragment.kt @@ -9,7 +9,7 @@ import com.meloda.fast.base.viewmodel.VKEvent import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach -abstract class BaseVMFragment : BaseFragment { +abstract class BaseViewModelFragment : BaseFragment { constructor() : super() diff --git a/app/src/main/kotlin/com/meloda/fast/base/viewmodel/Events.kt b/app/src/main/kotlin/com/meloda/fast/base/viewmodel/Events.kt index dfa637b3..f06d859d 100644 --- a/app/src/main/kotlin/com/meloda/fast/base/viewmodel/Events.kt +++ b/app/src/main/kotlin/com/meloda/fast/base/viewmodel/Events.kt @@ -8,4 +8,6 @@ data class ShowDialogInfoEvent( ) : VKEvent() object StartProgressEvent : VKEvent() -object StopProgressEvent : VKEvent() \ No newline at end of file +object StopProgressEvent : VKEvent() + +abstract class VKEvent \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/base/viewmodel/VKEvent.kt b/app/src/main/kotlin/com/meloda/fast/base/viewmodel/VKEvent.kt deleted file mode 100644 index 34d800a9..00000000 --- a/app/src/main/kotlin/com/meloda/fast/base/viewmodel/VKEvent.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.meloda.fast.base.viewmodel - -abstract class VKEvent \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/common/FragmentSwitcher.kt b/app/src/main/kotlin/com/meloda/fast/common/FragmentSwitcher.kt deleted file mode 100644 index 07a63ede..00000000 --- a/app/src/main/kotlin/com/meloda/fast/common/FragmentSwitcher.kt +++ /dev/null @@ -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 - ) { - 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() - } -} diff --git a/app/src/main/kotlin/com/meloda/fast/common/UpdateManager.kt b/app/src/main/kotlin/com/meloda/fast/common/UpdateManager.kt deleted file mode 100644 index 759aefc7..00000000 --- a/app/src/main/kotlin/com/meloda/fast/common/UpdateManager.kt +++ /dev/null @@ -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() - 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) -// } -// } -// } - } - } - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/concurrent/EventInfo.kt b/app/src/main/kotlin/com/meloda/fast/concurrent/EventInfo.kt deleted file mode 100644 index 5b975967..00000000 --- a/app/src/main/kotlin/com/meloda/fast/concurrent/EventInfo.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.meloda.fast.concurrent - -class EventInfo constructor(var key: String, var data: T? = null) \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/concurrent/LowThread.kt b/app/src/main/kotlin/com/meloda/fast/concurrent/LowThread.kt deleted file mode 100644 index 13b1c214..00000000 --- a/app/src/main/kotlin/com/meloda/fast/concurrent/LowThread.kt +++ /dev/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() - } - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/concurrent/TaskManager.kt b/app/src/main/kotlin/com/meloda/fast/concurrent/TaskManager.kt deleted file mode 100644 index 6629f087..00000000 --- a/app/src/main/kotlin/com/meloda/fast/concurrent/TaskManager.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.meloda.fast.concurrent - -object TaskManager { - - private const val TAG = "TaskManager" - - private val listeners = arrayListOf() - - 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<*>) - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/database/storage/UsersStorage.kt b/app/src/main/kotlin/com/meloda/fast/database/storage/UsersStorage.kt index db83abaf..c0a35901 100644 --- a/app/src/main/kotlin/com/meloda/fast/database/storage/UsersStorage.kt +++ b/app/src/main/kotlin/com/meloda/fast/database/storage/UsersStorage.kt @@ -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() { } override fun getAllValues(): ArrayList { - val cursor = selectCursor(TABLE_USERS) + val cursor = CacheStorage.selectCursor(TABLE_USERS) val users = ArrayList() while (cursor.moveToNext()) users.add(parseValue(cursor)) diff --git a/app/src/main/kotlin/com/meloda/fast/extensions/NavigationExtensions.kt b/app/src/main/kotlin/com/meloda/fast/extensions/NavigationExtensions.kt index ad2b3c72..b1313de3 100644 --- a/app/src/main/kotlin/com/meloda/fast/extensions/NavigationExtensions.kt +++ b/app/src/main/kotlin/com/meloda/fast/extensions/NavigationExtensions.kt @@ -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 { // Map of tags - val graphIdToTagMap = SparseArray() + val graphIdToTagMap = SparseArrayCompat() // Result. Mutable live data with the selected controlled val selectedNavController = MutableLiveData() @@ -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 -> diff --git a/app/src/main/kotlin/com/meloda/fast/model/NewUpdateInfo.kt b/app/src/main/kotlin/com/meloda/fast/model/NewUpdateInfo.kt deleted file mode 100644 index 5a18e6ed..00000000 --- a/app/src/main/kotlin/com/meloda/fast/model/NewUpdateInfo.kt +++ /dev/null @@ -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") - } - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/model/UpdateInfo.kt b/app/src/main/kotlin/com/meloda/fast/model/UpdateInfo.kt deleted file mode 100644 index 042ae0dd..00000000 --- a/app/src/main/kotlin/com/meloda/fast/model/UpdateInfo.kt +++ /dev/null @@ -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") - } - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/net/HttpRequest.kt b/app/src/main/kotlin/com/meloda/fast/net/HttpRequest.kt deleted file mode 100644 index a43dc092..00000000 --- a/app/src/main/kotlin/com/meloda/fast/net/HttpRequest.kt +++ /dev/null @@ -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 = ArrayMap() -) { - companion object { - const val GET = "GET" - const val POST = "POST" - - operator fun get( - url: String, - params: ArrayMap = 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 "" - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/receiver/DownloadUpdateReceiver.kt b/app/src/main/kotlin/com/meloda/fast/receiver/DownloadUpdateReceiver.kt deleted file mode 100644 index a375da0a..00000000 --- a/app/src/main/kotlin/com/meloda/fast/receiver/DownloadUpdateReceiver.kt +++ /dev/null @@ -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? = null - - override fun onReceive(context: Context?, intent: Intent?) { - listener?.onResponse(null) - } - - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/screens/login/LoginFragment.kt b/app/src/main/kotlin/com/meloda/fast/screens/login/LoginFragment.kt index 653d8e33..d0291586 100644 --- a/app/src/main/kotlin/com/meloda/fast/screens/login/LoginFragment.kt +++ b/app/src/main/kotlin/com/meloda/fast/screens/login/LoginFragment.kt @@ -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(R.layout.fragment_login) { +class LoginFragment : BaseViewModelFragment(R.layout.fragment_login) { override val viewModel: LoginViewModel by viewModels() private val binding: FragmentLoginBinding by viewBinding() diff --git a/app/src/main/kotlin/com/meloda/fast/screens/login/LoginViewModel.kt b/app/src/main/kotlin/com/meloda/fast/screens/login/LoginViewModel.kt index afe5c5b5..d63903dc 100644 --- a/app/src/main/kotlin/com/meloda/fast/screens/login/LoginViewModel.kt +++ b/app/src/main/kotlin/com/meloda/fast/screens/login/LoginViewModel.kt @@ -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)) diff --git a/app/src/main/kotlin/com/meloda/fast/screens/login/ValidationFragment.kt b/app/src/main/kotlin/com/meloda/fast/screens/login/ValidationFragment.kt deleted file mode 100644 index 62db202e..00000000 --- a/app/src/main/kotlin/com/meloda/fast/screens/login/ValidationFragment.kt +++ /dev/null @@ -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") - } - } - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/screens/main/MainFragment.kt b/app/src/main/kotlin/com/meloda/fast/screens/main/MainFragment.kt index 1d024439..ccdeaece 100644 --- a/app/src/main/kotlin/com/meloda/fast/screens/main/MainFragment.kt +++ b/app/src/main/kotlin/com/meloda/fast/screens/main/MainFragment.kt @@ -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(R.layout.fragment_main) { +class MainFragment : BaseViewModelFragment(R.layout.fragment_main) { override val viewModel: MainViewModel by viewModels() private val binding: FragmentMainBinding by viewBinding() diff --git a/app/src/main/kotlin/com/meloda/fast/screens/messages/ConversationsFragment.kt b/app/src/main/kotlin/com/meloda/fast/screens/messages/ConversationsFragment.kt index f1b6f817..e311d331 100644 --- a/app/src/main/kotlin/com/meloda/fast/screens/messages/ConversationsFragment.kt +++ b/app/src/main/kotlin/com/meloda/fast/screens/messages/ConversationsFragment.kt @@ -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(R.layout.fragment_conversations) { +class ConversationsFragment : BaseViewModelFragment(R.layout.fragment_conversations) { override val viewModel: ConversationsViewModel by viewModels() private val binding: FragmentConversationsBinding by viewBinding() diff --git a/app/src/main/kotlin/com/meloda/fast/service/LongPollService.kt b/app/src/main/kotlin/com/meloda/fast/service/LongPollService.kt index f2ad56da..55df17be 100644 --- a/app/src/main/kotlin/com/meloda/fast/service/LongPollService.kt +++ b/app/src/main/kotlin/com/meloda/fast/service/LongPollService.kt @@ -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() - 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() +// 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) } } diff --git a/app/src/main/kotlin/com/meloda/fast/util/VKUtils.kt b/app/src/main/kotlin/com/meloda/fast/util/VKUtils.kt index 04782be7..f06a8035 100644 --- a/app/src/main/kotlin/com/meloda/fast/util/VKUtils.kt +++ b/app/src/main/kotlin/com/meloda/fast/util/VKUtils.kt @@ -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? = 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? = 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): 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 + 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, + "" + ) } + + } } diff --git a/app/src/main/kotlin/com/meloda/fast/viewmodel/ChatsViewModel.kt b/app/src/main/kotlin/com/meloda/fast/viewmodel/ChatsViewModel.kt deleted file mode 100644 index 02d56102..00000000 --- a/app/src/main/kotlin/com/meloda/fast/viewmodel/ChatsViewModel.kt +++ /dev/null @@ -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() - - 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() - 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 } - } - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/widget/CircleImageView.kt b/app/src/main/kotlin/com/meloda/fast/widget/CircleImageView.kt index 86c7c5b2..6492c7a2 100644 --- a/app/src/main/kotlin/com/meloda/fast/widget/CircleImageView.kt +++ b/app/src/main/kotlin/com/meloda/fast/widget/CircleImageView.kt @@ -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 { diff --git a/app/src/main/kotlin/com/meloda/fast/widget/Toolbar.kt b/app/src/main/kotlin/com/meloda/fast/widget/Toolbar.kt deleted file mode 100644 index 15b24544..00000000 --- a/app/src/main/kotlin/com/meloda/fast/widget/Toolbar.kt +++ /dev/null @@ -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(R.id.toolbarTitle).text = title - } - - override fun setTitleTextColor(color: Int) { - findViewById(R.id.toolbarTitle).setTextColor(color) - } - - override fun onDraw(canvas: Canvas?) { - super.onDraw(canvas) - init() - } - - override fun setNavigationIcon(icon: Drawable?) { - findViewById(R.id.toolbarNavigationIcon).setImageDrawable(icon) - } - - override fun setNavigationIcon(@DrawableRes resId: Int) { - findViewById(R.id.toolbarNavigationIcon).setImageResource(resId) - } - -// fun setNavigationIconTintList(tintList: ColorStateList?) { -// findViewById(R.id.toolbarNavigationIcon).drawable?.setTintList(tintList) -// } -// -// fun setNavigationIconTint(@ColorInt tintColor: Int) { -// findViewById(R.id.toolbarNavigationIcon).drawable?.setTint(tintColor) -// } - - fun setNavigationClickListener(listener: OnClickListener?) { - findViewById(R.id.toolbarNavigation).setOnClickListener(listener) - } - - fun setNavigationOnBackClickListener(activity: Activity) { - findViewById(R.id.toolbarNavigation).setOnClickListener { activity.onBackPressed() } - } - - fun setNavigationVisibility(visible: Boolean) { - findViewById(R.id.toolbarNavigation).visibility = if (visible) VISIBLE else GONE - } - - fun tintNavigationIcon(@ColorInt color: Int) { - findViewById(R.id.toolbarNavigationIcon).imageTintList = - ColorStateList.valueOf(color) - } - - fun setAvatarIcon(icon: Drawable?) { - findViewById(R.id.toolbarAvatar).setImageDrawable(icon) - } - - fun setAvatarIcon(@DrawableRes resId: Int) { -// findViewById(R.id.toolbarAvatar).setActualImageResource(resId) - } - - fun setAvatarClickListener(listener: OnClickListener?) { - findViewById(R.id.toolbarAvatar).setOnClickListener(listener) - } - - fun setAvatarVisibility(visible: Boolean) { - findViewById(R.id.toolbarAvatar).visibility = if (visible) VISIBLE else GONE - } - -// fun getAvatar(): SimpleDraweeView { -// return findViewById(R.id.toolbarAvatar) -// } - - fun setTitleMode(titleMode: TitleMode) { - val title = findViewById(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 - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_validation.xml b/app/src/main/res/layout/fragment_validation.xml deleted file mode 100644 index 7a6e0918..00000000 --- a/app/src/main/res/layout/fragment_validation.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/toolbar.xml b/app/src/main/res/layout/toolbar.xml index 61920395..3ab5718b 100644 --- a/app/src/main/res/layout/toolbar.xml +++ b/app/src/main/res/layout/toolbar.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/navigation/login.xml b/app/src/main/res/navigation/login.xml index 60528bb8..ebc0f0ba 100644 --- a/app/src/main/res/navigation/login.xml +++ b/app/src/main/res/navigation/login.xml @@ -17,24 +17,6 @@ app:popUpTo="@id/loginFragment" app:popUpToInclusive="true" /> - - - - - - - - diff --git a/app/src/main/res/navigation/main.xml b/app/src/main/res/navigation/main.xml index 2aecd907..ca936bea 100644 --- a/app/src/main/res/navigation/main.xml +++ b/app/src/main/res/navigation/main.xml @@ -29,24 +29,6 @@ app:popUpTo="@id/loginFragment" app:popUpToInclusive="true" /> - - - - - - - - \ No newline at end of file From cb25112e833bc25910aec0aefeb9b1e43485cef6 Mon Sep 17 00:00:00 2001 From: Danil Nikolaev Date: Tue, 31 Aug 2021 16:28:06 +0300 Subject: [PATCH 2/2] api refactored and cleaned --- .../fast/api/network/ResultCallFactory.kt | 2 - .../RequestMessagesGetConversations.kt | 21 ------- .../network/response/ConversationsResponse.kt | 1 + .../api/network/response/MessagesResponse.kt | 13 ---- .../com/meloda/fast/common/AppGlobal.kt | 7 +++ .../meloda/fast/service/LongPollService.kt | 3 +- .../com/meloda/fast/util/AndroidUtils.kt | 62 +++++-------------- 7 files changed, 23 insertions(+), 86 deletions(-) delete mode 100644 app/src/main/kotlin/com/meloda/fast/api/network/request/RequestMessagesGetConversations.kt create mode 100644 app/src/main/kotlin/com/meloda/fast/api/network/response/ConversationsResponse.kt delete mode 100644 app/src/main/kotlin/com/meloda/fast/api/network/response/MessagesResponse.kt diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/ResultCallFactory.kt b/app/src/main/kotlin/com/meloda/fast/api/network/ResultCallFactory.kt index ddc3309c..9cf21bd5 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/ResultCallFactory.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/network/ResultCallFactory.kt @@ -1,6 +1,5 @@ package com.meloda.fast.api.network -import android.util.Log import com.meloda.fast.api.VKException import okhttp3.Request import okio.IOException @@ -76,7 +75,6 @@ internal class ResultCall(proxy: Call) : CallDelegate>(proxy) private val callback: Callback> ) : Callback { - // TODO: 8/31/2021 parse VK errors override fun onResponse(call: Call, response: Response) { val result: Answer = if (response.isSuccessful) Answer.Success(response.body() as T) diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/request/RequestMessagesGetConversations.kt b/app/src/main/kotlin/com/meloda/fast/api/network/request/RequestMessagesGetConversations.kt deleted file mode 100644 index 8c99e76b..00000000 --- a/app/src/main/kotlin/com/meloda/fast/api/network/request/RequestMessagesGetConversations.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.meloda.fast.api.network.request - -import com.google.gson.annotations.SerializedName - -class RequestMessagesGetConversations( - @SerializedName("offset") - private val offset: Int = 0, - - @SerializedName("count") - private val count: Int = 0, - - //values = all, unread - @SerializedName("filter") - private val filter: String = "", - - @SerializedName("extended") - private val extended: Boolean = false, - - @SerializedName("fields") - private var fields: String = "" -) \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/response/ConversationsResponse.kt b/app/src/main/kotlin/com/meloda/fast/api/network/response/ConversationsResponse.kt new file mode 100644 index 00000000..dfe2424b --- /dev/null +++ b/app/src/main/kotlin/com/meloda/fast/api/network/response/ConversationsResponse.kt @@ -0,0 +1 @@ +package com.meloda.fast.api.network.response \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/response/MessagesResponse.kt b/app/src/main/kotlin/com/meloda/fast/api/network/response/MessagesResponse.kt deleted file mode 100644 index e9542f23..00000000 --- a/app/src/main/kotlin/com/meloda/fast/api/network/response/MessagesResponse.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.meloda.fast.api.network.response - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -class MessagesResponse( - val count: Int -) { -} - -@Parcelize -data class GetConversationsResponse(val a: String) : Parcelable -// TODO: 7/12/2021 use hilt for this like in LIR and make simple conversations' screen diff --git a/app/src/main/kotlin/com/meloda/fast/common/AppGlobal.kt b/app/src/main/kotlin/com/meloda/fast/common/AppGlobal.kt index 4f79d1cf..6ea4bf2f 100644 --- a/app/src/main/kotlin/com/meloda/fast/common/AppGlobal.kt +++ b/app/src/main/kotlin/com/meloda/fast/common/AppGlobal.kt @@ -2,11 +2,13 @@ package com.meloda.fast.common import android.annotation.SuppressLint import android.app.Application +import android.content.ClipboardManager import android.content.Context import android.content.SharedPreferences import android.content.pm.PackageManager import android.content.res.Resources import android.database.sqlite.SQLiteDatabase +import android.net.ConnectivityManager import android.os.Handler import android.view.inputmethod.InputMethodManager import androidx.core.content.pm.PackageInfoCompat @@ -37,6 +39,8 @@ class AppGlobal : Application() { companion object { lateinit var inputMethodManager: InputMethodManager + lateinit var connectivityManager: ConnectivityManager + lateinit var clipboardManager: ClipboardManager lateinit var preferences: SharedPreferences lateinit var locale: Locale @@ -84,10 +88,13 @@ class AppGlobal : Application() { Companion.packageName = packageName Companion.packageManager = packageManager + screenWidth = AndroidUtils.getDisplayWidth() screenHeight = AndroidUtils.getDisplayHeight() inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + clipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/service/LongPollService.kt b/app/src/main/kotlin/com/meloda/fast/service/LongPollService.kt index 55df17be..35865e0b 100644 --- a/app/src/main/kotlin/com/meloda/fast/service/LongPollService.kt +++ b/app/src/main/kotlin/com/meloda/fast/service/LongPollService.kt @@ -11,7 +11,7 @@ import com.meloda.fast.util.AndroidUtils import org.json.JSONArray import org.json.JSONObject -// TODO: 8/31/2021 rewrite +// TODO: 8/31/2021 rewrite, use job @Deprecated("Absolutely obsolete") class LongPollService : Service() { private var thread: Thread? = null @@ -19,7 +19,6 @@ class LongPollService : Service() { override fun onCreate() { super.onCreate() - running = false // thread = LowThread(Updater()) diff --git a/app/src/main/kotlin/com/meloda/fast/util/AndroidUtils.kt b/app/src/main/kotlin/com/meloda/fast/util/AndroidUtils.kt index ce6197a9..344075c1 100644 --- a/app/src/main/kotlin/com/meloda/fast/util/AndroidUtils.kt +++ b/app/src/main/kotlin/com/meloda/fast/util/AndroidUtils.kt @@ -1,15 +1,12 @@ package com.meloda.fast.util +import android.content.ClipData import android.content.Context -import android.content.Intent import android.content.res.Configuration -import android.net.Uri -import android.os.Build -import android.provider.Settings +import android.net.NetworkCapabilities import android.util.DisplayMetrics import android.util.TypedValue import androidx.annotation.AttrRes -import com.meloda.fast.BuildConfig import com.meloda.fast.common.AppGlobal @@ -36,20 +33,18 @@ object AndroidUtils { } } - //TODO fun hasConnection(): Boolean { - return false -// val network = AppGlobal.connectivityManager.activeNetwork ?: return false -// val activeNetwork = -// AppGlobal.connectivityManager.getNetworkCapabilities(network) ?: return false -// -// return when { -// activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true -// activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true -// activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true -// activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true -// else -> false -// } + val network = AppGlobal.connectivityManager.activeNetwork ?: return false + val activeNetwork = + AppGlobal.connectivityManager.getNetworkCapabilities(network) ?: return false + + return when { + activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true + activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true + activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true + activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true + else -> false + } } fun getDisplayWidth(): Int { @@ -60,37 +55,8 @@ object AndroidUtils { return AppGlobal.resources.displayMetrics.heightPixels } - fun isDeveloperSettingsEnabled(context: Context) = Settings.Secure.getInt( - context.contentResolver, - Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, - 0 - ) == 1 - - @Suppress("DEPRECATION") - fun isCanInstallUnknownApps(context: Context) = - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - Settings.Secure.getInt( - context.contentResolver, - Settings.Secure.INSTALL_NON_MARKET_APPS - ) == 1 - } else { - AppGlobal.packageManager.canRequestPackageInstalls() - } - - fun openInstallUnknownAppsScreen(context: Context) { - context.startActivity(Intent().apply { - action = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - Settings.ACTION_SECURITY_SETTINGS - } else { - data = Uri.parse("package:${BuildConfig.APPLICATION_ID}") - Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES - } - }) - } - - //TODO fun copyText(label: String? = "", text: String) { -// AppGlobal.clipboardManager.setPrimaryClip(ClipData.newPlainText(label, text)) + AppGlobal.clipboardManager.setPrimaryClip(ClipData.newPlainText(label, text)) } fun getThemeAttrColor(context: Context, @AttrRes resId: Int): Int {