From 7ded400a30e6aa8a39fc417648cd119649f5838c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 15 Oct 2022 19:07:12 +0200 Subject: [PATCH] [API/Usos] Implement first login. --- app/src/main/AndroidManifest.xml | 4 + .../edziennik/data/api/Errors.kt | 3 + .../data/api/edziennik/usos/DataUsos.kt | 9 ++- .../data/api/edziennik/usos/data/UsosApi.kt | 16 ++-- .../usos/firstlogin/UsosFirstLogin.kt | 63 ++++++++++++++- .../api/edziennik/usos/login/UsosLoginApi.kt | 73 +++++++++++++----- .../edziennik/ext/JsonExtensions.kt | 10 ++- .../edziennik/ext/TextExtensions.kt | 1 + .../edziennik/ui/dialogs/OAuthLoginDialog.kt | 67 ---------------- .../edziennik/ui/login/LoginInfo.kt | 2 +- .../ui/login/oauth/OAuthLoginActivity.kt | 64 +++++++++++++++ .../ui/login/oauth/OAuthLoginResult.kt | 10 +++ .../utils/managers/UserActionManager.kt | 49 +++++++----- app/src/main/res/drawable/login_logo_usos.png | Bin 15635 -> 16760 bytes .../main/res/drawable/login_mode_usos_api.png | Bin 0 -> 5392 bytes 15 files changed, 255 insertions(+), 116 deletions(-) delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginActivity.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginResult.kt create mode 100644 app/src/main/res/drawable/login_mode_usos_api.png diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c5c273b4..fb824573 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -157,6 +157,10 @@ android:configChanges="orientation|keyboardHidden" android:exported="false" android:theme="@style/Base.Theme.AppCompat" /> + diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt index 617ef5ed..10405e5f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt @@ -205,6 +205,9 @@ const val ERROR_PODLASIE_API_OTHER = 631 const val ERROR_PODLASIE_API_DATA_MISSING = 632 const val ERROR_USOS_OAUTH_LOGIN_REQUEST = 701 +const val ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN = 702 +const val ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE = 703 +const val ERROR_USOS_NO_STUDENT_PROGRAMMES = 704 const val ERROR_TEMPLATE_WEB_OTHER = 801 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt index f374db94..0fd1b2ba 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt @@ -16,7 +16,7 @@ class DataUsos( loginStore: LoginStore, ) : Data(app, profile, loginStore) { - fun isApiLoginValid() = oauthTokenKey != null && oauthTokenSecret != null + fun isApiLoginValid() = oauthTokenKey != null && oauthTokenSecret != null && oauthTokenIsUser override fun satisfyLoginMethods() { loginMethods.clear() @@ -25,7 +25,7 @@ class DataUsos( } } - override fun generateUserCode() = "USOS:TEST" + override fun generateUserCode() = "$schoolId:${studentNumber ?: studentId}" var schoolId: String? get() { mSchoolId = mSchoolId ?: loginStore.getLoginData("schoolId", null); return mSchoolId } @@ -62,6 +62,11 @@ class DataUsos( set(value) { loginStore.putLoginData("oauthTokenSecret", value); mOauthTokenSecret = value } private var mOauthTokenSecret: String? = null + var oauthTokenIsUser: Boolean + get() { mOauthTokenIsUser = mOauthTokenIsUser ?: loginStore.getLoginData("oauthTokenIsUser", false); return mOauthTokenIsUser ?: false } + set(value) { loginStore.putLoginData("oauthTokenIsUser", value); mOauthTokenIsUser = value } + private var mOauthTokenIsUser: Boolean? = null + var studentId: String? get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId } set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt index ac73e29a..1d3ab69c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt @@ -76,7 +76,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { service: String, params: Map, responseType: ResponseType, - onSuccess: (data: T) -> Unit, + onSuccess: (data: T, response: Response?) -> Unit, ) { val url = "${data.instanceUrl}services/$service" d(tag, "Request: Usos/Api - $url") @@ -123,10 +123,10 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { private fun getCallback( tag: String, responseType: ResponseType, - onSuccess: (data: T) -> Unit, + onSuccess: (data: T, response: Response?) -> Unit, ) = when (responseType) { ResponseType.OBJECT -> object : JsonCallbackHandler() { - override fun onSuccess(data: JsonObject?, response: Response?) { + override fun onSuccess(data: JsonObject?, response: Response) { processResponse(response, data as T, onSuccess) } @@ -135,7 +135,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { } } ResponseType.ARRAY -> object : JsonArrayCallbackHandler() { - override fun onSuccess(data: JsonArray?, response: Response?) { + override fun onSuccess(data: JsonArray?, response: Response) { processResponse(response, data as T, onSuccess) } @@ -144,7 +144,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { } } ResponseType.PLAIN -> object : TextCallbackHandler() { - override fun onSuccess(data: String?, response: Response?) { + override fun onSuccess(data: String?, response: Response) { processResponse(response, data as T, onSuccess) } @@ -155,11 +155,11 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { } private fun processResponse( - response: Response?, + response: Response, data: T, - onSuccess: (data: T) -> Unit, + onSuccess: (data: T, response: Response?) -> Unit, ) { - onSuccess(data) + onSuccess(data, response) } private fun processError( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt index 3094980c..ad51cf92 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt @@ -4,9 +4,18 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin +import com.google.gson.JsonObject +import org.greenrobot.eventbus.EventBus +import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_NO_STUDENT_PROGRAMMES +import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_USOS +import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLoginApi +import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent +import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.ext.* class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) { companion object { @@ -16,8 +25,60 @@ class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) { private val api = UsosApi(data, null) init { - UsosLoginApi(data) { + val loginStoreId = data.loginStore.id + val loginStoreType = LOGIN_TYPE_USOS + var firstProfileId = loginStoreId + UsosLoginApi(data) { + api.apiRequest( + tag = TAG, + service = "users/user", + params = mapOf( + "fields" to listOf( + "id", + "first_name", + "last_name", + "student_number", + "student_programmes" to listOf( + "programme" to listOf("id"), + ), + ), + ), + responseType = UsosApi.ResponseType.OBJECT, + ) { json, response -> + val programmes = json.getJsonArray("student_programmes") + if (programmes.isNullOrEmpty()) { + data.error(ApiError(TAG, ERROR_USOS_NO_STUDENT_PROGRAMMES) + .withApiResponse(json) + .withResponse(response)) + return@apiRequest + } + + val firstName = json.getString("first_name") + val lastName = json.getString("last_name") + val studentName = buildFullName(firstName, lastName) + + val profile = Profile( + id = firstProfileId++, + loginStoreId = loginStoreId, loginStoreType = loginStoreType, + name = studentName, + subname = data.schoolId, + studentNameLong = studentName, + studentNameShort = studentName.getShortName(), + accountName = null, // student account + studentData = JsonObject( + "studentId" to json.getInt("id"), + "studentNumber" to json.getInt("student_number"), + ), + ).also { + it.studentClassName = programmes.getJsonObject(0).getJsonObject("programme").getString("id") + } + + EventBus.getDefault().postSticky( + FirstLoginFinishedEvent(listOf(profile), data.loginStore), + ) + onSuccess() + } } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt index 3027c334..f49c0cea 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt @@ -4,9 +4,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login -import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_OAUTH_LOGIN_REQUEST -import pl.szczodrzynski.edziennik.data.api.USOS_API_OAUTH_REDIRECT_URL -import pl.szczodrzynski.edziennik.data.api.USOS_API_SCOPES +import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -21,19 +19,21 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { private const val TAG = "UsosLoginApi" } - init { run { - if (data.isApiLoginValid()) { - onSuccess() - } else if (data.oauthLoginResponse != null) { - login() - } else { - authorize() + private val api = UsosApi(data, null) + + init { + run { + if (data.isApiLoginValid()) { + onSuccess() + } else if (data.oauthLoginResponse != null) { + login() + } else { + authorize() + } } - }} + } private fun authorize() { - val api = UsosApi(data, null) - api.apiRequest( tag = TAG, service = "oauth/request_token", @@ -42,10 +42,11 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { "scopes" to USOS_API_SCOPES, ), responseType = UsosApi.ResponseType.PLAIN, - ) { - val response = it.fromQueryString() - data.oauthTokenKey = response["oauth_token"] - data.oauthTokenSecret = response["oauth_token_secret"] + ) { text, _ -> + val authorizeData = text.fromQueryString() + data.oauthTokenKey = authorizeData["oauth_token"] + data.oauthTokenSecret = authorizeData["oauth_token_secret"] + data.oauthTokenIsUser = false val authUrl = "${data.instanceUrl}services/oauth/authorize" val authParams = mapOf( @@ -63,6 +64,42 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { } private fun login() { - d(TAG, "Login to ${data.schoolId} with ${data.oauthLoginResponse} (${data.oauthTokenSecret})") + d(TAG, "Login to ${data.schoolId} with ${data.oauthLoginResponse}") + + val authorizeResponse = data.oauthLoginResponse?.fromQueryString() + ?: return // checked in init {} + if (authorizeResponse["oauth_token"] != data.oauthTokenKey) { + // got different token + data.error(ApiError(TAG, ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN) + .withApiResponse(data.oauthLoginResponse)) + return + } + val verifier = authorizeResponse["oauth_verifier"] + if (verifier.isNullOrBlank()) { + data.error(ApiError(TAG, ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE) + .withApiResponse(data.oauthLoginResponse)) + return + } + + api.apiRequest( + tag = TAG, + service = "oauth/access_token", + params = mapOf( + "oauth_verifier" to verifier, + ), + responseType = UsosApi.ResponseType.PLAIN, + ) { text, response -> + val accessData = text.fromQueryString() + data.oauthTokenKey = accessData["oauth_token"] + data.oauthTokenSecret = accessData["oauth_token_secret"] + data.oauthTokenIsUser = data.oauthTokenKey != null && data.oauthTokenSecret != null + + if (!data.oauthTokenIsUser) + data.error(ApiError(TAG, ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE) + .withApiResponse(text) + .withResponse(response)) + else + onSuccess() + } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt index 9f0db8ad..14d25b48 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt @@ -10,6 +10,8 @@ import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonParser import com.google.gson.JsonPrimitive +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract fun JsonObject?.get(key: String): JsonElement? = this?.get(key) @@ -93,7 +95,13 @@ fun JsonArray(vararg properties: Any?): JsonArray { } } -fun JsonArray?.isNullOrEmpty(): Boolean = (this?.size() ?: 0) == 0 +@OptIn(ExperimentalContracts::class) +fun JsonArray?.isNullOrEmpty(): Boolean { + contract { + returns(false) implies (this@isNullOrEmpty != null) + } + return this == null || this.isEmpty +} operator fun JsonArray.plusAssign(o: JsonElement) = this.add(o) operator fun JsonArray.plusAssign(o: String) = this.add(o) operator fun JsonArray.plusAssign(o: Char) = this.add(o) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt index d7717c7b..adb6fe55 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt @@ -355,6 +355,7 @@ fun Map.toQueryString() = this .joinToString("&") { "${it.first}=${it.second}" } fun String.fromQueryString() = this + .substringAfter('?') .split("&") .map { it.split("=") } .associate { it[0].urlDecode() to it[1].urlDecode() } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt deleted file mode 100644 index b777377e..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2022-10-14. - */ - -package pl.szczodrzynski.edziennik.ui.dialogs - -import android.annotation.SuppressLint -import android.graphics.Bitmap -import android.view.ViewGroup -import android.view.ViewGroup.LayoutParams.MATCH_PARENT -import android.webkit.WebView -import android.webkit.WebViewClient -import android.widget.FrameLayout -import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.updateLayoutParams -import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.ext.dp -import pl.szczodrzynski.edziennik.ui.dialogs.base.ViewDialog -import pl.szczodrzynski.edziennik.utils.Utils.d - -class OAuthLoginDialog( - activity: AppCompatActivity, - private val authorizeUrl: String, - private val redirectUrl: String, - private val onSuccess: (responseUrl: String) -> Unit, - private val onFailure: (() -> Unit)?, - onShowListener: ((tag: String) -> Unit)? = null, - onDismissListener: ((tag: String) -> Unit)? = null, -) : ViewDialog(activity, onShowListener, onDismissListener) { - - override val TAG = "OAuthLoginDialog" - - override fun getTitleRes() = R.string.oauth_dialog_title - override fun getPositiveButtonText() = R.string.close - - private var isSuccessful = false - - @SuppressLint("SetJavaScriptEnabled") - override fun getRootView(): WebView { - val webView = WebView(activity) - webView.webViewClient = object : WebViewClient() { - override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { - d(TAG, "Navigating to $url") - if (url.startsWith(redirectUrl)) { - isSuccessful = true - onSuccess(url) - dismiss() - } - } - } - webView.settings.javaScriptEnabled = true - return webView - } - - override suspend fun onShow() { - dialog.window?.setLayout(MATCH_PARENT, MATCH_PARENT) - root.minimumHeight = activity.windowManager.defaultDisplay?.height?.div(2) ?: 300.dp - root.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) - root.loadUrl(authorizeUrl) - } - - override fun onDismiss() { - root.stopLoading() - if (!isSuccessful) - onFailure?.invoke() - } -} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt index 15a7021d..8b605734 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt @@ -324,7 +324,7 @@ object LoginInfo { Mode( loginMode = LOGIN_MODE_USOS_OAUTH, name = R.string.login_mode_usos_oauth, - icon = R.drawable.login_logo_usos, + icon = R.drawable.login_mode_usos_api, guideText = R.string.login_mode_usos_oauth_guide, isPlatformSelection = true, credentials = listOf(), diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginActivity.kt new file mode 100644 index 00000000..c80c3d82 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginActivity.kt @@ -0,0 +1,64 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-15. + */ + +package pl.szczodrzynski.edziennik.ui.login.oauth + +import android.annotation.SuppressLint +import android.graphics.Bitmap +import android.os.Bundle +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.webkit.WebView +import android.webkit.WebViewClient +import android.widget.FrameLayout +import androidx.appcompat.app.AppCompatActivity +import org.greenrobot.eventbus.EventBus +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.utils.Utils.d + +class OAuthLoginActivity : AppCompatActivity() { + companion object { + private const val TAG = "OAuthLoginActivity" + } + + private var isSuccessful = false + + @SuppressLint("SetJavaScriptEnabled") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setTitle(R.string.oauth_dialog_title) + + val authorizeUrl = intent.getStringExtra("authorizeUrl") ?: return + val redirectUrl = intent.getStringExtra("redirectUrl") ?: return + + val webView = WebView(this) + webView.webViewClient = object : WebViewClient() { + override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { + d(TAG, "Navigating to $url") + if (url.startsWith(redirectUrl)) { + isSuccessful = true + EventBus.getDefault().post(OAuthLoginResult( + isError = false, + responseUrl = url, + )) + finish() + } + } + } + webView.settings.javaScriptEnabled = true + webView.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + setContentView(webView) + + webView.loadUrl(authorizeUrl) + } + + override fun onDestroy() { + super.onDestroy() + if (!isSuccessful) + EventBus.getDefault().post(OAuthLoginResult( + isError = false, + responseUrl = null, + )) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginResult.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginResult.kt new file mode 100644 index 00000000..108c0c8e --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginResult.kt @@ -0,0 +1,10 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-15. + */ + +package pl.szczodrzynski.edziennik.ui.login.oauth + +data class OAuthLoginResult( + val isError: Boolean, + val responseUrl: String?, +) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt index c848c47a..3117c650 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt @@ -11,6 +11,8 @@ import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.core.app.NotificationCompat import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R @@ -21,7 +23,8 @@ import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ui.captcha.LibrusCaptchaDialog -import pl.szczodrzynski.edziennik.ui.dialogs.OAuthLoginDialog +import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginActivity +import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginResult import pl.szczodrzynski.edziennik.utils.Utils.d class UserActionManager(val app: App) { @@ -143,25 +146,35 @@ class UserActionManager(val app: App) { return false val extras = params.getBundle("extras") val storeKey = params.getString("responseStoreKey") ?: return false + params.getString("authorizeUrl") ?: return false + params.getString("redirectUrl") ?: return false - OAuthLoginDialog( - activity = activity, - authorizeUrl = params.getString("authorizeUrl") ?: return false, - redirectUrl = params.getString("redirectUrl") ?: return false, - onSuccess = { responseUrl -> - val args = Bundle( - storeKey to responseUrl, - ) - if (extras != null) - args.putAll(extras) + var listener: Any? = null + listener = object { + @Subscribe(threadMode = ThreadMode.MAIN) + fun onOAuthLoginResult(result: OAuthLoginResult) { + EventBus.getDefault().unregister(listener) + when { + result.isError -> onFailure?.invoke() + result.responseUrl != null -> { + val args = Bundle( + storeKey to result.responseUrl, + ) + if (extras != null) + args.putAll(extras) - if (onSuccess != null) - onSuccess(args) - else - EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity) - }, - onFailure = onFailure, - ).show() + if (onSuccess != null) + onSuccess(args) + else + EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity) + } + } + } + } + EventBus.getDefault().register(listener) + + val intent = Intent(activity, OAuthLoginActivity::class.java).putExtras(params) + activity.startActivity(intent) return true } } diff --git a/app/src/main/res/drawable/login_logo_usos.png b/app/src/main/res/drawable/login_logo_usos.png index 7c376bddaf28d4462635115fed43a00a484a8a3c..98d95b3496facdc49f2236148d5fa501ce1d2d0c 100644 GIT binary patch literal 16760 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 diff --git a/app/src/main/res/drawable/login_mode_usos_api.png b/app/src/main/res/drawable/login_mode_usos_api.png new file mode 100644 index 0000000000000000000000000000000000000000..6ec32631ce9eb9390d4c71a0b1f308d20e903948 GIT binary patch literal 5392 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 u5nlQ5*SGm#+$-Utt>PQQ|0ni;8~zU