mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Device link related views removed. General unused code cleanup.
This commit is contained in:
parent
a94273fdfc
commit
eafa7c7a77
@ -101,7 +101,7 @@
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.Session.DayNight.FlatActionBar"/>
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.loki.activities.RestoreActivity"
|
||||
android:name="org.thoughtcrime.securesms.loki.activities.RecoveryPhraseRestoreActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:theme="@style/Theme.Session.DayNight.FlatActionBar" />
|
||||
|
@ -1,60 +0,0 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import network.loki.messenger.R;
|
||||
|
||||
public class DeviceLinkFragment extends Fragment implements View.OnClickListener {
|
||||
|
||||
private LinearLayout container;
|
||||
private LinkClickedListener linkClickedListener;
|
||||
private Uri uri;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) {
|
||||
this.container = (LinearLayout) inflater.inflate(R.layout.device_link_fragment, container, false);
|
||||
this.container.findViewById(R.id.link_device).setOnClickListener(this);
|
||||
|
||||
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
container.setOrientation(LinearLayout.HORIZONTAL);
|
||||
} else {
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
}
|
||||
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfiguration) {
|
||||
super.onConfigurationChanged(newConfiguration);
|
||||
if (newConfiguration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
container.setOrientation(LinearLayout.HORIZONTAL);
|
||||
} else {
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLinkClickedListener(Uri uri, LinkClickedListener linkClickedListener) {
|
||||
this.uri = uri;
|
||||
this.linkClickedListener = linkClickedListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (linkClickedListener != null) {
|
||||
linkClickedListener.onLink(uri);
|
||||
}
|
||||
}
|
||||
|
||||
public interface LinkClickedListener {
|
||||
void onLink(Uri uri);
|
||||
}
|
||||
}
|
@ -1,249 +0,0 @@
|
||||
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;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.ListFragment;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
|
||||
import com.melnykov.fab.FloatingActionButton;
|
||||
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.loaders.DeviceListLoader;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.devicelist.Device;
|
||||
import org.thoughtcrime.securesms.loki.dialogs.DeviceEditingOptionsBottomSheet;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.session.libsignal.libsignal.util.guava.Function;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import kotlin.Pair;
|
||||
import kotlin.Unit;
|
||||
import network.loki.messenger.R;
|
||||
|
||||
import static org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt.toPx;
|
||||
|
||||
public class DeviceListFragment extends ListFragment
|
||||
implements LoaderManager.LoaderCallbacks<List<Device>>,
|
||||
ListView.OnItemClickListener, InjectableType, Button.OnClickListener
|
||||
{
|
||||
|
||||
private static final String TAG = DeviceListFragment.class.getSimpleName();
|
||||
|
||||
private Locale locale;
|
||||
private View empty;
|
||||
private View progressContainer;
|
||||
private FloatingActionButton addDeviceButton;
|
||||
private Button.OnClickListener addDeviceButtonListener;
|
||||
private Function<String, Void> handleDisconnectDevice;
|
||||
private Function<Pair<String, String>, Void> handleDeviceNameChange;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
this.locale = (Locale) getArguments().getSerializable(PassphraseRequiredActionBarActivity.LOCALE_EXTRA);
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
this.empty = view.findViewById(R.id.emptyStateTextView);
|
||||
this.progressContainer = view.findViewById(R.id.activityIndicator);
|
||||
this.addDeviceButton = ViewUtil.findById(view, R.id.addDeviceButton);
|
||||
this.addDeviceButton.setOnClickListener(this);
|
||||
updateAddDeviceButtonVisibility();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle bundle) {
|
||||
super.onActivityCreated(bundle);
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
getListView().setOnItemClickListener(this);
|
||||
}
|
||||
|
||||
public void setAddDeviceButtonListener(Button.OnClickListener listener) {
|
||||
this.addDeviceButtonListener = listener;
|
||||
}
|
||||
|
||||
public void setHandleDisconnectDevice(Function<String, Void> handler) {
|
||||
this.handleDisconnectDevice = handler;
|
||||
}
|
||||
|
||||
public void setHandleDeviceNameChange(Function<Pair<String, String>, Void> handler) {
|
||||
this.handleDeviceNameChange = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Loader<List<Device>> onCreateLoader(int id, Bundle args) {
|
||||
empty.setVisibility(View.GONE);
|
||||
progressContainer.setVisibility(View.VISIBLE);
|
||||
|
||||
return new DeviceListLoader(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(@NonNull Loader<List<Device>> loader, List<Device> data) {
|
||||
progressContainer.setVisibility(View.GONE);
|
||||
|
||||
if (data == null) {
|
||||
handleLoaderFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
setListAdapter(new DeviceListAdapter(getActivity(), R.layout.device_list_item_view, data, locale));
|
||||
|
||||
if (data.isEmpty()) {
|
||||
empty.setVisibility(View.VISIBLE);
|
||||
TextSecurePreferences.setMultiDevice(getActivity(), false);
|
||||
} else {
|
||||
empty.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(@NonNull Loader<List<Device>> loader) {
|
||||
setListAdapter(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final boolean hasDeviceName = ((DeviceListItem)view).hasDeviceName(); // Tells us whether the name is set to shortId or the device name
|
||||
final String deviceName = ((DeviceListItem)view).getDeviceName();
|
||||
final String deviceId = ((DeviceListItem)view).getDeviceId();
|
||||
|
||||
DeviceEditingOptionsBottomSheet bottomSheet = new DeviceEditingOptionsBottomSheet();
|
||||
bottomSheet.setOnEditTapped(() -> {
|
||||
bottomSheet.dismiss();
|
||||
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 : "");
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setTitle(R.string.DeviceListActivity_edit_device_name);
|
||||
builder.setView(deviceNameEditTextContainer);
|
||||
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 (handleDeviceNameChange != null) { handleDeviceNameChange.apply(new Pair<>(deviceId, deviceNameEditText.getText().toString().trim())); }
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
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());
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
updateAddDeviceButtonVisibility();
|
||||
getLoaderManager().restartLoader(0, null, DeviceListFragment.this);
|
||||
}
|
||||
|
||||
private void updateAddDeviceButtonVisibility() {
|
||||
if (addDeviceButton != null) {
|
||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(getContext());
|
||||
boolean isDeviceLinkingEnabled = DatabaseFactory.getLokiAPIDatabase(getContext()).getDeviceLinks(userHexEncodedPublicKey).isEmpty();
|
||||
addDeviceButton.setVisibility(isDeviceLinkingEnabled ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
getLoaderManager().restartLoader(0, null, DeviceListFragment.this);
|
||||
}
|
||||
});
|
||||
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (addDeviceButtonListener != null) addDeviceButtonListener.onClick(v);
|
||||
}
|
||||
|
||||
private static class DeviceListAdapter extends ArrayAdapter<Device> {
|
||||
|
||||
private final int resource;
|
||||
private final Locale locale;
|
||||
|
||||
public DeviceListAdapter(Context context, int resource, List<Device> objects, Locale locale) {
|
||||
super(context, resource, objects);
|
||||
this.resource = resource;
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull View getView(int position, View convertView, @NonNull ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = ((Activity)getContext()).getLayoutInflater().inflate(resource, parent, false);
|
||||
}
|
||||
|
||||
((DeviceListItem)convertView).set(getItem(position), locale);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.devicelist.Device;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import network.loki.messenger.R;
|
||||
|
||||
public class DeviceListItem extends LinearLayout {
|
||||
|
||||
private String deviceId;
|
||||
private TextView name;
|
||||
private TextView shortId;
|
||||
|
||||
public DeviceListItem(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public DeviceListItem(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
this.name = (TextView) findViewById(R.id.name);
|
||||
this.shortId = (TextView) findViewById(R.id.shortId);
|
||||
}
|
||||
|
||||
public void set(Device deviceInfo, Locale locale) {
|
||||
this.deviceId = deviceInfo.getId();
|
||||
boolean hasName = !TextUtils.isEmpty(deviceInfo.getName());
|
||||
this.name.setText(hasName ? deviceInfo.getName() : deviceInfo.getShortId());
|
||||
this.shortId.setText(deviceInfo.getShortId());
|
||||
this.shortId.setVisibility(hasName ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return name.getText().toString();
|
||||
}
|
||||
|
||||
public boolean hasDeviceName() {
|
||||
return shortId.getVisibility() == VISIBLE;
|
||||
}
|
||||
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package org.thoughtcrime.securesms.database.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.devicelist.Device;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.AsyncLoader;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.session.libsignal.service.loki.protocol.shelved.multidevice.MultiDeviceProtocol;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class DeviceListLoader extends AsyncLoader<List<Device>> {
|
||||
|
||||
private static final String TAG = DeviceListLoader.class.getSimpleName();
|
||||
|
||||
public DeviceListLoader(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> loadInBackground() {
|
||||
try {
|
||||
String userPublicKey = TextSecurePreferences.getLocalNumber(getContext());
|
||||
Set<String> slaveDevicePublicKeys = MultiDeviceProtocol.shared.getSlaveDevices(userPublicKey);
|
||||
List<Device> devices = Stream.of(slaveDevicePublicKeys).map(this::mapToDevice).toList();
|
||||
Collections.sort(devices, new DeviceComparator());
|
||||
return devices;
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Device mapToDevice(@NonNull String hexEncodedPublicKey) {
|
||||
String shortId = "";
|
||||
String name = DatabaseFactory.getLokiUserDatabase(getContext()).getDisplayName(hexEncodedPublicKey);
|
||||
return new Device(hexEncodedPublicKey, shortId, name);
|
||||
}
|
||||
|
||||
private static class DeviceComparator implements Comparator<Device> {
|
||||
|
||||
@Override
|
||||
public int compare(Device lhs, Device rhs) {
|
||||
return lhs.getName().compareTo(rhs.getName());
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,6 @@ import org.session.libsignal.service.api.util.UptimeSleepTimer;
|
||||
import org.session.libsignal.service.api.websocket.ConnectivityListener;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.CreateProfileActivity;
|
||||
import org.thoughtcrime.securesms.DeviceListFragment;
|
||||
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob;
|
||||
@ -79,7 +78,6 @@ import network.loki.messenger.BuildConfig;
|
||||
MultiDeviceGroupUpdateJob.class,
|
||||
MultiDeviceReadUpdateJob.class,
|
||||
MultiDeviceBlockedUpdateJob.class,
|
||||
DeviceListFragment.class,
|
||||
RefreshAttributesJob.class,
|
||||
RequestGroupInfoJob.class,
|
||||
PushGroupUpdateJob.class,
|
||||
|
@ -1,20 +0,0 @@
|
||||
package org.thoughtcrime.securesms.devicelist;
|
||||
|
||||
public class Device {
|
||||
|
||||
private final String id;
|
||||
private final String shortId;
|
||||
private final String name;
|
||||
|
||||
public Device(String id, String shortId, String name) {
|
||||
this.id = id;
|
||||
this.shortId = shortId;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
public String getShortId() { return shortId; }
|
||||
public String getName() { return name; }
|
||||
}
|
@ -13,7 +13,6 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_create_closed_group.*
|
||||
import kotlinx.android.synthetic.main.activity_linked_devices.recyclerView
|
||||
import network.loki.messenger.R
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
@ -31,6 +30,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.session.libsignal.libsignal.util.guava.Optional
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
//TODO Refactor to avoid using kotlinx.android.synthetic
|
||||
class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), LoaderManager.LoaderCallbacks<List<String>> {
|
||||
private var isLoading = false
|
||||
set(newValue) { field = newValue; invalidateOptionsMenu() }
|
||||
@ -121,9 +121,9 @@ class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), LoaderM
|
||||
}
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
|
||||
isLoading = true
|
||||
loader.fadeIn()
|
||||
loaderContainer.fadeIn()
|
||||
ClosedGroupsProtocol.createClosedGroup(this, name.toString(), selectedMembers + setOf( userPublicKey )).successUi { groupID ->
|
||||
loader.fadeOut()
|
||||
loaderContainer.fadeOut()
|
||||
isLoading = false
|
||||
val threadID = DatabaseFactory.getThreadDatabase(this).getOrCreateThreadIdFor(Recipient.from(this, Address.fromSerialized(groupID), false))
|
||||
if (!isFinishing) {
|
||||
|
@ -3,25 +3,20 @@ package org.thoughtcrime.securesms.loki.activities
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.loader.app.LoaderManager
|
||||
import androidx.loader.content.Loader
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import kotlinx.android.synthetic.main.activity_create_closed_group.*
|
||||
import kotlinx.android.synthetic.main.activity_create_closed_group.emptyStateContainer
|
||||
import kotlinx.android.synthetic.main.activity_create_closed_group.mainContentContainer
|
||||
import kotlinx.android.synthetic.main.activity_edit_closed_group.*
|
||||
import kotlinx.android.synthetic.main.activity_edit_closed_group.loader
|
||||
import kotlinx.android.synthetic.main.activity_linked_devices.recyclerView
|
||||
import android.widget.*
|
||||
import androidx.loader.app.LoaderManager
|
||||
import androidx.loader.content.Loader
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import network.loki.messenger.R
|
||||
import nl.komponents.kovenant.ui.failUi
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.session.libsignal.service.loki.utilities.toHexString
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.database.Address
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
@ -32,10 +27,8 @@ import org.thoughtcrime.securesms.loki.utilities.fadeIn
|
||||
import org.thoughtcrime.securesms.loki.utilities.fadeOut
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.GroupUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil
|
||||
import org.session.libsignal.service.loki.utilities.toHexString
|
||||
import java.io.IOException
|
||||
|
||||
class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() {
|
||||
@ -60,6 +53,14 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() {
|
||||
EditClosedGroupMembersAdapter(this, GlideApp.with(this), this::onMemberClick)
|
||||
}
|
||||
|
||||
private lateinit var mainContentContainer: LinearLayout
|
||||
private lateinit var cntGroupNameEdit: LinearLayout
|
||||
private lateinit var cntGroupNameDisplay: LinearLayout
|
||||
private lateinit var edtGroupName: EditText
|
||||
private lateinit var emptyStateContainer: LinearLayout
|
||||
private lateinit var lblGroupNameDisplay: TextView
|
||||
private lateinit var loaderContainer: View
|
||||
|
||||
companion object {
|
||||
@JvmStatic val groupIDKey = "groupIDKey"
|
||||
private val loaderID = 0
|
||||
@ -79,15 +80,27 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() {
|
||||
originalName = DatabaseFactory.getGroupDatabase(this).getGroup(groupID).get().title
|
||||
name = originalName
|
||||
|
||||
addMembersClosedGroupButton.setOnClickListener { onAddMembersClick() }
|
||||
mainContentContainer = findViewById(R.id.mainContentContainer)
|
||||
cntGroupNameEdit = findViewById(R.id.cntGroupNameEdit)
|
||||
cntGroupNameDisplay = findViewById(R.id.cntGroupNameDisplay)
|
||||
edtGroupName = findViewById(R.id.edtGroupName)
|
||||
emptyStateContainer = findViewById(R.id.emptyStateContainer)
|
||||
lblGroupNameDisplay = findViewById(R.id.lblGroupNameDisplay)
|
||||
loaderContainer = findViewById(R.id.loaderContainer)
|
||||
|
||||
recyclerView.adapter = memberListAdapter
|
||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
findViewById<View>(R.id.addMembersClosedGroupButton).setOnClickListener {
|
||||
onAddMembersClick()
|
||||
}
|
||||
|
||||
findViewById<RecyclerView>(R.id.rvUserList).apply {
|
||||
adapter = memberListAdapter
|
||||
layoutManager = LinearLayoutManager(this@EditClosedGroupActivity)
|
||||
}
|
||||
|
||||
lblGroupNameDisplay.text = originalName
|
||||
cntGroupNameDisplay.setOnClickListener { isEditingName = true }
|
||||
btnCancelGroupNameEdit.setOnClickListener { isEditingName = false }
|
||||
btnSaveGroupNameEdit.setOnClickListener { saveName() }
|
||||
findViewById<Button>(R.id.btnCancelGroupNameEdit).setOnClickListener { isEditingName = false }
|
||||
findViewById<Button>(R.id.btnSaveGroupNameEdit).setOnClickListener { saveName() }
|
||||
edtGroupName.setImeActionLabel(getString(R.string.save), EditorInfo.IME_ACTION_DONE)
|
||||
edtGroupName.setOnEditorActionListener { _, actionId, _ ->
|
||||
when (actionId) {
|
||||
@ -247,9 +260,9 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() {
|
||||
|
||||
if (isSSKBasedClosedGroup) {
|
||||
isLoading = true
|
||||
loader.fadeIn()
|
||||
loaderContainer.fadeIn()
|
||||
ClosedGroupsProtocol.update(this, groupPublicKey!!, members.map { it.address.serialize() }, name).successUi {
|
||||
loader.fadeOut()
|
||||
loaderContainer.fadeOut()
|
||||
isLoading = false
|
||||
finish()
|
||||
}.failUi { exception ->
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.thoughtcrime.securesms.loki.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_landing.*
|
||||
@ -9,34 +8,11 @@ import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||
import org.thoughtcrime.securesms.database.Address
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase
|
||||
import org.thoughtcrime.securesms.logging.Log
|
||||
import org.thoughtcrime.securesms.loki.dialogs.LinkDeviceSlaveModeDialog
|
||||
import org.thoughtcrime.securesms.loki.dialogs.LinkDeviceSlaveModeDialogDelegate
|
||||
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation
|
||||
import org.thoughtcrime.securesms.loki.protocol.shelved.MultiDeviceProtocol
|
||||
import org.thoughtcrime.securesms.loki.utilities.push
|
||||
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo
|
||||
import org.thoughtcrime.securesms.loki.utilities.show
|
||||
import org.thoughtcrime.securesms.util.Base64
|
||||
import org.thoughtcrime.securesms.util.Hex
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.curve25519.Curve25519
|
||||
import org.session.libsignal.libsignal.ecc.Curve
|
||||
import org.session.libsignal.libsignal.ecc.ECKeyPair
|
||||
import org.session.libsignal.libsignal.util.KeyHelper
|
||||
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager
|
||||
import org.session.libsignal.service.loki.protocol.meta.SessionMetaProtocol
|
||||
import org.session.libsignal.service.loki.protocol.shelved.multidevice.DeviceLink
|
||||
import org.session.libsignal.service.loki.protocol.sessionmanagement.SessionManagementProtocol
|
||||
import org.session.libsignal.service.loki.protocol.shelved.syncmessages.SyncMessagesProtocol
|
||||
import org.session.libsignal.service.loki.utilities.hexEncodedPublicKey
|
||||
import org.session.libsignal.service.loki.utilities.retryIfNeeded
|
||||
import java.lang.UnsupportedOperationException
|
||||
|
||||
class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelegate {
|
||||
class LandingActivity : BaseActionBarActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -44,109 +20,26 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega
|
||||
setUpActionBarSessionLogo(true)
|
||||
fakeChatView.startAnimating()
|
||||
registerButton.setOnClickListener { register() }
|
||||
restoreButton.setOnClickListener { restore() }
|
||||
restoreBackupButton.setOnClickListener {
|
||||
val intent = Intent(this, BackupRestoreActivity::class.java)
|
||||
push(intent)
|
||||
}
|
||||
// linkButton.setOnClickListener { linkDevice() }
|
||||
restoreButton.setOnClickListener { restoreFromRecoveryPhrase() }
|
||||
restoreBackupButton.setOnClickListener { restoreFromBackup() }
|
||||
if (TextSecurePreferences.getWasUnlinked(this)) {
|
||||
Toast.makeText(this, R.string.activity_landing_device_unlinked_dialog_title, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, intent)
|
||||
if (resultCode != RESULT_OK) { return }
|
||||
val hexEncodedPublicKey = data!!.getStringExtra("hexEncodedPublicKey")
|
||||
requestDeviceLink(hexEncodedPublicKey)
|
||||
}
|
||||
|
||||
private fun register() {
|
||||
val intent = Intent(this, RegisterActivity::class.java)
|
||||
push(intent)
|
||||
}
|
||||
|
||||
private fun restore() {
|
||||
val intent = Intent(this, RestoreActivity::class.java)
|
||||
private fun restoreFromRecoveryPhrase() {
|
||||
val intent = Intent(this, RecoveryPhraseRestoreActivity::class.java)
|
||||
push(intent)
|
||||
}
|
||||
|
||||
private fun linkDevice() {
|
||||
val intent = Intent(this, LinkDeviceActivity::class.java)
|
||||
show(intent, true)
|
||||
}
|
||||
|
||||
private fun requestDeviceLink(hexEncodedPublicKey: String) {
|
||||
var seed: ByteArray? = null
|
||||
var keyPair: ECKeyPair? = null
|
||||
|
||||
//FIXME AC: Previously we used the modified version of the Signal's Curve25519 lib to generate the seed and key pair.
|
||||
// If you need to restore this logic you should probably fork and patch the lib to support that method as well.
|
||||
// https://github.com/signalapp/curve25519-java
|
||||
fun generateKeyPair() {
|
||||
throw UnsupportedOperationException("Generating device link key pair is not supported at the moment.")
|
||||
// val seedCandidate = Curve25519.getInstance(Curve25519.BEST).generateSeed(16)
|
||||
// try {
|
||||
// keyPair = Curve.generateKeyPair(seedCandidate + seedCandidate) // Validate the seed
|
||||
// } catch (exception: Exception) {
|
||||
// return generateKeyPair()
|
||||
// }
|
||||
// seed = seedCandidate
|
||||
}
|
||||
generateKeyPair()
|
||||
IdentityKeyUtil.save(this, IdentityKeyUtil.LOKI_SEED, Hex.toStringCondensed(seed))
|
||||
IdentityKeyUtil.save(this, IdentityKeyUtil.IDENTITY_PUBLIC_KEY_PREF, Base64.encodeBytes(keyPair!!.publicKey.serialize()))
|
||||
IdentityKeyUtil.save(this, IdentityKeyUtil.IDENTITY_PRIVATE_KEY_PREF, Base64.encodeBytes(keyPair!!.privateKey.serialize()))
|
||||
val userHexEncodedPublicKey = keyPair!!.hexEncodedPublicKey
|
||||
val registrationID = KeyHelper.generateRegistrationId(false)
|
||||
TextSecurePreferences.setLocalRegistrationId(this, registrationID)
|
||||
DatabaseFactory.getIdentityDatabase(this).saveIdentity(Address.fromSerialized(userHexEncodedPublicKey),
|
||||
IdentityKeyUtil.getIdentityKeyPair(this).publicKey, IdentityDatabase.VerifiedStatus.VERIFIED,
|
||||
true, System.currentTimeMillis(), true)
|
||||
TextSecurePreferences.setLocalNumber(this, userHexEncodedPublicKey)
|
||||
TextSecurePreferences.setHasSeenWelcomeScreen(this, true)
|
||||
TextSecurePreferences.setPromptedPushRegistration(this, true)
|
||||
val deviceLink = DeviceLink(hexEncodedPublicKey, userHexEncodedPublicKey).sign(DeviceLink.Type.REQUEST, keyPair!!.privateKey.serialize())
|
||||
if (deviceLink == null) {
|
||||
Log.d("Loki", "Failed to sign device link request.")
|
||||
reset()
|
||||
return Toast.makeText(application, R.string.device_linking_failed, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
val application = ApplicationContext.getInstance(this)
|
||||
application.startPollingIfNeeded()
|
||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(this)
|
||||
val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
|
||||
val userDB = DatabaseFactory.getLokiUserDatabase(this)
|
||||
val sskDatabase = DatabaseFactory.getSSKDatabase(this)
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
|
||||
val sessionResetImpl = SessionResetImplementation(this)
|
||||
MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB)
|
||||
SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey)
|
||||
org.session.libsignal.service.loki.protocol.shelved.multidevice.MultiDeviceProtocol.configureIfNeeded(apiDB)
|
||||
SessionManagementProtocol.configureIfNeeded(sessionResetImpl, sskDatabase, application)
|
||||
SyncMessagesProtocol.configureIfNeeded(apiDB, userPublicKey)
|
||||
application.setUpP2PAPIIfNeeded()
|
||||
application.setUpStorageAPIIfNeeded()
|
||||
val linkDeviceDialog = LinkDeviceSlaveModeDialog()
|
||||
linkDeviceDialog.delegate = this
|
||||
linkDeviceDialog.show(supportFragmentManager, "Link Device Dialog")
|
||||
AsyncTask.execute {
|
||||
retryIfNeeded(8) {
|
||||
MultiDeviceProtocol.sendDeviceLinkMessage(this@LandingActivity, deviceLink.masterPublicKey, deviceLink)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) {
|
||||
TextSecurePreferences.setMasterHexEncodedPublicKey(this, deviceLink.masterPublicKey)
|
||||
val intent = Intent(this, HomeActivity::class.java)
|
||||
show(intent)
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onDeviceLinkCanceled() {
|
||||
reset()
|
||||
private fun restoreFromBackup() {
|
||||
val intent = Intent(this, BackupRestoreActivity::class.java)
|
||||
push(intent)
|
||||
}
|
||||
|
||||
private fun reset() {
|
||||
|
@ -1,104 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentPagerAdapter
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_link_device.*
|
||||
import kotlinx.android.synthetic.main.fragment_enter_session_id.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragment
|
||||
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragmentDelegate
|
||||
import org.session.libsignal.service.loki.utilities.PublicKeyValidation
|
||||
|
||||
class LinkDeviceActivity : BaseActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
|
||||
private val adapter = LinkDeviceActivityAdapter(this)
|
||||
|
||||
// region Lifecycle
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
// Set content view
|
||||
setContentView(R.layout.activity_link_device)
|
||||
// Set title
|
||||
supportActionBar!!.title = resources.getString(R.string.activity_link_device_title)
|
||||
// Set up view pager
|
||||
viewPager.adapter = adapter
|
||||
tabLayout.setupWithViewPager(viewPager)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Interaction
|
||||
override fun handleQRCodeScanned(hexEncodedPublicKey: String) {
|
||||
requestDeviceLinkIfPossible(hexEncodedPublicKey)
|
||||
}
|
||||
|
||||
fun requestDeviceLinkIfPossible(hexEncodedPublicKey: String) {
|
||||
if (!PublicKeyValidation.isValid(hexEncodedPublicKey)) {
|
||||
Toast.makeText(this, R.string.invalid_session_id, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
val intent = Intent()
|
||||
intent.putExtra("hexEncodedPublicKey", hexEncodedPublicKey)
|
||||
setResult(RESULT_OK, intent)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
||||
// region Adapter
|
||||
private class LinkDeviceActivityAdapter(val activity: LinkDeviceActivity) : FragmentPagerAdapter(activity.supportFragmentManager) {
|
||||
|
||||
override fun getCount(): Int {
|
||||
return 2
|
||||
}
|
||||
|
||||
override fun getItem(index: Int): Fragment {
|
||||
return when (index) {
|
||||
0 -> EnterSessionIDFragment()
|
||||
1 -> {
|
||||
val result = ScanQRCodeWrapperFragment()
|
||||
result.delegate = activity
|
||||
result.message = activity.resources.getString(R.string.activity_link_device_scan_qr_code_explanation)
|
||||
result
|
||||
}
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPageTitle(index: Int): CharSequence? {
|
||||
return when (index) {
|
||||
0 -> activity.getString(R.string.activity_link_device_enter_session_id_tab_title)
|
||||
1 -> activity.getString(R.string.activity_link_device_scan_qr_code_tab_title)
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Enter Session ID Fragment
|
||||
class EnterSessionIDFragment : Fragment() {
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return inflater.inflate(R.layout.fragment_enter_session_id, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sessionIDEditText.imeOptions = sessionIDEditText.imeOptions or 16777216 // Always use incognito keyboard
|
||||
requestDeviceLinkButton.setOnClickListener { requestDeviceLinkIfPossible() }
|
||||
}
|
||||
|
||||
private fun requestDeviceLinkIfPossible() {
|
||||
val inputMethodManager = context!!.getSystemService(BaseActionBarActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.hideSoftInputFromWindow(sessionIDEditText.windowToken, 0)
|
||||
val hexEncodedPublicKey = sessionIDEditText.text.trim().toString().toLowerCase()
|
||||
(activity!! as LinkDeviceActivity).requestDeviceLinkIfPossible(hexEncodedPublicKey)
|
||||
}
|
||||
}
|
||||
// endregion
|
@ -1,178 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.loader.app.LoaderManager
|
||||
import androidx.loader.content.Loader
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_linked_devices.*
|
||||
import network.loki.messenger.R
|
||||
import nl.komponents.kovenant.ui.failUi
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil
|
||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.devicelist.Device
|
||||
import org.thoughtcrime.securesms.logging.Log
|
||||
import org.thoughtcrime.securesms.loki.dialogs.*
|
||||
import org.thoughtcrime.securesms.loki.protocol.shelved.SyncMessagesProtocol
|
||||
import org.thoughtcrime.securesms.loki.utilities.recipient
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.session.libsignal.service.api.messages.SignalServiceDataMessage
|
||||
import org.session.libsignal.service.api.push.SignalServiceAddress
|
||||
import org.session.libsignal.service.loki.api.fileserver.FileServerAPI
|
||||
import java.util.*
|
||||
import kotlin.concurrent.schedule
|
||||
|
||||
class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LoaderManager.LoaderCallbacks<List<Device>>, DeviceClickListener, EditDeviceNameDialogDelegate, LinkDeviceMasterModeDialogDelegate {
|
||||
private var devices = listOf<Device>()
|
||||
set(value) { field = value; linkedDevicesAdapter.devices = value }
|
||||
|
||||
private val linkedDevicesAdapter by lazy {
|
||||
val result = LinkedDevicesAdapter(this)
|
||||
result.deviceClickListener = this
|
||||
result
|
||||
}
|
||||
|
||||
// region Lifecycle
|
||||
constructor() : super()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
||||
super.onCreate(savedInstanceState, isReady)
|
||||
setContentView(R.layout.activity_linked_devices)
|
||||
supportActionBar!!.title = resources.getString(R.string.activity_linked_devices_title)
|
||||
recyclerView.adapter = linkedDevicesAdapter
|
||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
linkDeviceButton.setOnClickListener { linkDevice() }
|
||||
LoaderManager.getInstance(this).initLoader(0, null, this)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_linked_devices, menu)
|
||||
return true
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Updating
|
||||
override fun onCreateLoader(id: Int, bundle: Bundle?): Loader<List<Device>> {
|
||||
return LinkedDevicesLoader(this)
|
||||
}
|
||||
|
||||
override fun onLoadFinished(loader: Loader<List<Device>>, devices: List<Device>?) {
|
||||
update(devices ?: listOf())
|
||||
}
|
||||
|
||||
override fun onLoaderReset(loader: Loader<List<Device>>) {
|
||||
update(listOf())
|
||||
}
|
||||
|
||||
private fun update(devices: List<Device>) {
|
||||
this.devices = devices
|
||||
emptyStateContainer.visibility = if (devices.isEmpty()) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun handleDeviceNameChanged(device: Device) {
|
||||
LoaderManager.getInstance(this).restartLoader(0, null, this)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Interaction
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
val id = item.itemId
|
||||
when(id) {
|
||||
R.id.linkDeviceButton -> linkDevice()
|
||||
else -> { /* Do nothing */ }
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun linkDevice() {
|
||||
if (devices.isEmpty()) {
|
||||
val linkDeviceDialog = LinkDeviceMasterModeDialog()
|
||||
linkDeviceDialog.delegate = this
|
||||
linkDeviceDialog.show(supportFragmentManager, "Link Device Dialog")
|
||||
} else {
|
||||
val builder = AlertDialog.Builder(this)
|
||||
builder.setTitle(resources.getString(R.string.activity_linked_devices_multi_device_limit_reached_dialog_title))
|
||||
builder.setMessage(resources.getString(R.string.activity_linked_devices_multi_device_limit_reached_dialog_explanation))
|
||||
builder.setPositiveButton(resources.getString(R.string.ok), { dialog, _ -> dialog.dismiss() })
|
||||
builder.create().show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDeviceClick(device: Device) {
|
||||
val bottomSheet = DeviceEditingOptionsBottomSheet()
|
||||
bottomSheet.onEditTapped = {
|
||||
bottomSheet.dismiss()
|
||||
val editDeviceNameDialog = EditDeviceNameDialog()
|
||||
editDeviceNameDialog.device = device
|
||||
editDeviceNameDialog.delegate = this
|
||||
editDeviceNameDialog.show(supportFragmentManager, "Edit Device Name Dialog")
|
||||
}
|
||||
bottomSheet.onUnlinkTapped = {
|
||||
bottomSheet.dismiss()
|
||||
unlinkDevice(device.id)
|
||||
}
|
||||
bottomSheet.show(supportFragmentManager, bottomSheet.tag)
|
||||
}
|
||||
|
||||
private fun unlinkDevice(slaveDevicePublicKey: String) {
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
|
||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(this)
|
||||
val deviceLinks = apiDB.getDeviceLinks(userPublicKey)
|
||||
val deviceLink = deviceLinks.find { it.masterPublicKey == userPublicKey && it.slavePublicKey == slaveDevicePublicKey }
|
||||
if (deviceLink == null) {
|
||||
return Toast.makeText(this, R.string.activity_linked_devices_unlinking_failed_message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
FileServerAPI.shared.setDeviceLinks(setOf()).successUi {
|
||||
DatabaseFactory.getLokiAPIDatabase(this).clearDeviceLinks(userPublicKey)
|
||||
deviceLinks.forEach { deviceLink ->
|
||||
// We don't use PushEphemeralMessageJob because want these messages to send before the pre key and
|
||||
// session associated with the slave device have been deleted
|
||||
val unlinkingRequest = SignalServiceDataMessage.newBuilder()
|
||||
.withTimestamp(System.currentTimeMillis())
|
||||
.asDeviceUnlinkingRequest(true)
|
||||
val messageSender = ApplicationContext.getInstance(this@LinkedDevicesActivity).communicationModule.provideSignalMessageSender()
|
||||
val address = SignalServiceAddress(deviceLink.slavePublicKey)
|
||||
try {
|
||||
val udAccess = UnidentifiedAccessUtil.getAccessFor(this@LinkedDevicesActivity, recipient(this@LinkedDevicesActivity, deviceLink.slavePublicKey))
|
||||
messageSender.sendMessage(0, address, udAccess, unlinkingRequest.build()) // The message ID doesn't matter
|
||||
} catch (e: Exception) {
|
||||
Log.d("Loki", "Failed to send unlinking request due to error: $e.")
|
||||
throw e
|
||||
}
|
||||
DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(deviceLink.slavePublicKey)
|
||||
val sessionStore = TextSecureSessionStore(this@LinkedDevicesActivity)
|
||||
sessionStore.deleteAllSessions(deviceLink.slavePublicKey)
|
||||
}
|
||||
LoaderManager.getInstance(this).restartLoader(0, null, this)
|
||||
Toast.makeText(this, R.string.activity_linked_devices_unlinking_successful_message, Toast.LENGTH_LONG).show()
|
||||
}.failUi {
|
||||
Toast.makeText(this, R.string.activity_linked_devices_unlinking_failed_message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDeviceLinkRequestAuthorized() {
|
||||
SyncMessagesProtocol.syncAllClosedGroups(this)
|
||||
SyncMessagesProtocol.syncAllOpenGroups(this)
|
||||
Timer().schedule(4000) { // Not the best way to do this but the idea is to wait for the closed groups sync to go through first
|
||||
SyncMessagesProtocol.syncAllContacts(this@LinkedDevicesActivity)
|
||||
}
|
||||
LoaderManager.getInstance(this).restartLoader(0, null, this)
|
||||
}
|
||||
|
||||
override fun onDeviceLinkAuthorizationFailed() {
|
||||
Toast.makeText(this, R.string.activity_linked_devices_linking_failed_message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
override fun onDeviceLinkCanceled() {
|
||||
// Do nothing
|
||||
}
|
||||
// endregion
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki.activities
|
||||
|
||||
import android.content.Context
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.view.ViewGroup
|
||||
import org.thoughtcrime.securesms.devicelist.Device
|
||||
import org.thoughtcrime.securesms.loki.views.DeviceView
|
||||
|
||||
class LinkedDevicesAdapter(private val context: Context) : RecyclerView.Adapter<LinkedDevicesAdapter.ViewHolder>() {
|
||||
var devices = listOf<Device>()
|
||||
set(value) { field = value; notifyDataSetChanged() }
|
||||
var deviceClickListener: DeviceClickListener? = null
|
||||
|
||||
class ViewHolder(val view: DeviceView) : RecyclerView.ViewHolder(view)
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return devices.size
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = DeviceView(context)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
|
||||
val device = devices[position]
|
||||
viewHolder.view.setOnClickListener { deviceClickListener?.onDeviceClick(device) }
|
||||
viewHolder.view.bind(device)
|
||||
}
|
||||
}
|
||||
|
||||
interface DeviceClickListener {
|
||||
|
||||
fun onDeviceClick(device: Device)
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki.activities
|
||||
|
||||
import android.content.Context
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.devicelist.Device
|
||||
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.util.AsyncLoader
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.session.libsignal.service.loki.crypto.MnemonicCodec
|
||||
import org.session.libsignal.service.loki.protocol.shelved.multidevice.MultiDeviceProtocol
|
||||
import java.io.File
|
||||
|
||||
class LinkedDevicesLoader(context: Context) : AsyncLoader<List<Device>>(context) {
|
||||
|
||||
private val mnemonicCodec by lazy {
|
||||
val loadFileContents: (String) -> String = { fileName ->
|
||||
MnemonicUtilities.loadFileContents(context, fileName)
|
||||
}
|
||||
MnemonicCodec(loadFileContents)
|
||||
}
|
||||
|
||||
override fun loadInBackground(): List<Device>? {
|
||||
try {
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
val slaveDevices = MultiDeviceProtocol.shared.getSlaveDevices(userPublicKey)
|
||||
return slaveDevices.map { device ->
|
||||
val shortID = MnemonicUtilities.getFirst3Words(mnemonicCodec, device)
|
||||
val name = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(device)
|
||||
Device(device, shortID, name)
|
||||
}.sortedBy { it.name }
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ import android.text.style.ClickableSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_restore.*
|
||||
import kotlinx.android.synthetic.main.activity_recovery_phrase_restore.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||
@ -28,13 +28,13 @@ import org.session.libsignal.libsignal.util.KeyHelper
|
||||
import org.session.libsignal.service.loki.crypto.MnemonicCodec
|
||||
import org.session.libsignal.service.loki.utilities.hexEncodedPublicKey
|
||||
|
||||
class RestoreActivity : BaseActionBarActivity() {
|
||||
class RecoveryPhraseRestoreActivity : BaseActionBarActivity() {
|
||||
|
||||
// region Lifecycle
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setUpActionBarSessionLogo()
|
||||
setContentView(R.layout.activity_restore)
|
||||
setContentView(R.layout.activity_recovery_phrase_restore)
|
||||
mnemonicEditText.imeOptions = mnemonicEditText.imeOptions or 16777216 // Always use incognito keyboard
|
||||
restoreButton.setOnClickListener { restore() }
|
||||
val termsExplanation = SpannableStringBuilder("By using this service, you agree to our Terms of Service and Privacy Policy")
|
@ -9,15 +9,15 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.activity_create_closed_group.*
|
||||
import kotlinx.android.synthetic.main.activity_create_closed_group.emptyStateContainer
|
||||
import kotlinx.android.synthetic.main.activity_create_closed_group.mainContentContainer
|
||||
import kotlinx.android.synthetic.main.activity_linked_devices.recyclerView
|
||||
import kotlinx.android.synthetic.main.activity_select_contacts.*
|
||||
import kotlinx.android.synthetic.main.activity_select_contacts.recyclerView
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
|
||||
//TODO Refactor to avoid using kotlinx.android.synthetic
|
||||
class SelectContactsActivity : PassphraseRequiredActionBarActivity(), LoaderManager.LoaderCallbacks<List<String>> {
|
||||
private var members = listOf<String>()
|
||||
set(value) { field = value; selectContactsAdapter.members = value }
|
||||
|
@ -288,11 +288,6 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
push(intent)
|
||||
}
|
||||
|
||||
private fun showLinkedDevices() {
|
||||
val intent = Intent(this, LinkedDevicesActivity::class.java)
|
||||
push(intent)
|
||||
}
|
||||
|
||||
private fun sendInvitation() {
|
||||
val intent = Intent()
|
||||
intent.action = Intent.ACTION_SEND
|
||||
|
@ -1,42 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.dialog_edit_device_name.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.devicelist.Device
|
||||
|
||||
class EditDeviceNameDialog : DialogFragment() {
|
||||
private lateinit var contentView: View
|
||||
var device: Device? = null
|
||||
var delegate: EditDeviceNameDialogDelegate? = null
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val builder = AlertDialog.Builder(context!!)
|
||||
contentView = LayoutInflater.from(context!!).inflate(R.layout.dialog_edit_device_name, null)
|
||||
contentView.cancelButton.setOnClickListener { dismiss() }
|
||||
contentView.okButton.setOnClickListener { updateDeviceName() }
|
||||
builder.setView(contentView)
|
||||
val result = builder.create()
|
||||
result.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
return result
|
||||
}
|
||||
|
||||
private fun updateDeviceName() {
|
||||
DatabaseFactory.getLokiUserDatabase(context).setDisplayName(device!!.id, contentView.deviceNameEditText.text.toString())
|
||||
delegate?.handleDeviceNameChanged(device!!)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
interface EditDeviceNameDialogDelegate {
|
||||
|
||||
fun handleDeviceNameChanged(device: Device)
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.dialog_link_device_master_mode.view.*
|
||||
import network.loki.messenger.R
|
||||
import nl.komponents.kovenant.functional.bind
|
||||
import nl.komponents.kovenant.ui.failUi
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.loki.protocol.shelved.MultiDeviceProtocol
|
||||
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.loki.utilities.QRCodeUtilities
|
||||
import org.thoughtcrime.securesms.loki.utilities.toPx
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.session.libsignal.service.loki.api.SnodeAPI
|
||||
import org.session.libsignal.service.loki.api.fileserver.FileServerAPI
|
||||
import org.session.libsignal.service.loki.crypto.MnemonicCodec
|
||||
import org.session.libsignal.service.loki.protocol.shelved.multidevice.DeviceLink
|
||||
import org.session.libsignal.service.loki.protocol.shelved.multidevice.DeviceLinkingSession
|
||||
import org.session.libsignal.service.loki.protocol.shelved.multidevice.DeviceLinkingSessionListener
|
||||
|
||||
class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListener {
|
||||
private lateinit var contentView: View
|
||||
private var deviceLink: DeviceLink? = null
|
||||
var delegate: LinkDeviceMasterModeDialogDelegate? = null
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val builder = AlertDialog.Builder(requireContext())
|
||||
contentView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_link_device_master_mode, null)
|
||||
val size = toPx(128, resources)
|
||||
val hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(requireContext())
|
||||
val qrCode = QRCodeUtilities.encode(hexEncodedPublicKey, size, false, false)
|
||||
contentView.qrCodeImageView.setImageBitmap(qrCode)
|
||||
contentView.cancelButton.setOnClickListener { onDeviceLinkCanceled() }
|
||||
contentView.authorizeButton.setOnClickListener { authorizeDeviceLink() }
|
||||
builder.setView(contentView)
|
||||
DeviceLinkingSession.shared.startListeningForLinkingRequests() // FIXME: This flag is named poorly as it's actually also used for authorizations
|
||||
DeviceLinkingSession.shared.addListener(this)
|
||||
val result = builder.create()
|
||||
result.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
return result
|
||||
}
|
||||
|
||||
override fun requestUserAuthorization(deviceLink: DeviceLink) {
|
||||
if (deviceLink.type != DeviceLink.Type.REQUEST || deviceLink.masterPublicKey != TextSecurePreferences.getLocalNumber(requireContext()) || this.deviceLink != null) { return }
|
||||
Util.runOnMain {
|
||||
this.deviceLink = deviceLink
|
||||
contentView.qrCodeImageView.visibility = View.GONE
|
||||
val titleTextViewLayoutParams = contentView.titleTextView.layoutParams as LinearLayout.LayoutParams
|
||||
titleTextViewLayoutParams.topMargin = toPx(8, resources)
|
||||
contentView.titleTextView.layoutParams = titleTextViewLayoutParams
|
||||
contentView.titleTextView.text = resources.getString(R.string.dialog_link_device_master_mode_title_2)
|
||||
contentView.explanationTextView.text = resources.getString(R.string.dialog_link_device_master_mode_explanation_2)
|
||||
contentView.mnemonicTextView.visibility = View.VISIBLE
|
||||
val loadFileContents: (String) -> String = { fileName ->
|
||||
MnemonicUtilities.loadFileContents(requireContext(), fileName)
|
||||
}
|
||||
contentView.mnemonicTextView.text = MnemonicUtilities.getFirst3Words(MnemonicCodec(loadFileContents), deviceLink.slavePublicKey)
|
||||
contentView.authorizeButton.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
private fun authorizeDeviceLink() {
|
||||
val deviceLink = this.deviceLink ?: return
|
||||
DeviceLinkingSession.shared.stopListeningForLinkingRequests()
|
||||
DeviceLinkingSession.shared.removeListener(this)
|
||||
Util.runOnMain {
|
||||
contentView.qrCodeImageViewContainer.visibility = View.GONE
|
||||
contentView.spinner.visibility = View.VISIBLE
|
||||
val titleTextViewLayoutParams = contentView.titleTextView.layoutParams as LinearLayout.LayoutParams
|
||||
titleTextViewLayoutParams.topMargin = toPx(24, resources)
|
||||
contentView.titleTextView.layoutParams = titleTextViewLayoutParams
|
||||
contentView.titleTextView.text = resources.getString(R.string.dialog_link_device_master_mode_title_3)
|
||||
contentView.explanationTextView.text = resources.getString(R.string.dialog_link_device_master_mode_explanation_3)
|
||||
contentView.mnemonicTextView.visibility = View.GONE
|
||||
contentView.buttonContainer.visibility = View.GONE
|
||||
contentView.cancelButton.visibility = View.GONE
|
||||
contentView.authorizeButton.visibility = View.GONE
|
||||
}
|
||||
FileServerAPI.shared.addDeviceLink(deviceLink).bind(SnodeAPI.sharedContext) {
|
||||
MultiDeviceProtocol.signAndSendDeviceLinkMessage(requireContext(), deviceLink)
|
||||
}.success {
|
||||
TextSecurePreferences.setMultiDevice(requireContext(), true)
|
||||
}.successUi {
|
||||
delegate?.onDeviceLinkRequestAuthorized()
|
||||
dismiss()
|
||||
}.fail {
|
||||
FileServerAPI.shared.removeDeviceLink(deviceLink) // If this fails we have a problem
|
||||
DatabaseFactory.getLokiPreKeyBundleDatabase(requireContext()).removePreKeyBundle(deviceLink.slavePublicKey)
|
||||
}.failUi {
|
||||
delegate?.onDeviceLinkAuthorizationFailed()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onDeviceLinkCanceled() {
|
||||
DeviceLinkingSession.shared.stopListeningForLinkingRequests()
|
||||
DeviceLinkingSession.shared.removeListener(this)
|
||||
if (deviceLink != null) {
|
||||
DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(deviceLink!!.slavePublicKey)
|
||||
}
|
||||
dismiss()
|
||||
delegate?.onDeviceLinkCanceled()
|
||||
}
|
||||
}
|
||||
|
||||
interface LinkDeviceMasterModeDialogDelegate {
|
||||
|
||||
fun onDeviceLinkRequestAuthorized()
|
||||
fun onDeviceLinkAuthorizationFailed()
|
||||
fun onDeviceLinkCanceled()
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.dialog_link_device_slave_mode.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.session.libsignal.service.loki.crypto.MnemonicCodec
|
||||
import org.session.libsignal.service.loki.protocol.shelved.multidevice.DeviceLink
|
||||
import org.session.libsignal.service.loki.protocol.shelved.multidevice.DeviceLinkingSession
|
||||
import org.session.libsignal.service.loki.protocol.shelved.multidevice.DeviceLinkingSessionListener
|
||||
|
||||
class LinkDeviceSlaveModeDialog : DialogFragment(), DeviceLinkingSessionListener {
|
||||
private lateinit var contentView: View
|
||||
private var deviceLink: DeviceLink? = null
|
||||
var delegate: LinkDeviceSlaveModeDialogDelegate? = null
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val builder = AlertDialog.Builder(requireContext())
|
||||
contentView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_link_device_slave_mode, null)
|
||||
val hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
val loadFileContents: (String) -> String = { fileName ->
|
||||
MnemonicUtilities.loadFileContents(requireContext(), fileName)
|
||||
}
|
||||
contentView.mnemonicTextView.text = MnemonicUtilities.getFirst3Words(MnemonicCodec(loadFileContents), hexEncodedPublicKey)
|
||||
contentView.cancelButton.setOnClickListener { onDeviceLinkCanceled() }
|
||||
builder.setView(contentView)
|
||||
DeviceLinkingSession.shared.startListeningForLinkingRequests()
|
||||
DeviceLinkingSession.shared.addListener(this)
|
||||
val result = builder.create()
|
||||
result.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
return result
|
||||
}
|
||||
|
||||
override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) {
|
||||
if (deviceLink.type != DeviceLink.Type.AUTHORIZATION || deviceLink.slavePublicKey != TextSecurePreferences.getLocalNumber(requireContext()) || this.deviceLink != null) { return }
|
||||
Util.runOnMain {
|
||||
this.deviceLink = deviceLink
|
||||
DeviceLinkingSession.shared.stopListeningForLinkingRequests()
|
||||
DeviceLinkingSession.shared.removeListener(this)
|
||||
contentView.spinner.visibility = View.GONE
|
||||
val titleTextViewLayoutParams = contentView.titleTextView.layoutParams as LinearLayout.LayoutParams
|
||||
titleTextViewLayoutParams.topMargin = 0
|
||||
contentView.titleTextView.layoutParams = titleTextViewLayoutParams
|
||||
contentView.titleTextView.text = resources.getString(R.string.dialog_link_device_slave_mode_title_2)
|
||||
contentView.explanationTextView.text = resources.getString(R.string.dialog_link_device_slave_mode_explanation_2)
|
||||
contentView.mnemonicTextView.visibility = View.GONE
|
||||
contentView.cancelButton.visibility = View.GONE
|
||||
Handler().postDelayed({
|
||||
dismiss()
|
||||
delegate?.onDeviceLinkRequestAuthorized(deviceLink)
|
||||
}, 4000)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onDeviceLinkCanceled() {
|
||||
DeviceLinkingSession.shared.stopListeningForLinkingRequests()
|
||||
DeviceLinkingSession.shared.removeListener(this)
|
||||
dismiss()
|
||||
delegate?.onDeviceLinkCanceled()
|
||||
}
|
||||
}
|
||||
|
||||
interface LinkDeviceSlaveModeDialogDelegate {
|
||||
|
||||
fun onDeviceLinkRequestAuthorized(authorization: DeviceLink)
|
||||
fun onDeviceLinkCanceled()
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki.views
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.view_device.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.devicelist.Device
|
||||
import org.thoughtcrime.securesms.loki.utilities.toPx
|
||||
|
||||
class DeviceView : LinearLayout {
|
||||
var device: Device? = null
|
||||
|
||||
// region Lifecycle
|
||||
constructor(context: Context) : super(context) {
|
||||
setUpViewHierarchy()
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||
setUpViewHierarchy()
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||
setUpViewHierarchy()
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||
setUpViewHierarchy()
|
||||
}
|
||||
|
||||
private fun setUpViewHierarchy() {
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
val contentView = inflater.inflate(R.layout.view_device, null)
|
||||
addView(contentView)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Updating
|
||||
fun bind(device: Device) {
|
||||
titleTextView.text = if (!device.name.isNullOrBlank()) device.name else "Unnamed Device"
|
||||
// FIXME: Hacky way of getting the view to be screen width
|
||||
val titleTextViewLayoutParams = titleTextView.layoutParams
|
||||
titleTextViewLayoutParams.width = resources.displayMetrics.widthPixels - toPx(32, resources)
|
||||
titleTextView.layoutParams = titleTextViewLayoutParams
|
||||
subtitleTextView.text = device.shortId
|
||||
}
|
||||
// endregion
|
||||
}
|
@ -66,7 +66,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/loader"
|
||||
android:id="@+id/loaderContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#A4000000"
|
||||
|
@ -129,7 +129,7 @@
|
||||
android:background="?android:dividerHorizontal" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:id="@+id/rvUserList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:listitem="@layout/view_user"/>
|
||||
@ -147,7 +147,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/loader"
|
||||
android:id="@+id/loaderContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#A4000000"
|
||||
|
@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
style="@style/Widget.Session.TabLayout"
|
||||
android:id="@+id/tabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tab_bar_height" />
|
||||
|
||||
</androidx.viewpager.widget.ViewPager>
|
@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/emptyStateContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:layout_centerInParent="true">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="@string/activity_linked_devices_empty_state_message" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Common.ProminentOutline"
|
||||
android:id="@+id/linkDeviceButton"
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:text="@string/activity_linked_devices_empty_state_button_title" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<FrameLayout android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<org.thoughtcrime.securesms.components.camera.CameraView
|
||||
android:id="@+id/scanner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:camera="0"/>
|
||||
|
||||
<LinearLayout android:id="@+id/overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:weightSum="2">
|
||||
|
||||
<org.thoughtcrime.securesms.components.ShapeScrim
|
||||
android:layout_weight="1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:background="?android:windowBackground"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView android:id="@+id/devices"
|
||||
android:src="@drawable/ic_devices_white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:tint="@color/gray27"
|
||||
android:transitionName="devices"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView android:text="@string/device_add_fragment__scan_the_qr_code_displayed_on_the_device_to_link"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:textColorSecondary"/>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
@ -1,88 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_devices_white"
|
||||
android:transitionName="devices"
|
||||
android:tint="@color/gray27"
|
||||
android:layout_marginBottom="25dp"
|
||||
android:contentDescription="@string/device_link_fragment__link_device"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp">
|
||||
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="?device_link_item_card_background">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/DeviceProvisioningActivity_link_this_device"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
<View android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="#1E000000"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:text="@string/DeviceProvisioningActivity_content_intro"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:text="@string/DeviceProvisioningActivity_content_bullets"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
<View android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="#1E000000"/>
|
||||
|
||||
<LinearLayout android:id="@+id/link_device"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:clickable="true">
|
||||
|
||||
<ImageView android:id="@+id/check"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/ic_check_white_24dp"
|
||||
android:tint="@color/blue_400"
|
||||
android:clickable="false"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/blue_400"
|
||||
android:text="@string/device_link_fragment__link_device"
|
||||
android:clickable="false"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
@ -1,49 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:fab="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/activityIndicator"
|
||||
android:indeterminate="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/emptyStateTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:textSize="20sp"
|
||||
android:visibility="gone"
|
||||
android:text="@string/device_list_fragment__no_devices_linked"
|
||||
android:paddingStart="16dip"
|
||||
android:paddingEnd="16dip"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<ListView
|
||||
android:id="@id/android:list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:drawSelectorOnTop="false" />
|
||||
|
||||
<com.melnykov.fab.FloatingActionButton
|
||||
android:id="@+id/addDeviceButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_margin="16dp"
|
||||
android:src="@drawable/ic_add_white_original_24dp"
|
||||
android:focusable="true"
|
||||
android:contentDescription="@string/device_list_fragment__link_new_device"
|
||||
fab:fab_colorNormal="?fab_color"
|
||||
fab:fab_colorPressed="@color/textsecure_primary_dark"
|
||||
fab:fab_colorRipple="@color/textsecure_primary_dark" />
|
||||
|
||||
</RelativeLayout>
|
@ -1,34 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.thoughtcrime.securesms.DeviceListItem
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:text="Name"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="?attr/conversation_list_item_contact_color"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/shortId"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:text="shortId"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="#A2A2A2"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</org.thoughtcrime.securesms.DeviceListItem>
|
@ -1,59 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/default_dialog_background_inset"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="32dp"
|
||||
android:paddingTop="@dimen/medium_spacing"
|
||||
android:paddingRight="32dp"
|
||||
android:paddingBottom="@dimen/medium_spacing">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Change Device Name"
|
||||
android:textStyle="bold"
|
||||
android:textSize="@dimen/medium_font_size" />
|
||||
|
||||
<EditText
|
||||
style="@style/SessionEditText"
|
||||
android:id="@+id/deviceNameEditText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/medium_spacing"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:layout_marginRight="@dimen/medium_spacing"
|
||||
android:textAlignment="center"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:hint="@string/dialog_edit_device_name_edit_text_hint" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.Unimportant"
|
||||
android:id="@+id/cancelButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/cancel" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.Unimportant"
|
||||
android:id="@+id/okButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginLeft="@dimen/medium_spacing"
|
||||
android:text="@string/ok" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:background="@drawable/default_dialog_background_inset"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="32dp"
|
||||
android:paddingTop="@dimen/medium_spacing"
|
||||
android:paddingRight="32dp"
|
||||
android:paddingBottom="@dimen/medium_spacing">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/qrCodeImageViewContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/small_spacing"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/qrCodeImageView"
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="128dp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<com.github.ybq.android.spinkit.SpinKitView
|
||||
style="@style/SpinKitView.DoubleBounce"
|
||||
android:id="@+id/spinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:visibility="gone"
|
||||
app:SpinKit_Color="@color/text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/titleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="@string/dialog_link_device_master_mode_title_1"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:textSize="@dimen/medium_font_size" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/explanationTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="@string/dialog_link_device_master_mode_explanation_1"
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textAlignment="center" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mnemonicTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="puffin circle idled"
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textAlignment="center"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/buttonContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.Unimportant"
|
||||
android:id="@+id/cancelButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/cancel" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.Prominent"
|
||||
android:id="@+id/authorizeButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="@dimen/medium_spacing"
|
||||
android:text="@string/dialog_link_device_master_mode_authorize_button_title"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -1,61 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:background="@drawable/default_dialog_background_inset"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="32dp"
|
||||
android:paddingTop="@dimen/medium_spacing"
|
||||
android:paddingRight="32dp"
|
||||
android:paddingBottom="@dimen/medium_spacing">
|
||||
|
||||
<com.github.ybq.android.spinkit.SpinKitView
|
||||
style="@style/SpinKitView.DoubleBounce"
|
||||
android:id="@+id/spinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:SpinKit_Color="@color/text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/titleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="@string/dialog_link_device_slave_mode_title_1"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:textSize="@dimen/medium_font_size" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/explanationTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="@string/dialog_link_device_slave_mode_explanation_1"
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textAlignment="center" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mnemonicTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="puffin circle idled"
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textAlignment="center" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.Unimportant"
|
||||
android:id="@+id/cancelButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="@string/cancel" />
|
||||
|
||||
</LinearLayout>
|
Loading…
Reference in New Issue
Block a user