2015-11-19 18:21:19 +00:00
|
|
|
package org.thoughtcrime.securesms;
|
|
|
|
|
|
|
|
import android.app.Activity;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.DialogInterface;
|
|
|
|
import android.os.Bundle;
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
import android.widget.AdapterView;
|
|
|
|
import android.widget.ArrayAdapter;
|
|
|
|
import android.widget.Button;
|
2019-11-20 23:50:33 +00:00
|
|
|
import android.widget.EditText;
|
2019-12-02 04:03:12 +00:00
|
|
|
import android.widget.LinearLayout;
|
2015-11-19 18:21:19 +00:00
|
|
|
import android.widget.ListView;
|
|
|
|
|
2020-08-19 01:29:52 +00:00
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.appcompat.app.AlertDialog;
|
|
|
|
import androidx.fragment.app.ListFragment;
|
|
|
|
import androidx.loader.app.LoaderManager;
|
|
|
|
import androidx.loader.content.Loader;
|
|
|
|
|
2015-11-19 18:21:19 +00:00
|
|
|
import com.melnykov.fab.FloatingActionButton;
|
|
|
|
|
2019-11-20 00:44:44 +00:00
|
|
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
2015-11-19 18:21:19 +00:00
|
|
|
import org.thoughtcrime.securesms.database.loaders.DeviceListLoader;
|
|
|
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
2019-07-24 02:30:23 +00:00
|
|
|
import org.thoughtcrime.securesms.devicelist.Device;
|
2020-05-11 06:19:26 +00:00
|
|
|
import org.thoughtcrime.securesms.loki.dialogs.DeviceEditingOptionsBottomSheet;
|
2015-11-19 18:21:19 +00:00
|
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
|
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
2019-12-02 04:03:12 +00:00
|
|
|
import org.whispersystems.libsignal.util.guava.Function;
|
2015-11-19 18:21:19 +00:00
|
|
|
|
|
|
|
import java.util.List;
|
2015-12-02 07:35:07 +00:00
|
|
|
import java.util.Locale;
|
2015-11-19 18:21:19 +00:00
|
|
|
|
2019-11-20 23:50:33 +00:00
|
|
|
import kotlin.Pair;
|
|
|
|
import kotlin.Unit;
|
2019-07-24 02:30:23 +00:00
|
|
|
import network.loki.messenger.R;
|
|
|
|
|
2020-05-12 01:46:11 +00:00
|
|
|
import static org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt.toPx;
|
2019-12-02 04:03:12 +00:00
|
|
|
|
2015-11-19 18:21:19 +00:00
|
|
|
public class DeviceListFragment extends ListFragment
|
2018-12-19 16:09:22 +00:00
|
|
|
implements LoaderManager.LoaderCallbacks<List<Device>>,
|
2015-11-19 18:21:19 +00:00
|
|
|
ListView.OnItemClickListener, InjectableType, Button.OnClickListener
|
|
|
|
{
|
|
|
|
|
|
|
|
private static final String TAG = DeviceListFragment.class.getSimpleName();
|
|
|
|
|
2015-12-02 07:35:07 +00:00
|
|
|
private Locale locale;
|
|
|
|
private View empty;
|
2015-11-19 18:21:19 +00:00
|
|
|
private View progressContainer;
|
2015-12-02 07:35:07 +00:00
|
|
|
private FloatingActionButton addDeviceButton;
|
2015-11-19 18:21:19 +00:00
|
|
|
private Button.OnClickListener addDeviceButtonListener;
|
2019-11-19 22:50:40 +00:00
|
|
|
private Function<String, Void> handleDisconnectDevice;
|
2019-11-20 23:50:33 +00:00
|
|
|
private Function<Pair<String, String>, Void> handleDeviceNameChange;
|
2015-11-19 18:21:19 +00:00
|
|
|
|
2015-12-02 07:35:07 +00:00
|
|
|
@Override
|
|
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
this.locale = (Locale) getArguments().getSerializable(PassphraseRequiredActionBarActivity.LOCALE_EXTRA);
|
|
|
|
}
|
|
|
|
|
2015-11-19 18:21:19 +00:00
|
|
|
@Override
|
|
|
|
public void onAttach(Activity activity) {
|
|
|
|
super.onAttach(activity);
|
|
|
|
ApplicationContext.getInstance(activity).injectDependencies(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
|
|
|
View view = inflater.inflate(R.layout.device_list_fragment, container, false);
|
|
|
|
|
2019-12-02 04:03:12 +00:00
|
|
|
this.empty = view.findViewById(R.id.emptyStateTextView);
|
|
|
|
this.progressContainer = view.findViewById(R.id.activityIndicator);
|
|
|
|
this.addDeviceButton = ViewUtil.findById(view, R.id.addDeviceButton);
|
2015-11-19 18:21:19 +00:00
|
|
|
this.addDeviceButton.setOnClickListener(this);
|
2019-11-20 00:44:44 +00:00
|
|
|
updateAddDeviceButtonVisibility();
|
2015-11-19 18:21:19 +00:00
|
|
|
|
|
|
|
return view;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onActivityCreated(Bundle bundle) {
|
|
|
|
super.onActivityCreated(bundle);
|
2016-09-14 12:46:18 +00:00
|
|
|
getLoaderManager().initLoader(0, null, this);
|
2015-11-19 18:21:19 +00:00
|
|
|
getListView().setOnItemClickListener(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setAddDeviceButtonListener(Button.OnClickListener listener) {
|
|
|
|
this.addDeviceButtonListener = listener;
|
|
|
|
}
|
|
|
|
|
2019-11-19 22:50:40 +00:00
|
|
|
public void setHandleDisconnectDevice(Function<String, Void> handler) {
|
|
|
|
this.handleDisconnectDevice = handler;
|
|
|
|
}
|
|
|
|
|
2019-11-20 23:50:33 +00:00
|
|
|
public void setHandleDeviceNameChange(Function<Pair<String, String>, Void> handler) {
|
|
|
|
this.handleDeviceNameChange = handler;
|
|
|
|
}
|
|
|
|
|
2015-11-19 18:21:19 +00:00
|
|
|
@Override
|
2019-05-22 16:51:56 +00:00
|
|
|
public @NonNull Loader<List<Device>> onCreateLoader(int id, Bundle args) {
|
2015-11-19 18:21:19 +00:00
|
|
|
empty.setVisibility(View.GONE);
|
|
|
|
progressContainer.setVisibility(View.VISIBLE);
|
|
|
|
|
2020-08-19 01:29:52 +00:00
|
|
|
return new DeviceListLoader(getActivity());
|
2015-11-19 18:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2019-05-22 16:51:56 +00:00
|
|
|
public void onLoadFinished(@NonNull Loader<List<Device>> loader, List<Device> data) {
|
2015-11-19 18:21:19 +00:00
|
|
|
progressContainer.setVisibility(View.GONE);
|
|
|
|
|
|
|
|
if (data == null) {
|
|
|
|
handleLoaderFailed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-12-02 07:35:07 +00:00
|
|
|
setListAdapter(new DeviceListAdapter(getActivity(), R.layout.device_list_item_view, data, locale));
|
2015-11-19 18:21:19 +00:00
|
|
|
|
|
|
|
if (data.isEmpty()) {
|
|
|
|
empty.setVisibility(View.VISIBLE);
|
|
|
|
TextSecurePreferences.setMultiDevice(getActivity(), false);
|
|
|
|
} else {
|
|
|
|
empty.setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2019-05-22 16:51:56 +00:00
|
|
|
public void onLoaderReset(@NonNull Loader<List<Device>> loader) {
|
2015-11-19 18:21:19 +00:00
|
|
|
setListAdapter(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
2019-11-20 23:50:33 +00:00
|
|
|
final boolean hasDeviceName = ((DeviceListItem)view).hasDeviceName(); // Tells us whether the name is set to shortId or the device name
|
2015-11-19 18:21:19 +00:00
|
|
|
final String deviceName = ((DeviceListItem)view).getDeviceName();
|
2019-11-20 23:50:33 +00:00
|
|
|
final String deviceId = ((DeviceListItem)view).getDeviceId();
|
|
|
|
|
2020-01-31 20:58:32 +00:00
|
|
|
DeviceEditingOptionsBottomSheet bottomSheet = new DeviceEditingOptionsBottomSheet();
|
2019-11-20 23:50:33 +00:00
|
|
|
bottomSheet.setOnEditTapped(() -> {
|
|
|
|
bottomSheet.dismiss();
|
2019-12-02 04:03:12 +00:00
|
|
|
EditText deviceNameEditText = new EditText(getContext());
|
|
|
|
LinearLayout deviceNameEditTextContainer = new LinearLayout(getContext());
|
|
|
|
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
|
|
layoutParams.setMarginStart(toPx(18, getResources()));
|
|
|
|
layoutParams.setMarginEnd(toPx(18, getResources()));
|
|
|
|
deviceNameEditText.setLayoutParams(layoutParams);
|
|
|
|
deviceNameEditTextContainer.addView(deviceNameEditText);
|
|
|
|
deviceNameEditText.setText(hasDeviceName ? deviceName : "");
|
2019-11-20 23:50:33 +00:00
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
|
|
|
builder.setTitle(R.string.DeviceListActivity_edit_device_name);
|
2019-12-02 04:03:12 +00:00
|
|
|
builder.setView(deviceNameEditTextContainer);
|
2019-11-20 23:50:33 +00:00
|
|
|
builder.setNegativeButton(android.R.string.cancel, null);
|
|
|
|
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
2019-12-02 04:03:12 +00:00
|
|
|
if (handleDeviceNameChange != null) { handleDeviceNameChange.apply(new Pair<>(deviceId, deviceNameEditText.getText().toString().trim())); }
|
2019-11-20 23:50:33 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
builder.show();
|
|
|
|
return Unit.INSTANCE;
|
2015-11-19 18:21:19 +00:00
|
|
|
});
|
2019-11-20 23:50:33 +00:00
|
|
|
bottomSheet.setOnUnlinkTapped(() -> {
|
|
|
|
bottomSheet.dismiss();
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
|
|
|
builder.setTitle(getActivity().getString(R.string.DeviceListActivity_unlink_s, deviceName));
|
|
|
|
builder.setMessage(R.string.DeviceListActivity_by_unlinking_this_device_it_will_no_longer_be_able_to_send_or_receive);
|
|
|
|
builder.setNegativeButton(android.R.string.cancel, null);
|
|
|
|
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
if (handleDisconnectDevice != null) { handleDisconnectDevice.apply(deviceId); }
|
|
|
|
}
|
|
|
|
});
|
|
|
|
builder.show();
|
|
|
|
return Unit.INSTANCE;
|
|
|
|
});
|
|
|
|
bottomSheet.show(getFragmentManager(), bottomSheet.getTag());
|
2015-11-19 18:21:19 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 22:50:40 +00:00
|
|
|
public void refresh() {
|
2019-11-20 00:44:44 +00:00
|
|
|
updateAddDeviceButtonVisibility();
|
2019-11-19 22:50:40 +00:00
|
|
|
getLoaderManager().restartLoader(0, null, DeviceListFragment.this);
|
|
|
|
}
|
|
|
|
|
2019-11-20 00:44:44 +00:00
|
|
|
private void updateAddDeviceButtonVisibility() {
|
|
|
|
if (addDeviceButton != null) {
|
|
|
|
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(getContext());
|
2020-02-12 01:26:27 +00:00
|
|
|
boolean isDeviceLinkingEnabled = DatabaseFactory.getLokiAPIDatabase(getContext()).getDeviceLinks(userHexEncodedPublicKey).isEmpty();
|
2019-11-20 00:44:44 +00:00
|
|
|
addDeviceButton.setVisibility(isDeviceLinkingEnabled ? View.VISIBLE : View.INVISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-19 18:21:19 +00:00
|
|
|
private void handleLoaderFailed() {
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
|
|
|
builder.setMessage(R.string.DeviceListActivity_network_connection_failed);
|
|
|
|
builder.setPositiveButton(R.string.DeviceListActivity_try_again,
|
|
|
|
new DialogInterface.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
2016-09-14 12:46:18 +00:00
|
|
|
getLoaderManager().restartLoader(0, null, DeviceListFragment.this);
|
2015-11-19 18:21:19 +00:00
|
|
|
}
|
|
|
|
});
|
2015-12-14 18:29:39 +00:00
|
|
|
|
|
|
|
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
DeviceListFragment.this.getActivity().onBackPressed();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
|
|
|
@Override
|
|
|
|
public void onCancel(DialogInterface dialog) {
|
|
|
|
DeviceListFragment.this.getActivity().onBackPressed();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-11-19 18:21:19 +00:00
|
|
|
builder.show();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onClick(View v) {
|
|
|
|
if (addDeviceButtonListener != null) addDeviceButtonListener.onClick(v);
|
|
|
|
}
|
|
|
|
|
2018-12-19 16:09:22 +00:00
|
|
|
private static class DeviceListAdapter extends ArrayAdapter<Device> {
|
2015-11-19 18:21:19 +00:00
|
|
|
|
2015-12-02 07:35:07 +00:00
|
|
|
private final int resource;
|
|
|
|
private final Locale locale;
|
2015-11-19 18:21:19 +00:00
|
|
|
|
2018-12-19 16:09:22 +00:00
|
|
|
public DeviceListAdapter(Context context, int resource, List<Device> objects, Locale locale) {
|
2015-11-19 18:21:19 +00:00
|
|
|
super(context, resource, objects);
|
|
|
|
this.resource = resource;
|
2015-12-02 07:35:07 +00:00
|
|
|
this.locale = locale;
|
2015-11-19 18:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2019-05-22 16:51:56 +00:00
|
|
|
public @NonNull View getView(int position, View convertView, @NonNull ViewGroup parent) {
|
2015-11-19 18:21:19 +00:00
|
|
|
if (convertView == null) {
|
|
|
|
convertView = ((Activity)getContext()).getLayoutInflater().inflate(resource, parent, false);
|
|
|
|
}
|
|
|
|
|
2015-12-02 07:35:07 +00:00
|
|
|
((DeviceListItem)convertView).set(getItem(position), locale);
|
2015-11-19 18:21:19 +00:00
|
|
|
|
|
|
|
return convertView;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|