abandoning old account code

This commit is contained in:
Mariotaku Lee 2016-12-03 23:45:13 +08:00
parent 907d377b9e
commit ddccb2c34b
19 changed files with 279 additions and 340 deletions

View File

@ -46,6 +46,7 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
String ACCOUNT_USER_DATA_USER = "user";
String ACCOUNT_USER_DATA_EXTRAS = "extras";
String ACCOUNT_USER_DATA_COLOR = "color";
String ACCOUNT_USER_DATA_POSITION = "position";
String LOGTAG = TWIDERE_APP_NAME;

View File

@ -0,0 +1,27 @@
package org.mariotaku.twidere.model;
import android.accounts.Account;
import android.support.annotation.ColorInt;
import org.mariotaku.twidere.annotation.AccountType;
import org.mariotaku.twidere.model.account.cred.Credentials;
/**
* Created by mariotaku on 2016/12/3.
*/
public class AccountDetails {
public Account account;
public UserKey key;
public Credentials credentials;
public ParcelableUser user;
@ColorInt
public int color;
public int position;
public boolean activated;
@AccountType
public String type;
@Credentials.Type
public String credentials_type;
}

View File

@ -42,6 +42,12 @@
<!-- Used for account management -->
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<!-- Used for account sync -->
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission android:name="org.mariotaku.twidere.permission.SHORTEN_STATUS"/>
<uses-permission android:name="org.mariotaku.twidere.permission.UPLOAD_MEDIA"/>
@ -465,13 +471,26 @@
<service
android:name=".service.BackgroundOperationService"
android:label="@string/label_background_operation_service"/>
<service android:name=".service.AccountAuthenticatorService">
<service
android:name=".service.AccountAuthenticatorService"
android:exported="true">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator"/>
android:resource="@xml/account_authenticator"/>
</service>
<service
android:name=".service.AccountSyncService"
android:exported="true"
android:process=":sync">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_adapter"/>
</service>
<service

View File

