From dbed424d6f8aa8895a76f68f20bc4f6176dc0711 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 10 Mar 2017 23:31:08 +0100 Subject: [PATCH 1/3] Implement search When displaying displayName, fallback to local username --- .../keylesspalace/tusky/AccountActivity.java | 2 +- .../keylesspalace/tusky/BlocksAdapter.java | 2 +- .../keylesspalace/tusky/FollowAdapter.java | 2 +- .../com/keylesspalace/tusky/MainActivity.java | 78 ++++++++++++++++++- .../tusky/NotificationsAdapter.java | 4 +- .../tusky/PullNotificationService.java | 2 +- .../keylesspalace/tusky/StatusViewHolder.java | 4 +- .../keylesspalace/tusky/entity/Account.java | 50 +++++++++++- 8 files changed, 133 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java index 2cd848d0..ddb59820 100644 --- a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java @@ -180,7 +180,7 @@ public class AccountActivity extends BaseActivity { getString(R.string.status_username_format), account.username); username.setText(usernameFormatted); - displayName.setText(account.displayName); + displayName.setText(account.getDisplayName()); note.setText(account.note); note.setLinksClickable(true); diff --git a/app/src/main/java/com/keylesspalace/tusky/BlocksAdapter.java b/app/src/main/java/com/keylesspalace/tusky/BlocksAdapter.java index 739cec35..52f64a52 100644 --- a/app/src/main/java/com/keylesspalace/tusky/BlocksAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/BlocksAdapter.java @@ -105,7 +105,7 @@ class BlocksAdapter extends AccountAdapter { void setupWithAccount(Account account) { id = account.id; - displayName.setText(account.displayName); + displayName.setText(account.getDisplayName()); String format = username.getContext().getString(R.string.status_username_format); String formattedUsername = String.format(format, account.username); username.setText(formattedUsername); diff --git a/app/src/main/java/com/keylesspalace/tusky/FollowAdapter.java b/app/src/main/java/com/keylesspalace/tusky/FollowAdapter.java index 6512aff2..d15708cf 100644 --- a/app/src/main/java/com/keylesspalace/tusky/FollowAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/FollowAdapter.java @@ -95,7 +95,7 @@ class FollowAdapter extends AccountAdapter { String format = username.getContext().getString(R.string.status_username_format); String formattedUsername = String.format(format, account.username); username.setText(formattedUsername); - displayName.setText(account.displayName); + displayName.setText(account.getDisplayName()); note.setText(account.note); Context context = avatar.getContext(); Picasso.with(context) diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java index 94116846..fb4aa650 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java @@ -20,6 +20,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.SystemClock; @@ -29,10 +30,17 @@ import android.support.design.widget.TabLayout; import android.support.v4.view.ViewPager; import android.os.Bundle; import android.support.v7.widget.Toolbar; +import android.text.Html; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; import android.view.View; import android.widget.ImageView; +import android.widget.TextView; import com.arlib.floatingsearchview.FloatingSearchView; +import com.arlib.floatingsearchview.suggestions.SearchSuggestionsAdapter; +import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion; import com.keylesspalace.tusky.entity.Account; import com.mikepenz.google_material_typeface_library.GoogleMaterial; import com.mikepenz.materialdrawer.AccountHeader; @@ -49,10 +57,12 @@ import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader; import com.mikepenz.materialdrawer.util.DrawerImageLoader; import com.squareup.picasso.Picasso; +import java.util.List; import java.util.Stack; import retrofit2.Call; import retrofit2.Callback; +import retrofit2.Response; public class MainActivity extends BaseActivity { private static final String TAG = "MainActivity"; // logging tag and Volley request tag @@ -164,6 +174,70 @@ public class MainActivity extends BaseActivity { searchView.attachNavigationDrawerToMenuButton(drawer.getDrawerLayout()); + searchView.setOnQueryChangeListener(new FloatingSearchView.OnQueryChangeListener() { + @Override + public void onSearchTextChanged(String oldQuery, String newQuery) { + if (!oldQuery.equals("") && newQuery.equals("")) { + searchView.clearSuggestions(); + return; + } + + if (newQuery.length() < 3) { + return; + } + + searchView.showProgress(); + + mastodonAPI.searchAccounts(newQuery, false, 5).enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + searchView.swapSuggestions(response.body()); + searchView.hideProgress(); + } + + @Override + public void onFailure(Call> call, Throwable t) { + searchView.hideProgress(); + } + }); + } + }); + + searchView.setOnSearchListener(new FloatingSearchView.OnSearchListener() { + @Override + public void onSuggestionClicked(SearchSuggestion searchSuggestion) { + Account accountSuggestion = (Account) searchSuggestion; + Intent intent = new Intent(MainActivity.this, AccountActivity.class); + intent.putExtra("id", accountSuggestion.id); + startActivity(intent); + } + + @Override + public void onSearchAction(String currentQuery) { + + } + }); + + searchView.setOnBindSuggestionCallback(new SearchSuggestionsAdapter.OnBindSuggestionCallback() { + @Override + public void onBindSuggestion(View suggestionView, ImageView leftIcon, TextView textView, SearchSuggestion item, int itemPosition) { + Account accountSuggestion = ((Account) item); + + Picasso.with(MainActivity.this) + .load(accountSuggestion.avatar) + .placeholder(R.drawable.avatar_default) + .into(leftIcon); + + String searchStr = accountSuggestion.getDisplayName() + " " + accountSuggestion.username; + final SpannableStringBuilder str = new SpannableStringBuilder(searchStr); + + str.setSpan(new android.text.style.StyleSpan(Typeface.BOLD), 0, accountSuggestion.getDisplayName().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + textView.setText(str); + textView.setMaxLines(1); + textView.setEllipsize(TextUtils.TruncateAt.END); + } + }); + // Setup the tabs and timeline pager. TimelinePagerAdapter adapter = new TimelinePagerAdapter(getSupportFragmentManager()); String[] pageTitles = { @@ -256,12 +330,12 @@ public class MainActivity extends BaseActivity { headerResult.addProfiles( new ProfileDrawerItem() - .withName(me.displayName) + .withName(me.getDisplayName()) .withEmail(String.format("%s@%s", me.username, domain)) .withIcon(me.avatar) ); - //onFetchUserInfoSuccess(response.body().id, response.body().username); + onFetchUserInfoSuccess(me.id, me.username); } @Override diff --git a/app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java b/app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java index 630b9568..212a4b99 100644 --- a/app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java @@ -96,13 +96,13 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe case FAVOURITE: case REBLOG: { StatusNotificationViewHolder holder = (StatusNotificationViewHolder) viewHolder; - holder.setMessage(type, notification.account.displayName, + holder.setMessage(type, notification.account.getDisplayName(), notification.status); break; } case FOLLOW: { FollowViewHolder holder = (FollowViewHolder) viewHolder; - holder.setMessage(notification.account.displayName, notification.account.username, + holder.setMessage(notification.account.getDisplayName(), notification.account.username, notification.account.avatar); holder.setupButtons(followListener, notification.account.id); break; diff --git a/app/src/main/java/com/keylesspalace/tusky/PullNotificationService.java b/app/src/main/java/com/keylesspalace/tusky/PullNotificationService.java index 44fc636f..745e0371 100644 --- a/app/src/main/java/com/keylesspalace/tusky/PullNotificationService.java +++ b/app/src/main/java/com/keylesspalace/tusky/PullNotificationService.java @@ -119,7 +119,7 @@ public class PullNotificationService extends IntentService { if (status != null) { MentionResult mention = new MentionResult(); mention.content = status.content.toString(); - mention.displayName = notification.account.displayName; + mention.displayName = notification.account.getDisplayName(); mention.avatarUrl = status.account.avatar; mentions.add(mention); } diff --git a/app/src/main/java/com/keylesspalace/tusky/StatusViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/StatusViewHolder.java index c64f669f..35168d04 100644 --- a/app/src/main/java/com/keylesspalace/tusky/StatusViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/StatusViewHolder.java @@ -343,14 +343,14 @@ class StatusViewHolder extends RecyclerView.ViewHolder { void setupWithStatus(Status status, StatusActionListener listener) { Status realStatus = status.getActionableStatus(); - setDisplayName(realStatus.account.displayName); + setDisplayName(realStatus.account.getDisplayName()); setUsername(realStatus.account.username); setCreatedAt(realStatus.createdAt); setContent(realStatus.content, realStatus.mentions, listener); setAvatar(realStatus.account.avatar); setReblogged(realStatus.reblogged); setFavourited(realStatus.favourited); - String rebloggedByDisplayName = status.account.displayName; + String rebloggedByDisplayName = status.account.getDisplayName(); if (status.reblog == null) { hideRebloggedByDisplayName(); } else { diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Account.java b/app/src/main/java/com/keylesspalace/tusky/entity/Account.java index d091512e..76574b94 100644 --- a/app/src/main/java/com/keylesspalace/tusky/entity/Account.java +++ b/app/src/main/java/com/keylesspalace/tusky/entity/Account.java @@ -15,13 +15,18 @@ package com.keylesspalace.tusky.entity; +import android.os.Parcel; import android.text.Spanned; +import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion; import com.google.gson.annotations.SerializedName; -public class Account { +public class Account implements SearchSuggestion { public String id; + @SerializedName("username") + public String localUsername; + @SerializedName("acct") public String username; @@ -62,4 +67,47 @@ public class Account { Account account = (Account) other; return account.id.equals(this.id); } + + public String getDisplayName() { + if (displayName.length() == 0) { + return localUsername; + } + + return displayName; + } + + @Override + public String getBody() { + return username; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + + } + + public Account() { + + } + + protected Account(Parcel in) { + + } + + public static final Creator CREATOR = new Creator() { + @Override + public Account createFromParcel(Parcel source) { + return new Account(source); + } + + @Override + public Account[] newArray(int size) { + return new Account[size]; + } + }; } From 1015f27554eab53d714bb6bf54294b9b87d0688c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 10 Mar 2017 23:37:02 +0100 Subject: [PATCH 2/3] Mention action on profiles --- .../java/com/keylesspalace/tusky/AccountActivity.java | 9 +++++++++ app/src/main/res/menu/account_toolbar.xml | 4 ++++ app/src/main/res/values/strings.xml | 1 + 3 files changed, 14 insertions(+) diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java index ddb59820..0a217c9f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java @@ -61,6 +61,7 @@ public class AccountActivity extends BaseActivity { private boolean isSelf; private String openInWebUrl; private TabLayout tabLayout; + private Account loadedAccount; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -170,6 +171,8 @@ public class AccountActivity extends BaseActivity { } 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); @@ -448,6 +451,12 @@ public class AccountActivity extends BaseActivity { onBackPressed(); return true; } + case R.id.action_mention: { + 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: { Uri uri = Uri.parse(openInWebUrl); Intent intent = new Intent(Intent.ACTION_VIEW, uri); diff --git a/app/src/main/res/menu/account_toolbar.xml b/app/src/main/res/menu/account_toolbar.xml index 64b2f22f..41205d26 100644 --- a/app/src/main/res/menu/account_toolbar.xml +++ b/app/src/main/res/menu/account_toolbar.xml @@ -2,6 +2,10 @@ + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 94fa8373..558e3593 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -128,5 +128,6 @@ That user wasn\'t muted. Search accounts… NSFW + Mention From c1fc6959e797958cbc8f8028ddf31158b967e93b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 10 Mar 2017 23:47:04 +0100 Subject: [PATCH 3/3] Fix up report activity/layout --- .../keylesspalace/tusky/ReportActivity.java | 73 ++++++++++++----- app/src/main/res/layout/activity_report.xml | 80 +++++++++---------- app/src/main/res/menu/report_toolbar.xml | 10 +++ app/src/main/res/values/strings.xml | 2 +- app/src/main/res/values/styles.xml | 4 +- 5 files changed, 101 insertions(+), 68 deletions(-) create mode 100644 app/src/main/res/menu/report_toolbar.xml diff --git a/app/src/main/java/com/keylesspalace/tusky/ReportActivity.java b/app/src/main/java/com/keylesspalace/tusky/ReportActivity.java index e53601c5..3f4b5c0b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ReportActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/ReportActivity.java @@ -17,6 +17,7 @@ package com.keylesspalace.tusky; import android.content.Intent; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; @@ -25,6 +26,8 @@ import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; @@ -45,6 +48,11 @@ public class ReportActivity extends BaseActivity { private View anyView; // what Snackbar will use to find the root view private ReportAdapter adapter; private boolean reportAlreadyInFlight; + private String accountId; + private String accountUsername; + private String statusId; + private String statusContent; + private EditText comment; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -52,10 +60,10 @@ public class ReportActivity extends BaseActivity { setContentView(R.layout.activity_report); Intent intent = getIntent(); - final String accountId = intent.getStringExtra("account_id"); - String accountUsername = intent.getStringExtra("account_username"); - String statusId = intent.getStringExtra("status_id"); - String statusContent = intent.getStringExtra("status_content"); + accountId = intent.getStringExtra("account_id"); + accountUsername = intent.getStringExtra("account_username"); + statusId = intent.getStringExtra("status_id"); + statusContent = intent.getStringExtra("status_content"); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); @@ -64,6 +72,8 @@ public class ReportActivity extends BaseActivity { String title = String.format(getString(R.string.report_username_format), accountUsername); bar.setTitle(title); + bar.setDisplayHomeAsUpEnabled(true); + bar.setDisplayShowHomeEnabled(true); } anyView = toolbar; @@ -85,28 +95,28 @@ public class ReportActivity extends BaseActivity { HtmlUtils.fromHtml(statusContent), true); adapter.addItem(reportStatus); - final EditText comment = (EditText) findViewById(R.id.report_comment); - Button send = (Button) findViewById(R.id.report_send); + comment = (EditText) findViewById(R.id.report_comment); + reportAlreadyInFlight = false; - send.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (reportAlreadyInFlight) { - return; - } - String[] statusIds = adapter.getCheckedStatusIds(); - if (statusIds.length > 0) { - reportAlreadyInFlight = true; - sendReport(accountId, statusIds, comment.getText().toString()); - } else { - comment.setError(getString(R.string.error_report_too_few_statuses)); - } - } - }); fetchRecentStatuses(accountId); } + private void onClickSend() { + if (reportAlreadyInFlight) { + return; + } + + String[] statusIds = adapter.getCheckedStatusIds(); + + if (statusIds.length > 0) { + reportAlreadyInFlight = true; + sendReport(accountId, statusIds, comment.getText().toString()); + } else { + comment.setError(getString(R.string.error_report_too_few_statuses)); + } + } + private void sendReport(final String accountId, final String[] statusIds, final String comment) { mastodonAPI.report(accountId, Arrays.asList(statusIds), comment).enqueue(new Callback() { @@ -167,4 +177,25 @@ public class ReportActivity extends BaseActivity { private void onFetchStatusesFailure(Exception exception) { Log.e(TAG, "Failed to fetch recent statuses to report. " + exception.getMessage()); } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.report_toolbar, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: { + onBackPressed(); + return true; + } + case R.id.action_report: { + onClickSend(); + return true; + } + } + return super.onOptionsItemSelected(item); + } } diff --git a/app/src/main/res/layout/activity_report.xml b/app/src/main/res/layout/activity_report.xml index 9b884f32..c9f89a22 100644 --- a/app/src/main/res/layout/activity_report.xml +++ b/app/src/main/res/layout/activity_report.xml @@ -1,51 +1,43 @@ - - - + android:layout_height="match_parent" + android:orientation="vertical"> + - + - - - - -