diff options
author | Christian Schneppe <christian@pix-art.de> | 2019-04-26 23:12:05 +0200 |
---|---|---|
committer | Christian Schneppe <christian@pix-art.de> | 2019-04-26 23:12:22 +0200 |
commit | f9f07063876ec5f3917ce72385b015e1b5f31d7e (patch) | |
tree | 093f9ded3021800b20e1e8dcb22d4d8ac17dc7db /src/main/java/de/pixart/messenger/ui | |
parent | 35276c6519afa1da6042dd485ddae09b06c68aeb (diff) |
implement channel discovery
refactor muc search to use http
cache channel search results
Diffstat (limited to 'src/main/java/de/pixart/messenger/ui')
3 files changed, 279 insertions, 1 deletions
diff --git a/src/main/java/de/pixart/messenger/ui/ChannelDiscoveryActivity.java b/src/main/java/de/pixart/messenger/ui/ChannelDiscoveryActivity.java new file mode 100644 index 000000000..e0b70b6ac --- /dev/null +++ b/src/main/java/de/pixart/messenger/ui/ChannelDiscoveryActivity.java @@ -0,0 +1,196 @@ +package de.pixart.messenger.ui; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.SharedPreferences; +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.support.v7.widget.Toolbar; +import android.text.Html; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.TextView; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import de.pixart.messenger.R; +import de.pixart.messenger.databinding.ActivityChannelDiscoveryBinding; +import de.pixart.messenger.entities.Account; +import de.pixart.messenger.entities.Conversation; +import de.pixart.messenger.http.services.MuclumbusService; +import de.pixart.messenger.services.ChannelDiscoveryService; +import de.pixart.messenger.ui.adapter.ChannelSearchResultAdapter; +import de.pixart.messenger.ui.util.PendingItem; +import de.pixart.messenger.ui.util.SoftKeyboardUtils; +import de.pixart.messenger.utils.AccountUtils; +import rocks.xmpp.addr.Jid; + +public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.OnActionExpandListener, TextView.OnEditorActionListener, ChannelDiscoveryService.OnChannelSearchResultsFound, ChannelSearchResultAdapter.OnChannelSearchResultSelected { + private static final String CHANNEL_DISCOVERY_OPT_IN = "channel_discovery_opt_in"; + private final ChannelSearchResultAdapter adapter = new ChannelSearchResultAdapter(); + private ActivityChannelDiscoveryBinding binding; + private final PendingItem<String> mInitialSearchValue = new PendingItem<>(); + private MenuItem mMenuSearchView; + private EditText mSearchEditText; + private boolean optedIn = false; + + @Override + protected void refreshUiReal() { + + } + + @Override + void onBackendConnected() { + if (optedIn) { + String query; + if (mMenuSearchView != null && mMenuSearchView.isActionViewExpanded()) { + query = mSearchEditText.getText().toString(); + } else { + query = mInitialSearchValue.peek(); + } + xmppConnectionService.discoverChannels(query, this); + } + } + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = DataBindingUtil.setContentView(this, R.layout.activity_channel_discovery); + setSupportActionBar((Toolbar) binding.toolbar); + configureActionBar(getSupportActionBar(), true); + binding.list.setAdapter(this.adapter); + this.adapter.setOnChannelSearchResultSelectedListener(this); + optedIn = getPreferences().getBoolean(CHANNEL_DISCOVERY_OPT_IN, false); + + final String search = savedInstanceState == null ? null : savedInstanceState.getString("search"); + if (search != null) { + mInitialSearchValue.push(search); + } + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.muc_users_activity, menu); + mMenuSearchView = menu.findItem(R.id.action_search); + final View mSearchView = mMenuSearchView.getActionView(); + mSearchEditText = mSearchView.findViewById(R.id.search_field); + mSearchEditText.setHint(R.string.search_channels); + String initialSearchValue = mInitialSearchValue.pop(); + if (initialSearchValue != null) { + mMenuSearchView.expandActionView(); + mSearchEditText.append(initialSearchValue); + mSearchEditText.requestFocus(); + if (optedIn) { + xmppConnectionService.discoverChannels(initialSearchValue, this); + } + } + mSearchEditText.setOnEditorActionListener(this); + mMenuSearchView.setOnActionExpandListener(this); + return true; + } + + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + mSearchEditText.post(() -> { + mSearchEditText.requestFocus(); + final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(mSearchEditText, InputMethodManager.SHOW_IMPLICIT); + }); + return true; + } + + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY); + mSearchEditText.setText(""); + toggleLoadingScreen(); + if (optedIn) { + xmppConnectionService.discoverChannels(null, this); + } + return true; + } + + private void toggleLoadingScreen() { + adapter.submitList(Collections.emptyList()); + binding.progressBar.setVisibility(View.VISIBLE); + } + + @Override + public void onStart() { + super.onStart(); + if (!optedIn) { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.channel_discovery_opt_in_title); + builder.setMessage(Html.fromHtml(getString(R.string.channel_discover_opt_in_message))); + builder.setNegativeButton(R.string.cancel, (dialog, which) -> finish()); + builder.setPositiveButton(R.string.confirm, (dialog, which) -> optIn()); + builder.setOnCancelListener(dialog -> finish()); + final AlertDialog dialog = builder.create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + } + } + + @Override + public void onSaveInstanceState(Bundle savedInstanceState) { + if (mMenuSearchView != null && mMenuSearchView.isActionViewExpanded()) { + savedInstanceState.putString("search", mSearchEditText != null ? mSearchEditText.getText().toString() : null); + } + super.onSaveInstanceState(savedInstanceState); + } + + private void optIn() { + SharedPreferences preferences = getPreferences(); + preferences.edit().putBoolean(CHANNEL_DISCOVERY_OPT_IN, true).apply(); + optedIn = true; + xmppConnectionService.discoverChannels(null, this); + } + + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (optedIn) { + xmppConnectionService.discoverChannels(v.getText().toString(), this); + } + toggleLoadingScreen(); + SoftKeyboardUtils.hideSoftKeyboard(this); + return true; + } + + @Override + public void onChannelSearchResultsFound(List<MuclumbusService.Room> results) { + runOnUiThread(() -> { + adapter.submitList(results); + binding.list.setVisibility(View.VISIBLE); + binding.progressBar.setVisibility(View.GONE); + }); + } + + @Override + public void onChannelSearchResult(final MuclumbusService.Room result) { + List<String> accounts = AccountUtils.getEnabledAccounts(xmppConnectionService); + if (accounts.size() == 1) { + joinChannelSearchResult(accounts.get(0), result); + } else if (accounts.size() > 0) { + final AtomicReference<String> account = new AtomicReference<>(accounts.get(0)); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.choose_account); + builder.setSingleChoiceItems(accounts.toArray(new CharSequence[0]), 0, (dialog, which) -> account.set(accounts.get(which))); + builder.setPositiveButton(R.string.join, (dialog, which) -> joinChannelSearchResult(account.get(), result)); + builder.setNegativeButton(R.string.cancel, null); + builder.create().show(); + } + } + + public void joinChannelSearchResult(String accountJid, MuclumbusService.Room result) { + Account account = xmppConnectionService.findAccountByJid(Jid.of(accountJid)); + final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, result.getRoom(), true, true, true); + switchToConversation(conversation); + } +}
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java b/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java index 6706d004c..75e7c2f52 100644 --- a/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java +++ b/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java @@ -70,6 +70,7 @@ import de.pixart.messenger.ui.interfaces.OnBackendConnected; import de.pixart.messenger.ui.util.JidDialog; import de.pixart.messenger.ui.util.PendingItem; import de.pixart.messenger.ui.util.SoftKeyboardUtils; +import de.pixart.messenger.utils.AccountUtils; import de.pixart.messenger.utils.MenuDoubleTabUtil; import de.pixart.messenger.utils.XmppUri; import de.pixart.messenger.xmpp.OnUpdateBlocklist; @@ -307,6 +308,9 @@ public class StartConversationActivity extends XmppActivity implements XmppConne prefilled = null; } switch (actionItem.getId()) { + case R.id.discover_public_channels: + startActivity(new Intent(this, ChannelDiscoveryActivity.class)); + break; case R.id.join_public_channel: showJoinConferenceDialog(prefilled); break; @@ -763,7 +767,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne onActivityResult(mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second); this.mPostponedActivityResult = null; } - this.mActivatedAccounts.clear(); + this.mActivatedAccounts.addAll(AccountUtils.getEnabledAccounts(xmppConnectionService)); for (Account account : xmppConnectionService.getAccounts()) { if (account.getStatus() != Account.State.DISABLED) { if (Config.DOMAIN_LOCK != null) { diff --git a/src/main/java/de/pixart/messenger/ui/adapter/ChannelSearchResultAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/ChannelSearchResultAdapter.java new file mode 100644 index 000000000..d137e3a6f --- /dev/null +++ b/src/main/java/de/pixart/messenger/ui/adapter/ChannelSearchResultAdapter.java @@ -0,0 +1,78 @@ +package de.pixart.messenger.ui.adapter; + +import android.databinding.DataBindingUtil; +import android.support.annotation.NonNull; +import android.support.v7.recyclerview.extensions.ListAdapter; +import android.support.v7.util.DiffUtil; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import de.pixart.messenger.R; +import de.pixart.messenger.databinding.SearchResultItemBinding; +import de.pixart.messenger.http.services.MuclumbusService; +import de.pixart.messenger.ui.util.AvatarWorkerTask; + + +public class ChannelSearchResultAdapter extends ListAdapter<MuclumbusService.Room, ChannelSearchResultAdapter.ViewHolder> { + + private OnChannelSearchResultSelected listener; + + private static final DiffUtil.ItemCallback<MuclumbusService.Room> DIFF = new DiffUtil.ItemCallback<MuclumbusService.Room>() { + @Override + public boolean areItemsTheSame(@NonNull MuclumbusService.Room a, @NonNull MuclumbusService.Room b) { + return a.address != null && a.address.equals(b.address); + } + + @Override + public boolean areContentsTheSame(@NonNull MuclumbusService.Room a, @NonNull MuclumbusService.Room b) { + return a.equals(b); + } + }; + + public ChannelSearchResultAdapter() { + super(DIFF); + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.search_result_item, viewGroup, false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) { + final MuclumbusService.Room searchResult = getItem(position); + viewHolder.binding.name.setText(searchResult.getName()); + final String description = searchResult.getDescription(); + if (TextUtils.isEmpty(description)) { + viewHolder.binding.description.setVisibility(View.GONE); + } else { + viewHolder.binding.description.setText(description); + viewHolder.binding.description.setVisibility(View.VISIBLE); + } + viewHolder.binding.room.setText(searchResult.getRoom().asBareJid().toString()); + AvatarWorkerTask.loadAvatar(searchResult, viewHolder.binding.avatar, R.dimen.avatar); + viewHolder.binding.getRoot().setOnClickListener(v -> listener.onChannelSearchResult(searchResult)); + } + + public void setOnChannelSearchResultSelectedListener(OnChannelSearchResultSelected listener) { + this.listener = listener; + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + + private final SearchResultItemBinding binding; + + private ViewHolder(SearchResultItemBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } + + public interface OnChannelSearchResultSelected { + void onChannelSearchResult(MuclumbusService.Room result); + } +}
\ No newline at end of file |