123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- /* Copyright 2017 Andrew Dawson
- *
- * 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 <http://www.gnu.org/licenses>. */
- package com.keylesspalace.tusky;
- import android.content.Context;
- import android.content.Intent;
- import android.content.SharedPreferences;
- import android.graphics.drawable.Drawable;
- import android.net.Uri;
- import android.os.Bundle;
- import android.support.annotation.AttrRes;
- import android.support.annotation.Nullable;
- import android.support.design.widget.AppBarLayout;
- import android.support.design.widget.CollapsingToolbarLayout;
- import android.support.design.widget.FloatingActionButton;
- import android.support.design.widget.Snackbar;
- import android.support.design.widget.TabLayout;
- import android.support.v4.view.ViewCompat;
- import android.support.v4.view.ViewPager;
- import android.support.v7.app.ActionBar;
- import android.support.v7.widget.Toolbar;
- import android.text.method.LinkMovementMethod;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.widget.ImageView;
- import android.widget.TextView;
- import com.keylesspalace.tusky.entity.Account;
- import com.keylesspalace.tusky.entity.Relationship;
- import com.pkmmte.view.CircularImageView;
- import com.squareup.picasso.Picasso;
- import java.text.NumberFormat;
- import java.util.ArrayList;
- import java.util.List;
- import butterknife.BindView;
- import butterknife.ButterKnife;
- import retrofit2.Call;
- import retrofit2.Callback;
- import retrofit2.Response;
- public class AccountActivity extends BaseActivity {
- private static final String TAG = "AccountActivity"; // logging tag
- private String accountId;
- private boolean following = false;
- private boolean blocking = false;
- private boolean muting = false;
- private boolean isSelf;
- private TabLayout tabLayout;
- private Account loadedAccount;
- @BindView(R.id.account_locked) ImageView accountLockedView;
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_account);
- ButterKnife.bind(this);
- if (savedInstanceState != null) {
- accountId = savedInstanceState.getString("accountId");
- } else {
- Intent intent = getIntent();
- accountId = intent.getStringExtra("id");
- }
- SharedPreferences preferences = getSharedPreferences(
- getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
- String loggedInAccountId = preferences.getString("loggedInAccountId", null);
- final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setTitle(null);
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- // Add a listener to change the toolbar icon color when it enters/exits its collapsed state.
- AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.account_app_bar_layout);
- final CollapsingToolbarLayout collapsingToolbar =
- (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
- appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
- @AttrRes int priorAttribute = R.attr.account_toolbar_icon_tint_uncollapsed;
- @Override
- public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
- @AttrRes int attribute;
- if (collapsingToolbar.getHeight() + verticalOffset
- < 2 * ViewCompat.getMinimumHeight(collapsingToolbar)) {
- attribute = R.attr.account_toolbar_icon_tint_collapsed;
- } else {
- attribute = R.attr.account_toolbar_icon_tint_uncollapsed;
- }
- if (attribute != priorAttribute) {
- priorAttribute = attribute;
- Context context = toolbar.getContext();
- ThemeUtils.setDrawableTint(context, toolbar.getNavigationIcon(), attribute);
- ThemeUtils.setDrawableTint(context, toolbar.getOverflowIcon(), attribute);
- }
- }
- });
- FloatingActionButton floatingBtn = (FloatingActionButton) findViewById(R.id.floating_btn);
- floatingBtn.hide();
- CircularImageView avatar = (CircularImageView) findViewById(R.id.account_avatar);
- ImageView header = (ImageView) findViewById(R.id.account_header);
- avatar.setImageResource(R.drawable.avatar_default);
- header.setImageResource(R.drawable.account_header_default);
- obtainAccount();
- if (!accountId.equals(loggedInAccountId)) {
- isSelf = false;
- obtainRelationships();
- } else {
- /* Cause the options menu to update and instead show an options menu for when the
- * account being shown is their own account. */
- isSelf = true;
- invalidateOptionsMenu();
- }
- // Setup the tabs and timeline pager.
- AccountPagerAdapter adapter = new AccountPagerAdapter(getSupportFragmentManager(), this,
- accountId);
- String[] pageTitles = {
- getString(R.string.title_statuses),
- getString(R.string.title_follows),
- getString(R.string.title_followers)
- };
- adapter.setPageTitles(pageTitles);
- ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
- int pageMargin = getResources().getDimensionPixelSize(R.dimen.tab_page_margin);
- viewPager.setPageMargin(pageMargin);
- Drawable pageMarginDrawable = ThemeUtils.getDrawable(this, R.attr.tab_page_margin_drawable,
- R.drawable.tab_page_margin_dark);
- viewPager.setPageMarginDrawable(pageMarginDrawable);
- viewPager.setAdapter(adapter);
- tabLayout = (TabLayout) findViewById(R.id.tab_layout);
- tabLayout.setupWithViewPager(viewPager);
- for (int i = 0; i < tabLayout.getTabCount(); i++) {
- TabLayout.Tab tab = tabLayout.getTabAt(i);
- if (tab != null) {
- tab.setCustomView(adapter.getTabView(i, tabLayout));
- }
- }
- }
- private void obtainAccount() {
- mastodonAPI.account(accountId).enqueue(new Callback<Account>() {
- @Override
- public void onResponse(Call<Account> call, retrofit2.Response<Account> response) {
- if (response.isSuccessful()) {
- onObtainAccountSuccess(response.body());
- } else {
- onObtainAccountFailure();
- }
- }
- @Override
- public void onFailure(Call<Account> call, Throwable t) {
- onObtainAccountFailure();
- }
- });
- }
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- outState.putString("accountId", accountId);
- super.onSaveInstanceState(outState);
- }
- private void onObtainAccountSuccess(Account account) {
- loadedAccount = account;
- TextView username = (TextView) findViewById(R.id.account_username);
- TextView displayName = (TextView) findViewById(R.id.account_display_name);
- TextView note = (TextView) findViewById(R.id.account_note);
- CircularImageView avatar = (CircularImageView) findViewById(R.id.account_avatar);
- ImageView header = (ImageView) findViewById(R.id.account_header);
- String usernameFormatted = String.format(
- getString(R.string.status_username_format), account.username);
- username.setText(usernameFormatted);
- displayName.setText(account.getDisplayName());
- note.setText(account.note);
- note.setLinksClickable(true);
- note.setMovementMethod(LinkMovementMethod.getInstance());
- if (account.locked) {
- accountLockedView.setVisibility(View.VISIBLE);
- } else {
- accountLockedView.setVisibility(View.GONE);
- }
- Picasso.with(this)
- .load(account.avatar)
- .placeholder(R.drawable.avatar_default)
- .error(R.drawable.avatar_error)
- .into(avatar);
- Picasso.with(this)
- .load(account.header)
- .placeholder(R.drawable.account_header_missing)
- .into(header);
- NumberFormat nf = NumberFormat.getInstance();
- // Add counts to the tabs in the TabLayout.
- String[] counts = {
- nf.format(Integer.parseInt(account.statusesCount)),
- nf.format(Integer.parseInt(account.followingCount)),
- nf.format(Integer.parseInt(account.followersCount)),
- };
- for (int i = 0; i < tabLayout.getTabCount(); i++) {
- TabLayout.Tab tab = tabLayout.getTabAt(i);
- if (tab != null) {
- View view = tab.getCustomView();
- if (view != null) {
- TextView total = (TextView) view.findViewById(R.id.total);
- total.setText(counts[i]);
- }
- }
- }
- }
- private void onObtainAccountFailure() {
- Snackbar.make(tabLayout, R.string.error_generic, Snackbar.LENGTH_LONG)
- .setAction(R.string.action_retry, new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- obtainAccount();
- }
- })
- .show();
- }
- private void obtainRelationships() {
- List<String> ids = new ArrayList<>(1);
- ids.add(accountId);
- mastodonAPI.relationships(ids).enqueue(new Callback<List<Relationship>>() {
- @Override
- public void onResponse(Call<List<Relationship>> call, retrofit2.Response<List<Relationship>> response) {
- if (response.isSuccessful()) {
- Relationship relationship = response.body().get(0);
- onObtainRelationshipsSuccess(relationship.following, relationship.blocking, relationship.muting);
- } else {
- onObtainRelationshipsFailure(new Exception(response.message()));
- }
- }
- @Override
- public void onFailure(Call<List<Relationship>> call, Throwable t) {
- onObtainRelationshipsFailure((Exception) t);
- }
- });
- }
- private void onObtainRelationshipsSuccess(boolean following, boolean blocking, boolean muting) {
- this.following = following;
- this.blocking = blocking;
- this.muting = muting;
- if (!following || !blocking || !muting) {
- invalidateOptionsMenu();
- }
- updateButtons();
- }
- private void updateButtons() {
- invalidateOptionsMenu();
- final FloatingActionButton floatingBtn = (FloatingActionButton) findViewById(R.id.floating_btn);
- if(!isSelf && !blocking) {
- floatingBtn.show();
- if (following) {
- floatingBtn.setImageResource(R.drawable.ic_person_minus_24px);
- } else {
- floatingBtn.setImageResource(R.drawable.ic_person_add_24dp);
- }
- floatingBtn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- follow(accountId);
- if (following) {
- floatingBtn.setImageResource(R.drawable.ic_person_minus_24px);
- } else {
- floatingBtn.setImageResource(R.drawable.ic_person_add_24dp);
- }
- }
- });
- }
- }
- private void onObtainRelationshipsFailure(Exception exception) {
- Log.e(TAG, "Could not obtain relationships. " + exception.getMessage());
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.account_toolbar, menu);
- return super.onCreateOptionsMenu(menu);
- }
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- if (!isSelf) {
- MenuItem follow = menu.findItem(R.id.action_follow);
- String title;
- if (following) {
- title = getString(R.string.action_unfollow);
- } else {
- title = getString(R.string.action_follow);
- }
- follow.setTitle(title);
- MenuItem block = menu.findItem(R.id.action_block);
- if (blocking) {
- title = getString(R.string.action_unblock);
- } else {
- title = getString(R.string.action_block);
- }
- block.setTitle(title);
- MenuItem mute = menu.findItem(R.id.action_mute);
- if (muting) {
- title = getString(R.string.action_unmute);
- } else {
- title = getString(R.string.action_mute);
- }
- mute.setTitle(title);
- } else {
- // It shouldn't be possible to block or follow yourself.
- menu.removeItem(R.id.action_follow);
- menu.removeItem(R.id.action_block);
- menu.removeItem(R.id.action_mute);
- }
- return super.onPrepareOptionsMenu(menu);
- }
- private void follow(final String id) {
- Callback<Relationship> cb = new Callback<Relationship>() {
- @Override
- public void onResponse(Call<Relationship> call, retrofit2.Response<Relationship> response) {
- if (response.isSuccessful()) {
- following = response.body().following;
- // TODO: display message/indicator when "requested" is true (i.e. when the follow is awaiting approval)
- updateButtons();
- } else {
- onFollowFailure(id);
- }
- }
- @Override
- public void onFailure(Call<Relationship> call, Throwable t) {
- onFollowFailure(id);
- }
- };
- if (following) {
- mastodonAPI.unfollowAccount(id).enqueue(cb);
- } else {
- mastodonAPI.followAccount(id).enqueue(cb);
- }
- }
- private void onFollowFailure(final String id) {
- View.OnClickListener listener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- follow(id);
- }
- };
- View anyView = findViewById(R.id.activity_account);
- Snackbar.make(anyView, R.string.error_generic, Snackbar.LENGTH_LONG)
- .setAction(R.string.action_retry, listener)
- .show();
- }
- private void block(final String id) {
- Callback<Relationship> cb = new Callback<Relationship>() {
- @Override
- public void onResponse(Call<Relationship> call, retrofit2.Response<Relationship> response) {
- if (response.isSuccessful()) {
- blocking = response.body().blocking;
- updateButtons();
- } else {
- onBlockFailure(id);
- }
- }
- @Override
- public void onFailure(Call<Relationship> call, Throwable t) {
- onBlockFailure(id);
- }
- };
- if (blocking) {
- mastodonAPI.unblockAccount(id).enqueue(cb);
- } else {
- mastodonAPI.blockAccount(id).enqueue(cb);
- }
- }
- private void onBlockFailure(final String id) {
- View.OnClickListener listener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- block(id);
- }
- };
- View anyView = findViewById(R.id.activity_account);
- Snackbar.make(anyView, R.string.error_generic, Snackbar.LENGTH_LONG)
- .setAction(R.string.action_retry, listener)
- .show();
- }
- private void mute(final String id) {
- Callback<Relationship> cb = new Callback<Relationship>() {
- @Override
- public void onResponse(Call<Relationship> call, Response<Relationship> response) {
- if (response.isSuccessful()) {
- muting = response.body().muting;
- updateButtons();
- } else {
- onMuteFailure(id);
- }
- }
- @Override
- public void onFailure(Call<Relationship> call, Throwable t) {
- onMuteFailure(id);
- }
- };
- if (muting) {
- mastodonAPI.unmuteAccount(id).enqueue(cb);
- } else {
- mastodonAPI.muteAccount(id).enqueue(cb);
- }
- }
- private void onMuteFailure(final String id) {
- View.OnClickListener listener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mute(id);
- }
- };
- View anyView = findViewById(R.id.activity_account);
- Snackbar.make(anyView, R.string.error_generic, Snackbar.LENGTH_LONG)
- .setAction(R.string.action_retry, listener)
- .show();
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home: {
- onBackPressed();
- return true;
- }
- case R.id.action_mention: {
- if (loadedAccount == null) {
- // If the account isn't loaded yet, eat the input.
- return false;
- }
- Intent intent = new Intent(this, ComposeActivity.class);
- intent.putExtra("mentioned_usernames", new String[] { loadedAccount.username });
- startActivity(intent);
- return true;
- }
- case R.id.action_open_in_web: {
- if (loadedAccount == null) {
- // If the account isn't loaded yet, eat the input.
- return false;
- }
- Uri uri = Uri.parse(loadedAccount.url);
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- startActivity(intent);
- return true;
- }
- case R.id.action_follow: {
- follow(accountId);
- return true;
- }
- case R.id.action_block: {
- block(accountId);
- return true;
- }
- case R.id.action_mute: {
- mute(accountId);
- return true;
- }
- }
- return super.onOptionsItemSelected(item);
- }
- }
|