implementing mastodon login flow
This commit is contained in:
parent
d1a5de7489
commit
527078025f
|
@ -36,7 +36,7 @@ subprojects {
|
|||
Kotlin : '1.1.1',
|
||||
SupportLib : '25.3.1',
|
||||
MariotakuCommons : '0.9.13',
|
||||
RestFu : '0.9.49',
|
||||
RestFu : '0.9.50',
|
||||
ObjectCursor : '0.9.16',
|
||||
PlayServices : '10.2.1',
|
||||
MapsUtils : '0.4.4',
|
||||
|
|
|
@ -45,6 +45,7 @@ dependencies {
|
|||
compile "com.bluelinelabs:logansquare:${libVersions['LoganSquare']}"
|
||||
compile "com.github.mariotaku.RestFu:library:${libVersions['RestFu']}"
|
||||
compile "com.github.mariotaku.RestFu:oauth:${libVersions['RestFu']}"
|
||||
compile "com.github.mariotaku.RestFu:oauth2:${libVersions['RestFu']}"
|
||||
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.2'
|
||||
compile "com.github.mariotaku.ObjectCursor:core:${libVersions['ObjectCursor']}"
|
||||
compile "com.github.mariotaku.CommonsLibrary:objectcursor:${libVersions['MariotakuCommons']}"
|
||||
|
|
|
@ -21,8 +21,27 @@
|
|||
|
||||
package org.mariotaku.microblog.library.mastodon;
|
||||
|
||||
import org.mariotaku.microblog.library.mastodon.api.AccountResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.ApplicationResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.BlockResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.FavouriteResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.FollowRequestResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.FollowResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.InstanceResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.MediaResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.MuteResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.NotificationResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.ReportResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.SearchResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.StatusResources;
|
||||
import org.mariotaku.microblog.library.mastodon.api.TimelineResources;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/4/17.
|
||||
*/
|
||||
public interface Mastodon {
|
||||
public interface Mastodon extends AccountResources, ApplicationResources, BlockResources,
|
||||
FavouriteResources, FollowRequestResources, FollowResources, InstanceResources,
|
||||
MediaResources, MuteResources, NotificationResources, ReportResources, SearchResources,
|
||||
StatusResources, TimelineResources {
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.mariotaku.microblog.library.mastodon;
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.microblog.library.twitter.auth.OAuth2Token;
|
||||
import org.mariotaku.restfu.annotation.method.GET;
|
||||
import org.mariotaku.restfu.annotation.param.Query;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/4/18.
|
||||
*/
|
||||
|
||||
public interface MastodonOAuth2 {
|
||||
|
||||
@GET("/v1/oauth/token")
|
||||
OAuth2Token getToken(@Query("client_id") String clientId, @Query("client_secret") String clientSecret,
|
||||
@Query("grant_type") String grantType, @Query("code") String code,
|
||||
@Query("redirect_uri") String redirectUri) throws MicroBlogException;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.mariotaku.microblog.library.mastodon.annotation;
|
||||
|
||||
import android.support.annotation.StringDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/4/18.
|
||||
*/
|
||||
@StringDef({AuthScope.READ, AuthScope.WRITE, AuthScope.FOLLOW})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface AuthScope {
|
||||
String READ = "read";
|
||||
String WRITE = "write";
|
||||
String FOLLOW = "follow";
|
||||
}
|
|
@ -43,48 +43,48 @@ import java.util.List;
|
|||
|
||||
public interface AccountResources {
|
||||
|
||||
@GET("/api/v1/accounts/{id}")
|
||||
@GET("/v1/accounts/{id}")
|
||||
Account getAccount(@Path("id") String id) throws MicroBlogException;
|
||||
|
||||
@GET("/api/v1/accounts/verify_credentials")
|
||||
@GET("/v1/accounts/verify_credentials")
|
||||
Account verifyCredentials() throws MicroBlogException;
|
||||
|
||||
@PATCH("/api/v1/accounts/update_credentials")
|
||||
@PATCH("/v1/accounts/update_credentials")
|
||||
Account updateCredentials(@Param AccountUpdate update) throws MicroBlogException;
|
||||
|
||||
@GET("/api/v1/accounts/{id}/followers")
|
||||
@GET("/v1/accounts/{id}/followers")
|
||||
List<Account> getFollowers(@Path("id") String id, @Query Paging paging)
|
||||
throws MicroBlogException;
|
||||
|
||||
@GET("/api/v1/accounts/{id}/following")
|
||||
@GET("/v1/accounts/{id}/following")
|
||||
List<Account> getFollowing(@Path("id") String id, @Query Paging paging)
|
||||
throws MicroBlogException;
|
||||
|
||||
@GET("/api/v1/accounts/{id}/statuses")
|
||||
@GET("/v1/accounts/{id}/statuses")
|
||||
List<Status> getStatuses(@Path("id") String id, @Query Paging paging,
|
||||
@Query TimelineOption option) throws MicroBlogException;
|
||||
|
||||
@POST("/api/v1/accounts/{id}/follow")
|
||||
@POST("/v1/accounts/{id}/follow")
|
||||
Relationship followUser(@Path("id") String id) throws MicroBlogException;
|
||||
|
||||
@POST("/api/v1/accounts/{id}/unfollow")
|
||||
@POST("/v1/accounts/{id}/unfollow")
|
||||
Relationship unfollowUser(@Path("id") String id) throws MicroBlogException;
|
||||
|
||||
@POST("/api/v1/accounts/{id}/block")
|
||||
@POST("/v1/accounts/{id}/block")
|
||||
Relationship blockUser(@Path("id") String id) throws MicroBlogException;
|
||||
|
||||
@POST("/api/v1/accounts/{id}/unblock")
|
||||
@POST("/v1/accounts/{id}/unblock")
|
||||
Relationship unblockUser(@Path("id") String id) throws MicroBlogException;
|
||||
|
||||
@POST("/api/v1/accounts/{id}/mute")
|
||||
@POST("/v1/accounts/{id}/mute")
|
||||
Relationship muteUser(@Path("id") String id) throws MicroBlogException;
|
||||
|
||||
@POST("/api/v1/accounts/{id}/unmute")
|
||||
@POST("/v1/accounts/{id}/unmute")
|
||||
Relationship unmuteUser(@Path("id") String id) throws MicroBlogException;
|
||||
|
||||
@GET("/api/v1/accounts/relationships")
|
||||
@GET("/v1/accounts/relationships")
|
||||
List<Relationship> getRelationships(@Path("id") String id) throws MicroBlogException;
|
||||
|
||||
@GET("/api/v1/accounts/search")
|
||||
@GET("/v1/accounts/search")
|
||||
List<Account> searchAccounts(@Query("q") String query) throws MicroBlogException;
|
||||
}
|
||||
|
|
|
@ -33,9 +33,9 @@ import org.mariotaku.restfu.annotation.param.Param;
|
|||
*/
|
||||
|
||||
public interface ApplicationResources {
|
||||
@POST("/api/v1/apps")
|
||||
@POST("/v1/apps")
|
||||
RegisteredApplication registerApplication(@Param("client_name") String clientName,
|
||||
@Param("redirect_uris") String redirectUris,
|
||||
@Param(value = "scopes", arrayDelimiter = ' ') String scopes,
|
||||
@Param(value = "scopes", arrayDelimiter = ' ') String[] scopes,
|
||||
@Nullable @Param("website") String website) throws MicroBlogException;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,10 @@ public class OAuth2Token {
|
|||
String tokenType;
|
||||
@JsonField(name = "access_token")
|
||||
String accessToken;
|
||||
@JsonField(name = "expires_in")
|
||||
long expiresIn;
|
||||
@JsonField(name = "refresh_token")
|
||||
String refreshToken;
|
||||
|
||||
public String getTokenType() {
|
||||
return tokenType;
|
||||
|
@ -41,4 +45,22 @@ public class OAuth2Token {
|
|||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public long getExpiresIn() {
|
||||
return expiresIn;
|
||||
}
|
||||
|
||||
public String getRefreshToken() {
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OAuth2Token{" +
|
||||
"tokenType='" + tokenType + '\'' +
|
||||
", accessToken='" + accessToken + '\'' +
|
||||
", expiresIn=" + expiresIn +
|
||||
", refreshToken='" + refreshToken + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ import org.mariotaku.twidere.constant.SharedPreferenceConstants;
|
|||
public interface TwidereConstants extends SharedPreferenceConstants, IntentConstants, CompatibilityConstants {
|
||||
|
||||
String TWIDERE_APP_NAME = "Twidere";
|
||||
String TWIDERE_PROJECT_URL = "https://github.com/mariotaku/twidere";
|
||||
String TWIDERE_PROJECT_URL = "https://github.com/TwidereProject/";
|
||||
String TWIDERE_PROJECT_EMAIL = "twidere.project@gmail.com";
|
||||
String TWIDERE_PACKAGE_NAME = "org.mariotaku.twidere";
|
||||
|
||||
|
@ -172,13 +172,13 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
|
|||
|
||||
String OAUTH_CALLBACK_OOB = "oob";
|
||||
String OAUTH_CALLBACK_URL = PROTOCOL_TWIDERE + "com.twitter.oauth/";
|
||||
String MASTODON_CALLBACK_URL = "https://org.mariotaku.twidere/auth/callback/mastodon";
|
||||
|
||||
int REQUEST_TAKE_PHOTO = 1;
|
||||
int REQUEST_PICK_MEDIA = 2;
|
||||
int REQUEST_SELECT_ACCOUNT = 3;
|
||||
int REQUEST_COMPOSE = 4;
|
||||
int REQUEST_EDIT_API = 5;
|
||||
int REQUEST_BROWSER_SIGN_IN = 6;
|
||||
int REQUEST_SET_COLOR = 7;
|
||||
int REQUEST_SET_NICKNAME = 8;
|
||||
int REQUEST_EDIT_IMAGE = 9;
|
||||
|
|
|
@ -146,9 +146,12 @@ public interface IntentConstants {
|
|||
String EXTRA_TAB_POSITION = "tab_position";
|
||||
String EXTRA_TAB_ID = "tab_id";
|
||||
String EXTRA_OAUTH_VERIFIER = "oauth_verifier";
|
||||
String EXTRA_CODE = "code";
|
||||
String EXTRA_ACCESS_TOKEN = "access_token";
|
||||
String EXTRA_REQUEST_TOKEN = "request_token";
|
||||
String EXTRA_REQUEST_TOKEN_SECRET = "request_token_secret";
|
||||
String EXTRA_CLIENT_ID = "client_id";
|
||||
String EXTRA_CLIENT_SECRET = "client_secret";
|
||||
String EXTRA_OMIT_INTENT_EXTRA = "omit_intent_extra";
|
||||
String EXTRA_COMMAND = "command";
|
||||
String EXTRA_WIDTH = "width";
|
||||
|
@ -222,4 +225,5 @@ public interface IntentConstants {
|
|||
String EXTRA_PLACE_NAME = "place_name";
|
||||
String EXTRA_SCHEDULE_INFO = "schedule_info";
|
||||
String EXTRA_SAVE_DRAFT = "save_draft";
|
||||
String EXTRA_HOST = "host";
|
||||
}
|
||||
|
|
|
@ -24,8 +24,10 @@ package org.mariotaku.twidere.model.account.cred;
|
|||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
|
||||
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/2.
|
||||
|
@ -34,6 +36,11 @@ import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
|
|||
@ParcelablePlease
|
||||
@JsonObject
|
||||
public class OAuth2Credentials extends Credentials implements Parcelable {
|
||||
|
||||
@JsonField(name = "access_token")
|
||||
@ParcelableThisPlease
|
||||
public String access_token;
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
|
|
|
@ -6,6 +6,9 @@ import android.widget.TextView
|
|||
val TextView.empty: Boolean
|
||||
get() = length() <= 0
|
||||
|
||||
val TextView.string: String?
|
||||
get() = text?.toString()
|
||||
|
||||
fun TextView.applyFontFamily(lightFont: Boolean) {
|
||||
if (lightFont) {
|
||||
typeface = Typeface.create("sans-serif-light", typeface?.style ?: Typeface.NORMAL)
|
||||
|
|
|
@ -110,6 +110,8 @@ open class BaseActivity : ChameleonActivity(), IBaseActivity<BaseActivity>, IThe
|
|||
lateinit var defaultFeatures: DefaultFeatures
|
||||
@Inject
|
||||
lateinit var restHttpClient: RestHttpClient
|
||||
@Inject
|
||||
lateinit var mastodonApplicationRegistry: MastodonApplicationRegistry
|
||||
|
||||
protected val statusScheduleProvider: StatusScheduleProvider?
|
||||
get() = statusScheduleProviderFactory.newInstance(this)
|
||||
|
|
|
@ -24,7 +24,6 @@ import android.app.Activity
|
|||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.MenuItem
|
||||
|
@ -37,28 +36,17 @@ import android.widget.Toast
|
|||
import kotlinx.android.synthetic.main.activity_browser_sign_in.*
|
||||
import org.attoparser.ParseException
|
||||
import org.mariotaku.ktextension.removeAllCookiesSupport
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.twitter.TwitterOAuth
|
||||
import org.mariotaku.restfu.oauth.OAuthToken
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.*
|
||||
import org.mariotaku.twidere.extension.model.getOAuthAuthorization
|
||||
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
|
||||
import org.mariotaku.twidere.model.CustomAPIConfig
|
||||
import org.mariotaku.twidere.model.SingleResponse
|
||||
import org.mariotaku.twidere.util.AsyncTaskUtils
|
||||
import org.mariotaku.twidere.util.DebugLog
|
||||
import org.mariotaku.twidere.util.MicroBlogAPIFactory
|
||||
import org.mariotaku.twidere.util.OAuthPasswordAuthenticator
|
||||
import org.mariotaku.twidere.util.webkit.DefaultWebViewClient
|
||||
import java.io.IOException
|
||||
import java.io.StringReader
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class BrowserSignInActivity : BaseActivity() {
|
||||
|
||||
private var requestToken: OAuthToken? = null
|
||||
private var task: GetRequestTokenTask? = null
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
|
@ -84,13 +72,11 @@ class BrowserSignInActivity : BaseActivity() {
|
|||
webSettings.javaScriptEnabled = true
|
||||
webSettings.blockNetworkImage = false
|
||||
webSettings.saveFormData = true
|
||||
getRequestToken()
|
||||
|
||||
webView.loadUrl(intent.dataString)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
if (task?.status == AsyncTask.Status.RUNNING) {
|
||||
task?.cancel(true)
|
||||
}
|
||||
webView?.destroy()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
@ -105,16 +91,6 @@ class BrowserSignInActivity : BaseActivity() {
|
|||
super.onPause()
|
||||
}
|
||||
|
||||
private fun getRequestToken() {
|
||||
if (requestToken != null || task?.status == AsyncTask.Status.RUNNING) return
|
||||
task = GetRequestTokenTask(this)
|
||||
AsyncTaskUtils.executeTask(task)
|
||||
}
|
||||
|
||||
private fun loadUrl(url: String) {
|
||||
webView.loadUrl(url)
|
||||
}
|
||||
|
||||
private fun readOAuthPin(html: String): String? {
|
||||
try {
|
||||
val data = OAuthPasswordAuthenticator.OAuthPinData()
|
||||
|
@ -137,10 +113,6 @@ class BrowserSignInActivity : BaseActivity() {
|
|||
loadProgress.progress = progress
|
||||
}
|
||||
|
||||
private fun setRequestToken(token: OAuthToken) {
|
||||
requestToken = token
|
||||
}
|
||||
|
||||
internal class AuthorizationWebChromeClient(val activity: BrowserSignInActivity) : WebChromeClient() {
|
||||
override fun onProgressChanged(view: WebView, newProgress: Int) {
|
||||
super.onProgressChanged(view, newProgress)
|
||||
|
@ -166,17 +138,14 @@ class BrowserSignInActivity : BaseActivity() {
|
|||
val paramNames = uri.queryParameterNames
|
||||
if ("/oauth/authorize" == path && paramNames.contains("oauth_callback")) {
|
||||
// Sign in successful response.
|
||||
val requestToken = activity.requestToken
|
||||
if (requestToken != null) {
|
||||
val intent = Intent()
|
||||
intent.putExtra(EXTRA_REQUEST_TOKEN, requestToken.oauthToken)
|
||||
intent.putExtra(EXTRA_REQUEST_TOKEN_SECRET, requestToken.oauthTokenSecret)
|
||||
activity.setResult(Activity.RESULT_OK, intent)
|
||||
val intent = activity.intent
|
||||
val data = Intent()
|
||||
data.putExtra(EXTRA_EXTRAS, intent.getBundleExtra(EXTRA_EXTRAS))
|
||||
activity.setResult(Activity.RESULT_OK, data)
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("Deprecation", "OverridingDeprecatedMember")
|
||||
override fun onReceivedError(view: WebView, errorCode: Int, description: String?,
|
||||
|
@ -190,67 +159,20 @@ class BrowserSignInActivity : BaseActivity() {
|
|||
@Suppress("Deprecation", "OverridingDeprecatedMember")
|
||||
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
|
||||
val uri = Uri.parse(url)
|
||||
val data = Intent()
|
||||
data.putExtra(EXTRA_EXTRAS, activity.intent.getBundleExtra(EXTRA_EXTRAS))
|
||||
if (url.startsWith(OAUTH_CALLBACK_URL)) {
|
||||
val oauthVerifier = uri.getQueryParameter(EXTRA_OAUTH_VERIFIER)
|
||||
val activity = activity
|
||||
val requestToken = activity.requestToken
|
||||
if (oauthVerifier != null && requestToken != null) {
|
||||
val intent = Intent()
|
||||
intent.putExtra(EXTRA_OAUTH_VERIFIER, oauthVerifier)
|
||||
intent.putExtra(EXTRA_REQUEST_TOKEN, requestToken.oauthToken)
|
||||
intent.putExtra(EXTRA_REQUEST_TOKEN_SECRET, requestToken.oauthTokenSecret)
|
||||
activity.setResult(Activity.RESULT_OK, intent)
|
||||
activity.finish()
|
||||
}
|
||||
return true
|
||||
}
|
||||
val oauthVerifier = uri.getQueryParameter("oauth_verifier") ?: return false
|
||||
data.putExtra(EXTRA_OAUTH_VERIFIER, oauthVerifier)
|
||||
} else if (url.startsWith(MASTODON_CALLBACK_URL)) {
|
||||
val code = uri.getQueryParameter("code") ?: return false
|
||||
data.putExtra(EXTRA_CODE, code)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class GetRequestTokenTask(activity: BrowserSignInActivity) : AsyncTask<Any, Any, SingleResponse<OAuthToken>>() {
|
||||
private val activityRef: WeakReference<BrowserSignInActivity> = WeakReference(activity)
|
||||
private val apiConfig: CustomAPIConfig = activity.intent.getParcelableExtra(EXTRA_API_CONFIG)
|
||||
|
||||
override fun doInBackground(vararg params: Any): SingleResponse<OAuthToken> {
|
||||
val activity = activityRef.get() ?: return SingleResponse(exception = InterruptedException())
|
||||
try {
|
||||
val apiUrlFormat = apiConfig.apiUrlFormat ?:
|
||||
throw MicroBlogException("Invalid API URL format")
|
||||
val endpoint = MicroBlogAPIFactory.getOAuthSignInEndpoint(apiUrlFormat,
|
||||
apiConfig.isSameOAuthUrl)
|
||||
val auth = apiConfig.getOAuthAuthorization() ?:
|
||||
throw MicroBlogException("Invalid OAuth credentials")
|
||||
val oauth = newMicroBlogInstance(activity, endpoint, auth, apiConfig.type,
|
||||
TwitterOAuth::class.java)
|
||||
return SingleResponse(oauth.getRequestToken(OAUTH_CALLBACK_OOB))
|
||||
} catch (e: MicroBlogException) {
|
||||
return SingleResponse(exception = e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onPostExecute(result: SingleResponse<OAuthToken>) {
|
||||
val activity = activityRef.get() ?: return
|
||||
activity.setLoadProgressShown(false)
|
||||
if (result.hasData()) {
|
||||
val token = result.data!!
|
||||
activity.setRequestToken(token)
|
||||
val endpoint = MicroBlogAPIFactory.getOAuthSignInEndpoint(apiConfig.apiUrlFormat!!, true)
|
||||
activity.loadUrl(endpoint.construct("/oauth/authorize", arrayOf("oauth_token", token.oauthToken)))
|
||||
} else {
|
||||
DebugLog.w(LOGTAG, "Error while browser sign in", result.exception)
|
||||
if (!activity.isFinishing) {
|
||||
Toast.makeText(activity, R.string.message_toast_error_occurred, Toast.LENGTH_SHORT).show()
|
||||
activity.setResult(Activity.RESULT_OK, data)
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPreExecute() {
|
||||
val activity = activityRef.get() ?: return
|
||||
activity.setLoadProgressShown(true)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -260,13 +182,12 @@ class BrowserSignInActivity : BaseActivity() {
|
|||
@JavascriptInterface
|
||||
fun processHTML(html: String) {
|
||||
val oauthVerifier = activity.readOAuthPin(html)
|
||||
val requestToken = activity.requestToken
|
||||
if (oauthVerifier != null && requestToken != null) {
|
||||
val intent = Intent()
|
||||
intent.putExtra(EXTRA_OAUTH_VERIFIER, oauthVerifier)
|
||||
intent.putExtra(EXTRA_REQUEST_TOKEN, requestToken.oauthToken)
|
||||
intent.putExtra(EXTRA_REQUEST_TOKEN_SECRET, requestToken.oauthTokenSecret)
|
||||
activity.setResult(Activity.RESULT_OK, intent)
|
||||
if (oauthVerifier != null) {
|
||||
val intent = activity.intent
|
||||
val data = Intent()
|
||||
data.putExtra(EXTRA_OAUTH_VERIFIER, oauthVerifier)
|
||||
data.putExtra(EXTRA_EXTRAS, intent.getBundleExtra(EXTRA_EXTRAS))
|
||||
activity.setResult(Activity.RESULT_OK, data)
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,11 +49,15 @@ import kotlinx.android.synthetic.main.activity_sign_in.*
|
|||
import nl.komponents.kovenant.combine.and
|
||||
import nl.komponents.kovenant.task
|
||||
import nl.komponents.kovenant.ui.alwaysUi
|
||||
import nl.komponents.kovenant.ui.failUi
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.*
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.mastodon.Mastodon
|
||||
import org.mariotaku.microblog.library.mastodon.MastodonOAuth2
|
||||
import org.mariotaku.microblog.library.mastodon.annotation.AuthScope
|
||||
import org.mariotaku.microblog.library.twitter.TwitterOAuth
|
||||
import org.mariotaku.microblog.library.twitter.auth.BasicAuthorization
|
||||
import org.mariotaku.microblog.library.twitter.auth.EmptyAuthorization
|
||||
|
@ -167,11 +171,21 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
|||
setSignInButton()
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
REQUEST_BROWSER_SIGN_IN -> {
|
||||
REQUEST_BROWSER_TWITTER_SIGN_IN -> {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
handleBrowserLoginResult(data)
|
||||
}
|
||||
}
|
||||
REQUEST_BROWSER_MASTODON_SIGN_IN -> {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
val extras = data.getBundleExtra(EXTRA_EXTRAS)
|
||||
val host = extras.getString(EXTRA_HOST)
|
||||
val clientId = extras.getString(EXTRA_CLIENT_ID)
|
||||
val clientSecret = extras.getString(EXTRA_CLIENT_SECRET)
|
||||
val code = extras.getString(EXTRA_CODE)
|
||||
finishMastodonBrowserLogin(host, clientId, clientSecret, code)
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
@ -208,12 +222,16 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
|||
editUsername.text = null
|
||||
editPassword.text = null
|
||||
}
|
||||
when (apiConfig.credentialsType) {
|
||||
if (apiConfig.type == AccountType.MASTODON) {
|
||||
performMastodonLogin()
|
||||
} else when (apiConfig.credentialsType) {
|
||||
Credentials.Type.OAUTH -> {
|
||||
doBrowserLogin()
|
||||
performBrowserLogin()
|
||||
}
|
||||
else -> {
|
||||
doLogin()
|
||||
val username = editUsername.text.toString()
|
||||
val password = editPassword.text.toString()
|
||||
performUserPassLogin(username, password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -283,26 +301,127 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
|||
invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
internal fun doBrowserLogin(): Boolean {
|
||||
if (apiConfig.credentialsType != Credentials.Type.OAUTH || signInTask != null && signInTask!!.status == AsyncTask.Status.RUNNING)
|
||||
return true
|
||||
val intent = Intent(this, BrowserSignInActivity::class.java)
|
||||
intent.putExtra(EXTRA_API_CONFIG, apiConfig)
|
||||
startActivityForResult(intent, REQUEST_BROWSER_SIGN_IN)
|
||||
return false
|
||||
|
||||
private fun performBrowserLogin() {
|
||||
val weakThis = WeakReference(this)
|
||||
executeAfterFragmentResumed { activity ->
|
||||
ProgressDialogFragment.show(activity.supportFragmentManager, "get_request_token")
|
||||
} and task {
|
||||
val activity = weakThis.get() ?: throw InterruptedException()
|
||||
val apiConfig = activity.apiConfig
|
||||
val apiUrlFormat = apiConfig.apiUrlFormat ?:
|
||||
throw MicroBlogException("Invalid API URL format")
|
||||
val endpoint = MicroBlogAPIFactory.getOAuthSignInEndpoint(apiUrlFormat,
|
||||
apiConfig.isSameOAuthUrl)
|
||||
val auth = apiConfig.getOAuthAuthorization() ?:
|
||||
throw MicroBlogException("Invalid OAuth credentials")
|
||||
val oauth = newMicroBlogInstance(activity, endpoint, auth, apiConfig.type,
|
||||
TwitterOAuth::class.java)
|
||||
return@task oauth.getRequestToken(OAUTH_CALLBACK_OOB)
|
||||
}.successUi { requestToken ->
|
||||
val activity = weakThis.get() ?: return@successUi
|
||||
val intent = Intent(activity, BrowserSignInActivity::class.java)
|
||||
val apiConfig = activity.apiConfig
|
||||
val endpoint = MicroBlogAPIFactory.getOAuthSignInEndpoint(apiConfig.apiUrlFormat!!, true)
|
||||
intent.data = Uri.parse(endpoint.construct("/oauth/authorize", arrayOf("oauth_token",
|
||||
requestToken.oauthToken)))
|
||||
intent.putExtra(EXTRA_EXTRAS, Bundle {
|
||||
this[EXTRA_REQUEST_TOKEN] = requestToken.oauthToken
|
||||
this[EXTRA_REQUEST_TOKEN_SECRET] = requestToken.oauthTokenSecret
|
||||
})
|
||||
activity.startActivityForResult(intent, REQUEST_BROWSER_TWITTER_SIGN_IN)
|
||||
}.failUi {
|
||||
val activity = weakThis.get() ?: return@failUi
|
||||
// TODO show error message
|
||||
}.alwaysUi {
|
||||
executeAfterFragmentResumed {
|
||||
it.supportFragmentManager.dismissDialogFragment("get_request_token")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun doLogin() {
|
||||
private fun performMastodonLogin() {
|
||||
val weakThis = WeakReference(this)
|
||||
val userKey = editUsername.string?.takeIf(String::isNotEmpty)
|
||||
?.let(UserKey::valueOf) ?: run {
|
||||
Toast.makeText(this, R.string.message_toast_invalid_mastodon_username,
|
||||
Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
val scopes = arrayOf(AuthScope.READ, AuthScope.WRITE, AuthScope.FOLLOW)
|
||||
executeAfterFragmentResumed { activity ->
|
||||
ProgressDialogFragment.show(activity.supportFragmentManager, "open_browser_auth")
|
||||
} and task {
|
||||
val host = userKey.host ?: throw IOException()
|
||||
val activity = weakThis.get() ?: throw InterruptedException()
|
||||
val registry = activity.mastodonApplicationRegistry
|
||||
return@task Pair(host, registry[host] ?: run {
|
||||
val endpoint = Endpoint("https://$host/api/")
|
||||
val mastodon = newMicroBlogInstance(activity, endpoint, EmptyAuthorization(),
|
||||
AccountType.MASTODON, Mastodon::class.java)
|
||||
val registered = mastodon.registerApplication("Twidere for Android",
|
||||
MASTODON_CALLBACK_URL, scopes, TWIDERE_PROJECT_URL)
|
||||
registry[host] = registered
|
||||
return@run registered
|
||||
})
|
||||
}.successUi { (host, app) ->
|
||||
val activity = weakThis.get() ?: return@successUi
|
||||
val endpoint = Endpoint("https://$host/")
|
||||
val intent = Intent(activity, BrowserSignInActivity::class.java)
|
||||
intent.data = Uri.parse(endpoint.construct("/oauth/authorize",
|
||||
arrayOf("response_type", "code"),
|
||||
arrayOf("client_id", app.clientId),
|
||||
arrayOf("redirect_uri", MASTODON_CALLBACK_URL),
|
||||
arrayOf("scope", scopes.joinToString(" "))))
|
||||
intent.putExtra(EXTRA_EXTRAS, Bundle {
|
||||
this[EXTRA_HOST] = host
|
||||
this[EXTRA_CLIENT_ID] = app.clientId
|
||||
this[EXTRA_CLIENT_SECRET] = app.clientSecret
|
||||
})
|
||||
activity.startActivityForResult(intent, REQUEST_BROWSER_MASTODON_SIGN_IN)
|
||||
}.failUi {
|
||||
val activity = weakThis.get() ?: return@failUi
|
||||
// TODO show error message
|
||||
}.alwaysUi {
|
||||
executeAfterFragmentResumed {
|
||||
it.supportFragmentManager.dismissDialogFragment("open_browser_auth")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun performUserPassLogin(username: String, password: String) {
|
||||
if (signInTask != null && signInTask!!.status == AsyncTask.Status.RUNNING) {
|
||||
signInTask!!.cancel(true)
|
||||
}
|
||||
|
||||
val username = editUsername.text.toString()
|
||||
val password = editPassword.text.toString()
|
||||
signInTask = SignInTask(this, username, password, apiConfig)
|
||||
AsyncTaskUtils.executeTask<AbstractSignInTask, Any>(signInTask)
|
||||
}
|
||||
|
||||
private fun finishMastodonBrowserLogin(host: String, clientId: String, clientSecret: String,
|
||||
code: String) {
|
||||
val weakThis = WeakReference(this)
|
||||
executeAfterFragmentResumed { activity ->
|
||||
ProgressDialogFragment.show(activity.supportFragmentManager, "open_browser_auth")
|
||||
} and task {
|
||||
val activity = weakThis.get() ?: throw InterruptedException()
|
||||
val endpoint = Endpoint("https://$host/api/")
|
||||
val oauth2 = newMicroBlogInstance(activity, endpoint, EmptyAuthorization(),
|
||||
AccountType.MASTODON, MastodonOAuth2::class.java)
|
||||
return@task oauth2.getToken(clientId, clientSecret, "code", code,
|
||||
MASTODON_CALLBACK_URL)
|
||||
}.successUi { token ->
|
||||
DebugLog.d(msg = "$token")
|
||||
}.failUi {
|
||||
val activity = weakThis.get() ?: return@failUi
|
||||
// TODO show error message
|
||||
}.alwaysUi {
|
||||
executeAfterFragmentResumed {
|
||||
it.supportFragmentManager.dismissDialogFragment("open_browser_auth")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun onSignInResult(result: SignInResponse) {
|
||||
val am = AccountManager.get(this)
|
||||
setSignInButton()
|
||||
|
@ -373,11 +492,6 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
|||
}
|
||||
}
|
||||
|
||||
internal fun setUsernamePassword(username: String, password: String) {
|
||||
editUsername.setText(username)
|
||||
editPassword.setText(password)
|
||||
}
|
||||
|
||||
private fun updateDefaultFeatures() {
|
||||
val weakThis = WeakReference(this)
|
||||
executeAfterFragmentResumed {
|
||||
|
@ -416,14 +530,11 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
|||
|
||||
private fun handleBrowserLoginResult(intent: Intent?) {
|
||||
if (intent == null) return
|
||||
if (signInTask?.status == AsyncTask.Status.RUNNING) {
|
||||
signInTask?.cancel(true)
|
||||
}
|
||||
val verifier = intent.getStringExtra(EXTRA_OAUTH_VERIFIER)
|
||||
val requestToken = OAuthToken(intent.getStringExtra(EXTRA_REQUEST_TOKEN),
|
||||
intent.getStringExtra(EXTRA_REQUEST_TOKEN_SECRET))
|
||||
signInTask = BrowserSignInTask(this, apiConfig, requestToken, verifier)
|
||||
AsyncTaskUtils.executeTask<AbstractSignInTask, Any>(signInTask)
|
||||
AsyncTaskUtils.executeTask(signInTask)
|
||||
}
|
||||
|
||||
private fun setDefaultAPI() {
|
||||
|
@ -719,9 +830,9 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
|||
val editUsername = alertDialog.findViewById(R.id.username) as EditText
|
||||
val editPassword = alertDialog.findViewById(R.id.password) as EditText
|
||||
val activity = activity as SignInActivity
|
||||
activity.setUsernamePassword(editUsername.text.toString(),
|
||||
editPassword.text.toString())
|
||||
activity.doLogin()
|
||||
val username = editUsername.text.toString()
|
||||
val password = editPassword.text.toString()
|
||||
activity.performUserPassLogin(username, password)
|
||||
}
|
||||
builder.setNegativeButton(android.R.string.cancel, null)
|
||||
|
||||
|
@ -797,15 +908,9 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/7/7.
|
||||
*/
|
||||
internal class BrowserSignInTask(
|
||||
context: SignInActivity,
|
||||
private val apiConfig: CustomAPIConfig,
|
||||
private val requestToken: OAuthToken,
|
||||
private val oauthVerifier: String?
|
||||
) : AbstractSignInTask(context) {
|
||||
internal class BrowserSignInTask(context: SignInActivity, private val apiConfig: CustomAPIConfig,
|
||||
private val requestToken: OAuthToken, private val oauthVerifier: String?) :
|
||||
AbstractSignInTask(context) {
|
||||
|
||||
private val context: Context
|
||||
|
||||
|
@ -865,64 +970,6 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
|||
|
||||
}
|
||||
|
||||
internal data class SignInResponse(
|
||||
val alreadyLoggedIn: Boolean,
|
||||
@Credentials.Type val credsType: String = Credentials.Type.EMPTY,
|
||||
val credentials: Credentials,
|
||||
val user: ParcelableUser,
|
||||
val color: Int = 0,
|
||||
val typeExtras: Pair<String, AccountExtras?>
|
||||
) {
|
||||
|
||||
private fun writeAccountInfo(action: (k: String, v: String?) -> Unit) {
|
||||
action(ACCOUNT_USER_DATA_KEY, user.key.toString())
|
||||
action(ACCOUNT_USER_DATA_TYPE, typeExtras.first)
|
||||
action(ACCOUNT_USER_DATA_CREDS_TYPE, credsType)
|
||||
|
||||
action(ACCOUNT_USER_DATA_ACTIVATED, true.toString())
|
||||
action(ACCOUNT_USER_DATA_COLOR, toHexColor(color, format = HexColorFormat.RGB))
|
||||
|
||||
action(ACCOUNT_USER_DATA_USER, JsonSerializer.serialize(user))
|
||||
action(ACCOUNT_USER_DATA_EXTRAS, typeExtras.second?.let { JsonSerializer.serialize(it) })
|
||||
}
|
||||
|
||||
private fun writeAuthToken(am: AccountManager, account: Account) {
|
||||
val authToken = JsonSerializer.serialize(credentials)
|
||||
am.setAuthToken(account, ACCOUNT_AUTH_TOKEN_TYPE, authToken)
|
||||
}
|
||||
|
||||
fun updateAccount(am: AccountManager) {
|
||||
val account = AccountUtils.findByAccountKey(am, user.key) ?: return
|
||||
writeAccountInfo { k, v ->
|
||||
am.setUserData(account, k, v)
|
||||
}
|
||||
writeAuthToken(am, account)
|
||||
}
|
||||
|
||||
fun addAccount(am: AccountManager, randomizeAccountName: Boolean): Account {
|
||||
var accountName: String
|
||||
if (randomizeAccountName) {
|
||||
val usedNames = ArraySet<String>()
|
||||
AccountUtils.getAccounts(am).mapTo(usedNames, Account::name)
|
||||
do {
|
||||
accountName = UUID.randomUUID().toString()
|
||||
} while (accountName in usedNames)
|
||||
} else {
|
||||
accountName = generateAccountName(user.screen_name, user.key.host)
|
||||
}
|
||||
val account = Account(accountName, ACCOUNT_TYPE)
|
||||
val accountPosition = AccountUtils.getAccounts(am).size
|
||||
// Don't add UserData in this method, see http://stackoverflow.com/a/29776224/859190
|
||||
am.addAccountExplicitly(account, null, null)
|
||||
writeAccountInfo { k, v ->
|
||||
am.setUserData(account, k, v)
|
||||
}
|
||||
am.setUserData(account, ACCOUNT_USER_DATA_POSITION, accountPosition.toString())
|
||||
writeAuthToken(am, account)
|
||||
return account
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class SignInTask(
|
||||
activity: SignInActivity,
|
||||
|
@ -1141,8 +1188,68 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
|||
|
||||
}
|
||||
|
||||
internal data class SignInResponse(
|
||||
val alreadyLoggedIn: Boolean,
|
||||
@Credentials.Type val credsType: String = Credentials.Type.EMPTY,
|
||||
val credentials: Credentials,
|
||||
val user: ParcelableUser,
|
||||
val color: Int = 0,
|
||||
val typeExtras: Pair<String, AccountExtras?>
|
||||
) {
|
||||
|
||||
private fun writeAccountInfo(action: (k: String, v: String?) -> Unit) {
|
||||
action(ACCOUNT_USER_DATA_KEY, user.key.toString())
|
||||
action(ACCOUNT_USER_DATA_TYPE, typeExtras.first)
|
||||
action(ACCOUNT_USER_DATA_CREDS_TYPE, credsType)
|
||||
|
||||
action(ACCOUNT_USER_DATA_ACTIVATED, true.toString())
|
||||
action(ACCOUNT_USER_DATA_COLOR, toHexColor(color, format = HexColorFormat.RGB))
|
||||
|
||||
action(ACCOUNT_USER_DATA_USER, JsonSerializer.serialize(user))
|
||||
action(ACCOUNT_USER_DATA_EXTRAS, typeExtras.second?.let { JsonSerializer.serialize(it) })
|
||||
}
|
||||
|
||||
private fun writeAuthToken(am: AccountManager, account: Account) {
|
||||
val authToken = JsonSerializer.serialize(credentials)
|
||||
am.setAuthToken(account, ACCOUNT_AUTH_TOKEN_TYPE, authToken)
|
||||
}
|
||||
|
||||
fun updateAccount(am: AccountManager) {
|
||||
val account = AccountUtils.findByAccountKey(am, user.key) ?: return
|
||||
writeAccountInfo { k, v ->
|
||||
am.setUserData(account, k, v)
|
||||
}
|
||||
writeAuthToken(am, account)
|
||||
}
|
||||
|
||||
fun addAccount(am: AccountManager, randomizeAccountName: Boolean): Account {
|
||||
var accountName: String
|
||||
if (randomizeAccountName) {
|
||||
val usedNames = ArraySet<String>()
|
||||
AccountUtils.getAccounts(am).mapTo(usedNames, Account::name)
|
||||
do {
|
||||
accountName = UUID.randomUUID().toString()
|
||||
} while (accountName in usedNames)
|
||||
} else {
|
||||
accountName = generateAccountName(user.screen_name, user.key.host)
|
||||
}
|
||||
val account = Account(accountName, ACCOUNT_TYPE)
|
||||
val accountPosition = AccountUtils.getAccounts(am).size
|
||||
// Don't add UserData in this method, see http://stackoverflow.com/a/29776224/859190
|
||||
am.addAccountExplicitly(account, null, null)
|
||||
writeAccountInfo { k, v ->
|
||||
am.setUserData(account, k, v)
|
||||
}
|
||||
am.setUserData(account, ACCOUNT_USER_DATA_POSITION, accountPosition.toString())
|
||||
writeAuthToken(am, account)
|
||||
return account
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val REQUEST_BROWSER_TWITTER_SIGN_IN = 101
|
||||
const val REQUEST_BROWSER_MASTODON_SIGN_IN = 102
|
||||
|
||||
private val FRAGMENT_TAG_SIGN_IN_PROGRESS = "sign_in_progress"
|
||||
private val FRAGMENT_TAG_LOADING_DEFAULT_FEATURES = "loading_default_features"
|
||||
|
|
|
@ -6,6 +6,8 @@ import android.text.TextUtils
|
|||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.fanfou.FanfouStream
|
||||
import org.mariotaku.microblog.library.mastodon.Mastodon
|
||||
import org.mariotaku.microblog.library.mastodon.MastodonOAuth2
|
||||
import org.mariotaku.microblog.library.twitter.*
|
||||
import org.mariotaku.microblog.library.twitter.auth.BasicAuthorization
|
||||
import org.mariotaku.microblog.library.twitter.auth.EmptyAuthorization
|
||||
|
@ -17,12 +19,10 @@ import org.mariotaku.restfu.http.MultiValueMap
|
|||
import org.mariotaku.restfu.oauth.OAuthAuthorization
|
||||
import org.mariotaku.restfu.oauth.OAuthEndpoint
|
||||
import org.mariotaku.restfu.oauth.OAuthToken
|
||||
import org.mariotaku.restfu.oauth2.OAuth2Authorization
|
||||
import org.mariotaku.twidere.TwidereConstants.DEFAULT_TWITTER_API_URL_FORMAT
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.model.account.cred.BasicCredentials
|
||||
import org.mariotaku.twidere.model.account.cred.Credentials
|
||||
import org.mariotaku.twidere.model.account.cred.EmptyCredentials
|
||||
import org.mariotaku.twidere.model.account.cred.OAuthCredentials
|
||||
import org.mariotaku.twidere.model.account.cred.*
|
||||
import org.mariotaku.twidere.util.HttpClientFactory
|
||||
import org.mariotaku.twidere.util.MicroBlogAPIFactory
|
||||
import org.mariotaku.twidere.util.MicroBlogAPIFactory.sFanfouConstantPool
|
||||
|
@ -50,6 +50,9 @@ fun Credentials.getAuthorization(cls: Class<*>?): Authorization {
|
|||
return OAuthAuthorization(consumer_key, consumer_secret, OAuthToken(access_token,
|
||||
access_token_secret))
|
||||
}
|
||||
is OAuth2Credentials -> {
|
||||
return OAuth2Authorization(access_token)
|
||||
}
|
||||
is BasicCredentials -> {
|
||||
return BasicAuthorization(username, password)
|
||||
}
|
||||
|
@ -107,6 +110,14 @@ fun Credentials.getEndpoint(cls: Class<*>): Endpoint {
|
|||
domain = null
|
||||
versionSuffix = null
|
||||
}
|
||||
Mastodon::class.java.isAssignableFrom(cls) -> {
|
||||
domain = null
|
||||
versionSuffix = null
|
||||
}
|
||||
MastodonOAuth2::class.java.isAssignableFrom(cls) -> {
|
||||
domain = null
|
||||
versionSuffix = null
|
||||
}
|
||||
else -> throw UnsupportedOperationException("Unsupported class $cls")
|
||||
}
|
||||
val endpointUrl = MicroBlogAPIFactory.getApiUrl(apiUrlFormat, domain, versionSuffix)
|
||||
|
@ -124,8 +135,7 @@ fun Credentials.getEndpoint(cls: Class<*>): Endpoint {
|
|||
|
||||
fun <T> Credentials.newMicroBlogInstance(context: Context, @AccountType accountType: String? = null,
|
||||
cls: Class<T>): T {
|
||||
return newMicroBlogInstance(context, getEndpoint(cls), getAuthorization(cls), accountType,
|
||||
cls)
|
||||
return newMicroBlogInstance(context, getEndpoint(cls), getAuthorization(cls), accountType, cls)
|
||||
}
|
||||
|
||||
fun <T> newMicroBlogInstance(context: Context, endpoint: Endpoint, auth: Authorization,
|
||||
|
|
|
@ -1323,4 +1323,5 @@
|
|||
<string name="users_blocked">Blocked these users.</string>
|
||||
<string name="users_lists_with_name"><xliff:g id="name">%s</xliff:g>\'s lists</string>
|
||||
<string name="users_statuses">User\'s tweets</string>
|
||||
<string name="message_toast_invalid_mastodon_username">Invalid Mastodon username (username@mastodon-site)</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue