Telegram - added chats list

This commit is contained in:
crimean 2018-06-07 17:44:43 +03:00
parent 2a36e5ffb0
commit 27ccc38a08
19 changed files with 461 additions and 150 deletions

View file

@ -120,6 +120,7 @@ dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
implementation 'com.android.support:support-annotations:27.1.1'
implementation 'commons-logging:commons-logging-api:1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'

View file

@ -11,6 +11,8 @@ import android.view.WindowManager
import android.view.inputmethod.EditorInfo
import android.widget.Button
import android.widget.EditText
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.PlatformUtil
class LoginDialogFragment : DialogFragment() {

View file

@ -2,11 +2,12 @@ package net.osmand.telegram
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import android.support.v7.widget.*
import android.view.*
import android.widget.Toast
import net.osmand.telegram.LoginDialogFragment.LoginDialogType
import net.osmand.telegram.TelegramHelper.*
import org.drinkless.td.libcore.telegram.TdApi
class MainActivity : AppCompatActivity(), TelegramListener {
@ -17,9 +18,13 @@ class MainActivity : AppCompatActivity(), TelegramListener {
private const val PROGRESS_MENU_ID = 2
}
private var authParamRequestHandler: AuthParamRequestHandler? = null
private var telegramAuthorizationRequestHandler: TelegramAuthorizationRequestHandler? = null
private var paused: Boolean = false
private lateinit var chatsView: RecyclerView
private lateinit var chatViewAdapter: ChatsAdapter
private lateinit var chatViewManager: RecyclerView.LayoutManager
private val app: TelegramApplication
get() = application as TelegramApplication
@ -32,20 +37,30 @@ class MainActivity : AppCompatActivity(), TelegramListener {
paused = false
authParamRequestHandler = telegramHelper.setAuthParamRequestHandler(object : AuthParamRequestListener {
override fun onRequestAuthParam(paramType: AuthParamType) {
runOnUiThread {
if (!paused) {
showLoginDialog(paramType)
}
chatViewManager = LinearLayoutManager(this)
chatViewAdapter = ChatsAdapter()
chatsView = findViewById<RecyclerView>(R.id.groups_view).apply {
//setHasFixedSize(true)
// use a linear layout manager
layoutManager = chatViewManager
// specify an viewAdapter (see also next example)
adapter = chatViewAdapter
}
telegramAuthorizationRequestHandler = telegramHelper.setTelegramAuthorizationRequestHandler(object : TelegramAuthorizationRequestListener {
override fun onRequestTelegramAuthenticationParameter(parameterType: TelegramAuthenticationParameterType) {
runOnUi {
showLoginDialog(parameterType)
}
}
override fun onAuthRequestError(code: Int, message: String) {
runOnUiThread {
if (!paused) {
Toast.makeText(this@MainActivity, "$code - $message", Toast.LENGTH_LONG).show()
}
override fun onTelegramAuthorizationRequestError(code: Int, message: String) {
runOnUi {
Toast.makeText(this@MainActivity, "$code - $message", Toast.LENGTH_LONG).show()
}
}
})
@ -66,24 +81,59 @@ class MainActivity : AppCompatActivity(), TelegramListener {
paused = true
}
override fun onTelegramStatusChanged(prevAutoState: AuthState, newAuthState: AuthState) {
runOnUiThread {
if (!paused) {
val fm = supportFragmentManager
when (newAuthState) {
AuthState.READY,
AuthState.CLOSED,
AuthState.UNKNOWN -> LoginDialogFragment.dismiss(fm)
else -> Unit
override fun onTelegramStatusChanged(prevTelegramAuthorizationState: TelegramAuthorizationState,
newTelegramAuthorizationState: TelegramAuthorizationState) {
runOnUi {
val fm = supportFragmentManager
when (newTelegramAuthorizationState) {
TelegramAuthorizationState.READY,
TelegramAuthorizationState.CLOSED,
TelegramAuthorizationState.UNKNOWN -> LoginDialogFragment.dismiss(fm)
else -> Unit
}
invalidateOptionsMenu()
updateTitle()
when (newTelegramAuthorizationState) {
TelegramAuthorizationState.READY -> {
updateChatsList()
telegramHelper.requestChats()
}
invalidateOptionsMenu()
updateTitle()
TelegramAuthorizationState.CLOSED,
TelegramAuthorizationState.UNKNOWN -> {
chatViewAdapter.chats = emptyList()
}
else -> Unit
}
}
}
override fun onTelegramChatsRead() {
runOnUi {
updateChatsList()
}
}
override fun onTelegramError(code: Int, message: String) {
runOnUi {
Toast.makeText(this@MainActivity, "$code - $message", Toast.LENGTH_LONG).show()
}
}
private fun updateChatsList() {
val chatList = telegramHelper.getChatList()
val chats: MutableList<TdApi.Chat> = mutableListOf()
for (orderedChat in chatList) {
val chat = telegramHelper.getChat(orderedChat.chatId)
if (chat != null) {
chats.add(chat)
}
}
chatViewAdapter.chats = chats
}
fun logoutTelegram(silent: Boolean = false) {
if (telegramHelper.getAuthState() == AuthState.READY) {
if (telegramHelper.getTelegramAuthorizationState() == TelegramAuthorizationState.READY) {
telegramHelper.logout()
} else {
invalidateOptionsMenu()
@ -98,6 +148,12 @@ class MainActivity : AppCompatActivity(), TelegramListener {
telegramHelper.close()
}
private fun runOnUi(action: (() -> Unit)) {
if (!paused) {
runOnUiThread(action)
}
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
return when (item?.itemId) {
LOGIN_MENU_ID -> {
@ -115,17 +171,17 @@ class MainActivity : AppCompatActivity(), TelegramListener {
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
if (menu != null) {
menu.clear()
when (telegramHelper.getAuthState()) {
AuthState.UNKNOWN,
AuthState.WAIT_PARAMETERS,
AuthState.WAIT_PHONE_NUMBER,
AuthState.WAIT_CODE,
AuthState.WAIT_PASSWORD,
AuthState.LOGGING_OUT,
AuthState.CLOSING -> createProgressMenuItem(menu)
AuthState.READY -> createMenuItem(menu, LOGOUT_MENU_ID, R.string.shared_string_logout,
when (telegramHelper.getTelegramAuthorizationState()) {
TelegramAuthorizationState.UNKNOWN,
TelegramAuthorizationState.WAIT_PARAMETERS,
TelegramAuthorizationState.WAIT_PHONE_NUMBER,
TelegramAuthorizationState.WAIT_CODE,
TelegramAuthorizationState.WAIT_PASSWORD,
TelegramAuthorizationState.LOGGING_OUT,
TelegramAuthorizationState.CLOSING -> createProgressMenuItem(menu)
TelegramAuthorizationState.READY -> createMenuItem(menu, LOGOUT_MENU_ID, R.string.shared_string_logout,
MenuItem.SHOW_AS_ACTION_WITH_TEXT or MenuItem.SHOW_AS_ACTION_ALWAYS)
AuthState.CLOSED -> createMenuItem(menu, LOGIN_MENU_ID, R.string.shared_string_login,
TelegramAuthorizationState.CLOSED -> createMenuItem(menu, LOGIN_MENU_ID, R.string.shared_string_login,
MenuItem.SHOW_AS_ACTION_WITH_TEXT or MenuItem.SHOW_AS_ACTION_ALWAYS)
}
}
@ -148,35 +204,35 @@ class MainActivity : AppCompatActivity(), TelegramListener {
}
private fun updateTitle() {
title = when (telegramHelper.getAuthState()) {
title = when (telegramHelper.getTelegramAuthorizationState()) {
AuthState.UNKNOWN,
AuthState.WAIT_PHONE_NUMBER,
AuthState.WAIT_CODE,
AuthState.WAIT_PASSWORD,
AuthState.READY,
AuthState.CLOSED -> getString(R.string.app_name)
TelegramAuthorizationState.UNKNOWN,
TelegramAuthorizationState.WAIT_PHONE_NUMBER,
TelegramAuthorizationState.WAIT_CODE,
TelegramAuthorizationState.WAIT_PASSWORD,
TelegramAuthorizationState.READY,
TelegramAuthorizationState.CLOSED -> getString(R.string.app_name)
AuthState.WAIT_PARAMETERS -> getString(R.string.initialization) + "..."
AuthState.LOGGING_OUT -> getString(R.string.logging_out) + "..."
AuthState.CLOSING -> getString(R.string.closing) + "..."
TelegramAuthorizationState.WAIT_PARAMETERS -> getString(R.string.initialization) + "..."
TelegramAuthorizationState.LOGGING_OUT -> getString(R.string.logging_out) + "..."
TelegramAuthorizationState.CLOSING -> getString(R.string.closing) + "..."
}
}
private fun showLoginDialog(authParamType: AuthParamType) {
when (authParamType) {
AuthParamType.PHONE_NUMBER -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_PHONE_NUMBER)
AuthParamType.CODE -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_CODE)
AuthParamType.PASSWORD -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_PASSWORD)
private fun showLoginDialog(telegramAuthenticationParameterType: TelegramAuthenticationParameterType) {
when (telegramAuthenticationParameterType) {
TelegramAuthenticationParameterType.PHONE_NUMBER -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_PHONE_NUMBER)
TelegramAuthenticationParameterType.CODE -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_CODE)
TelegramAuthenticationParameterType.PASSWORD -> LoginDialogFragment.showDialog(supportFragmentManager, LoginDialogType.ENTER_PASSWORD)
}
}
fun applyAuthParam(loginDialogFragment: LoginDialogFragment?, loginDialogType: LoginDialogType, text: String) {
loginDialogFragment?.updateDialog(LoginDialogType.SHOW_PROGRESS)
when (loginDialogType) {
LoginDialogType.ENTER_PHONE_NUMBER -> authParamRequestHandler?.applyAuthParam(AuthParamType.PHONE_NUMBER, text)
LoginDialogType.ENTER_CODE -> authParamRequestHandler?.applyAuthParam(AuthParamType.CODE, text)
LoginDialogType.ENTER_PASSWORD -> authParamRequestHandler?.applyAuthParam(AuthParamType.PASSWORD, text)
LoginDialogType.ENTER_PHONE_NUMBER -> telegramAuthorizationRequestHandler?.applyAuthenticationParameter(TelegramAuthenticationParameterType.PHONE_NUMBER, text)
LoginDialogType.ENTER_CODE -> telegramAuthorizationRequestHandler?.applyAuthenticationParameter(TelegramAuthenticationParameterType.CODE, text)
LoginDialogType.ENTER_PASSWORD -> telegramAuthorizationRequestHandler?.applyAuthenticationParameter(TelegramAuthenticationParameterType.PASSWORD, text)
else -> Unit
}
}
@ -185,4 +241,35 @@ class MainActivity : AppCompatActivity(), TelegramListener {
super.onDestroy()
telegramHelper.close()
}
inner class ChatsAdapter :
RecyclerView.Adapter<ChatsAdapter.ViewHolder>() {
var chats: List<TdApi.Chat> = emptyList()
set(value) {
field = value
notifyDataSetChanged()
}
inner class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
val icon: AppCompatImageView? = view.findViewById(R.id.icon)
val groupName: AppCompatTextView? = view.findViewById(R.id.name)
val shareLocationSwitch: SwitchCompat? = view.findViewById(R.id.share_location_switch)
val showOnMapSwitch: SwitchCompat? = view.findViewById(R.id.show_on_map_switch)
}
override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): ChatsAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.chat_list_item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.groupName?.text = chats[position].title
}
override fun getItemCount() = chats.size
}
}

View file

@ -1,7 +1,9 @@
package net.osmand.telegram
import android.text.TextUtils
import net.osmand.telegram.TelegramHelper.AuthParamType.*
import net.osmand.telegram.TelegramHelper.TelegramAuthenticationParameterType.*
import net.osmand.telegram.utils.CancellableAsyncTask
import net.osmand.telegram.utils.PlatformUtil
import org.drinkless.td.libcore.telegram.Client
import org.drinkless.td.libcore.telegram.Client.ResultHandler
import org.drinkless.td.libcore.telegram.TdApi
@ -10,12 +12,56 @@ import java.io.File
import java.util.*
import java.util.concurrent.ConcurrentHashMap
class TelegramHelper private constructor() {
companion object {
private val log = PlatformUtil.getLog(TelegramHelper::class.java)
private const val CHATS_LIMIT = 100
private var helper: TelegramHelper? = null
private val users = ConcurrentHashMap<Int, TdApi.User>()
private val basicGroups = ConcurrentHashMap<Int, TdApi.BasicGroup>()
private val supergroups = ConcurrentHashMap<Int, TdApi.Supergroup>()
private val secretChats = ConcurrentHashMap<Int, TdApi.SecretChat>()
private val chats = ConcurrentHashMap<Long, TdApi.Chat>()
private val chatList = TreeSet<OrderedChat>()
private val usersFullInfo = ConcurrentHashMap<Int, TdApi.UserFullInfo>()
private val basicGroupsFullInfo = ConcurrentHashMap<Int, TdApi.BasicGroupFullInfo>()
private val supergroupsFullInfo = ConcurrentHashMap<Int, TdApi.SupergroupFullInfo>()
val instance: TelegramHelper
get() {
if (helper == null) {
helper = TelegramHelper()
}
return helper!!
}
private fun setChatOrder(chat: TdApi.Chat, order: Long) {
synchronized(chatList) {
if (chat.order != 0L) {
chatList.remove(OrderedChat(chat.order, chat.id))
}
chat.order = order
if (chat.order != 0L) {
chatList.add(OrderedChat(chat.order, chat.id))
}
}
}
}
var appDir: String? = null
private var libraryLoaded = false
private var authParamRequestHandler: AuthParamRequestHandler? = null
private var telegramAuthorizationRequestHandler: TelegramAuthorizationRequestHandler? = null
private var client: Client? = null
private var haveFullChatList: Boolean = false
private var authorizationState: AuthorizationState? = null
private var isHaveAuthorization = false
@ -24,13 +70,23 @@ class TelegramHelper private constructor() {
var listener: TelegramListener? = null
enum class AuthParamType {
fun getChatList(): TreeSet<OrderedChat> {
synchronized(chatList) {
return TreeSet<OrderedChat>(chatList)
}
}
fun getChat(id: Long): TdApi.Chat? {
return chats[id]
}
enum class TelegramAuthenticationParameterType {
PHONE_NUMBER,
CODE,
PASSWORD
}
enum class AuthState {
enum class TelegramAuthorizationState {
UNKNOWN,
WAIT_PARAMETERS,
WAIT_PHONE_NUMBER,
@ -43,46 +99,51 @@ class TelegramHelper private constructor() {
}
interface TelegramListener {
fun onTelegramStatusChanged(prevAutoState: AuthState, newAuthState: AuthState)
fun onTelegramStatusChanged(prevTelegramAuthorizationState: TelegramAuthorizationState,
newTelegramAuthorizationState: TelegramAuthorizationState)
fun onTelegramChatsRead()
fun onTelegramError(code: Int, message: String)
}
interface AuthParamRequestListener {
fun onRequestAuthParam(paramType: AuthParamType)
fun onAuthRequestError(code: Int, message: String)
interface TelegramAuthorizationRequestListener {
fun onRequestTelegramAuthenticationParameter(parameterType: TelegramAuthenticationParameterType)
fun onTelegramAuthorizationRequestError(code: Int, message: String)
}
inner class AuthParamRequestHandler(val authParamRequestListener: AuthParamRequestListener) {
inner class TelegramAuthorizationRequestHandler(val telegramAuthorizationRequestListener: TelegramAuthorizationRequestListener) {
fun applyAuthParam(paramType: AuthParamType, paramValue: String) {
if (!TextUtils.isEmpty(paramValue)) {
when (paramType) {
PHONE_NUMBER -> client!!.send(TdApi.SetAuthenticationPhoneNumber(paramValue, false, false), AuthorizationRequestHandler())
CODE -> client!!.send(TdApi.CheckAuthenticationCode(paramValue, "", ""), AuthorizationRequestHandler())
PASSWORD -> client!!.send(TdApi.CheckAuthenticationPassword(paramValue), AuthorizationRequestHandler())
fun applyAuthenticationParameter(parameterType: TelegramAuthenticationParameterType, parameterValue: String) {
if (!TextUtils.isEmpty(parameterValue)) {
when (parameterType) {
PHONE_NUMBER -> client!!.send(TdApi.SetAuthenticationPhoneNumber(parameterValue, false, false), AuthorizationRequestHandler())
CODE -> client!!.send(TdApi.CheckAuthenticationCode(parameterValue, "", ""), AuthorizationRequestHandler())
PASSWORD -> client!!.send(TdApi.CheckAuthenticationPassword(parameterValue), AuthorizationRequestHandler())
}
}
}
}
fun getAuthState(): AuthState {
val authorizationState = this.authorizationState ?: return AuthState.UNKNOWN
fun getTelegramAuthorizationState(): TelegramAuthorizationState {
val authorizationState = this.authorizationState
?: return TelegramAuthorizationState.UNKNOWN
return when (authorizationState.constructor) {
TdApi.AuthorizationStateWaitTdlibParameters.CONSTRUCTOR -> AuthState.WAIT_PARAMETERS
TdApi.AuthorizationStateWaitPhoneNumber.CONSTRUCTOR -> AuthState.WAIT_PHONE_NUMBER
TdApi.AuthorizationStateWaitCode.CONSTRUCTOR -> AuthState.WAIT_CODE
TdApi.AuthorizationStateWaitPassword.CONSTRUCTOR -> AuthState.WAIT_PASSWORD
TdApi.AuthorizationStateReady.CONSTRUCTOR -> AuthState.READY
TdApi.AuthorizationStateLoggingOut.CONSTRUCTOR -> AuthState.LOGGING_OUT
TdApi.AuthorizationStateClosing.CONSTRUCTOR -> AuthState.CLOSING
TdApi.AuthorizationStateClosed.CONSTRUCTOR -> AuthState.CLOSED
else -> AuthState.UNKNOWN
TdApi.AuthorizationStateWaitTdlibParameters.CONSTRUCTOR -> TelegramAuthorizationState.WAIT_PARAMETERS
TdApi.AuthorizationStateWaitPhoneNumber.CONSTRUCTOR -> TelegramAuthorizationState.WAIT_PHONE_NUMBER
TdApi.AuthorizationStateWaitCode.CONSTRUCTOR -> TelegramAuthorizationState.WAIT_CODE
TdApi.AuthorizationStateWaitPassword.CONSTRUCTOR -> TelegramAuthorizationState.WAIT_PASSWORD
TdApi.AuthorizationStateReady.CONSTRUCTOR -> TelegramAuthorizationState.READY
TdApi.AuthorizationStateLoggingOut.CONSTRUCTOR -> TelegramAuthorizationState.LOGGING_OUT
TdApi.AuthorizationStateClosing.CONSTRUCTOR -> TelegramAuthorizationState.CLOSING
TdApi.AuthorizationStateClosed.CONSTRUCTOR -> TelegramAuthorizationState.CLOSED
else -> TelegramAuthorizationState.UNKNOWN
}
}
fun setAuthParamRequestHandler(authParamRequestListener: AuthParamRequestListener): AuthParamRequestHandler {
val authParamRequestHandler = AuthParamRequestHandler(authParamRequestListener)
this.authParamRequestHandler = authParamRequestHandler
return authParamRequestHandler
fun setTelegramAuthorizationRequestHandler(telegramAuthorizationRequestListener: TelegramAuthorizationRequestListener): TelegramAuthorizationRequestHandler {
val handler = TelegramAuthorizationRequestHandler(telegramAuthorizationRequestListener)
this.telegramAuthorizationRequestHandler = handler
return handler
}
init {
@ -108,6 +169,42 @@ class TelegramHelper private constructor() {
}
}
fun requestChats() {
synchronized(chatList) {
if (!haveFullChatList && CHATS_LIMIT > chatList.size) {
// have enough chats in the chat list or chat list is too small
var offsetOrder = java.lang.Long.MAX_VALUE
var offsetChatId: Long = 0
if (!chatList.isEmpty()) {
val last = chatList.last()
offsetOrder = last.order
offsetChatId = last.chatId
}
client?.send(TdApi.GetChats(offsetOrder, offsetChatId, CHATS_LIMIT - chatList.size), { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
listener?.onTelegramError(error.code, error.message)
}
TdApi.Chats.CONSTRUCTOR -> {
val chatIds = (obj as TdApi.Chats).chatIds
if (chatIds.isEmpty()) {
synchronized(chatList) {
haveFullChatList = true
}
}
// chats had already been received through updates, let's retry request
requestChats()
}
else -> listener?.onTelegramError(-1, "Receive wrong response from TDLib: $obj")
}
})
return
}
}
listener?.onTelegramChatsRead()
}
fun logout(): Boolean {
return if (libraryLoaded) {
isHaveAuthorization = false
@ -129,7 +226,7 @@ class TelegramHelper private constructor() {
}
private fun onAuthorizationStateUpdated(authorizationState: AuthorizationState?) {
val prevAuthState = getAuthState()
val prevAuthState = getTelegramAuthorizationState()
if (authorizationState != null) {
this.authorizationState = authorizationState
}
@ -156,15 +253,15 @@ class TelegramHelper private constructor() {
}
TdApi.AuthorizationStateWaitPhoneNumber.CONSTRUCTOR -> {
log.info("Request phone number")
authParamRequestHandler?.authParamRequestListener?.onRequestAuthParam(PHONE_NUMBER)
telegramAuthorizationRequestHandler?.telegramAuthorizationRequestListener?.onRequestTelegramAuthenticationParameter(PHONE_NUMBER)
}
TdApi.AuthorizationStateWaitCode.CONSTRUCTOR -> {
log.info("Request code")
authParamRequestHandler?.authParamRequestListener?.onRequestAuthParam(CODE)
telegramAuthorizationRequestHandler?.telegramAuthorizationRequestListener?.onRequestTelegramAuthenticationParameter(CODE)
}
TdApi.AuthorizationStateWaitPassword.CONSTRUCTOR -> {
log.info("Request password")
authParamRequestHandler?.authParamRequestListener?.onRequestAuthParam(PASSWORD)
telegramAuthorizationRequestHandler?.telegramAuthorizationRequestListener?.onRequestTelegramAuthenticationParameter(PASSWORD)
}
TdApi.AuthorizationStateReady.CONSTRUCTOR -> {
isHaveAuthorization = true
@ -183,11 +280,11 @@ class TelegramHelper private constructor() {
}
else -> log.error("Unsupported authorization state: " + this.authorizationState!!)
}
val newAuthState = getAuthState()
val newAuthState = getTelegramAuthorizationState()
listener?.onTelegramStatusChanged(prevAuthState, newAuthState)
}
private class OrderedChat internal constructor(internal val order: Long, internal val chatId: Long) : Comparable<OrderedChat> {
class OrderedChat internal constructor(internal val order: Long, internal val chatId: Long) : Comparable<OrderedChat> {
override fun compareTo(other: OrderedChat): Int {
if (this.order != other.order) {
@ -257,6 +354,9 @@ class TelegramHelper private constructor() {
chat.order = 0
setChatOrder(chat, order)
}
CancellableAsyncTask.run("onTelegramChatsRead", 100, {
listener?.onTelegramChatsRead()
})
}
TdApi.UpdateChatTitle.CONSTRUCTOR -> {
val updateChat = obj as TdApi.UpdateChatTitle
@ -371,7 +471,7 @@ class TelegramHelper private constructor() {
TdApi.Error.CONSTRUCTOR -> {
log.error("Receive an error: $obj")
val errorObj = obj as TdApi.Error
authParamRequestHandler?.authParamRequestListener?.onAuthRequestError(errorObj.code, errorObj.message)
telegramAuthorizationRequestHandler?.telegramAuthorizationRequestListener?.onTelegramAuthorizationRequestError(errorObj.code, errorObj.message)
onAuthorizationStateUpdated(null) // repeat last action
}
TdApi.Ok.CONSTRUCTOR -> {
@ -380,44 +480,4 @@ class TelegramHelper private constructor() {
}// result is already received through UpdateAuthorizationState, nothing to do
}
}
companion object {
private val log = PlatformUtil.getLog(TelegramHelper::class.java)
private var helper: TelegramHelper? = null
private val users = ConcurrentHashMap<Int, TdApi.User>()
private val basicGroups = ConcurrentHashMap<Int, TdApi.BasicGroup>()
private val supergroups = ConcurrentHashMap<Int, TdApi.Supergroup>()
private val secretChats = ConcurrentHashMap<Int, TdApi.SecretChat>()
private val chats = ConcurrentHashMap<Long, TdApi.Chat>()
private val chatList = TreeSet<OrderedChat>()
private val usersFullInfo = ConcurrentHashMap<Int, TdApi.UserFullInfo>()
private val basicGroupsFullInfo = ConcurrentHashMap<Int, TdApi.BasicGroupFullInfo>()
private val supergroupsFullInfo = ConcurrentHashMap<Int, TdApi.SupergroupFullInfo>()
val instance: TelegramHelper
get() {
if (helper == null) {
helper = TelegramHelper()
}
return helper!!
}
private fun setChatOrder(chat: TdApi.Chat, order: Long) {
synchronized(chatList) {
if (chat.order != 0L) {
chatList.remove(OrderedChat(chat.order, chat.id))
}
chat.order = order
if (chat.order != 0L) {
chatList.add(OrderedChat(chat.order, chat.id))
}
}
}
}
}

View file

@ -1,4 +1,4 @@
package net.osmand.telegram
package net.osmand.telegram.utils
import android.app.Activity
import android.content.Context

View file

@ -0,0 +1,76 @@
package net.osmand.telegram.utils
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicInteger
class CancellableAsyncTask(val taskId: String, val executeTimeout: Long = 0) {
companion object {
private const val SLEEP_TIME = 50L
private val requestNumbersMap = ConcurrentHashMap<String, AtomicInteger>()
private val singleThreadExecutorsMap = ConcurrentHashMap<String, ExecutorService>()
fun run(taskId: String, executeTimeout: Long = 0, action: (() -> Unit)) {
CancellableAsyncTask(taskId, executeTimeout).run(action)
}
fun clearResources(taskId: String) {
requestNumbersMap.remove(taskId)
singleThreadExecutorsMap.remove(taskId)
}
}
private val singleThreadExecutor: ExecutorService
private var requestNumber: AtomicInteger
var isCancelled: Boolean = false
init {
val requestNumber = requestNumbersMap[taskId]
if (requestNumber == null) {
this.requestNumber = AtomicInteger()
requestNumbersMap[taskId] = this.requestNumber
} else {
this.requestNumber = requestNumber
}
val singleThreadExecutor = singleThreadExecutorsMap[taskId]
if (singleThreadExecutor == null) {
this.singleThreadExecutor = Executors.newSingleThreadExecutor()
singleThreadExecutorsMap[taskId] = this.singleThreadExecutor
} else {
this.singleThreadExecutor = singleThreadExecutor
}
}
fun run(action: (() -> Unit)) {
val req = requestNumber.incrementAndGet()
singleThreadExecutor.submit(object : Runnable {
private val isCancelled: Boolean
get() = requestNumber.get() != req || this@CancellableAsyncTask.isCancelled
override fun run() {
try {
if (executeTimeout > 0) {
val startTime = System.currentTimeMillis()
while (System.currentTimeMillis() - startTime <= executeTimeout) {
if (isCancelled) {
return
}
Thread.sleep(SLEEP_TIME)
}
}
if (!isCancelled) {
action.invoke()
}
} catch (e: InterruptedException) {
// ignore
}
}
})
}
}

View file

@ -1,4 +1,4 @@
package net.osmand.telegram;
package net.osmand.telegram.utils;
import org.apache.commons.logging.Log;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -3,11 +3,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:paddingRight="16dp"
android:paddingLeft="16dp">
android:paddingRight="@dimen/content_padding_standard"
android:paddingLeft="@dimen/content_padding_standard">
<ProgressBar
android:layout_width="32dp"
android:layout_height="32dp" />
android:layout_width="@dimen/progress_bar_size_small"
android:layout_height="@dimen/progress_bar_size_small" />
</LinearLayout>

View file

@ -1,16 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
<android.support.v7.widget.RecyclerView
android:id="@+id/groups_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="Hello World!" />
android:layout_height="match_parent"
android:scrollbars="vertical" />
</LinearLayout>

View file

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:minHeight="@dimen/list_item_height_min"
android:orientation="horizontal"
android:paddingBottom="@dimen/content_padding_half"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingStart="@dimen/content_padding_standard"
android:paddingTop="@dimen/content_padding_half">
<android.support.v7.widget.AppCompatImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:src="@drawable/ic_group"
android:tint="?attr/icon_color"
android:visibility="visible" />
<android.support.v7.widget.AppCompatTextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/content_padding_half"
android:layout_marginStart="@dimen/content_padding_half"
android:layout_weight="1"
android:gravity="center_vertical"
tools:text="Group name" />
<android.support.v7.widget.SwitchCompat
android:id="@+id/share_location_switch"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/content_padding_half"
android:layout_marginLeft="@dimen/content_padding_standard"
android:layout_marginRight="@dimen/content_padding_half"
android:layout_marginStart="@dimen/content_padding_standard"
android:focusableInTouchMode="true" />
<android.support.v7.widget.SwitchCompat
android:id="@+id/show_on_map_switch"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/content_padding_standard"
android:layout_marginLeft="@dimen/content_padding_half"
android:layout_marginRight="@dimen/content_padding_standard"
android:layout_marginStart="@dimen/content_padding_half"
android:focusableInTouchMode="true" />
</LinearLayout>
</LinearLayout>

View file

@ -4,10 +4,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:paddingBottom="24dp"
android:paddingLeft="48dp"
android:paddingRight="48dp"
android:paddingTop="24dp">
android:paddingBottom="@dimen/dialog_padding_vertical"
android:paddingLeft="@dimen/dialog_padding_horizontal"
android:paddingRight="@dimen/dialog_padding_horizontal"
android:paddingTop="@dimen/dialog_padding_vertical">
<LinearLayout
android:layout_width="match_parent"
@ -20,7 +20,7 @@
android:layout_weight="0.2"
android:gravity="center"
android:text="@string/login_to_telegram"
android:textSize="22sp"
android:textSize="@dimen/dialog_title_text_size"
android:textStyle="bold" />
<LinearLayout
@ -106,8 +106,8 @@
android:visibility="visible">
<ProgressBar
android:layout_width="32dp"
android:layout_height="32dp" />
android:layout_width="@dimen/progress_bar_size_small"
android:layout_height="@dimen/progress_bar_size_small" />
</LinearLayout>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AppTheme">
<attr name="bg_color" format="reference" />
<attr name="icon_color" format="reference" />
</declare-styleable>
</resources>

View file

@ -3,4 +3,10 @@
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="bg_color_light">#fff</color>
<color name="bg_color_dark">#333b40</color>
<color name="icon_color_light">#ccc</color>
<color name="icon_color_dark">#ff4f4f4f</color>
</resources>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="content_padding_half">8dp</dimen>
<dimen name="content_padding_standard">16dp</dimen>
<dimen name="progress_bar_size_small">32dp</dimen>
<dimen name="dialog_title_text_size">22sp</dimen>
<dimen name="dialog_padding_vertical">24dp</dimen>
<dimen name="dialog_padding_horizontal">48dp</dimen>
<dimen name="list_item_height_min">48dp</dimen>
</resources>

View file

@ -6,6 +6,9 @@
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="bg_color">@color/bg_color_light</item>
<item name="icon_color">@color/icon_color_light</item>
</style>
<style name="AppTheme.NoActionbar">