diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 27d129af..68419415 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -48,11 +48,6 @@ - - @@ -78,6 +73,15 @@ + + + + + + + + accounts = accountManager.getAllAccountsOrderedByActive(); + AccountEntity activeAccount = accountManager.getActiveAccount(); + + switch(accounts.size()) { + case 1: + listener.onAccountSelected(activeAccount); + return; + case 2: + if (!showActiveAccount) { + for (AccountEntity account : accounts) { + if (activeAccount != account) { + listener.onAccountSelected(account); + return; + } + } + } + break; + } + + if (!showActiveAccount && activeAccount != null) { + accounts.remove(activeAccount); + } + AccountSelectionAdapter adapter = new AccountSelectionAdapter(this); + adapter.addAll(accounts); + + new AlertDialog.Builder(this) + .setTitle(dialogTitle) + .setAdapter(adapter, (dialogInterface, index) -> listener.onAccountSelected(accounts.get(index))) + .show(); + } } diff --git a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java index 8fb3cff6..30fcdf71 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java @@ -1615,6 +1615,11 @@ public final class ComposeActivity return maximumTootCharacters; } + static boolean canHandleMimeType(@Nullable String mimeType) { + return (mimeType != null && + (mimeType.startsWith("image/") || mimeType.startsWith("video/") || mimeType.equals("text/plain"))); + } + public static final class QueuedMedia { Type type; ProgressImageView preview; diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java index 19ef6023..e2110c8c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java @@ -108,6 +108,14 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut private Drawer drawer; private ViewPager viewPager; + private void forwardShare(Intent intent) { + Intent composeIntent = new Intent(this, ComposeActivity.class); + composeIntent.setAction(intent.getAction()); + composeIntent.setType(intent.getType()); + composeIntent.putExtras(intent); + startActivity(composeIntent); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -117,18 +125,40 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut if (intent != null) { long accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1); + boolean accountRequested = (accountId != -1); - if (accountId != -1) { - // user clicked a notification, show notification tab and switch user if necessary - tabPosition = 1; + if (accountRequested) { AccountEntity account = accountManager.getActiveAccount(); - if (account == null || accountId != account.getId()) { accountManager.setActiveAccount(accountId); } } - } + if (ComposeActivity.canHandleMimeType(intent.getType())) { + // Sharing to Tusky from an external app + if (accountRequested) { + // The correct account is already active + forwardShare(intent); + } else { + // No account was provided, show the chooser + showAccountChooserDialog(getString(R.string.action_share_as), true, account -> { + long requestedId = account.getId(); + AccountEntity activeAccount = accountManager.getActiveAccount(); + if (activeAccount != null && requestedId == activeAccount.getId()) { + // The correct account is already active + forwardShare(intent); + } else { + // A different account was requested, restart the activity + intent.putExtra(NotificationHelper.ACCOUNT_ID, requestedId); + changeAccount(requestedId, intent); + } + }); + } + } else if (accountRequested) { + // user clicked a notification, show notification tab and switch user if necessary + tabPosition = 1; + } + } setContentView(R.layout.activity_main); composeButton = findViewById(R.id.floating_btn); @@ -420,17 +450,22 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut return true; } //change Account - changeAccount(profile.getIdentifier()); + changeAccount(profile.getIdentifier(), null); return false; } - private void changeAccount(long newSelectedId) { + private void changeAccount(long newSelectedId, @Nullable Intent forward) { cacheUpdater.stop(); accountManager.setActiveAccount(newSelectedId); Intent intent = new Intent(this, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + if (forward != null) { + intent.setType(forward.getType()); + intent.setAction(forward.getAction()); + intent.putExtras(forward); + } startActivity(intent); finishWithoutSlideOutAnimation(); diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt new file mode 100644 index 00000000..7db9a643 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt @@ -0,0 +1,58 @@ +/* Copyright 2019 Levi Bard + * + * This file is a part of Tusky. + * + * 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. + * + * Tusky 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 Tusky; if not, + * see . */ + +package com.keylesspalace.tusky.adapter + +import android.content.Context +import android.text.TextUtils +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import com.keylesspalace.tusky.R +import com.keylesspalace.tusky.db.AccountEntity +import com.keylesspalace.tusky.util.CustomEmojiHelper +import com.squareup.picasso.Picasso + +import kotlinx.android.synthetic.main.item_autocomplete_account.view.* + +class AccountSelectionAdapter(context: Context): ArrayAdapter(context, R.layout.item_autocomplete_account) { + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var view = convertView + + if (convertView == null) { + val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater + view = layoutInflater.inflate(R.layout.item_autocomplete_account, parent, false) + } + view!! + + val account = getItem(position) + if (account != null) { + val username = view.username + val displayName = view.display_name + val avatar = view.avatar + username.text = account.fullName + displayName.text = CustomEmojiHelper.emojifyString(account.displayName, account.emojis, displayName) + if (!TextUtils.isEmpty(account.profilePictureUrl)) { + Picasso.with(context) + .load(account.profilePictureUrl) + .placeholder(R.drawable.avatar_default) + .into(avatar) + } + } + + return view + } +} \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt index 9015b5f2..327ef284 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.di +import com.keylesspalace.tusky.service.AccountChooserService import com.keylesspalace.tusky.service.SendTootService import dagger.Module import dagger.android.ContributesAndroidInjector @@ -23,4 +24,6 @@ import dagger.android.ContributesAndroidInjector abstract class ServicesModule { @ContributesAndroidInjector abstract fun contributesSendTootService(): SendTootService + @ContributesAndroidInjector + abstract fun contributesAccountChooserService(): AccountChooserService } \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java index ea144cfb..f14abd73 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java @@ -337,26 +337,7 @@ public abstract class SFragment extends BaseFragment { } private void showOpenAsDialog(String statusUrl, CharSequence dialogTitle) { - List accounts = accountManager.getAllAccountsOrderedByActive(); - AccountEntity activeAccount = accountManager.getActiveAccount(); - - if (accounts.size() == 2) { - for (AccountEntity account : accounts) { - if (activeAccount != account) { - openAsAccount(statusUrl, account); - break; - } - } - } else { - accounts.remove(activeAccount); - CharSequence[] accountNames = new CharSequence[accounts.size()]; - for (int i = 0; i < accounts.size(); ++i) { - accountNames[i] = accounts.get(i).getFullName(); - } - new AlertDialog.Builder(getActivity()) - .setTitle(dialogTitle) - .setItems(accountNames, (dialogInterface, index) -> openAsAccount(statusUrl, accounts.get(index))) - .show(); - } + BaseActivity activity = (BaseActivity)getActivity(); + activity.showAccountChooserDialog(dialogTitle, false, account -> openAsAccount(statusUrl, account)); } } diff --git a/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountSelectionListener.kt b/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountSelectionListener.kt new file mode 100644 index 00000000..04b1ebd2 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountSelectionListener.kt @@ -0,0 +1,22 @@ +/* Copyright 2019 Levi Bard + * + * This file is a part of Tusky. + * + * 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. + * + * Tusky 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 Tusky; if not, + * see . */ + +package com.keylesspalace.tusky.interfaces + +import com.keylesspalace.tusky.db.AccountEntity + +interface AccountSelectionListener { + fun onAccountSelected(account: AccountEntity) +} \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/service/AccountChooserService.kt b/app/src/main/java/com/keylesspalace/tusky/service/AccountChooserService.kt new file mode 100644 index 00000000..dd39160d --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/service/AccountChooserService.kt @@ -0,0 +1,61 @@ +/* Copyright 2019 Levi Bard + * + * This file is a part of Tusky. + * + * 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. + * + * Tusky 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 Tusky; if not, + * see . */ + +package com.keylesspalace.tusky.service + +import android.annotation.TargetApi +import android.content.ComponentName +import android.content.IntentFilter +import android.graphics.drawable.Icon +import android.os.Bundle +import android.service.chooser.ChooserTarget +import android.service.chooser.ChooserTargetService +import android.text.TextUtils +import com.keylesspalace.tusky.R +import com.keylesspalace.tusky.db.AccountManager +import com.keylesspalace.tusky.di.Injectable +import com.keylesspalace.tusky.util.NotificationHelper +import com.squareup.picasso.Picasso +import dagger.android.AndroidInjection +import javax.inject.Inject + +@TargetApi(23) +class AccountChooserService : ChooserTargetService(), Injectable { + @Inject + lateinit var accountManager: AccountManager + + override fun onCreate() { + super.onCreate() + AndroidInjection.inject(this) + } + + override fun onGetChooserTargets(targetActivityName: ComponentName?, intentFilter: IntentFilter?): MutableList { + val targets = mutableListOf() + for (account in accountManager.getAllAccountsOrderedByActive()) { + val icon: Icon = if (TextUtils.isEmpty(account.profilePictureUrl)) { + Icon.createWithResource(applicationContext, R.drawable.avatar_default) + } else { + Icon.createWithBitmap(Picasso.with(this).load(account.profilePictureUrl) + .error(R.drawable.avatar_default) + .placeholder(R.drawable.avatar_default) + .get()) + } + val bundle = Bundle() + bundle.putLong(NotificationHelper.ACCOUNT_ID, account.id) + targets.add(ChooserTarget(account.displayName, icon, 1.0f, targetActivityName, bundle)) + } + return targets + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eef63087..7bdb52da 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -116,6 +116,7 @@ Copy the link Open as %s + Share as … Share toot URL to… Share toot to…