adding google drive sync
This commit is contained in:
parent
a97edf5571
commit
dcd6c81bcd
|
@ -98,6 +98,7 @@ dependencies {
|
|||
// START Non-FOSS component
|
||||
googleCompile "com.google.android.gms:play-services-maps:$play_services_version"
|
||||
googleCompile "com.google.android.gms:play-services-auth:$play_services_version"
|
||||
googleCompile "com.google.android.gms:play-services-drive:$play_services_version"
|
||||
googleCompile 'com.google.maps.android:android-maps-utils:0.4.4'
|
||||
googleCompile('com.crashlytics.sdk.android:crashlytics:2.6.5@aar') { transitive = true }
|
||||
googleCompile 'com.anjlab.android.iab.v3:library:1.0.38'
|
||||
|
|
|
@ -31,7 +31,10 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.DropboxAuthStarterActivity"
|
||||
android:name=".activity.sync.DropboxAuthStarterActivity"
|
||||
android:theme="@style/Theme.Twidere.NoDisplay"/>
|
||||
<activity
|
||||
android:name=".activity.sync.GoogleDriveAuthActivity"
|
||||
android:theme="@style/Theme.Twidere.NoDisplay"/>
|
||||
<activity
|
||||
android:name="com.dropbox.core.android.AuthActivity"
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package org.mariotaku.twidere.activity
|
||||
package org.mariotaku.twidere.activity.sync
|
||||
|
||||
import android.os.Bundle
|
||||
import com.dropbox.core.android.Auth
|
||||
import org.mariotaku.kpreferences.set
|
||||
import org.mariotaku.twidere.Constants.DROPBOX_APP_KEY
|
||||
import org.mariotaku.twidere.activity.BaseActivity
|
||||
import org.mariotaku.twidere.constant.dataSyncProviderInfoKey
|
||||
import org.mariotaku.twidere.model.sync.DropboxSyncProviderInfo
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package org.mariotaku.twidere.activity.sync
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.IntentSender
|
||||
import android.os.Bundle
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
import com.google.android.gms.common.GooglePlayServicesUtil
|
||||
import com.google.android.gms.common.api.GoogleApiClient
|
||||
import com.google.android.gms.drive.Drive
|
||||
import org.mariotaku.kpreferences.set
|
||||
import org.mariotaku.twidere.activity.BaseActivity
|
||||
import org.mariotaku.twidere.constant.dataSyncProviderInfoKey
|
||||
import org.mariotaku.twidere.model.sync.GoogleDriveSyncProviderInfo
|
||||
|
||||
|
||||
class GoogleDriveAuthActivity : BaseActivity(), GoogleApiClient.ConnectionCallbacks,
|
||||
GoogleApiClient.OnConnectionFailedListener {
|
||||
private lateinit var googleApiClient: GoogleApiClient
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
googleApiClient = GoogleApiClient.Builder(this)
|
||||
.addApi(Drive.API)
|
||||
.addScope(Drive.SCOPE_APPFOLDER)
|
||||
.addConnectionCallbacks(this)
|
||||
.addOnConnectionFailedListener(this)
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
googleApiClient.connect()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
googleApiClient.disconnect()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
|
||||
when (requestCode) {
|
||||
RESOLVE_CONNECTION_REQUEST_CODE -> if (resultCode == Activity.RESULT_OK) {
|
||||
googleApiClient.connect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConnectionFailed(connectionResult: ConnectionResult) {
|
||||
if (connectionResult.hasResolution()) {
|
||||
try {
|
||||
connectionResult.startResolutionForResult(this, RESOLVE_CONNECTION_REQUEST_CODE)
|
||||
} catch (e: IntentSender.SendIntentException) {
|
||||
// Unable to resolve, message user appropriately
|
||||
}
|
||||
|
||||
} else {
|
||||
preferences[dataSyncProviderInfoKey] = null
|
||||
GooglePlayServicesUtil.showErrorDialogFragment(connectionResult.errorCode, this, null, 0) {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConnected(connectionHint: Bundle?) {
|
||||
preferences[dataSyncProviderInfoKey] = GoogleDriveSyncProviderInfo()
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onConnectionSuspended(cause: Int) {
|
||||
finish()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val RESOLVE_CONNECTION_REQUEST_CODE: Int = 101
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package org.mariotaku.twidere.model.sync
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import org.mariotaku.twidere.util.sync.SyncTaskRunner
|
||||
import org.mariotaku.twidere.util.sync.google.GoogleDriveSyncTaskRunner
|
||||
|
||||
class GoogleDriveSyncProviderInfo : SyncProviderInfo(GoogleDriveSyncProviderInfo.TYPE) {
|
||||
override fun writeToPreferences(editor: SharedPreferences.Editor) {
|
||||
|
||||
}
|
||||
|
||||
override fun newSyncTaskRunner(context: Context): SyncTaskRunner {
|
||||
return GoogleDriveSyncTaskRunner(context)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TYPE = "google_drive"
|
||||
|
||||
fun newInstance(preferences: SharedPreferences): GoogleDriveSyncProviderInfo? {
|
||||
return GoogleDriveSyncProviderInfo()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
package org.mariotaku.twidere.util.sync
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.activity.DropboxAuthStarterActivity
|
||||
import org.mariotaku.twidere.activity.sync.DropboxAuthStarterActivity
|
||||
import org.mariotaku.twidere.activity.sync.GoogleDriveAuthActivity
|
||||
import org.mariotaku.twidere.model.sync.DropboxSyncProviderInfo
|
||||
import org.mariotaku.twidere.model.sync.GoogleDriveSyncProviderInfo
|
||||
import org.mariotaku.twidere.model.sync.SyncProviderEntry
|
||||
import org.mariotaku.twidere.model.sync.SyncProviderInfo
|
||||
|
||||
|
@ -17,6 +20,7 @@ class NonFreeSyncProviderInfoFactory : SyncProviderInfoFactory() {
|
|||
override fun getInfoForType(type: String, preferences: SharedPreferences): SyncProviderInfo? {
|
||||
return when (type) {
|
||||
DropboxSyncProviderInfo.TYPE -> DropboxSyncProviderInfo.newInstance(preferences)
|
||||
GoogleDriveSyncProviderInfo.TYPE -> GoogleDriveSyncProviderInfo.newInstance(preferences)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +29,11 @@ class NonFreeSyncProviderInfoFactory : SyncProviderInfoFactory() {
|
|||
return listOf(
|
||||
SyncProviderEntry(DropboxSyncProviderInfo.TYPE,
|
||||
context.getString(R.string.sync_provider_name_dropbox),
|
||||
Intent(context, DropboxAuthStarterActivity::class.java))
|
||||
Intent(context, DropboxAuthStarterActivity::class.java)),
|
||||
SyncProviderEntry(GoogleDriveSyncProviderInfo.TYPE,
|
||||
context.getString(R.string.sync_provider_name_google_drive),
|
||||
Intent(context, GoogleDriveAuthActivity::class.java))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,10 @@ import org.mariotaku.twidere.util.sync.FileBasedDraftsSyncAction
|
|||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
class DropboxDraftsSyncAction(context: Context, val client: DbxClientV2) : FileBasedDraftsSyncAction<FileMetadata>(context) {
|
||||
class DropboxDraftsSyncAction(
|
||||
context: Context,
|
||||
val client: DbxClientV2
|
||||
) : FileBasedDraftsSyncAction<FileMetadata>(context) {
|
||||
@Throws(IOException::class)
|
||||
override fun Draft.saveToRemote(): FileMetadata {
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package org.mariotaku.twidere.util.sync.google
|
||||
|
||||
import android.content.Context
|
||||
import com.google.android.gms.common.api.GoogleApiClient
|
||||
import com.google.android.gms.drive.Drive
|
||||
import com.google.android.gms.drive.DriveFile
|
||||
import com.google.android.gms.drive.DriveId
|
||||
import com.google.android.gms.drive.MetadataChangeSet
|
||||
import org.mariotaku.twidere.extension.model.filename
|
||||
import org.mariotaku.twidere.extension.model.readMimeMessageFrom
|
||||
import org.mariotaku.twidere.extension.model.writeMimeMessageTo
|
||||
import org.mariotaku.twidere.model.Draft
|
||||
import org.mariotaku.twidere.util.sync.FileBasedDraftsSyncAction
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
class GoogleDriveDraftsSyncAction(
|
||||
context: Context,
|
||||
val client: GoogleApiClient
|
||||
) : FileBasedDraftsSyncAction<GoogleDriveDraftsSyncAction.DriveFileInfo>(context) {
|
||||
@Throws(IOException::class)
|
||||
override fun Draft.saveToRemote(): DriveFileInfo {
|
||||
try {
|
||||
val folder = Drive.DriveApi.getAppFolder(client)
|
||||
val driveContents = Drive.DriveApi.newDriveContents(client).await().driveContents
|
||||
this.writeMimeMessageTo(context, driveContents.outputStream)
|
||||
val filename = "/Drafts/$filename"
|
||||
val changeSet = MetadataChangeSet.Builder().setTitle(filename).build()
|
||||
val driveFile = folder.createFile(client, changeSet, driveContents).await().driveFile
|
||||
return DriveFileInfo(driveFile.driveId, filename, Date())
|
||||
} catch (e: Exception) {
|
||||
throw IOException(e)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun Draft.loadFromRemote(info: DriveFileInfo): Boolean {
|
||||
try {
|
||||
val file = info.driveId.asDriveFile()
|
||||
val result = file.open(client, DriveFile.MODE_READ_ONLY, null).await()
|
||||
result.driveContents.inputStream.use {
|
||||
val parsed = this.readMimeMessageFrom(context, it)
|
||||
if (parsed) {
|
||||
this.timestamp = info.draftTimestamp
|
||||
this.unique_id = info.draftFileName.substringBeforeLast(".eml")
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw IOException(e)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun removeDrafts(list: List<DriveFileInfo>): Boolean {
|
||||
try {
|
||||
list.forEach { info ->
|
||||
info.driveId.asDriveFile().delete(client).await()
|
||||
}
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
throw IOException(e)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun removeDraft(info: DriveFileInfo): Boolean {
|
||||
try {
|
||||
return info.driveId.asDriveFile().delete(client).await().isSuccess
|
||||
} catch (e: Exception) {
|
||||
throw IOException(e)
|
||||
}
|
||||
}
|
||||
|
||||
override val DriveFileInfo.draftTimestamp: Long get() = this.modifiedDate.time
|
||||
|
||||
override val DriveFileInfo.draftFileName: String get() = this.name
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun listRemoteDrafts(): List<DriveFileInfo> {
|
||||
val pendingResult = Drive.DriveApi.getAppFolder(client).listChildren(client)
|
||||
val result = ArrayList<DriveFileInfo>()
|
||||
try {
|
||||
val requestResult = pendingResult.await()
|
||||
requestResult.metadataBuffer.mapTo(result) { metadata ->
|
||||
DriveFileInfo(metadata.driveId, metadata.originalFilename, metadata.modifiedDate)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw IOException(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
data class DriveFileInfo(val driveId: DriveId, val name: String, val modifiedDate: Date)
|
||||
|
||||
}
|
|
@ -1,11 +1,56 @@
|
|||
package org.mariotaku.twidere.util.sync.google
|
||||
|
||||
import android.content.ComponentCallbacks
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import com.dropbox.core.DbxRequestConfig
|
||||
import com.dropbox.core.v2.DbxClientV2
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
import com.google.android.gms.common.api.GoogleApiClient
|
||||
import com.google.android.gms.drive.Drive
|
||||
import nl.komponents.kovenant.task
|
||||
import nl.komponents.kovenant.then
|
||||
import nl.komponents.kovenant.ui.failUi
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.mariotaku.twidere.BuildConfig
|
||||
import org.mariotaku.twidere.util.TaskServiceRunner
|
||||
import org.mariotaku.twidere.util.sync.ISyncAction
|
||||
import org.mariotaku.twidere.util.sync.SyncTaskRunner
|
||||
import org.mariotaku.twidere.util.sync.UserColorsSyncProcessor
|
||||
import org.mariotaku.twidere.util.sync.UserNicknamesSyncProcessor
|
||||
import org.mariotaku.twidere.util.sync.dropbox.DropboxDraftsSyncAction
|
||||
import org.mariotaku.twidere.util.sync.dropbox.DropboxFiltersDataSyncAction
|
||||
import org.mariotaku.twidere.util.sync.dropbox.DropboxPreferencesValuesSyncAction
|
||||
import java.net.ConnectException
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/1/6.
|
||||
*/
|
||||
|
||||
class GoogleDriveSyncTaskRunner(context: Context) {
|
||||
class GoogleDriveSyncTaskRunner(context: Context) : SyncTaskRunner(context) {
|
||||
override fun onRunningTask(action: String, callback: (Boolean) -> Unit): Boolean {
|
||||
val client = GoogleApiClient.Builder(context)
|
||||
.addApi(Drive.API)
|
||||
.addScope(Drive.SCOPE_APPFOLDER)
|
||||
.build()
|
||||
val syncAction: ISyncAction = when (action) {
|
||||
TaskServiceRunner.ACTION_SYNC_DRAFTS -> GoogleDriveDraftsSyncAction(context, client)
|
||||
else -> null
|
||||
} ?: return false
|
||||
task {
|
||||
val connResult = client.blockingConnect()
|
||||
if (!connResult.isSuccess) {
|
||||
throw ConnectException()
|
||||
}
|
||||
syncAction.execute()
|
||||
}.successUi {
|
||||
callback(true)
|
||||
}.failUi {
|
||||
callback(false)
|
||||
}.always {
|
||||
client.disconnect()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -477,6 +477,7 @@
|
|||
<activity
|
||||
android:name=".activity.PremiumDashboardActivity"
|
||||
android:label="@string/title_premium_features_name"
|
||||
android:parentActivityName=".activity.HomeActivity"
|
||||
android:theme="@style/Theme.Twidere">
|
||||
|
||||
<meta-data
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
"same_oauth_url": true,
|
||||
"no_version_suffix": false,
|
||||
"consumer_key": "i5XtSVfoWjLjKlnrvhiLPMZC0",
|
||||
"consumer_secret": "sQncmZ2atQR6tKbqnnAtqjrECqN8k6FD4p4OoNS0XTDkUz3HGH"
|
||||
"consumer_secret": "sQncmZ2atQR6tKbqnnAtqjrECqN8k6FD4p4OoNS0XTDkUz3HGH",
|
||||
"sign_up_url": "https://twitter.com/signup"
|
||||
},
|
||||
{
|
||||
"name": "Fanfou",
|
||||
|
@ -19,7 +20,8 @@
|
|||
"same_oauth_url": true,
|
||||
"no_version_suffix": true,
|
||||
"consumer_key": "86d1146dda1d21d59351008a1d1058fd",
|
||||
"consumer_secret": "c00f4b83dbfc52e2ed78a21d4edfc3cc"
|
||||
"consumer_secret": "c00f4b83dbfc52e2ed78a21d4edfc3cc",
|
||||
"sign_up_url": "http://fanfou.com/register"
|
||||
},
|
||||
{
|
||||
"name": "Quitter.se",
|
||||
|
@ -30,7 +32,8 @@
|
|||
"same_oauth_url": true,
|
||||
"no_version_suffix": true,
|
||||
"consumer_key": "3584cd86bd8e04948be15650acbd0d59",
|
||||
"consumer_secret": "84a39eff81c0a0ecbfba5239d25c0367"
|
||||
"consumer_secret": "84a39eff81c0a0ecbfba5239d25c0367",
|
||||
"sign_up_url": "https://quitter.se/"
|
||||
},
|
||||
{
|
||||
"name": "LoadAverage.org",
|
||||
|
|
|
@ -55,6 +55,9 @@ public final class CustomAPIConfig implements Parcelable {
|
|||
String consumerKey;
|
||||
@JsonField(name = "consumer_secret")
|
||||
String consumerSecret;
|
||||
@Nullable
|
||||
@JsonField(name = "sign_up_url")
|
||||
String signUpUrl;
|
||||
|
||||
public CustomAPIConfig() {
|
||||
}
|
||||
|
@ -139,6 +142,11 @@ public final class CustomAPIConfig implements Parcelable {
|
|||
this.noVersionSuffix = noVersionSuffix;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getSignUpUrl() {
|
||||
return signUpUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.accounts.AccountAuthenticatorResponse
|
|||
import android.accounts.AccountManager
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
|
@ -31,6 +32,7 @@ import android.content.res.ColorStateList
|
|||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.support.customtabs.CustomTabsIntent
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v4.util.ArraySet
|
||||
|
@ -52,6 +54,8 @@ import android.widget.Toast
|
|||
import com.bluelinelabs.logansquare.LoganSquare
|
||||
import com.rengwuxian.materialedittext.MaterialEditText
|
||||
import kotlinx.android.synthetic.main.activity_sign_in.*
|
||||
import org.mariotaku.chameleon.Chameleon
|
||||
import org.mariotaku.chameleon.ChameleonUtils
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.*
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
|
@ -71,6 +75,7 @@ import org.mariotaku.twidere.activity.iface.APIEditorActivity
|
|||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_API_CONFIG
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_CREDENTIALS_TYPE
|
||||
import org.mariotaku.twidere.constant.chromeCustomTabKey
|
||||
import org.mariotaku.twidere.constant.defaultAPIConfigKey
|
||||
import org.mariotaku.twidere.constant.randomizeAccountNameKey
|
||||
import org.mariotaku.twidere.extension.model.getColor
|
||||
|
@ -125,7 +130,6 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
|
|||
|
||||
val isTwipOMode = apiConfig.credentialsType == Credentials.Type.EMPTY
|
||||
usernamePasswordContainer.visibility = if (isTwipOMode) View.GONE else View.VISIBLE
|
||||
signInSignUpContainer.orientation = if (isTwipOMode) LinearLayout.VERTICAL else LinearLayout.HORIZONTAL
|
||||
|
||||
editUsername.addTextChangedListener(this)
|
||||
editPassword.addTextChangedListener(this)
|
||||
|
@ -208,15 +212,12 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
|
|||
when (apiConfig.credentialsType) {
|
||||
Credentials.Type.XAUTH, Credentials.Type.BASIC -> {
|
||||
usernamePasswordContainer.visibility = View.VISIBLE
|
||||
signInSignUpContainer.orientation = LinearLayout.HORIZONTAL
|
||||
}
|
||||
Credentials.Type.EMPTY -> {
|
||||
usernamePasswordContainer.visibility = View.GONE
|
||||
signInSignUpContainer.orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
else -> {
|
||||
usernamePasswordContainer.visibility = View.GONE
|
||||
signInSignUpContainer.orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -224,8 +225,25 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
|
|||
override fun onClick(v: View) {
|
||||
when (v) {
|
||||
signUp -> {
|
||||
val intent = Intent(Intent.ACTION_VIEW).setData(Uri.parse(TWITTER_SIGNUP_URL))
|
||||
startActivity(intent)
|
||||
val signUpUrl = apiConfig.signUpUrl ?: return
|
||||
val uri = Uri.parse(signUpUrl)
|
||||
if (preferences[chromeCustomTabKey]) {
|
||||
val builder = CustomTabsIntent.Builder()
|
||||
builder.setToolbarColor(overrideTheme.colorToolbar)
|
||||
val intent = builder.build()
|
||||
try {
|
||||
intent.launchUrl(this, uri)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
// Ignore
|
||||
}
|
||||
} else {
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
try {
|
||||
startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
signIn -> {
|
||||
if (usernamePasswordContainer.visibility != View.VISIBLE) {
|
||||
|
@ -235,11 +253,9 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
|
|||
doLogin()
|
||||
}
|
||||
passwordSignIn -> {
|
||||
executeAfterFragmentResumed {
|
||||
val fm = supportFragmentManager
|
||||
executeAfterFragmentResumed { fragment ->
|
||||
val df = PasswordSignInDialogFragment()
|
||||
df.show(fm.beginTransaction(), "password_sign_in")
|
||||
Unit
|
||||
df.show(fragment.supportFragmentManager, "password_sign_in")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -377,6 +393,16 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
|
|||
signIn.isEnabled = true
|
||||
}
|
||||
}
|
||||
signUp.visibility = if (apiConfig.signUpUrl != null) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
passwordSignIn.visibility = if (apiConfig.type == null || apiConfig.type == AccountType.TWITTER) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
internal fun onSignInResult(result: SignInResponse) {
|
||||
|
|
|
@ -37,6 +37,7 @@ import android.widget.RadioGroup
|
|||
import android.widget.RadioGroup.OnCheckedChangeListener
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import com.bluelinelabs.logansquare.LoganSquare
|
||||
import kotlinx.android.synthetic.main.activity_api_editor.*
|
||||
import kotlinx.android.synthetic.main.layout_api_editor.*
|
||||
import kotlinx.android.synthetic.main.layout_api_editor_advanced_fields.*
|
||||
|
@ -63,6 +64,38 @@ import javax.inject.Inject
|
|||
class APIEditorActivity : BaseActivity(), OnCheckedChangeListener, OnClickListener, CompoundButton.OnCheckedChangeListener {
|
||||
private var editNoVersionSuffixChanged: Boolean = false
|
||||
|
||||
private lateinit var apiConfig: CustomAPIConfig
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_api_editor)
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
apiConfig = savedInstanceState.getParcelable(EXTRA_API_CONFIG)
|
||||
} else {
|
||||
apiConfig = intent.getParcelableExtra(EXTRA_API_CONFIG) ?: kPreferences[defaultAPIConfigKey]
|
||||
}
|
||||
|
||||
editAuthType.setOnCheckedChangeListener(this)
|
||||
editNoVersionSuffix.setOnCheckedChangeListener(this)
|
||||
save.setOnClickListener(this)
|
||||
apiUrlFormatHelp.setOnClickListener(this)
|
||||
|
||||
loadDefaults.visibility = View.VISIBLE
|
||||
loadDefaults.setOnClickListener(this)
|
||||
|
||||
editApiUrlFormat.setText(apiConfig.apiUrlFormat)
|
||||
editSameOAuthSigningUrl.isChecked = apiConfig.isSameOAuthUrl
|
||||
editNoVersionSuffix.isChecked = apiConfig.isNoVersionSuffix
|
||||
editConsumerKey.setText(apiConfig.consumerKey)
|
||||
editConsumerSecret.setText(apiConfig.consumerSecret)
|
||||
|
||||
editAuthType.check(getAuthTypeId(apiConfig.credentialsType))
|
||||
if (editAuthType.checkedRadioButtonId == -1) {
|
||||
oauth.isChecked = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCheckedChanged(group: RadioGroup, checkedId: Int) {
|
||||
val authType = getCheckedAuthType(checkedId)
|
||||
val isOAuth = authType == Credentials.Type.OAUTH || authType == Credentials.Type.XAUTH
|
||||
|
@ -97,10 +130,6 @@ class APIEditorActivity : BaseActivity(), OnCheckedChangeListener, OnClickListen
|
|||
}
|
||||
}
|
||||
|
||||
private fun checkApiUrl(): Boolean {
|
||||
return MicroBlogAPIFactory.verifyApiFormat(editApiUrlFormat.text.toString())
|
||||
}
|
||||
|
||||
public override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putParcelable(EXTRA_API_CONFIG, createCustomAPIConfig())
|
||||
super.onSaveInstanceState(outState)
|
||||
|
@ -113,8 +142,22 @@ class APIEditorActivity : BaseActivity(), OnCheckedChangeListener, OnClickListen
|
|||
finish()
|
||||
}
|
||||
|
||||
|
||||
private fun checkApiUrl(): Boolean {
|
||||
return MicroBlogAPIFactory.verifyApiFormat(editApiUrlFormat.text.toString())
|
||||
}
|
||||
|
||||
private fun applyApiConfig() {
|
||||
editApiUrlFormat.setText(apiConfig.apiUrlFormat)
|
||||
editAuthType.check(getAuthTypeId(apiConfig.credentialsType))
|
||||
editSameOAuthSigningUrl.isChecked = apiConfig.isSameOAuthUrl
|
||||
editNoVersionSuffix.isChecked = apiConfig.isNoVersionSuffix
|
||||
editConsumerKey.setText(apiConfig.consumerKey)
|
||||
editConsumerSecret.setText(apiConfig.consumerSecret)
|
||||
}
|
||||
|
||||
private fun createCustomAPIConfig(): CustomAPIConfig {
|
||||
return CustomAPIConfig().apply {
|
||||
return apiConfig.apply {
|
||||
this.apiUrlFormat = editApiUrlFormat.text.toString()
|
||||
this.credentialsType = getCheckedAuthType(editAuthType.checkedRadioButtonId)
|
||||
this.isSameOAuthUrl = editSameOAuthSigningUrl.isChecked
|
||||
|
@ -124,53 +167,12 @@ class APIEditorActivity : BaseActivity(), OnCheckedChangeListener, OnClickListen
|
|||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_api_editor)
|
||||
|
||||
val apiConfig: CustomAPIConfig
|
||||
if (savedInstanceState != null) {
|
||||
apiConfig = savedInstanceState.getParcelable(EXTRA_API_CONFIG)
|
||||
} else {
|
||||
apiConfig = intent.getParcelableExtra(EXTRA_API_CONFIG) ?: kPreferences[defaultAPIConfigKey]
|
||||
}
|
||||
|
||||
editAuthType.setOnCheckedChangeListener(this)
|
||||
editNoVersionSuffix.setOnCheckedChangeListener(this)
|
||||
save.setOnClickListener(this)
|
||||
apiUrlFormatHelp.setOnClickListener(this)
|
||||
|
||||
loadDefaults.visibility = View.VISIBLE
|
||||
loadDefaults.setOnClickListener(this)
|
||||
|
||||
editApiUrlFormat.setText(apiConfig.apiUrlFormat)
|
||||
editSameOAuthSigningUrl.isChecked = apiConfig.isSameOAuthUrl
|
||||
editNoVersionSuffix.isChecked = apiConfig.isNoVersionSuffix
|
||||
editConsumerKey.setText(apiConfig.consumerKey)
|
||||
editConsumerSecret.setText(apiConfig.consumerSecret)
|
||||
|
||||
editAuthType.check(getAuthTypeId(apiConfig.credentialsType))
|
||||
if (editAuthType.checkedRadioButtonId == -1) {
|
||||
oauth.isChecked = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun setAPIConfig(apiConfig: CustomAPIConfig) {
|
||||
editApiUrlFormat.setText(apiConfig.apiUrlFormat)
|
||||
editAuthType.check(getAuthTypeId(apiConfig.credentialsType))
|
||||
editSameOAuthSigningUrl.isChecked = apiConfig.isSameOAuthUrl
|
||||
editNoVersionSuffix.isChecked = apiConfig.isNoVersionSuffix
|
||||
editConsumerKey.setText(apiConfig.consumerKey)
|
||||
editConsumerSecret.setText(apiConfig.consumerSecret)
|
||||
}
|
||||
|
||||
class LoadDefaultsChooserDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener,
|
||||
LoaderManager.LoaderCallbacks<List<CustomAPIConfig>?> {
|
||||
private lateinit var adapter: ArrayAdapter<CustomAPIConfig>
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val context = context
|
||||
val configs = CustomAPIConfig.listDefault(context)
|
||||
adapter = CustomAPIConfigArrayAdapter(context, configs)
|
||||
val builder = AlertDialog.Builder(context)
|
||||
|
@ -182,7 +184,9 @@ class APIEditorActivity : BaseActivity(), OnCheckedChangeListener, OnClickListen
|
|||
}
|
||||
|
||||
override fun onClick(dialog: DialogInterface, which: Int) {
|
||||
(activity as APIEditorActivity).setAPIConfig(adapter.getItem(which))
|
||||
val activity = activity as APIEditorActivity
|
||||
activity.apiConfig = adapter.getItem(which)
|
||||
activity.applyApiConfig()
|
||||
dismiss()
|
||||
}
|
||||
|
||||
|
@ -212,17 +216,16 @@ class APIEditorActivity : BaseActivity(), OnCheckedChangeListener, OnClickListen
|
|||
override fun loadInBackground(): List<CustomAPIConfig>? {
|
||||
val request = HttpRequest(GET.METHOD, DEFAULT_API_CONFIGS_URL,
|
||||
null, null, null)
|
||||
var response: HttpResponse? = null
|
||||
try {
|
||||
response = client.newCall(request).execute()
|
||||
if (response!!.isSuccessful) {
|
||||
val `is` = response.body.stream()
|
||||
return JsonSerializer.parseList(`is`, CustomAPIConfig::class.java)
|
||||
return client.newCall(request).execute().use { response ->
|
||||
if (response.isSuccessful) {
|
||||
return@use LoganSquare.parseList(response.body.stream(),
|
||||
CustomAPIConfig::class.java)
|
||||
}
|
||||
return@use null
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
// Ignore
|
||||
} finally {
|
||||
Utils.closeSilently(response)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.mariotaku.twidere.fragment.BaseFragment
|
|||
import org.mariotaku.twidere.fragment.ExtraFeaturesIntroductionDialogFragment
|
||||
import org.mariotaku.twidere.fragment.sync.SyncSettingsFragment
|
||||
import org.mariotaku.twidere.model.analyzer.PurchaseFinished
|
||||
import org.mariotaku.twidere.model.sync.SyncProviderEntry
|
||||
import org.mariotaku.twidere.util.Analyzer
|
||||
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
|
||||
import org.mariotaku.twidere.util.sync.SyncProviderInfoFactory
|
||||
|
@ -77,12 +78,14 @@ class SyncStatusFragment : BaseFragment() {
|
|||
}
|
||||
|
||||
private fun updateSyncSettingActions() {
|
||||
if (preferences[dataSyncProviderInfoKey] == null) {
|
||||
val providerInfo = preferences[dataSyncProviderInfoKey]
|
||||
if (providerInfo == null) {
|
||||
statusText.text = getText(R.string.message_sync_data_connect_hint)
|
||||
connectButton.visibility = View.VISIBLE
|
||||
settingsButton.visibility = View.GONE
|
||||
} else {
|
||||
statusText.text = getString(R.string.message_sync_data_synced_with_name, "Dropbox")
|
||||
val providerEntry = SyncProviderInfoFactory.getProviderEntry(context, providerInfo.type)!!
|
||||
statusText.text = getString(R.string.message_sync_data_synced_with_name, providerEntry.name)
|
||||
connectButton.visibility = View.GONE
|
||||
settingsButton.visibility = View.VISIBLE
|
||||
}
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
@ -44,8 +43,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:hint="@string/username"
|
||||
android:inputType="textEmailAddress"
|
||||
android:typeface="normal"
|
||||
android:maxLines="1"/>
|
||||
android:maxLines="1"
|
||||
android:typeface="normal" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editPassword"
|
||||
|
@ -54,49 +53,39 @@
|
|||
android:layout_marginTop="8dp"
|
||||
android:hint="@string/password"
|
||||
android:inputType="textPassword"
|
||||
android:typeface="normal"
|
||||
android:maxLines="1"/>
|
||||
android:maxLines="1"
|
||||
android:typeface="normal" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/signInSignUpContainer"
|
||||
<android.support.v7.widget.AppCompatButton
|
||||
android:id="@+id/signIn"
|
||||
style="?android:buttonStyleSmall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp">
|
||||
android:minHeight="@dimen/element_size_normal"
|
||||
android:text="@string/sign_in"
|
||||
app:backgroundTint="@color/material_light_green" />
|
||||
|
||||
<android.support.v7.widget.AppCompatButton
|
||||
android:id="@+id/signUp"
|
||||
style="?android:buttonStyleSmall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minHeight="@dimen/element_size_normal"
|
||||
android:text="@string/register"/>
|
||||
|
||||
<android.support.v7.widget.AppCompatButton
|
||||
android:id="@+id/signIn"
|
||||
style="?android:buttonStyleSmall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minHeight="@dimen/element_size_normal"
|
||||
android:text="@string/sign_in"
|
||||
app:backgroundTint="@color/material_light_green"/>
|
||||
|
||||
</LinearLayout>
|
||||
<Button
|
||||
android:id="@+id/signUp"
|
||||
style="?android:borderlessButtonStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start|center_vertical"
|
||||
android:minHeight="@dimen/element_size_xsmall"
|
||||
android:text="@string/register"
|
||||
android:textAppearance="?android:textAppearanceSmall" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/passwordSignIn"
|
||||
style="?android:borderlessButtonStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:clickable="true"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="36dp"
|
||||
android:text="@string/password_sign_in_twitter_only"
|
||||
android:textAppearance="?android:textAppearanceSmall"/>
|
||||
android:gravity="start|center_vertical"
|
||||
android:minHeight="@dimen/element_size_xsmall"
|
||||
android:text="@string/label_password_sign_in"
|
||||
android:textAppearance="?android:textAppearanceSmall" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
|
|
@ -888,6 +888,7 @@
|
|||
<string name="message_sync_data_synced_with_name">Twidere is now synced with <xliff:g example="ownCloud" id="name">%s</xliff:g></string>
|
||||
<string name="title_sync">Data sync</string>
|
||||
<string name="sync_provider_name_dropbox">Dropbox</string>
|
||||
<string name="sync_provider_name_google_drive">Google Drive</string>
|
||||
<!-- [verb] Disconnect from network storage -->
|
||||
<string name="action_sync_disconnect">Disconnect</string>
|
||||
<string name="action_sync_sync_now">Sync now</string>
|
||||
|
@ -904,4 +905,5 @@
|
|||
<string name="title_filters_subscription_url">URL</string>
|
||||
<string name="label_filters_subscription">Subscription</string>
|
||||
<string name="summary_interactions_not_available">Only available with official keys</string>
|
||||
<string name="label_password_sign_in">Password sign in</string>
|
||||
</resources>
|
Loading…
Reference in New Issue