@ -1,68 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.loader;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.mariotaku.microblog.library.MicroBlog;
import org.mariotaku.microblog.library.MicroBlogException;
import org.mariotaku.microblog.library.twitter.model.IDs;
import org.mariotaku.microblog.library.twitter.model.Paging;
import org.mariotaku.microblog.library.twitter.model.ResponseList;
import org.mariotaku.microblog.library.twitter.model.User;
import org.mariotaku.twidere.annotation.AccountType;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
import java.util.List;
public class IncomingFriendshipsLoader extends CursorSupportUsersLoader {
public IncomingFriendshipsLoader(final Context context,@Nullable final UserKey accountKey,
@Nullable final List<ParcelableUser> data, boolean fromUser) {
super(context, accountKey, data, fromUser);
}
@NonNull
@Override
protected IDs getIDs(@NonNull final MicroBlog twitter, @NonNull ParcelableCredentials credentials, @NonNull final Paging paging) throws MicroBlogException {
return twitter.getIncomingFriendships(paging);
}
@NonNull
@Override
protected ResponseList<User> getCursoredUsers(@NonNull MicroBlog twitter, @NonNull ParcelableCredentials credentials, @NonNull Paging paging) throws MicroBlogException {
return twitter.getFriendshipsRequests(paging);
}
@Override
protected boolean useIDs(@NonNull ParcelableCredentials credentials) {
switch (ParcelableAccountUtils.getAccountType(credentials)) {
case AccountType.FANFOU: {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,61 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.loader
import android.content.Context
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.model.IDs
import org.mariotaku.microblog.library.twitter.model.Paging
import org.mariotaku.microblog.library.twitter.model.ResponseList
import org.mariotaku.microblog.library.twitter.model.User
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.model.ParcelableCredentials
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.ParcelableAccountUtils
class IncomingFriendshipsLoader(
context: Context,
accountKey: UserKey?,
data: List<ParcelableUser>?,
fromUser: Boolean
) : CursorSupportUsersLoader(context, accountKey, data, fromUser) {
@Throws(MicroBlogException::class)
override fun getIDs(twitter: MicroBlog, credentials: ParcelableCredentials, paging: Paging): IDs {
return twitter.getIncomingFriendships(paging)
}
@Throws(MicroBlogException::class)
override fun getCursoredUsers(twitter: MicroBlog, credentials: ParcelableCredentials, paging: Paging): ResponseList<User> {
return twitter.getFriendshipsRequests(paging)
}
override fun useIDs(credentials: ParcelableCredentials): Boolean {
when (ParcelableAccountUtils.getAccountType(credentials)) {
AccountType.FANFOU -> {
return false
}
}
return true
}
}

View File

@ -6,6 +6,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.mariotaku.twidere.extension.AccountExtensionsKt;
import org.mariotaku.twidere.model.AccountDetails;
import org.mariotaku.twidere.model.UserKey;
import static org.mariotaku.twidere.TwidereConstants.ACCOUNT_TYPE;
@ -30,4 +31,26 @@ public class AccountUtils {
//noinspection MissingPermission
return am.getAccountsByType(ACCOUNT_TYPE);
}
public static AccountDetails[] getAllAccountDetails(@NonNull AccountManager am, @NonNull Account[] accounts) {
AccountDetails[] details = new AccountDetails[accounts.length];
for (int i = 0; i < accounts.length; i++) {
details[i] = getAccountDetails(am, accounts[i]);
}
return details;
}
public static AccountDetails getAccountDetails(@NonNull AccountManager am, @NonNull Account account) {
AccountDetails details = new AccountDetails();
details.key = AccountExtensionsKt.getAccountKey(account, am);
details.account = account;
details.color = AccountExtensionsKt.getColor(account, am);
details.position = AccountExtensionsKt.getPosition(account, am);
details.credentials = AccountExtensionsKt.getCredentials(account, am);
details.user = AccountExtensionsKt.getAccountUser(account, am);
details.activated = AccountExtensionsKt.isAccountActivated(account, am);
details.type = AccountExtensionsKt.getAccountType(account, am);
details.credentials_type = AccountExtensionsKt.getCredentialsType(account, am);
return details;
}
}

View File

@ -75,7 +75,7 @@ interface GeneralComponent {
fun inject(obj: BaseRecyclerViewAdapter<RecyclerView.ViewHolder>)
fun inject(obj: AccountsAdapter)
fun inject(obj: AccountDetailsAdapter)
fun inject(obj: ComposeAutoCompleteAdapter)

View File

@ -12,6 +12,14 @@ fun String.toLong(def: Long): Long {
}
}
fun String.toInt(def: Int): Int {
try {
return toInt()
} catch (e: NumberFormatException) {
return def
}
}
fun String.toDoubleOrNull(): Double? {
try {
return toDouble()

View File

@ -19,14 +19,9 @@
package org.mariotaku.twidere.activity
import android.accounts.AccountManager
import android.app.Activity
import android.app.LoaderManager.LoaderCallbacks
import android.content.CursorLoader
import android.content.Intent
import android.content.Loader
import android.database.ContentObserver
import android.database.Cursor
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.view.View.OnClickListener
@ -36,37 +31,18 @@ import android.widget.ListView
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_account_selector.*
import org.mariotaku.ktextension.toTypedArray
import org.mariotaku.sqliteqb.library.Columns
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.adapter.AccountsAdapter
import org.mariotaku.twidere.adapter.AccountDetailsAdapter
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.app.TwidereApplication
import org.mariotaku.twidere.model.ParcelableAccount
import org.mariotaku.twidere.model.ParcelableCredentials
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts
import java.util.*
import org.mariotaku.twidere.model.account.cred.Credentials
import org.mariotaku.twidere.model.util.AccountUtils
class AccountSelectorActivity : BaseActivity(), LoaderCallbacks<Cursor?>, OnClickListener, OnItemClickListener {
class AccountSelectorActivity : BaseActivity(), OnClickListener, OnItemClickListener {
private val mContentObserver = object : ContentObserver(null) {
override fun onChange(selfChange: Boolean) {
onChange(selfChange, null)
}
override fun onChange(selfChange: Boolean, uri: Uri?) {
// Handle change.
if (!isFinishing) {
loaderManager.restartLoader(0, null, this@AccountSelectorActivity)
}
}
}
private var adapter: AccountsAdapter? = null
private var adapter: AccountDetailsAdapter? = null
private var firstCreated: Boolean = false
@ -74,7 +50,7 @@ class AccountSelectorActivity : BaseActivity(), LoaderCallbacks<Cursor?>, OnClic
when (view.id) {
R.id.save -> {
val checkedIds = accountsList.checkedItemIds
if (checkedIds.size == 0 && !isSelectNoneAllowed) {
if (checkedIds.isEmpty() && !isSelectNoneAllowed) {
Toast.makeText(this, R.string.no_account_selected, Toast.LENGTH_SHORT).show()
return
}
@ -86,76 +62,20 @@ class AccountSelectorActivity : BaseActivity(), LoaderCallbacks<Cursor?>, OnClic
}
}
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor?> {
val conditions = ArrayList<Expression>()
val conditionArgs = ArrayList<String>()
if (isOAuthOnly) {
conditions.add(Expression.equalsArgs(Accounts.AUTH_TYPE))
conditionArgs.add(ParcelableCredentials.AuthTypeInt.OAUTH.toString())
}
val accountHost = accountHost
if (accountHost != null) {
if (USER_TYPE_TWITTER_COM == accountHost) {
conditions.add(Expression.or(
Expression.equalsArgs(Accounts.ACCOUNT_TYPE),
Expression.isNull(Columns.Column(Accounts.ACCOUNT_TYPE)),
Expression.likeRaw(Columns.Column(Accounts.ACCOUNT_KEY), "'%@'||?"),
Expression.notLikeRaw(Columns.Column(Accounts.ACCOUNT_KEY), "'%@%'")))
conditionArgs.add(AccountType.TWITTER)
conditionArgs.add(accountHost)
} else {
conditions.add(Expression.likeRaw(Columns.Column(Accounts.ACCOUNT_KEY), "'%@'||?"))
conditionArgs.add(accountHost)
}
}
val where: String?
val whereArgs: Array<String>?
if (conditions.isEmpty()) {
where = null
whereArgs = null
} else {
where = Expression.and(*conditions.toTypedArray()).sql
whereArgs = conditionArgs.toTypedArray()
}
return CursorLoader(this, Accounts.CONTENT_URI, Accounts.COLUMNS, where, whereArgs,
Accounts.SORT_POSITION)
}
override fun onLoadFinished(loader: Loader<Cursor?>, cursor: Cursor?) {
val adapter = adapter!!
adapter.swapCursor(cursor)
if (cursor != null && firstCreated) {
val activatedKeys = intentExtraIds
for (i in 0..adapter.count - 1) {
accountsList.setItemChecked(i, activatedKeys?.contains(adapter.getAccount(i)!!.account_key) ?: false)
}
}
if (adapter.count == 1 && shouldSelectOnlyItem()) {
selectSingleAccount(0)
} else if (adapter.isEmpty) {
Toast.makeText(this, R.string.no_account, Toast.LENGTH_SHORT).show()
finish()
}
}
override fun onLoaderReset(loader: Loader<Cursor?>) {
adapter!!.swapCursor(null)
}
override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) {
selectSingleAccount(position)
}
fun selectSingleAccount(position: Int) {
val adapter = adapter!!
val account = adapter.getAccount(position)
val account = adapter.getItem(position)
val data = Intent()
data.putExtra(EXTRA_ID, account!!.account_key.id)
data.putExtra(EXTRA_ACCOUNT_KEY, account.account_key)
data.putExtra(EXTRA_ID, account.key.id)
data.putExtra(EXTRA_ACCOUNT_KEY, account.key)
val startIntent = startIntent
if (startIntent != null) {
startIntent.putExtra(EXTRA_ACCOUNT_KEY, account.account_key)
startIntent.putExtra(EXTRA_ACCOUNT_KEY, account.key)
startActivity(startIntent)
}
@ -167,34 +87,30 @@ class AccountSelectorActivity : BaseActivity(), LoaderCallbacks<Cursor?>, OnClic
super.onCreate(savedInstanceState)
firstCreated = savedInstanceState == null
setContentView(R.layout.activity_account_selector)
adapter = AccountsAdapter(this)
val isSingleSelection = isSingleSelection
adapter = AccountDetailsAdapter(this).apply {
setSwitchEnabled(isSingleSelection)
setSortEnabled(false)
isProfileImageDisplayed = preferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true)
val am = AccountManager.get(context)
val allAccountDetails = AccountUtils.getAllAccountDetails(am, AccountUtils.getAccounts(am))
addAll(allAccountDetails.filter {
if (isOAuthOnly && it.credentials_type != Credentials.Type.OAUTH && it.credentials_type != Credentials.Type.XAUTH) {
return@filter false
}
if (USER_TYPE_TWITTER_COM == accountHost) {
if (it.key.host == null || it.type == AccountType.TWITTER) return@filter false
} else if (accountHost != null) {
if (accountHost != it.key.host) return@filter false
}
return@filter true
})
}
accountsList.choiceMode = if (isSingleSelection) ListView.CHOICE_MODE_NONE else ListView.CHOICE_MODE_MULTIPLE
adapter!!.setSwitchEnabled(!isSingleSelection)
adapter!!.setSortEnabled(false)
if (isSingleSelection) {
accountsList.onItemClickListener = this
}
selectAccountButtons.visibility = if (isSingleSelection) View.GONE else View.VISIBLE
accountsList.adapter = adapter
loaderManager.initLoader(0, null, this)
}
override fun onStart() {
super.onStart()
contentResolver.registerContentObserver(Accounts.CONTENT_URI, true, mContentObserver)
}
override fun onResume() {
super.onResume()
val displayProfileImage = preferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true)
adapter!!.isProfileImageDisplayed = displayProfileImage
}
override fun onStop() {
contentResolver.unregisterContentObserver(mContentObserver)
super.onStop()
}
private val intentExtraIds: Array<UserKey>?

View File

@ -132,14 +132,8 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
homeMenu.closeDrawers()
}
val activatedAccountKeys: Array<UserKey>
get() {
val fragment = leftDrawerFragment
if (fragment is AccountsDashboardFragment) {
return fragment.activatedAccountIds
}
return DataStoreUtils.getActivatedAccountKeys(this)
}
private val activatedAccountKeys: Array<UserKey>
get() = DataStoreUtils.getActivatedAccountKeys(this)
override val currentVisibleFragment: Fragment?
get() {

View File

@ -20,44 +20,31 @@
package org.mariotaku.twidere.adapter
import android.content.Context
import android.database.Cursor
import android.view.View
import android.view.ViewGroup
import android.widget.CompoundButton
import com.mobeta.android.dslv.SimpleDragSortCursorAdapter
import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.iface.IBaseAdapter
import org.mariotaku.twidere.model.ParcelableAccount
import org.mariotaku.twidere.model.ParcelableAccountCursorIndices
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.ParcelableAccountUtils
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts
import org.mariotaku.twidere.util.JsonSerializer
import org.mariotaku.twidere.util.MediaLoaderWrapper
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
import org.mariotaku.twidere.view.holder.AccountViewHolder
import javax.inject.Inject
class AccountsAdapter(context: Context) : SimpleDragSortCursorAdapter(context,
R.layout.list_item_account, null, arrayOf(Accounts.NAME),
intArrayOf(android.R.id.text1), 0), IBaseAdapter {
class AccountDetailsAdapter(context: Context) : ArrayAdapter<AccountDetails>(context, R.layout.list_item_account), IBaseAdapter {
@Inject
lateinit override var mediaLoader: MediaLoaderWrapper
override var isProfileImageDisplayed: Boolean = false
private var sortEnabled: Boolean = false
private var indices: ParcelableAccountCursorIndices? = null
private var switchEnabled: Boolean = false
private var onAccountToggleListener: OnAccountToggleListener? = null
private val mCheckedChangeListener = CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
val tag = buttonView.tag
if (tag !is String) return@OnCheckedChangeListener
private val checkedChangeListener = CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
val tag = buttonView.tag as? String ?: return@OnCheckedChangeListener
val accountKey = UserKey.valueOf(tag) ?: return@OnCheckedChangeListener
onAccountToggleListener?.onAccountToggle(accountKey, isChecked)
}
@ -66,43 +53,28 @@ class AccountsAdapter(context: Context) : SimpleDragSortCursorAdapter(context,
GeneralComponentHelper.build(context).inject(this)
}
fun getAccount(position: Int): ParcelableAccount? {
val c = cursor
if (c == null || c.isClosed || !c.moveToPosition(position)) return null
return indices!!.newObject(c)
}
override fun bindView(view: View, context: Context?, cursor: Cursor) {
val indices = indices!!
val color = cursor.getInt(indices.color)
val holder = view.tag as AccountViewHolder
holder.screenName.text = String.format("@%s", cursor.getString(indices.screen_name))
holder.setAccountColor(color)
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view = super.getView(position, convertView, parent)
val holder = view.tag as? AccountViewHolder ?: run {
val h = AccountViewHolder(view)
view.tag = h
return@run h
}
val details = getItem(position)
holder.screenName.text = String.format("@%s", details.user.screen_name)
holder.setAccountColor(details.color)
if (isProfileImageDisplayed) {
val user = JsonSerializer.parse(cursor.getString(indices.account_user), ParcelableUser::class.java)
if (user != null) {
mediaLoader.displayProfileImage(holder.profileImage, user)
} else {
mediaLoader.displayProfileImage(holder.profileImage,
cursor.getString(indices.profile_image_url))
}
mediaLoader.displayProfileImage(holder.profileImage, details.user)
} else {
mediaLoader.cancelDisplayTask(holder.profileImage)
}
val accountType = cursor.getString(indices.account_type)
val accountType = details.type
holder.accountType.setImageResource(ParcelableAccountUtils.getAccountTypeIcon(accountType))
holder.toggle.isChecked = cursor.getShort(indices.is_activated).toInt() == 1
holder.toggle.setOnCheckedChangeListener(mCheckedChangeListener)
holder.toggle.tag = cursor.getString(indices.account_key)
holder.toggle.isChecked = details.activated
holder.toggle.setOnCheckedChangeListener(checkedChangeListener)
holder.toggle.tag = details.user.key
holder.toggleContainer.visibility = if (switchEnabled) View.VISIBLE else View.GONE
holder.setSortEnabled(sortEnabled)
super.bindView(view, context, cursor)
}
override fun newView(context: Context?, cursor: Cursor?, parent: ViewGroup): View {
val view = super.newView(context, cursor, parent)
val holder = AccountViewHolder(view)
view.tag = holder
return view
}
@ -141,13 +113,6 @@ class AccountsAdapter(context: Context) : SimpleDragSortCursorAdapter(context,
onAccountToggleListener = listener
}
override fun swapCursor(cursor: Cursor?): Cursor? {
if (cursor != null) {
indices = ParcelableAccountCursorIndices(cursor)
}
return super.swapCursor(cursor)
}
fun setSortEnabled(sortEnabled: Boolean) {
if (this.sortEnabled == sortEnabled) return
this.sortEnabled = sortEnabled

View File

@ -5,6 +5,7 @@ import android.accounts.AccountManager
import android.graphics.Color
import android.support.annotation.ColorInt
import com.bluelinelabs.logansquare.LoganSquare
import org.mariotaku.ktextension.toInt
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.model.ParcelableUser
@ -16,6 +17,7 @@ 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.util.toHexColor
fun Account.getCredentials(am: AccountManager): Credentials {
@ -41,6 +43,10 @@ fun Account.getColor(am: AccountManager): Int {
return Color.parseColor(am.getUserData(this, ACCOUNT_USER_DATA_COLOR))
}
fun Account.getPosition(am: AccountManager): Int {
return am.getUserData(this, ACCOUNT_USER_DATA_POSITION).toInt(-1)
}
fun Account.getAccountExtras(am: AccountManager): AccountExtras? {
val json = am.getUserData(this, ACCOUNT_USER_DATA_EXTRAS) ?: return null
when (getAccountType(am)) {
@ -63,6 +69,11 @@ fun Account.isAccountActivated(am: AccountManager): Boolean {
return am.getUserData(this, ACCOUNT_USER_DATA_ACTIVATED).orEmpty().toBoolean()
}
fun Account.setColor(am: AccountManager, color: Int) {
am.setUserData(this, ACCOUNT_USER_DATA_COLOR, toHexColor(color))
}
private fun parseCredentials(authToken: String, @Credentials.Type authType: String): Credentials {
when (authType) {
Credentials.Type.OAUTH, Credentials.Type.XAUTH -> return LoganSquare.parse(authToken, OAuthCredentials::class.java)

View File

@ -1,5 +1,6 @@
package org.mariotaku.twidere.fragment
import android.accounts.AccountManager
import android.app.Activity
import android.app.AlertDialog
import android.app.Dialog
@ -8,19 +9,13 @@ import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.database.Cursor
import android.graphics.Color
import android.os.Bundle
import android.support.v4.app.LoaderManager.LoaderCallbacks
import android.support.v4.content.CursorLoader
import android.support.v4.content.Loader
import android.support.v4.util.SimpleArrayMap
import android.view.*
import android.view.ContextMenu.ContextMenuInfo
import android.widget.AbsListView
import android.widget.AdapterView
import android.widget.AdapterView.AdapterContextMenuInfo
import com.mobeta.android.dslv.DragSortListView.DropListener
import kotlinx.android.synthetic.main.layout_draggable_list_with_empty_view.*
import org.mariotaku.sqliteqb.library.ArgsArray
import org.mariotaku.sqliteqb.library.Columns
@ -29,10 +24,11 @@ import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.ColorPickerDialogActivity
import org.mariotaku.twidere.activity.SignInActivity
import org.mariotaku.twidere.adapter.AccountsAdapter
import org.mariotaku.twidere.adapter.AccountDetailsAdapter
import org.mariotaku.twidere.annotation.Referral
import org.mariotaku.twidere.constant.SharedPreferenceConstants
import org.mariotaku.twidere.model.ParcelableAccount
import org.mariotaku.twidere.extension.setColor
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.provider.TwidereDataStore.*
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.Inbox
@ -45,10 +41,11 @@ import org.mariotaku.twidere.util.collection.CompactHashSet
/**
* Created by mariotaku on 14/10/26.
*/
class AccountsManagerFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>, DropListener, OnSharedPreferenceChangeListener, AdapterView.OnItemClickListener, AccountsAdapter.OnAccountToggleListener {
class AccountsManagerFragment : BaseSupportFragment(), OnSharedPreferenceChangeListener,
AdapterView.OnItemClickListener, AccountDetailsAdapter.OnAccountToggleListener {
private var adapter: AccountsAdapter? = null
private var selectedAccount: ParcelableAccount? = null
private var adapter: AccountDetailsAdapter? = null
private var selectedAccount: AccountDetails? = null
private val activatedState = SimpleArrayMap<UserKey, Boolean>()
@ -57,20 +54,18 @@ class AccountsManagerFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>,
setHasOptionsMenu(true)
val activity = activity
preferences.registerOnSharedPreferenceChangeListener(this)
adapter = AccountsAdapter(activity)
adapter = AccountDetailsAdapter(activity)
Utils.configBaseAdapter(activity, adapter)
adapter!!.setSortEnabled(true)
adapter!!.setSwitchEnabled(true)
adapter!!.setOnAccountToggleListener(this)
listView.adapter = adapter
listView.isDragEnabled = true
listView.setDropListener(this)
listView.onItemClickListener = this
listView.setOnCreateContextMenuListener(this)
listView.emptyView = emptyView
emptyText.setText(R.string.no_account)
emptyIcon.setImageResource(R.drawable.ic_info_error_generic)
loaderManager.initLoader(0, null, this)
setListShown(false)
}
@ -79,12 +74,8 @@ class AccountsManagerFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>,
REQUEST_SET_COLOR -> {
if (resultCode != Activity.RESULT_OK || data == null || selectedAccount == null)
return
val values = ContentValues()
values.put(Accounts.COLOR, data.getIntExtra(EXTRA_COLOR, Color.WHITE))
val where = Expression.equalsArgs(Accounts.ACCOUNT_KEY)
val whereArgs = arrayOf(selectedAccount!!.account_key.toString())
val cr = contentResolver
cr.update(Accounts.CONTENT_URI, values, where.sql, whereArgs)
val am = AccountManager.get(context)
selectedAccount?.account?.setColor(am, data.getIntExtra(EXTRA_COLOR, Color.WHITE))
return
}
}
@ -107,22 +98,21 @@ class AccountsManagerFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>,
}
override fun onContextItemSelected(item: MenuItem?): Boolean {
val menuInfo = item!!.menuInfo
if (menuInfo !is AdapterContextMenuInfo) return false
val account = adapter!!.getAccount(menuInfo.position)
selectedAccount = account
if (account == null) return false
val menuInfo = item!!.menuInfo as? AdapterContextMenuInfo ?: return false
val details = adapter!!.getItem(menuInfo.position)
selectedAccount = details
if (details == null) return false
when (item.itemId) {
R.id.set_color -> {
val intent = Intent(activity, ColorPickerDialogActivity::class.java)
intent.putExtra(EXTRA_COLOR, account.color)
intent.putExtra(EXTRA_COLOR, details.color)
intent.putExtra(EXTRA_ALPHA_SLIDER, false)
startActivityForResult(intent, REQUEST_SET_COLOR)
}
R.id.delete -> {
val f = AccountDeletionDialogFragment()
val args = Bundle()
args.putLong(EXTRA_ID, account.id)
args.putParcelable(EXTRA_ACCOUNT, details.account)
f.arguments = args
f.show(childFragmentManager, FRAGMENT_TAG_ACCOUNT_DELETION)
}
@ -131,17 +121,10 @@ class AccountsManagerFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>,
}
override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) {
val context = context ?: return
val account = adapter!!.getAccount(position)
if (account!!.account_user != null) {
IntentUtils.openUserProfile(context, account.account_user!!, null,
preferences.getBoolean(SharedPreferenceConstants.KEY_NEW_DOCUMENT_API),
Referral.SELF_PROFILE)
} else {
IntentUtils.openUserProfile(context, account.account_key, account.account_key,
account.screen_name, null, preferences.getBoolean(SharedPreferenceConstants.KEY_NEW_DOCUMENT_API),
Referral.SELF_PROFILE)
}
val account = adapter!!.getItem(position)
IntentUtils.openUserProfile(context, account.user, null,
preferences.getBoolean(SharedPreferenceConstants.KEY_NEW_DOCUMENT_API),
Referral.SELF_PROFILE)
}
override fun onStop() {
@ -177,8 +160,8 @@ class AccountsManagerFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>,
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenuInfo) {
if (menuInfo !is AdapterContextMenuInfo) return
val account = adapter!!.getAccount(menuInfo.position)
menu.setHeaderTitle(account!!.name)
val account = adapter!!.getItem(menuInfo.position)
menu.setHeaderTitle(account!!.user.name)
val inflater = MenuInflater(v.context)
inflater.inflate(R.menu.action_manager_account, menu)
}
@ -197,43 +180,8 @@ class AccountsManagerFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>,
progressContainer.visibility = if (shown) View.GONE else View.VISIBLE
}
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor?> {
val uri = Accounts.CONTENT_URI
return CursorLoader(activity, uri, Accounts.COLUMNS, null, null, Accounts.SORT_POSITION)
}
override fun onLoadFinished(loader: Loader<Cursor?>, cursor: Cursor?) {
setListShown(true)
adapter!!.changeCursor(cursor)
}
override fun onLoaderReset(loader: Loader<Cursor?>) {
adapter!!.changeCursor(null)
}
override fun drop(from: Int, to: Int) {
adapter!!.drop(from, to)
if (listView.choiceMode != AbsListView.CHOICE_MODE_NONE) {
listView.moveCheckState(from, to)
}
saveAccountPositions()
}
private fun saveAccountPositions() {
val cr = contentResolver
val positions = adapter!!.cursorPositions
val c = adapter!!.cursor
if (positions != null && c != null && !c.isClosed) {
val idIdx = c.getColumnIndex(Accounts._ID)
for (i in 0 until positions.size) {
c.moveToPosition(positions[i])
val id = c.getLong(idIdx)
val values = ContentValues()
values.put(Accounts.SORT_POSITION, i)
val where = Expression.equals(Accounts._ID, id)
cr.update(Accounts.CONTENT_URI, values, where.sql, null)
}
}
}
override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String) {

View File

@ -32,7 +32,6 @@ import org.mariotaku.sqliteqb.library.ArgsArray
import org.mariotaku.sqliteqb.library.Columns.Column
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.HomeActivity
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_FROM_USER
@ -110,15 +109,10 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
override val accountKeys: Array<UserKey>
get() {
val context = context!!
val args = arguments
val accountKeys = Utils.getAccountKeys(context, args)
val accountKeys = Utils.getAccountKeys(context, arguments)
if (accountKeys != null) {
return accountKeys
}
if (context is HomeActivity) {
return context.activatedAccountKeys
}
return DataStoreUtils.getActivatedAccountKeys(context)
}

View File

@ -31,7 +31,6 @@ import org.mariotaku.sqliteqb.library.ArgsArray
import org.mariotaku.sqliteqb.library.Columns.Column
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.HomeActivity
import org.mariotaku.twidere.adapter.ListParcelableStatusesAdapter
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
@ -122,14 +121,10 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() {
override val accountKeys: Array<UserKey>
get() {
val args = arguments
val context = context
val accountKeys = Utils.getAccountKeys(context, args)
if (accountKeys != null) {
return accountKeys
}
if (context is HomeActivity) {
return context.activatedAccountKeys
}
return DataStoreUtils.getActivatedAccountKeys(context)
}

View File

@ -40,7 +40,6 @@ import org.mariotaku.sqliteqb.library.Columns.Column
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.NOTIFICATION_ID_DIRECT_MESSAGES
import org.mariotaku.twidere.activity.HomeActivity
import org.mariotaku.twidere.activity.LinkHandlerActivity
import org.mariotaku.twidere.activity.iface.IControlBarActivity
import org.mariotaku.twidere.adapter.MessageEntriesAdapter
@ -290,11 +289,7 @@ class DirectMessagesFragment : AbsContentListRecyclerViewFragment<MessageEntries
if (accountKeys != null) {
return accountKeys
}
val activity = activity
if (activity is HomeActivity) {
return activity.activatedAccountKeys
}
return DataStoreUtils.getActivatedAccountKeys(getActivity())
return DataStoreUtils.getActivatedAccountKeys(activity)
}
private fun addReadPosition(firstVisibleItem: Int) {

View File

@ -0,0 +1,41 @@
package org.mariotaku.twidere.service
import android.accounts.Account
import android.app.Service
import android.content.*
import android.os.Bundle
import android.os.IBinder
/**
* Created by mariotaku on 2016/12/3.
*/
class AccountSyncService : Service() {
override fun onCreate() {
/*
* Create the sync adapter as a singleton.
* Set the sync adapter as syncable
* Disallow parallel syncs
*/
synchronized(sSyncAdapterLock) {
syncAdapter = SyncAdapter(applicationContext, true)
}
}
override fun onBind(intent: Intent?): IBinder {
return syncAdapter.syncAdapterBinder
}
internal class SyncAdapter(context: Context, autoInitialize: Boolean) : AbstractThreadedSyncAdapter(context, autoInitialize) {
override fun onPerformSync(account: Account, extras: Bundle, authority: String,
provider: ContentProviderClient, syncResult: SyncResult) {
}
}
companion object {
private lateinit var syncAdapter: SyncAdapter
private val sSyncAdapterLock = Any()
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter
xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="org.mariotaku.twidere.account"
android:allowParallelSyncs="false"
android:contentAuthority="twidere"
android:isAlwaysSyncable="true"
android:supportsUploading="true"
android:userVisible="false"/>