open-keychain/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java
2020-05-30 15:47:09 +02:00

353 lines
14 KiB
Java

/*
* Copyright (C) 2017 Schürmann & Breitmoser GbR
*
* 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.sufficientlysecure.keychain.ui;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import androidx.fragment.app.Fragment;
import androidx.core.view.MotionEventCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
import org.sufficientlysecure.keychain.ui.dialog.AddEditKeyserverDialogFragment;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.recyclerview.ItemTouchHelperAdapter;
import org.sufficientlysecure.keychain.ui.util.recyclerview.ItemTouchHelperDragCallback;
import org.sufficientlysecure.keychain.ui.util.recyclerview.ItemTouchHelperViewHolder;
import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener;
import org.sufficientlysecure.keychain.util.Preferences;
public class SettingsKeyserverFragment extends Fragment implements RecyclerItemClickListener.OnItemClickListener {
private static final String ARG_KEYSERVER_ARRAY = "arg_keyserver_array";
private ItemTouchHelper mItemTouchHelper;
private ArrayList<HkpKeyserverAddress> mKeyserversMutable;
private List<HkpKeyserverAddress> mKeyservers;
private KeyserverListAdapter mAdapter;
private KeyMetadataDao keyMetadataDao;
public static SettingsKeyserverFragment newInstance(ArrayList<HkpKeyserverAddress> keyservers) {
Bundle args = new Bundle();
args.putParcelableArrayList(ARG_KEYSERVER_ARRAY, keyservers);
SettingsKeyserverFragment fragment = new SettingsKeyserverFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
keyMetadataDao = KeyMetadataDao.create(getContext());
return inflater.inflate(R.layout.settings_keyserver_fragment, null);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mKeyserversMutable = getArguments().getParcelableArrayList(ARG_KEYSERVER_ARRAY);
mKeyservers = Collections.unmodifiableList(new ArrayList<>(mKeyserversMutable));
mAdapter = new KeyserverListAdapter(mKeyserversMutable);
RecyclerView recyclerView = view.findViewById(R.id.keyserver_recycler_view);
// recyclerView.setHasFixedSize(true); // the size of the first item changes
recyclerView.setAdapter(mAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
ItemTouchHelper.Callback callback = new ItemTouchHelperDragCallback(mAdapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(recyclerView);
// for clicks
recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), this));
// can't use item decoration because it doesn't move with drag and drop
// recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null));
// We have a menu item to show in action bar.
setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
inflater.inflate(R.menu.keyserver_pref_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_add_keyserver:
startAddKeyserverDialog();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void startAddKeyserverDialog() {
// keyserver and position have no meaning
startEditKeyserverDialog(AddEditKeyserverDialogFragment.DialogAction.ADD, null, -1);
}
private void startEditKeyserverDialog(AddEditKeyserverDialogFragment.DialogAction action,
HkpKeyserverAddress keyserver, final int position) {
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
Bundle data = message.getData();
switch (message.what) {
case AddEditKeyserverDialogFragment.MESSAGE_OKAY: {
boolean deleted =
data.getBoolean(AddEditKeyserverDialogFragment.MESSAGE_KEYSERVER_DELETED
, false);
if (deleted) {
Notify.create(getActivity(),
getActivity().getString(
R.string.keyserver_preference_deleted, mKeyserversMutable.get(position)),
Notify.Style.OK)
.show();
deleteKeyserver(position);
return;
}
boolean verified =
data.getBoolean(AddEditKeyserverDialogFragment.MESSAGE_VERIFIED);
if (verified) {
Notify.create(getActivity(),
R.string.add_keyserver_connection_verified, Notify.Style.OK).show();
} else {
Notify.create(getActivity(),
R.string.add_keyserver_without_verification,
Notify.Style.WARN).show();
}
HkpKeyserverAddress keyserver = data.getParcelable(
AddEditKeyserverDialogFragment.MESSAGE_KEYSERVER);
AddEditKeyserverDialogFragment.DialogAction dialogAction
= (AddEditKeyserverDialogFragment.DialogAction) data.getSerializable(
AddEditKeyserverDialogFragment.MESSAGE_DIALOG_ACTION);
switch (dialogAction) {
case ADD:
addKeyserver(keyserver);
break;
case EDIT:
editKeyserver(keyserver, position);
break;
}
break;
}
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(returnHandler);
AddEditKeyserverDialogFragment dialogFragment = AddEditKeyserverDialogFragment
.newInstance(messenger, action, keyserver, position);
dialogFragment.show(getFragmentManager(), "addKeyserverDialog");
}
private void addKeyserver(HkpKeyserverAddress keyserver) {
mKeyserversMutable.add(keyserver);
mAdapter.notifyItemInserted(mKeyserversMutable.size() - 1);
saveKeyserverList();
}
private void editKeyserver(HkpKeyserverAddress newKeyserver, int position) {
mKeyserversMutable.set(position, newKeyserver);
mAdapter.notifyItemChanged(position);
saveKeyserverList();
}
private void deleteKeyserver(int position) {
if (mKeyserversMutable.size() == 1) {
Notify.create(getActivity(), R.string.keyserver_preference_cannot_delete_last,
Notify.Style.ERROR).show();
return;
}
mKeyserversMutable.remove(position);
// we use this
mAdapter.notifyItemRemoved(position);
if (position == 0 && mKeyserversMutable.size() > 0) {
// if we deleted the first item, we need the adapter to redraw the new first item
mAdapter.notifyItemChanged(0);
}
saveKeyserverList();
}
private void saveKeyserverList() {
if (mKeyserversMutable.equals(mKeyservers)) {
return;
}
Preferences.getPreferences(getActivity()).setKeyServers(mKeyserversMutable);
mKeyservers = Collections.unmodifiableList(new ArrayList<>(mKeyserversMutable));
keyMetadataDao.resetAllLastUpdatedTimes();
}
@Override
public void onItemClick(View view, int position) {
startEditKeyserverDialog(AddEditKeyserverDialogFragment.DialogAction.EDIT,
mKeyserversMutable.get(position), position);
}
public class KeyserverListAdapter extends RecyclerView.Adapter<KeyserverListAdapter.ViewHolder>
implements ItemTouchHelperAdapter {
private final ArrayList<HkpKeyserverAddress> mKeyservers;
public KeyserverListAdapter(ArrayList<HkpKeyserverAddress> keyservers) {
mKeyservers = keyservers;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.settings_keyserver_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.keyserverUrl.setText(mKeyservers.get(position).getUrl());
// Start a drag whenever the handle view it touched
holder.dragHandleView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
mItemTouchHelper.startDrag(holder);
}
return false;
}
});
selectUnselectKeyserver(holder, position);
}
private void selectUnselectKeyserver(ViewHolder holder, int position) {
if (position == 0) {
holder.showAsSelectedKeyserver();
} else {
holder.showAsUnselectedKeyserver();
}
}
@Override
public void onItemMove(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target,
int fromPosition, int toPosition) {
Collections.swap(mKeyservers, fromPosition, toPosition);
saveKeyserverList();
selectUnselectKeyserver((ViewHolder) target, fromPosition);
// we don't want source to change color while dragging, therefore we just set
// isSelectedKeyserver instead of selectUnselectKeyserver
((ViewHolder) source).isSelectedKeyserver = toPosition == 0;
notifyItemMoved(fromPosition, toPosition);
}
@Override
public int getItemCount() {
return mKeyservers.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements
ItemTouchHelperViewHolder {
public final ViewGroup outerLayout;
public final TextView selectedServerLabel;
public final TextView keyserverUrl;
public final ImageView dragHandleView;
private boolean isSelectedKeyserver = false;
public ViewHolder(View itemView) {
super(itemView);
outerLayout = itemView.findViewById(R.id.outer_layout);
selectedServerLabel = itemView.findViewById(
R.id.selected_keyserver_title);
keyserverUrl = itemView.findViewById(R.id.keyserver_tv);
dragHandleView = itemView.findViewById(R.id.drag_handle);
itemView.setClickable(true);
}
public void showAsSelectedKeyserver() {
isSelectedKeyserver = true;
selectedServerLabel.setVisibility(View.VISIBLE);
outerLayout.setBackgroundColor(FormattingUtils.getColorFromAttr(getContext(), R.attr.colorPrimaryDark));
}
public void showAsUnselectedKeyserver() {
isSelectedKeyserver = false;
selectedServerLabel.setVisibility(View.GONE);
outerLayout.setBackgroundColor(0);
}
@Override
public void onItemSelected() {
selectedServerLabel.setVisibility(View.GONE);
itemView.setBackgroundColor(FormattingUtils.getColorFromAttr(getContext(), R.attr.colorBrightToolbar));
}
@Override
public void onItemClear() {
if (isSelectedKeyserver) {
showAsSelectedKeyserver();
} else {
showAsUnselectedKeyserver();
}
}
}
}
}