Use validation instead of two-way binding

This is insane, but it appears to be working. We essentially store
things in a separate class for editing, and then commit it back at a
given time.

This business with onViewStateRestored in both TunnelEditorFragment and
in TunnelDetailFragment is buggy and likely wrong.

In general TunnelEditorFragment should probably be rewritten. The
relationship with the changed name is not clear.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2018-04-28 04:45:17 +02:00
parent 693228985d
commit 63071f57b7
11 changed files with 382 additions and 147 deletions

View File

@ -10,6 +10,7 @@ import android.view.ViewGroup;
import com.wireguard.android.R;
import com.wireguard.android.databinding.TunnelDetailFragmentBinding;
import com.wireguard.android.model.Tunnel;
import com.wireguard.config.Config;
/**
* Fragment that shows details about a specific tunnel.
@ -18,6 +19,7 @@ import com.wireguard.android.model.Tunnel;
public class TunnelDetailFragment extends BaseFragment {
private TunnelDetailFragmentBinding binding;
private boolean isViewStateRestored;
private String originalName;
@Override
public void onCreate(final Bundle savedInstanceState) {
@ -45,16 +47,34 @@ public class TunnelDetailFragment extends BaseFragment {
super.onDestroyView();
}
private void onConfigLoaded(Config config) {
binding.setConfig(new Config.Observable(config, originalName));
}
@Override
public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
if (binding != null && isViewStateRestored)
if (binding != null && isViewStateRestored) {
binding.setTunnel(newTunnel);
if (newTunnel == null)
binding.setConfig(null);
else {
originalName = newTunnel.getName();
newTunnel.getConfigAsync().thenAccept(this::onConfigLoaded);
}
}
}
@Override
public void onViewStateRestored(final Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
binding.setTunnel(getSelectedTunnel());
Tunnel tunnel = getSelectedTunnel();
binding.setTunnel(tunnel);
if (tunnel == null)
binding.setConfig(null);
else {
originalName = tunnel.getName();
tunnel.getConfigAsync().thenAccept(this::onConfigLoaded);
}
isViewStateRestored = true;
}
}

View File

@ -2,7 +2,6 @@ package com.wireguard.android.fragment;
import android.app.Activity;
import android.content.Context;
import android.databinding.ObservableField;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@ -31,11 +30,9 @@ import com.wireguard.config.Config;
public class TunnelEditorFragment extends BaseFragment {
private static final String KEY_LOCAL_CONFIG = "local_config";
private static final String KEY_LOCAL_NAME = "local_name";
private static final String KEY_ORIGINAL_NAME = "original_name";
private static final String TAG = "WireGuard/" + TunnelEditorFragment.class.getSimpleName();
private final ObservableField<String> localName = new ObservableField<>("");
private TunnelEditorFragmentBinding binding;
private boolean isViewStateRestored;
private Config localConfig = new Config();
@ -56,7 +53,7 @@ public class TunnelEditorFragment extends BaseFragment {
private void onConfigLoaded(final Config config) {
localConfig = copyParcelable(config);
if (binding != null && isViewStateRestored)
binding.setConfig(localConfig);
binding.setConfig(new Config.Observable(localConfig, originalName));
}
private void onConfigSaved(@SuppressWarnings("unused") final Config config,
@ -82,20 +79,17 @@ public class TunnelEditorFragment extends BaseFragment {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
localConfig = savedInstanceState.getParcelable(KEY_LOCAL_CONFIG);
localName.set(savedInstanceState.getString(KEY_LOCAL_NAME));
originalName = savedInstanceState.getString(KEY_ORIGINAL_NAME);
}
// Erase the remains of creating or editing a different tunnel.
if (getSelectedTunnel() != null && !getSelectedTunnel().getName().equals(originalName)) {
// The config must be loaded asynchronously since it's not an observable property.
localConfig = null;
getSelectedTunnel().getConfigAsync().thenAccept(this::onConfigLoaded);
originalName = getSelectedTunnel().getName();
localName.set(originalName);
getSelectedTunnel().getConfigAsync().thenAccept(this::onConfigLoaded);
} else if (getSelectedTunnel() == null && originalName != null) {
localConfig = new Config();
originalName = null;
localName.set("");
}
localTunnel = getSelectedTunnel();
setHasOptionsMenu(true);
@ -147,14 +141,26 @@ public class TunnelEditorFragment extends BaseFragment {
switch (item.getItemId()) {
case R.id.menu_action_save:
final Tunnel selectedTunnel = getSelectedTunnel();
if (localConfig != null) {
try {
binding.getConfig().commitData(localConfig);
} catch (Exception e) {
final String error = ExceptionLoggers.unwrap(e).getMessage();
final String message = getString(R.string.config_save_error, localTunnel.getName(), error);
Log.e(TAG, message, e);
final CoordinatorLayout container = binding.mainContainer;
Snackbar.make(container, error, Snackbar.LENGTH_LONG).show();
return false;
}
}
if (selectedTunnel == null) {
Log.d(TAG, "Attempting to create new tunnel " + localName.get());
Log.d(TAG, "Attempting to create new tunnel " + binding.getConfig().getName());
final TunnelManager manager = Application.getComponent().getTunnelManager();
manager.create(localName.get(), localConfig)
manager.create(binding.getConfig().getName(), localConfig)
.whenComplete(this::onTunnelCreated);
} else if (!selectedTunnel.getName().equals(localName.get())) {
Log.d(TAG, "Attempting to rename tunnel to " + localName.get());
selectedTunnel.setName(localName.get())
} else if (!selectedTunnel.getName().equals(binding.getConfig().getName())) {
Log.d(TAG, "Attempting to rename tunnel to " + binding.getConfig().getName());
selectedTunnel.setName(binding.getConfig().getName())
.whenComplete(this::onTunnelRenamed);
} else if (localConfig != null) {
Log.d(TAG, "Attempting to save config of " + selectedTunnel.getName());
@ -170,7 +176,6 @@ public class TunnelEditorFragment extends BaseFragment {
@Override
public void onSaveInstanceState(final Bundle outState) {
outState.putParcelable(KEY_LOCAL_CONFIG, localConfig);
outState.putString(KEY_LOCAL_NAME, localName.get());
outState.putString(KEY_ORIGINAL_NAME, originalName);
super.onSaveInstanceState(outState);
}
@ -181,15 +186,13 @@ public class TunnelEditorFragment extends BaseFragment {
if (newTunnel != null) {
// The config must be loaded asynchronously since it's not an observable property.
localConfig = null;
newTunnel.getConfigAsync().thenAccept(this::onConfigLoaded);
originalName = newTunnel.getName();
localName.set(originalName);
newTunnel.getConfigAsync().thenAccept(this::onConfigLoaded);
} else {
localConfig = new Config();
if (binding != null && isViewStateRestored)
binding.setConfig(localConfig);
binding.setConfig(new Config.Observable(localConfig, ""));
originalName = null;
localName.set("");
}
localTunnel = newTunnel;
}
@ -234,8 +237,9 @@ public class TunnelEditorFragment extends BaseFragment {
@Override
public void onViewStateRestored(final Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
binding.setConfig(localConfig);
binding.setName(localName);
if (localConfig == null)
localConfig = new Config();
binding.setConfig(new Config.Observable(localConfig, originalName));
isViewStateRestored = true;
}
}

View File

@ -54,6 +54,8 @@ enum Attribute {
}
public static String[] stringToList(final String string) {
if (string == null)
return new String[0];
return string.trim().split("\\s*,\\s*");
}

View File

@ -1,6 +1,9 @@
package com.wireguard.config;
import com.android.databinding.library.baseAdapters.BR;
import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.databinding.ObservableArrayList;
import android.databinding.ObservableList;
import android.os.Parcel;
@ -11,12 +14,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a wg-quick configuration file, its name, and its connection state.
*/
public class Config extends BaseObservable implements Parcelable {
public class Config implements Parcelable {
public static final Creator<Config> CREATOR = new Creator<Config>() {
@Override
public Config createFromParcel(final Parcel in) {
@ -29,8 +34,59 @@ public class Config extends BaseObservable implements Parcelable {
}
};
public static class Observable extends BaseObservable {
private String name;
private Interface.Observable observableInterface;
private ObservableList<Peer.Observable> observablePeers;
public Observable(Config parent, String name) {
this.name = name;
loadData(parent);
}
public void loadData(Config parent) {
this.observableInterface = new Interface.Observable(parent.interfaceSection);
this.observablePeers = new ObservableArrayList<>();
for (Peer peer : parent.getPeers())
this.observablePeers.add(new Peer.Observable(peer));
}
public void commitData(Config parent) {
this.observableInterface.commitData(parent.interfaceSection);
List<Peer> newPeers = new ArrayList<>(this.observablePeers.size());
for (Peer.Observable observablePeer : this.observablePeers) {
Peer peer = new Peer();
observablePeer.commitData(peer);
newPeers.add(peer);
}
parent.peers = newPeers;
notifyChange();
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
@Bindable
public Interface.Observable getInterfaceSection() {
return observableInterface;
}
@Bindable
public ObservableList<Peer.Observable> getPeers() {
return observablePeers;
}
}
private final Interface interfaceSection;
private final ObservableList<Peer> peers = new ObservableArrayList<>();
private List<Peer> peers = new ArrayList<>();
public Config() {
interfaceSection = new Interface();
@ -83,7 +139,7 @@ public class Config extends BaseObservable implements Parcelable {
return interfaceSection;
}
public ObservableList<Peer> getPeers() {
public List<Peer> getPeers() {
return peers;
}

View File

@ -6,7 +6,6 @@ import android.os.Parcelable;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class IPCidr implements Parcelable {
InetAddress address;

View File

@ -10,7 +10,6 @@ import com.wireguard.crypto.KeyEncoding;
import com.wireguard.crypto.Keypair;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;
@ -18,7 +17,7 @@ import java.util.List;
* Represents the configuration for a WireGuard interface (an [Interface] block).
*/
public class Interface extends BaseObservable implements Parcelable {
public class Interface implements Parcelable {
public static final Creator<Interface> CREATOR = new Creator<Interface>() {
@Override
public Interface createFromParcel(final Parcel in) {
@ -31,12 +30,114 @@ public class Interface extends BaseObservable implements Parcelable {
}
};
public static class Observable extends BaseObservable {
private String addresses;
private String dnses;
private String publicKey;
private String privateKey;
private String listenPort;
private String mtu;
public Observable(Interface parent) {
loadData(parent);
}
public void loadData(Interface parent) {
this.addresses = parent.getAddressString();
this.dnses = parent.getDnsString();
this.publicKey = parent.getPublicKey();
this.privateKey = parent.getPrivateKey();
this.listenPort = parent.getListenPortString();
this.mtu = parent.getMtuString();
}
public void commitData(Interface parent) {
parent.setAddressString(this.addresses);
parent.setDnsString(this.dnses);
parent.setPrivateKey(this.privateKey);
parent.setListenPortString(this.listenPort);
parent.setMtuString(this.mtu);
loadData(parent);
notifyChange();
}
@Bindable
public String getAddresses() {
return addresses;
}
public void setAddresses(String addresses) {
this.addresses = addresses;
notifyPropertyChanged(BR.addresses);
}
@Bindable
public String getDnses() {
return dnses;
}
public void setDnses(String dnses) {
this.dnses = dnses;
notifyPropertyChanged(BR.dnses);
}
@Bindable
public String getPublicKey() {
return publicKey;
}
@Bindable
public String getPrivateKey() {
return privateKey;
}
public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
try {
this.publicKey = new Keypair(privateKey).getPublicKey();
} catch (IllegalArgumentException ignored) {
this.publicKey = "";
}
notifyPropertyChanged(BR.privateKey);
notifyPropertyChanged(BR.publicKey);
}
public void generateKeypair() {
Keypair keypair = new Keypair();
privateKey = keypair.getPrivateKey();
publicKey = keypair.getPublicKey();
notifyPropertyChanged(BR.privateKey);
notifyPropertyChanged(BR.publicKey);
}
@Bindable
public String getListenPort() {
return listenPort;
}
public void setListenPort(String listenPort) {
this.listenPort = listenPort;
notifyPropertyChanged(BR.listenPort);
}
@Bindable
public String getMtu() {
return mtu;
}
public void setMtu(String mtu) {
this.mtu = mtu;
notifyPropertyChanged(BR.mtu);
}
}
private List<IPCidr> addressList;
private List<InetAddress> dnsList;
private Keypair keypair;
private int listenPort;
private int mtu;
private String privateKey;
public Interface() {
addressList = new LinkedList<>();
@ -63,76 +164,63 @@ public class Interface extends BaseObservable implements Parcelable {
return 0;
}
public void generateKeypair() {
keypair = new Keypair();
privateKey = keypair.getPrivateKey();
notifyPropertyChanged(BR.privateKey);
notifyPropertyChanged(BR.publicKey);
}
@Bindable
public String getAddressString() {
private String getAddressString() {
if (addressList.isEmpty())
return null;
return Attribute.listToString(addressList);
}
@Bindable
public IPCidr[] getAddresses() {
return addressList.toArray(new IPCidr[addressList.size()]);
}
public List<String> getDnsStrings() {
private List<String> getDnsStrings() {
List<String> strings = new LinkedList<>();
for (final InetAddress addr : dnsList)
strings.add(addr.getHostAddress());
return strings;
}
@Bindable
public String getDnsString() {
private String getDnsString() {
if (dnsList.isEmpty())
return null;
return Attribute.listToString(getDnsStrings());
}
@Bindable
public InetAddress[] getDnses() {
return dnsList.toArray(new InetAddress[dnsList.size()]);
}
@Bindable
public int getListenPort() {
return listenPort;
}
@Bindable
public String getListenPortString() {
private String getListenPortString() {
if (listenPort == 0)
return null;
return new Integer(listenPort).toString();
}
@Bindable
public int getMtu() {
return mtu;
}
@Bindable
public String getMtuString() {
private String getMtuString() {
if (mtu == 0)
return null;
return new Integer(mtu).toString();
}
@Bindable
public String getPrivateKey() {
return privateKey;
if (keypair == null)
return null;
return keypair.getPrivateKey();
}
@Bindable
public String getPublicKey() {
return keypair != null ? keypair.getPublicKey() : null;
if (keypair == null)
return null;
return keypair.getPublicKey();
}
public void parse(final String line) {
@ -151,7 +239,7 @@ public class Interface extends BaseObservable implements Parcelable {
throw new IllegalArgumentException(line);
}
public void addAddresses(String[] addresses) {
private void addAddresses(String[] addresses) {
if (addresses != null && addresses.length > 0) {
for (final String addr : addresses) {
if (addr.isEmpty())
@ -159,74 +247,55 @@ public class Interface extends BaseObservable implements Parcelable {
this.addressList.add(new IPCidr(addr));
}
}
notifyPropertyChanged(BR.addresses);
notifyPropertyChanged(BR.addressString);
}
public void setAddressString(final String addressString) {
private void setAddressString(final String addressString) {
this.addressList.clear();
addAddresses(Attribute.stringToList(addressString));
}
public void addDnses(String[] dnses) {
private void addDnses(String[] dnses) {
if (dnses != null && dnses.length > 0) {
for (final String dns : dnses) {
this.dnsList.add(Attribute.parseIPString(dns));
}
}
notifyPropertyChanged(BR.dnses);
notifyPropertyChanged(BR.dnsString);
}
public void setDnsString(final String dnsString) {
private void setDnsString(final String dnsString) {
this.dnsList.clear();
addDnses(Attribute.stringToList(dnsString));
}
public void setListenPort(int listenPort) {
private void setListenPort(int listenPort) {
this.listenPort = listenPort;
notifyPropertyChanged(BR.listenPort);
notifyPropertyChanged(BR.listenPortString);
}
public void setListenPortString(final String port) {
private void setListenPortString(final String port) {
if (port != null && !port.isEmpty())
setListenPort(Integer.parseInt(port, 10));
else
setListenPort(0);
}
public void setMtu(int mtu) {
private void setMtu(int mtu) {
this.mtu = mtu;
notifyPropertyChanged(BR.mtu);
notifyPropertyChanged(BR.mtuString);
}
public void setMtuString(final String mtu) {
private void setMtuString(final String mtu) {
if (mtu != null && !mtu.isEmpty())
setMtu(Integer.parseInt(mtu, 10));
else
setMtu(0);
}
public void setPrivateKey(String privateKey) {
private void setPrivateKey(String privateKey) {
if (privateKey != null && privateKey.isEmpty())
privateKey = null;
this.privateKey = privateKey;
if (privateKey != null && privateKey.length() == KeyEncoding.KEY_LENGTH_BASE64) {
try {
keypair = new Keypair(privateKey);
} catch (final IllegalArgumentException e) {
keypair = null;
throw e;
}
} else {
if (privateKey == null)
keypair = null;
}
notifyPropertyChanged(BR.privateKey);
notifyPropertyChanged(BR.publicKey);
else
keypair = new Keypair(privateKey);
}
@Override
@ -240,8 +309,8 @@ public class Interface extends BaseObservable implements Parcelable {
sb.append(Attribute.LISTEN_PORT.composeWith(listenPort));
if (mtu != 0)
sb.append(Attribute.MTU.composeWith(mtu));
if (privateKey != null)
sb.append(Attribute.PRIVATE_KEY.composeWith(privateKey));
if (keypair != null)
sb.append(Attribute.PRIVATE_KEY.composeWith(keypair.getPrivateKey()));
return sb.toString();
}
@ -253,6 +322,6 @@ public class Interface extends BaseObservable implements Parcelable {
dest.writeByteArray(addr.getAddress());
dest.writeInt(listenPort);
dest.writeInt(mtu);
dest.writeString(privateKey);
dest.writeString(keypair == null ? "" : keypair.getPrivateKey());
}
}

View File

@ -6,6 +6,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.android.databinding.library.baseAdapters.BR;
import com.wireguard.crypto.KeyEncoding;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
@ -19,7 +20,7 @@ import java.util.List;
* Represents the configuration for a WireGuard peer (a [Peer] block).
*/
public class Peer extends BaseObservable implements Parcelable {
public class Peer implements Parcelable {
public static final Creator<Peer> CREATOR = new Creator<Peer>() {
@Override
public Peer createFromParcel(final Parcel in) {
@ -32,6 +33,92 @@ public class Peer extends BaseObservable implements Parcelable {
}
};
public static class Observable extends BaseObservable {
private String allowedIPs;
private String endpoint;
private String persistentKeepalive;
private String preSharedKey;
private String publicKey;
public Observable(Peer parent) {
loadData(parent);
}
public static Observable newInstance() {
return new Observable(new Peer());
}
public void loadData(Peer parent) {
this.allowedIPs = parent.getAllowedIPsString();
this.endpoint = parent.getEndpointString();
this.persistentKeepalive = parent.getPersistentKeepaliveString();
this.preSharedKey = parent.getPreSharedKey();
this.publicKey = parent.getPublicKey();
}
public void commitData(Peer parent) {
parent.setAllowedIPsString(this.allowedIPs);
parent.setEndpointString(this.endpoint);
parent.setPersistentKeepaliveString(this.persistentKeepalive);
parent.setPreSharedKey(this.preSharedKey);
parent.setPublicKey(this.publicKey);
if (parent.getPublicKey() == null)
throw new IllegalArgumentException("Peer public key may not be empty");
loadData(parent);
notifyChange();
}
@Bindable
public String getAllowedIPs() {
return allowedIPs;
}
public void setAllowedIPs(String allowedIPs) {
this.allowedIPs = allowedIPs;
notifyPropertyChanged(BR.allowedIPs);
}
@Bindable
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
notifyPropertyChanged(BR.endpoint);
}
@Bindable
public String getPersistentKeepalive() {
return persistentKeepalive;
}
public void setPersistentKeepalive(String persistentKeepalive) {
this.persistentKeepalive = persistentKeepalive;
notifyPropertyChanged(BR.persistentKeepalive);
}
@Bindable
public String getPreSharedKey() {
return preSharedKey;
}
public void setPreSharedKey(String preSharedKey) {
this.preSharedKey = preSharedKey;
notifyPropertyChanged(BR.preSharedKey);
}
@Bindable
public String getPublicKey() {
return publicKey;
}
public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
notifyPropertyChanged(BR.publicKey);
}
}
private List<IPCidr> allowedIPsList;
private InetSocketAddress endpoint;
private int persistentKeepalive;
@ -57,35 +144,27 @@ public class Peer extends BaseObservable implements Parcelable {
publicKey = null;
}
public static Peer newInstance() {
return new Peer();
}
@Override
public int describeContents() {
return 0;
}
@Bindable
public String getAllowedIPsString() {
private String getAllowedIPsString() {
if (allowedIPsList.isEmpty())
return null;
return Attribute.listToString(allowedIPsList);
}
@Bindable
public IPCidr[] getAllowedIPs() {
return allowedIPsList.toArray(new IPCidr[allowedIPsList.size()]);
}
@Bindable
public InetSocketAddress getEndpoint() {
return endpoint;
}
@Bindable
public String getEndpointString() {
private String getEndpointString() {
if (endpoint == null)
return null;
return String.format("%s:%d", endpoint.getHostString(), endpoint.getPort());
@ -103,24 +182,20 @@ public class Peer extends BaseObservable implements Parcelable {
return String.format("%s:%d", endpoint.getAddress().getHostAddress(), endpoint.getPort());
}
@Bindable
public int getPersistentKeepalive() {
return persistentKeepalive;
}
@Bindable
public String getPersistentKeepaliveString() {
private String getPersistentKeepaliveString() {
if (persistentKeepalive == 0)
return null;
return new Integer(persistentKeepalive).toString();
}
@Bindable
public String getPreSharedKey() {
return preSharedKey;
}
@Bindable
public String getPublicKey() {
return publicKey;
}
@ -141,28 +216,24 @@ public class Peer extends BaseObservable implements Parcelable {
throw new IllegalArgumentException(line);
}
public void addAllowedIPs(String[] allowedIPs) {
private void addAllowedIPs(String[] allowedIPs) {
if (allowedIPs != null && allowedIPs.length > 0) {
for (final String allowedIP : allowedIPs) {
this.allowedIPsList.add(new IPCidr(allowedIP));
}
}
notifyPropertyChanged(BR.allowedIPs);
notifyPropertyChanged(BR.allowedIPsString);
}
public void setAllowedIPsString(final String allowedIPsString) {
private void setAllowedIPsString(final String allowedIPsString) {
this.allowedIPsList.clear();
addAllowedIPs(Attribute.stringToList(allowedIPsString));
}
public void setEndpoint(InetSocketAddress endpoint) {
private void setEndpoint(InetSocketAddress endpoint) {
this.endpoint = endpoint;
notifyPropertyChanged(BR.endpoint);
notifyPropertyChanged(BR.endpointString);
}
public void setEndpointString(final String endpoint) {
private void setEndpointString(final String endpoint) {
if (endpoint != null && !endpoint.isEmpty()) {
InetSocketAddress constructedEndpoint;
if (endpoint.indexOf('/') != -1 || endpoint.indexOf('?') != -1 || endpoint.indexOf('#') != -1)
@ -179,31 +250,31 @@ public class Peer extends BaseObservable implements Parcelable {
setEndpoint(null);
}
public void setPersistentKeepalive(int persistentKeepalive) {
private void setPersistentKeepalive(int persistentKeepalive) {
this.persistentKeepalive = persistentKeepalive;
notifyPropertyChanged(BR.persistentKeepalive);
notifyPropertyChanged(BR.persistentKeepaliveString);
}
public void setPersistentKeepaliveString(String persistentKeepalive) {
private void setPersistentKeepaliveString(String persistentKeepalive) {
if (persistentKeepalive != null && !persistentKeepalive.isEmpty())
setPersistentKeepalive(Integer.parseInt(persistentKeepalive, 10));
else
setPersistentKeepalive(0);
}
public void setPreSharedKey(String preSharedKey) {
private void setPreSharedKey(String preSharedKey) {
if (preSharedKey != null && preSharedKey.isEmpty())
preSharedKey = null;
if (preSharedKey != null)
KeyEncoding.keyFromBase64(preSharedKey);
this.preSharedKey = preSharedKey;
notifyPropertyChanged(BR.preSharedKey);
}
public void setPublicKey(String publicKey) {
private void setPublicKey(String publicKey) {
if (publicKey != null && publicKey.isEmpty())
publicKey = null;
if (publicKey != null)
KeyEncoding.keyFromBase64(publicKey);
this.publicKey = publicKey;
notifyPropertyChanged(BR.publicKey);
}
@Override

View File

@ -14,6 +14,10 @@
<variable
name="tunnel"
type="com.wireguard.android.model.Tunnel" />
<variable
name="config"
type="com.wireguard.config.Config.Observable" />
</data>
<ScrollView
@ -92,7 +96,25 @@
android:ellipsize="end"
android:maxLines="1"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{tunnel.config.interface.publicKey}" />
android:text="@{config.interfaceSection.publicKey}" />
<TextView
android:id="@+id/addresses_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/public_key_text"
android:layout_marginTop="8dp"
android:labelFor="@+id/addresses_text"
android:text="@string/addresses" />
<TextView
android:id="@+id/addresses_text"
style="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/addresses_label"
android:contentDescription="@string/addresses"
android:text="@{config.interfaceSection.addresses}" />
</RelativeLayout>
<LinearLayout
@ -101,7 +123,7 @@
android:layout_marginBottom="4dp"
android:divider="@null"
android:orientation="vertical"
app:items="@{tunnel.config.peers}"
app:items="@{config.peers}"
app:layout="@{@layout/tunnel_detail_peer}"
tools:ignore="UselessLeaf" />
</LinearLayout>

View File

@ -5,13 +5,9 @@
<import type="com.wireguard.android.util.ClipboardUtils" />
<variable
name="collection"
type="android.databinding.ObservableList&lt;com.wireguard.config.Peer&gt;" />
<variable
name="item"
type="com.wireguard.config.Peer" />
type="com.wireguard.config.Peer.Observable" />
</data>
<RelativeLayout
@ -69,7 +65,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/allowed_ips_label"
android:text="@{item.allowedIPsString}" />
android:text="@{item.allowedIPs}" />
<TextView
android:id="@+id/endpoint_label"
@ -86,6 +82,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/endpoint_label"
android:text="@{item.endpointString}" />
android:text="@{item.endpoint}" />
</RelativeLayout>
</layout>

View File

@ -15,11 +15,7 @@
<variable
name="config"
type="com.wireguard.config.Config" />
<variable
name="name"
type="android.databinding.ObservableField&lt;String&gt;" />
type="com.wireguard.config.Config.Observable" />
</data>
<com.commonsware.cwac.crossport.design.widget.CoordinatorLayout
@ -71,7 +67,7 @@
android:layout_height="wrap_content"
android:layout_below="@+id/interface_name_label"
android:inputType="textNoSuggestions|textVisiblePassword"
android:text="@={name}"
android:text="@={config.name}"
app:filter="@{NameInputFilter.newInstance()}" />
<TextView
@ -91,7 +87,7 @@
android:layout_toStartOf="@+id/generate_private_key_button"
android:contentDescription="@string/public_key_description"
android:inputType="textNoSuggestions|textVisiblePassword"
android:text="@={config.interface.privateKey}"
android:text="@={config.interfaceSection.privateKey}"
app:filter="@{KeyInputFilter.newInstance()}" />
<Button
@ -101,7 +97,7 @@
android:layout_alignBottom="@id/private_key_text"
android:layout_alignParentEnd="true"
android:layout_below="@+id/private_key_label"
android:onClick="@{() -> config.interface.generateKeypair()}"
android:onClick="@{() -> config.interfaceSection.generateKeypair()}"
android:text="@string/generate" />
<TextView
@ -124,7 +120,7 @@
android:maxLines="1"
android:contentDescription="@string/public_key_description"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{config.interface.publicKey}" />
android:text="@{config.interfaceSection.publicKey}" />
<TextView
android:id="@+id/addresses_label"
@ -144,7 +140,7 @@
android:layout_below="@+id/addresses_label"
android:layout_toStartOf="@+id/listen_port_text"
android:inputType="textNoSuggestions|textVisiblePassword"
android:text="@={config.interface.addressString}" />
android:text="@={config.interfaceSection.addresses}" />
<TextView
android:id="@+id/listen_port_label"
@ -165,7 +161,7 @@
android:layout_alignStart="@+id/generate_private_key_button"
android:hint="@string/hint_random"
android:inputType="number"
android:text="@={config.interface.listenPortString}"
android:text="@={config.interfaceSection.listenPort}"
android:textAlignment="center" />
<TextView
@ -186,7 +182,7 @@
android:layout_below="@+id/dns_servers_label"
android:layout_toStartOf="@+id/mtu_text"
android:inputType="textNoSuggestions|textVisiblePassword"
android:text="@={config.interface.dnsString}" />
android:text="@={config.interfaceSection.dnses}" />
<TextView
android:id="@+id/mtu_label"
@ -207,7 +203,7 @@
android:layout_alignStart="@+id/generate_private_key_button"
android:hint="@string/hint_automatic"
android:inputType="number"
android:text="@={config.interface.mtuString}"
android:text="@={config.interfaceSection.mtu}"
android:textAlignment="center" />
</RelativeLayout>
@ -226,7 +222,7 @@
android:layout_marginBottom="4dp"
android:layout_marginEnd="4dp"
android:layout_marginStart="4dp"
android:onClick="@{() -> config.peers.add(Peer.newInstance())}"
android:onClick="@{() -> config.peers.add(Peer.Observable.newInstance())}"
android:text="@string/add_peer" />
</LinearLayout>
</ScrollView>

View File

@ -8,11 +8,11 @@
<variable
name="collection"
type="android.databinding.ObservableList&lt;com.wireguard.config.Peer&gt;" />
type="android.databinding.ObservableList&lt;com.wireguard.config.Peer.Observable&gt;" />
<variable
name="item"
type="com.wireguard.config.Peer" />
type="com.wireguard.config.Peer.Observable" />
</data>
<RelativeLayout
@ -96,7 +96,7 @@
android:layout_height="wrap_content"
android:layout_below="@+id/allowed_ips_label"
android:inputType="textNoSuggestions|textVisiblePassword"
android:text="@={item.allowedIPsString}" />
android:text="@={item.allowedIPs}" />
<TextView
android:id="@+id/endpoint_label"
@ -116,7 +116,7 @@
android:layout_below="@+id/endpoint_label"
android:layout_toStartOf="@+id/persistent_keepalive_text"
android:inputType="textNoSuggestions|textVisiblePassword"
android:text="@={item.endpointString}" />
android:text="@={item.endpoint}" />
<TextView
android:id="@+id/persistent_keepalive_label"
@ -136,7 +136,7 @@
android:layout_alignStart="@+id/persistent_keepalive_label"
android:hint="@string/hint_optional"
android:inputType="number"
android:text="@={item.persistentKeepaliveString}"
android:text="@={item.persistentKeepalive}"
android:textAlignment="center" />
</RelativeLayout>
</layout>