mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Merge branch '1234-remote-contacts' into 'master'
Implement UX for adding contacts remotely Closes #1234 See merge request briar/briar!1035
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package org.briarproject.bramble.api.contact;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
@@ -10,12 +11,17 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface ContactManager {
|
||||
|
||||
int LINK_LENGTH = 64;
|
||||
Pattern LINK_REGEX =
|
||||
Pattern.compile("(briar://)?([a-z2-7]{" + LINK_LENGTH + "})");
|
||||
|
||||
/**
|
||||
* Registers a hook to be called whenever a contact is added or removed.
|
||||
* This method should be called before
|
||||
@@ -55,32 +61,27 @@ public interface ContactManager {
|
||||
/**
|
||||
* Returns the static link that needs to be sent to the contact to be added.
|
||||
*/
|
||||
String getRemoteContactLink();
|
||||
|
||||
/**
|
||||
* Returns true if the given link is syntactically valid.
|
||||
*/
|
||||
boolean isValidRemoteContactLink(String link);
|
||||
String getHandshakeLink() throws DbException;
|
||||
|
||||
/**
|
||||
* Requests a new contact to be added via the given {@code link}.
|
||||
*
|
||||
* @param link The link received from the contact we want to add.
|
||||
* @param alias The alias the user has given this contact.
|
||||
* @return A PendingContact representing the contact to be added.
|
||||
*/
|
||||
PendingContact addRemoteContactRequest(String link, String alias);
|
||||
void addPendingContact(String link, String alias)
|
||||
throws DbException, FormatException;
|
||||
|
||||
/**
|
||||
* Returns a list of {@link PendingContact}s.
|
||||
*/
|
||||
Collection<PendingContact> getPendingContacts();
|
||||
Collection<PendingContact> getPendingContacts() throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a {@link PendingContact} that is in state
|
||||
* {@link PendingContactState FAILED}.
|
||||
*/
|
||||
void removePendingContact(PendingContact pendingContact);
|
||||
void removePendingContact(PendingContactId pendingContact) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the contact with the given ID.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.briarproject.briar.api.introduction.event;
|
||||
package org.briarproject.bramble.api.contact.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
@@ -8,11 +8,11 @@ import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class IntroductionSucceededEvent extends Event {
|
||||
public class ContactAddedRemotelyEvent extends Event {
|
||||
|
||||
private final Contact contact;
|
||||
|
||||
public IntroductionSucceededEvent(Contact contact) {
|
||||
public ContactAddedRemotelyEvent(Contact contact) {
|
||||
this.contact = contact;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.briarproject.bramble.api.contact.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* An event that is broadcast when a pending contact is removed.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class PendingContactRemovedEvent extends Event {
|
||||
|
||||
private final PendingContactId id;
|
||||
|
||||
public PendingContactRemovedEvent(PendingContactId id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public PendingContactId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,16 +22,13 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED;
|
||||
@@ -42,11 +39,8 @@ import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||
@NotNullByDefault
|
||||
class ContactManagerImpl implements ContactManager {
|
||||
|
||||
private static final int LINK_LENGTH = 64;
|
||||
private static final String REMOTE_CONTACT_LINK =
|
||||
"briar://" + getRandomBase32String(LINK_LENGTH);
|
||||
private static final Pattern LINK_REGEX =
|
||||
Pattern.compile("(briar://)?([a-z2-7]{" + LINK_LENGTH + "})");
|
||||
|
||||
private final DatabaseComponent db;
|
||||
private final KeyManager keyManager;
|
||||
@@ -97,11 +91,12 @@ class ContactManagerImpl implements ContactManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteContactLink() {
|
||||
public String getHandshakeLink() {
|
||||
// TODO replace with real implementation
|
||||
return REMOTE_CONTACT_LINK;
|
||||
}
|
||||
|
||||
// TODO replace with real implementation
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static String getRandomBase32String(int length) {
|
||||
Random random = new Random();
|
||||
@@ -115,16 +110,9 @@ class ContactManagerImpl implements ContactManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidRemoteContactLink(String link) {
|
||||
return LINK_REGEX.matcher(link).matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingContact addRemoteContactRequest(String link, String alias) {
|
||||
public void addPendingContact(String link, String alias)
|
||||
throws DbException {
|
||||
// TODO replace with real implementation
|
||||
PendingContactId id = new PendingContactId(link.getBytes());
|
||||
return new PendingContact(id, new byte[MAX_PUBLIC_KEY_LENGTH], alias,
|
||||
WAITING_FOR_CONNECTION, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,7 +122,7 @@ class ContactManagerImpl implements ContactManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePendingContact(PendingContact pendingContact) {
|
||||
public void removePendingContact(PendingContactId id) throws DbException {
|
||||
// TODO replace with real implementation
|
||||
}
|
||||
|
||||
|
||||
57
briar-android/artwork/ic_nearby.svg
Normal file
57
briar-android/artwork/ic_nearby.svg
Normal file
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="svg12"
|
||||
sodipodi:docname="nearby.svg"
|
||||
style="fill:none"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)">
|
||||
<metadata
|
||||
id="metadata18">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs16" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1020"
|
||||
id="namedview14"
|
||||
showgrid="false"
|
||||
inkscape:zoom="15.170655"
|
||||
inkscape:cx="9.6488139"
|
||||
inkscape:cy="11.430963"
|
||||
inkscape:window-x="1440"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg12" />
|
||||
<path
|
||||
style="opacity:1;fill:#110000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.37658679px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 11.173062,2.4030645 C 9.9685672,2.4471125 8.7753453,2.7130268 7.6640583,3.2033016 8.187015,3.7262611 8.3967456,4.1446273 8.6059301,4.5629964 11.639055,3.412486 15.091396,4.0393524 17.497058,6.4449696 c 0.732151,0.7321412 1.359335,1.5691523 1.673062,2.5104781 0.418424,-0.2091845 0.941213,-0.3133673 1.464151,-0.3133672 h 0.104456 C 20.215788,7.3869735 19.482978,6.3401088 18.541616,5.2941863 16.528265,3.2807917 13.82295,2.3061587 11.173062,2.4030645 Z M 5.1695142,3.2316286 A 2.7193895,2.7193895 0 0 0 2.4501247,5.9510181 2.7193895,2.7193895 0 0 0 5.1695142,8.6704075 2.7193895,2.7193895 0 0 0 7.8889037,5.9510181 2.7193895,2.7193895 0 0 0 5.1695142,3.2316286 Z M 2.5404169,8.5358543 C 0.97153856,12.196552 1.7027262,16.484811 4.6313017,19.413413 c 1.8826514,1.987239 4.497171,2.930071 7.0073853,2.930071 2.510177,0 5.126431,-0.942832 7.009154,-2.930071 0.941272,-0.941362 1.672402,-2.091035 2.195341,-3.346124 h -0.104455 c -0.522939,0 -1.045818,-0.104155 -1.464151,-0.313367 -0.418423,0.941362 -0.940911,1.778328 -1.673062,2.510478 -3.242327,3.242419 -8.5770829,3.242419 -11.819429,0 C 3.27188,15.858828 2.6451458,12.406442 3.795656,9.3732707 3.377287,9.164086 2.9587814,8.9542233 2.5404169,8.5358543 Z m 9.0540081,0.8444984 a 2.9913288,2.9913284 0 0 0 -2.9902654,2.9902663 2.9913288,2.9913284 0 0 0 2.9902654,2.992036 2.9913288,2.9913284 0 0 0 2.992037,-2.992036 2.9913288,2.9913284 0 0 0 -2.992037,-2.9902663 z m 9.138991,0.423134 a 2.7193895,2.7193895 0 0 0 -2.71939,2.7193903 2.7193895,2.7193895 0 0 0 2.71939,2.719389 2.7193895,2.7193895 0 0 0 2.719389,-2.719389 2.7193895,2.7193895 0 0 0 -2.719389,-2.7193903 z"
|
||||
id="path832-3-6"
|
||||
inkscape:connector-curvature="0" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
176
briar-android/artwork/nickname.svg
Normal file
176
briar-android/artwork/nickname.svg
Normal file
@@ -0,0 +1,176 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="150"
|
||||
height="178"
|
||||
viewBox="0 0 150 178"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg129"
|
||||
sodipodi:docname="nickname.svg"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)">
|
||||
<metadata
|
||||
id="metadata133">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1020"
|
||||
id="namedview131"
|
||||
showgrid="false"
|
||||
inkscape:zoom="3.7500494"
|
||||
inkscape:cx="84.461975"
|
||||
inkscape:cy="96.344913"
|
||||
inkscape:window-x="1440"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg129" />
|
||||
<path
|
||||
d="M 85.1905,0.127869 3.35693,0.328805 C 2.46521,0.330621 1.6107,0.690255 0.981217,1.32866 0.351735,1.96706 -0.0011965,2.83198 3.04782e-6,3.73331 L 0.372743,156.201 c 0.001185,0.446 0.089367,0.888 0.259505,1.3 0.170138,0.412 0.418902,0.786 0.732092,1.101 0.31319,0.315 0.68466,0.564 1.09322,0.734 0.40856,0.17 0.84619,0.257 1.28792,0.256 l 81.83362,-0.201 c 0.8917,-0.003 1.746,-0.363 2.375,-1.002 0.6291,-0.639 0.9814,-1.504 0.9796,-2.405 L 88.5542,3.51639 C 88.5512,2.61665 88.1955,1.75479 87.565,1.11965 86.9345,0.484503 86.0807,0.127864 85.1905,0.127869 Z"
|
||||
id="path2"
|
||||
inkscape:connector-curvature="0"
|
||||
style="display:inline;opacity:0.25;fill:url(#paint0_linear)" />
|
||||
<path
|
||||
d="M 84.2815,-0.0019907 4.27572,0.195606 C 2.57395,0.199809 1.19777,1.59763 1.20193,3.31772 L 1.56691,154.298 c 0.00416,1.72 1.38709,3.111 3.08885,3.107 l 80.00584,-0.198 c 1.7017,-0.004 3.0779,-1.402 3.0737,-3.122 L 87.3704,3.1049 C 87.3662,1.38481 85.9833,-0.0061937 84.2815,-0.0019907 Z"
|
||||
id="path4"
|
||||
inkscape:connector-curvature="0"
|
||||
style="display:inline;opacity:0.25;fill:#6d6d6d;fill-opacity:0.7" />
|
||||
<path
|
||||
style="display:inline;opacity:0.25;fill:#646464"
|
||||
d="M 81.939453 3.9570312 L 65.933594 3.9960938 C 65.688694 5.6638138 64.861562 7.1881588 63.601562 8.2929688 C 62.341563 9.3977688 60.732453 10.010031 59.064453 10.019531 L 29.302734 10.091797 C 27.634734 10.090597 26.021259 9.4871919 24.755859 8.3886719 C 23.490459 7.2901519 22.655444 5.7700256 22.402344 4.1035156 L 6.6367188 4.1425781 C 5.7689587 4.1449981 4.9382819 4.4954875 4.3261719 5.1171875 C 3.7140519 5.7388975 3.3712469 6.5799313 3.3730469 7.4570312 L 3.4609375 44.068359 L 3.7167969 150.16797 C 3.7209769 151.04497 4.0691969 151.88495 4.6855469 152.50195 C 5.3018969 153.11895 6.1361462 153.46394 7.0039062 153.46094 L 82.306641 153.27539 C 83.171641 153.27039 83.999475 152.92078 84.609375 152.30078 C 85.219375 151.68078 85.560547 150.8408 85.560547 149.9668 L 85.306641 43.5625 L 85.220703 7.2558594 C 85.218303 6.3787594 84.870959 5.5386319 84.255859 4.9199219 C 83.640859 4.3012219 82.807253 3.9552112 81.939453 3.9570312 z M 52.652344 5.7910156 L 34.357422 6.0683594 C 34.107922 6.0721494 33.908409 6.27906 33.912109 6.53125 L 33.916016 6.8300781 C 33.919716 7.0822681 34.1255 7.28504 34.375 7.28125 L 52.671875 7.0019531 C 52.921375 6.9981731 53.118934 6.7912525 53.115234 6.5390625 L 53.111328 6.2402344 C 53.107628 5.9880444 52.901844 5.7872256 52.652344 5.7910156 z "
|
||||
id="path6" />
|
||||
<path
|
||||
d="M 57.2036,6.934 C 57.6016,6.92797 57.9193,6.59699 57.9133,6.19476 57.9074,5.79252 57.5799,5.47134 57.182,5.47738 c -0.398,0.00604 -0.7157,0.33701 -0.7098,0.73924 0.006,0.40224 0.3335,0.72342 0.7314,0.71738 z"
|
||||
id="path10"
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:0.25;fill:#dbdbdb" />
|
||||
<path
|
||||
style="display:inline;opacity:0.25;fill:#e0e0e0"
|
||||
d="m 17.640625,19.458984 c -4.1846,0 -7.576172,3.445513 -7.576172,7.695313 0,4.2498 3.391572,7.695312 7.576172,7.695312 4.1845,0 7.576172,-3.445512 7.576172,-7.695312 0,-4.2498 -3.391672,-7.695313 -7.576172,-7.695313 z m 19.882813,4.177735 v 3.234375 h 40.117187 v -3.234375 z m 0,6.466797 v 3.234375 H 77.640625 V 30.103516 Z M 17.640625,44.087891 c -4.1846,0 -7.576172,3.443559 -7.576172,7.693359 0,4.2498 3.391572,7.695313 7.576172,7.695312 4.1845,0 7.576172,-3.445512 7.576172,-7.695312 0,-4.2498 -3.391672,-7.693359 -7.576172,-7.693359 z m 19.882813,4.177734 V 51.5 h 40.117187 v -3.234375 z m 0,6.466797 v 3.232422 H 77.640625 V 54.732422 Z M 17.640625,68.714844 c -4.1846,0 -7.576172,3.445512 -7.576172,7.695312 0,4.2498 3.391572,7.695313 7.576172,7.695313 4.1845,0 7.576172,-3.445513 7.576172,-7.695313 0,-4.2498 -3.391672,-7.695312 -7.576172,-7.695312 z m 19.882813,4.179687 v 3.232422 h 40.117187 v -3.232422 z m 0,6.466797 V 82.59375 H 77.640625 V 79.361328 Z M 17.640625,93.34375 c -4.1846,0 -7.576172,3.445613 -7.576172,7.69531 0,4.25 3.391572,7.69532 7.576172,7.69532 4.1845,0 7.576172,-3.44532 7.576172,-7.69532 0,-4.249698 -3.391672,-7.69531 -7.576172,-7.69531 z m 19.882813,4.179688 v 3.232422 h 40.117187 v -3.232422 z m 0,6.464842 v 3.23438 h 40.117187 v -3.23438 z m -19.882813,13.98438 c -4.1846,0 -7.576172,3.44631 -7.576172,7.69531 0,4.25 3.391572,7.69336 7.576172,7.69336 4.1845,0 7.576172,-3.44336 7.576172,-7.69336 0,-4.249 -3.391672,-7.69531 -7.576172,-7.69531 z m 19.882813,4.17773 v 3.23438 h 40.117187 v -3.23438 z m 0,6.4668 v 3.23437 h 40.117187 v -3.23437 z"
|
||||
id="path12"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="display:inline;fill:#313131"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path44"
|
||||
d="m 136.95,18.4066 -80.0056,0.1976 c -1.7018,0.0042 -3.078,1.402 -3.0738,3.1221 l 0.365,150.9807 c 0.0041,1.72 1.3871,3.111 3.0888,3.107 l 80.0056,-0.198 c 1.702,-0.004 3.078,-1.402 3.074,-3.122 L 140.039,21.5135 c -0.004,-1.7201 -1.387,-3.1111 -3.089,-3.1069 z" />
|
||||
<path
|
||||
style="display:inline;fill:#3e3e3e"
|
||||
d="M 134.60938 22.357422 L 118.59961 22.394531 C 118.35561 24.062231 117.52758 25.586606 116.26758 26.691406 C 115.00758 27.796206 113.39847 28.408469 111.73047 28.417969 L 81.96875 28.492188 C 80.30065 28.490987 78.689228 27.885609 77.423828 26.787109 C 76.158428 25.688609 75.323313 24.168453 75.070312 22.501953 L 59.304688 22.541016 C 58.436887 22.543416 57.604288 22.893925 56.992188 23.515625 C 56.380088 24.137325 56.037262 24.980322 56.039062 25.857422 L 56.128906 62.46875 L 56.748047 62.466797 L 56.128906 62.470703 L 56.382812 168.57031 C 56.385213 169.44731 56.732656 170.28725 57.347656 170.90625 C 57.962756 171.52425 58.796362 171.87114 59.664062 171.86914 L 134.9668 171.68359 C 135.8348 171.68159 136.66534 171.33098 137.27734 170.70898 C 137.88934 170.08798 138.23247 169.24614 138.23047 168.36914 L 137.97266 62.21875 L 137.97461 62.21875 L 137.88867 25.65625 C 137.88667 24.77915 137.54078 23.939012 136.92578 23.320312 C 136.31078 22.701612 135.47738 22.355522 134.60938 22.357422 z "
|
||||
id="path46" />
|
||||
<path
|
||||
style="display:inline;fill:#e0e0e0"
|
||||
d="M 109.84961 23.890625 C 109.45161 23.896725 109.13462 24.228559 109.14062 24.630859 C 109.14663 25.033059 109.47309 25.353756 109.87109 25.347656 C 110.26909 25.341656 110.58608 25.009622 110.58008 24.607422 C 110.57408 24.205222 110.24761 23.884625 109.84961 23.890625 z M 105.32031 24.201172 L 87.025391 24.478516 C 86.775891 24.482316 86.576378 24.691159 86.580078 24.943359 L 86.583984 25.242188 C 86.587684 25.494387 86.793469 25.695206 87.042969 25.691406 L 105.33984 25.414062 C 105.58884 25.410363 105.7872 25.203372 105.7832 24.951172 L 105.7793 24.650391 C 105.7753 24.398191 105.56931 24.197372 105.32031 24.201172 z M 63.365234 37.568359 L 63.365234 53.738281 L 79.365234 53.738281 L 79.365234 37.568359 L 63.365234 37.568359 z M 86.748047 37.568359 L 86.748047 40.800781 L 126.86523 40.800781 L 126.86523 37.568359 L 86.748047 37.568359 z M 86.748047 44.037109 L 86.748047 47.269531 L 126.86523 47.269531 L 126.86523 44.037109 L 86.748047 44.037109 z M 71.787109 112.99609 C 67.602609 112.99609 64.210937 116.44141 64.210938 120.69141 C 64.210938 124.94141 67.602609 128.38672 71.787109 128.38672 C 75.971709 128.38672 79.365234 124.94141 79.365234 120.69141 C 79.365234 116.44141 75.971709 112.99609 71.787109 112.99609 z M 86.748047 116.92773 L 86.748047 120.16016 L 126.86523 120.16016 L 126.86523 116.92773 L 86.748047 116.92773 z M 86.748047 123.39258 L 86.748047 126.62695 L 126.86523 126.62695 L 126.86523 123.39258 L 86.748047 123.39258 z M 71.787109 142.60156 C 67.602609 142.60156 64.210937 146.04687 64.210938 150.29688 C 64.210938 154.54688 67.602609 157.99023 71.787109 157.99023 C 75.971709 157.99023 79.365234 154.54688 79.365234 150.29688 C 79.365234 146.04688 75.971709 142.60156 71.787109 142.60156 z M 86.748047 145.53516 L 86.748047 148.76758 L 126.86523 148.76758 L 126.86523 145.53516 L 86.748047 145.53516 z M 86.748047 152.00195 L 86.748047 155.23438 L 126.86523 155.23438 L 126.86523 152.00195 L 86.748047 152.00195 z "
|
||||
id="path50" />
|
||||
<path
|
||||
style="display:inline;fill:#d5d6d7"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path56"
|
||||
d="M 148.744,68.6655 H 45.619 v 33.5835 h 103.125 z" />
|
||||
<path
|
||||
style="display:inline;fill:#87c214"
|
||||
d="m 97.822266,50.503906 v 5.722656 h 17.966794 v -5.722656 z m -11.074219,30.59961 v 3.232422 h 40.117183 v -3.232422 z m 0,6.46875 v 3.232422 h 40.117183 v -3.232422 z"
|
||||
id="path58"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="display:inline;fill:#f5f5f5"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path68"
|
||||
d="m 66.8652,92.3143 c 4.1846,0 7.5768,-3.4451 7.5768,-7.695 0,-4.2498 -3.3922,-7.6949 -7.5768,-7.6949 -4.1846,0 -7.5768,3.4451 -7.5768,7.6949 0,4.2499 3.3922,7.695 7.5768,7.695 z" />
|
||||
<path
|
||||
style="display:inline;fill:#87c214"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path70"
|
||||
d="m 70.1296,90.0058 h -6.5738 c -0.3153,0.0024 -0.6253,0.0818 -0.9038,0.2312 -0.2784,0.1495 -0.5171,0.3647 -0.6956,0.6274 1.4766,0.8563 3.1474,1.3114 4.8498,1.321 1.7023,0.0096 3.3781,-0.4266 4.864,-1.2662 -0.1666,-0.265 -0.3932,-0.486 -0.6612,-0.6448 -0.2679,-0.1588 -0.5693,-0.2509 -0.8794,-0.2686 z" />
|
||||
<path
|
||||
style="display:inline;fill:#333333"
|
||||
d="m 66.861328,80.746094 c -2.0798,0 -3.765625,1.70444 -3.765625,3.80664 0,0.393506 0.07586,0.766 0.185547,1.123047 -0.327549,0.812667 -0.821888,1.878261 -1.158203,1.708985 0,0 5.069822,4.4252 9.544922,0 -0.355198,-0.613452 -0.773279,-1.18389 -1.21875,-1.732422 0.10502,-0.350063 0.177734,-0.714879 0.177734,-1.09961 0,-2.1022 -1.685825,-3.80664 -3.765625,-3.80664 z"
|
||||
id="path72"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="display:inline;fill:#fda57d"
|
||||
d="m 66.861328,81.570312 c -1.800651,0 -3.302121,1.279176 -3.673828,2.986329 -0.0049,-3.79e-4 -0.0088,-0.0059 -0.01367,-0.0059 -0.1933,0 -0.349609,0.297063 -0.349609,0.664063 0,0.347156 0.141531,0.622551 0.320312,0.652344 0.180942,1.407599 1.108928,2.5691 2.38086,3.058593 v 0.732422 c 0,0.3234 0.127315,0.634681 0.353515,0.863281 0.2263,0.2287 0.533616,0.357422 0.853516,0.357422 h 0.224609 c 0.1588,3e-4 0.316091,-0.03245 0.462891,-0.09375 0.1467,-0.0613 0.280278,-0.150172 0.392578,-0.263672 0.1123,-0.1135 0.201119,-0.248084 0.261719,-0.396484 0.0606,-0.1483 0.0921,-0.30825 0.0918,-0.46875 v -0.720703 c 1.288752,-0.483775 2.232282,-1.654559 2.412109,-3.076172 0.168226,-0.0485 0.298828,-0.311757 0.298828,-0.644531 0,-0.363137 -0.153161,-0.655938 -0.34375,-0.66211 -0.373249,-1.705035 -1.87271,-2.982422 -3.671875,-2.982422 z"
|
||||
id="path78"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="display:inline;fill:#333333"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path84"
|
||||
d="m 63.2529,83.9344 h 7.1792 c 0,0 -0.6122,-2.9296 -3.3275,-2.7401 -2.7154,0.1895 -3.8517,2.7401 -3.8517,2.7401 z" />
|
||||
<defs
|
||||
id="defs127">
|
||||
<linearGradient
|
||||
id="paint0_linear"
|
||||
x1="10.0511"
|
||||
y1="162.566"
|
||||
x2="80.1467"
|
||||
y2="-2.31086"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#808080"
|
||||
stop-opacity="0.25"
|
||||
id="stop110" />
|
||||
<stop
|
||||
offset="0.54"
|
||||
stop-color="#808080"
|
||||
stop-opacity="0.12"
|
||||
id="stop112" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#808080"
|
||||
stop-opacity="0.1"
|
||||
id="stop114" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear"
|
||||
x1="45488.3"
|
||||
y1="16529.6"
|
||||
x2="45488.3"
|
||||
y2="10752.2"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#808080"
|
||||
stop-opacity="0.25"
|
||||
id="stop117" />
|
||||
<stop
|
||||
offset="0.54"
|
||||
stop-color="#808080"
|
||||
stop-opacity="0.12"
|
||||
id="stop119" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#808080"
|
||||
stop-opacity="0.1"
|
||||
id="stop121" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="clip0">
|
||||
<rect
|
||||
width="150"
|
||||
height="178"
|
||||
fill="white"
|
||||
id="rect124" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
@@ -118,6 +118,7 @@ dependencies {
|
||||
implementation 'com.google.zxing:core:3.3.3'
|
||||
implementation 'uk.co.samuelwall:material-tap-target-prompt:2.14.0'
|
||||
implementation 'com.vanniktech:emoji-google:0.5.1'
|
||||
implementation 'com.github.kobakei:MaterialFabSpeedDial:1.2.1' // later versions already use androidx
|
||||
def glideVersion = '4.9.0'
|
||||
implementation("com.github.bumptech.glide:glide:$glideVersion") {
|
||||
exclude group: 'com.android.support'
|
||||
|
||||
@@ -425,5 +425,31 @@
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/BriarTheme.NoActionBar"/>
|
||||
|
||||
<activity
|
||||
android:name=".android.contact.add.remote.AddContactActivity"
|
||||
android:label="@string/add_contact_remotely_title_case"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/BriarTheme"
|
||||
android:windowSoftInputMode="stateHidden|adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
|
||||
<data android:scheme="briar"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".android.contact.add.remote.PendingContactListActivity"
|
||||
android:label="@string/pending_contact_requests"
|
||||
android:theme="@style/BriarTheme"/>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
|
||||
import org.briarproject.briar.api.conversation.event.ConversationMessageReceivedEvent;
|
||||
import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent;
|
||||
import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent;
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent;
|
||||
import org.briarproject.briar.api.privategroup.event.GroupMessageAddedEvent;
|
||||
|
||||
import java.util.Set;
|
||||
@@ -99,7 +99,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
private final Multiset<GroupId> groupCounts = new Multiset<>();
|
||||
private final Multiset<GroupId> forumCounts = new Multiset<>();
|
||||
private final Multiset<GroupId> blogCounts = new Multiset<>();
|
||||
private int introductionTotal = 0;
|
||||
private int contactAddedTotal = 0;
|
||||
private int nextRequestId = 0;
|
||||
private ContactId blockedContact = null;
|
||||
private GroupId blockedGroup = null;
|
||||
@@ -171,7 +171,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
clearGroupMessageNotification();
|
||||
clearForumPostNotification();
|
||||
clearBlogPostNotification();
|
||||
clearIntroductionSuccessNotification();
|
||||
clearContactAddedNotification();
|
||||
return null;
|
||||
});
|
||||
try {
|
||||
@@ -206,9 +206,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void clearIntroductionSuccessNotification() {
|
||||
introductionTotal = 0;
|
||||
notificationManager.cancel(INTRODUCTION_SUCCESS_NOTIFICATION_ID);
|
||||
private void clearContactAddedNotification() {
|
||||
contactAddedTotal = 0;
|
||||
notificationManager.cancel(CONTACT_ADDED_NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -230,8 +230,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
} else if (e instanceof BlogPostAddedEvent) {
|
||||
BlogPostAddedEvent b = (BlogPostAddedEvent) e;
|
||||
if (!b.isLocal()) showBlogPostNotification(b.getGroupId());
|
||||
} else if (e instanceof IntroductionSucceededEvent) {
|
||||
showIntroductionNotification();
|
||||
} else if (e instanceof ContactAddedRemotelyEvent) {
|
||||
showContactAddedNotification();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -563,24 +563,24 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void showIntroductionNotification() {
|
||||
introductionTotal++;
|
||||
updateIntroductionNotification();
|
||||
private void showContactAddedNotification() {
|
||||
contactAddedTotal++;
|
||||
updateContactAddedNotification();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void updateIntroductionNotification() {
|
||||
private void updateContactAddedNotification() {
|
||||
BriarNotificationBuilder b =
|
||||
new BriarNotificationBuilder(appContext, CONTACT_CHANNEL_ID);
|
||||
b.setSmallIcon(R.drawable.notification_introduction);
|
||||
b.setSmallIcon(R.drawable.notification_contact_added);
|
||||
b.setColorRes(R.color.briar_primary);
|
||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||
b.setContentText(appContext.getResources().getQuantityString(
|
||||
R.plurals.introduction_notification_text, introductionTotal,
|
||||
introductionTotal));
|
||||
R.plurals.contact_added_notification_text, contactAddedTotal,
|
||||
contactAddedTotal));
|
||||
b.setNotificationCategory(CATEGORY_MESSAGE);
|
||||
setAlertProperties(b);
|
||||
setDeleteIntent(b, INTRODUCTION_URI);
|
||||
setDeleteIntent(b, CONTACT_ADDED_URI);
|
||||
// Touching the notification shows the contact list
|
||||
Intent i = new Intent(appContext, NavDrawerActivity.class);
|
||||
i.putExtra(INTENT_CONTACTS, true);
|
||||
@@ -591,14 +591,13 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
t.addNextIntent(i);
|
||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||
|
||||
notificationManager.notify(INTRODUCTION_SUCCESS_NOTIFICATION_ID,
|
||||
notificationManager.notify(CONTACT_ADDED_NOTIFICATION_ID,
|
||||
b.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllIntroductionNotifications() {
|
||||
androidExecutor.runOnUiThread(
|
||||
this::clearIntroductionSuccessNotification);
|
||||
public void clearAllContactAddedNotifications() {
|
||||
androidExecutor.runOnUiThread(this::clearContactAddedNotification);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,7 +12,7 @@ import static org.briarproject.briar.api.android.AndroidNotificationManager.BLOG
|
||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_URI;
|
||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.FORUM_URI;
|
||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.GROUP_URI;
|
||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.INTRODUCTION_URI;
|
||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_ADDED_URI;
|
||||
|
||||
public class NotificationCleanupService extends IntentService {
|
||||
|
||||
@@ -46,8 +46,8 @@ public class NotificationCleanupService extends IntentService {
|
||||
notificationManager.clearAllForumPostNotifications();
|
||||
} else if (uri.equals(BLOG_URI)) {
|
||||
notificationManager.clearAllBlogPostNotifications();
|
||||
} else if (uri.equals(INTRODUCTION_URI)) {
|
||||
notificationManager.clearAllIntroductionNotifications();
|
||||
} else if (uri.equals(CONTACT_ADDED_URI)) {
|
||||
notificationManager.clearAllContactAddedNotifications();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,4 +36,9 @@ public interface TestingConstants {
|
||||
*/
|
||||
boolean FEATURE_FLAG_IMAGE_ATTACHMENTS = IS_DEBUG_BUILD;
|
||||
|
||||
/**
|
||||
* Feature flag for enabling adding contacts at a distance.
|
||||
*/
|
||||
boolean FEATURE_FLAG_REMOTE_CONTACTS = IS_DEBUG_BUILD;
|
||||
|
||||
}
|
||||
|
||||
@@ -15,8 +15,12 @@ import org.briarproject.briar.android.blog.ReblogFragment;
|
||||
import org.briarproject.briar.android.blog.RssFeedImportActivity;
|
||||
import org.briarproject.briar.android.blog.RssFeedManageActivity;
|
||||
import org.briarproject.briar.android.blog.WriteBlogPostActivity;
|
||||
import org.briarproject.briar.android.contact.add.remote.AddContactActivity;
|
||||
import org.briarproject.briar.android.contact.add.remote.LinkExchangeFragment;
|
||||
import org.briarproject.briar.android.contact.ContactListFragment;
|
||||
import org.briarproject.briar.android.contact.ContactModule;
|
||||
import org.briarproject.briar.android.contact.add.remote.NicknameFragment;
|
||||
import org.briarproject.briar.android.contact.add.remote.PendingContactListActivity;
|
||||
import org.briarproject.briar.android.conversation.AliasDialogFragment;
|
||||
import org.briarproject.briar.android.conversation.ConversationActivity;
|
||||
import org.briarproject.briar.android.conversation.ImageActivity;
|
||||
@@ -168,6 +172,10 @@ public interface ActivityComponent {
|
||||
|
||||
void inject(UnlockActivity activity);
|
||||
|
||||
void inject(AddContactActivity activity);
|
||||
|
||||
void inject(PendingContactListActivity activity);
|
||||
|
||||
// Fragments
|
||||
void inject(AuthorNameFragment fragment);
|
||||
|
||||
@@ -191,6 +199,10 @@ public interface ActivityComponent {
|
||||
|
||||
void inject(KeyAgreementFragment fragment);
|
||||
|
||||
void inject(LinkExchangeFragment fragment);
|
||||
|
||||
void inject(NicknameFragment fragment);
|
||||
|
||||
void inject(ContactChooserFragment fragment);
|
||||
|
||||
void inject(ShareForumFragment fragment);
|
||||
|
||||
@@ -5,8 +5,6 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
@@ -34,6 +32,7 @@ import org.briarproject.briar.android.controller.handler.UiResultExceptionHandle
|
||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||
import org.briarproject.briar.android.sharing.BlogSharingStatusActivity;
|
||||
import org.briarproject.briar.android.sharing.ShareBlogActivity;
|
||||
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||
import org.briarproject.briar.api.blog.BlogPostHeader;
|
||||
|
||||
@@ -44,6 +43,7 @@ import javax.inject.Inject;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||
import static android.support.design.widget.Snackbar.LENGTH_LONG;
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
||||
@@ -356,17 +356,12 @@ public class BlogFragment extends BaseFragment
|
||||
}
|
||||
|
||||
private void displaySnackbar(int stringId, boolean scroll) {
|
||||
Snackbar snackbar =
|
||||
Snackbar.make(list, stringId, Snackbar.LENGTH_LONG);
|
||||
snackbar.getView().setBackgroundResource(R.color.briar_primary);
|
||||
BriarSnackbarBuilder sb = new BriarSnackbarBuilder();
|
||||
if (scroll) {
|
||||
View.OnClickListener onClick = v -> list.smoothScrollToPosition(0);
|
||||
snackbar.setActionTextColor(ContextCompat
|
||||
.getColor(getContext(),
|
||||
R.color.briar_button_text_positive));
|
||||
snackbar.setAction(R.string.blogs_blog_post_scroll_to, onClick);
|
||||
sb.setAction(R.string.blogs_blog_post_scroll_to,
|
||||
v -> list.smoothScrollToPosition(0));
|
||||
}
|
||||
snackbar.show();
|
||||
sb.make(list, stringId, LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
private void showDeleteDialog() {
|
||||
|
||||
@@ -4,15 +4,12 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
@@ -23,6 +20,7 @@ import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.blog.FeedController.FeedListener;
|
||||
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||
import org.briarproject.briar.api.blog.Blog;
|
||||
import org.briarproject.briar.api.blog.BlogPostHeader;
|
||||
@@ -270,16 +268,12 @@ public class FeedFragment extends BaseFragment implements
|
||||
int count = adapter.getItemCount();
|
||||
boolean scroll = count > (lastVisible - firstVisible + 1);
|
||||
|
||||
Snackbar s = Snackbar.make(list, stringRes, LENGTH_LONG);
|
||||
s.getView().setBackgroundResource(R.color.briar_primary);
|
||||
BriarSnackbarBuilder sb = new BriarSnackbarBuilder();
|
||||
if (scroll) {
|
||||
OnClickListener onClick = v -> list.smoothScrollToPosition(0);
|
||||
s.setActionTextColor(ContextCompat
|
||||
.getColor(getContext(),
|
||||
R.color.briar_button_text_positive));
|
||||
s.setAction(R.string.blogs_blog_post_scroll_to, onClick);
|
||||
sb.setAction(R.string.blogs_blog_post_scroll_to,
|
||||
v -> list.smoothScrollToPosition(0));
|
||||
}
|
||||
s.show();
|
||||
sb.make(list, stringRes, LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,22 +3,25 @@ package org.briarproject.briar.android.contact;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.ActivityOptionsCompat;
|
||||
import android.support.v4.util.Pair;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent;
|
||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent;
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
@@ -32,9 +35,12 @@ import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener;
|
||||
import org.briarproject.briar.android.contact.add.remote.AddContactActivity;
|
||||
import org.briarproject.briar.android.contact.add.remote.PendingContactListActivity;
|
||||
import org.briarproject.briar.android.conversation.ConversationActivity;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||
import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
|
||||
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
||||
@@ -49,20 +55,28 @@ import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDial;
|
||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDial.OnMenuItemClickListener;
|
||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.support.design.widget.Snackbar.LENGTH_INDEFINITE;
|
||||
import static android.support.v4.app.ActivityOptionsCompat.makeSceneTransitionAnimation;
|
||||
import static android.support.v4.view.ViewCompat.getTransitionName;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
|
||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
import static org.briarproject.bramble.util.LogUtils.now;
|
||||
import static org.briarproject.briar.android.TestingConstants.FEATURE_FLAG_REMOTE_CONTACTS;
|
||||
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
|
||||
import static org.briarproject.briar.android.util.UiUtils.isSamsung7;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
public class ContactListFragment extends BaseFragment implements EventListener,
|
||||
OnMenuItemClickListener {
|
||||
|
||||
public static final String TAG = ContactListFragment.class.getName();
|
||||
private static final Logger LOG = Logger.getLogger(TAG);
|
||||
@@ -76,6 +90,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
|
||||
private ContactListAdapter adapter;
|
||||
private BriarRecyclerView list;
|
||||
private Snackbar snackbar;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
@@ -107,7 +122,23 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
requireNonNull(getActivity()).setTitle(R.string.contact_list_button);
|
||||
|
||||
View contentView = inflater.inflate(R.layout.list, container, false);
|
||||
View contentView = inflater.inflate(R.layout.fragment_contact_list,
|
||||
container, false);
|
||||
|
||||
FabSpeedDial speedDial = contentView.findViewById(R.id.speedDial);
|
||||
if (FEATURE_FLAG_REMOTE_CONTACTS) {
|
||||
speedDial.addOnMenuItemClickListener(this);
|
||||
} else {
|
||||
speedDial.setMenu(new FabSpeedDialMenu(contentView.getContext()));
|
||||
speedDial.addOnStateChangeListener(open -> {
|
||||
if (open) {
|
||||
Intent intent = new Intent(getContext(),
|
||||
ContactExchangeActivity.class);
|
||||
startActivity(intent);
|
||||
speedDial.closeMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
OnContactClickListener<ContactListItem> onContactClickListener =
|
||||
(view, item) -> {
|
||||
@@ -146,26 +177,28 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
list.setEmptyText(getString(R.string.no_contacts));
|
||||
list.setEmptyAction(getString(R.string.no_contacts_action));
|
||||
|
||||
snackbar = new BriarSnackbarBuilder()
|
||||
.setAction(R.string.show, v ->
|
||||
startActivity(new Intent(getContext(),
|
||||
PendingContactListActivity.class)))
|
||||
.make(contentView, R.string.pending_contact_requests_snackbar,
|
||||
LENGTH_INDEFINITE);
|
||||
|
||||
return contentView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.contact_list_actions, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Handle presses on the action bar items
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_add_contact:
|
||||
public void onMenuItemClick(FloatingActionButton fab, @Nullable TextView v,
|
||||
int itemId) {
|
||||
switch (itemId) {
|
||||
case R.id.action_add_contact_nearby:
|
||||
Intent intent =
|
||||
new Intent(getContext(), ContactExchangeActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
return;
|
||||
case R.id.action_add_contact_remotely:
|
||||
startActivity(
|
||||
new Intent(getContext(), AddContactActivity.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,11 +207,26 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
super.onStart();
|
||||
eventBus.addListener(this);
|
||||
notificationManager.clearAllContactNotifications();
|
||||
notificationManager.clearAllIntroductionNotifications();
|
||||
notificationManager.clearAllContactAddedNotifications();
|
||||
loadContacts();
|
||||
checkForPendingContacts();
|
||||
list.startPeriodicUpdate();
|
||||
}
|
||||
|
||||
private void checkForPendingContacts() {
|
||||
listener.runOnDbThread(() -> {
|
||||
try {
|
||||
if (contactManager.getPendingContacts().isEmpty()) {
|
||||
runOnUiThreadUnlessDestroyed(() -> snackbar.dismiss());
|
||||
} else {
|
||||
runOnUiThreadUnlessDestroyed(() -> snackbar.show());
|
||||
}
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
@@ -245,6 +293,16 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
(ConversationMessageReceivedEvent) e;
|
||||
ConversationMessageHeader h = p.getMessageHeader();
|
||||
updateItem(p.getContactId(), h);
|
||||
} else if (e instanceof PendingContactStateChangedEvent) {
|
||||
PendingContactStateChangedEvent pe =
|
||||
(PendingContactStateChangedEvent) e;
|
||||
// only re-check pending contacts for initial state
|
||||
if (pe.getPendingContactState() == WAITING_FOR_CONNECTION) {
|
||||
checkForPendingContacts();
|
||||
}
|
||||
} else if (e instanceof PendingContactRemovedEvent ||
|
||||
e instanceof ContactAddedRemotelyEvent) {
|
||||
checkForPendingContacts();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package org.briarproject.briar.android.contact.add.remote;
|
||||
|
||||
import android.arch.lifecycle.ViewModelProvider;
|
||||
import android.arch.lifecycle.ViewModelProviders;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.activity.BriarActivity;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.content.Intent.ACTION_SEND;
|
||||
import static android.content.Intent.ACTION_VIEW;
|
||||
import static android.content.Intent.EXTRA_TEXT;
|
||||
import static android.widget.Toast.LENGTH_LONG;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class AddContactActivity extends BriarActivity implements
|
||||
BaseFragmentListener {
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
private AddContactViewModel viewModel;
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle state) {
|
||||
super.onCreate(state);
|
||||
setContentView(R.layout.activity_fragment_container);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
viewModel = ViewModelProviders.of(this, viewModelFactory)
|
||||
.get(AddContactViewModel.class);
|
||||
viewModel.getRemoteLinkEntered().observeEvent(this, entered -> {
|
||||
if (entered) {
|
||||
NicknameFragment f = new NicknameFragment();
|
||||
showNextFragment(f);
|
||||
}
|
||||
});
|
||||
|
||||
Intent i = getIntent();
|
||||
if (i != null) {
|
||||
onNewIntent(i);
|
||||
setIntent(null); // don't keep the intent for configuration changes
|
||||
}
|
||||
|
||||
if (state == null) {
|
||||
showInitialFragment(new LinkExchangeFragment());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent i) {
|
||||
super.onNewIntent(i);
|
||||
String action = i.getAction();
|
||||
if (ACTION_SEND.equals(action) || ACTION_VIEW.equals(action)) {
|
||||
String text = i.getStringExtra(EXTRA_TEXT);
|
||||
String uri = i.getDataString();
|
||||
if (text != null) handleIncomingLink(text);
|
||||
else if (uri != null) handleIncomingLink(uri);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleIncomingLink(String link) {
|
||||
if (link.equals(viewModel.getHandshakeLink().getValue())) {
|
||||
Toast.makeText(this, R.string.intent_own_link, LENGTH_LONG)
|
||||
.show();
|
||||
} else if (viewModel.isValidRemoteContactLink(link)) {
|
||||
viewModel.setRemoteHandshakeLink(link);
|
||||
} else {
|
||||
Toast.makeText(this, R.string.invalid_link, LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package org.briarproject.briar.android.contact.add.remote;
|
||||
|
||||
import android.app.Application;
|
||||
import android.arch.lifecycle.AndroidViewModel;
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.MutableLiveData;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
||||
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.bramble.api.contact.ContactManager.LINK_REGEX;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@NotNullByDefault
|
||||
public class AddContactViewModel extends AndroidViewModel {
|
||||
|
||||
private final static Logger LOG =
|
||||
getLogger(AddContactViewModel.class.getName());
|
||||
|
||||
private final ContactManager contactManager;
|
||||
@DatabaseExecutor
|
||||
private final Executor dbExecutor;
|
||||
|
||||
private final MutableLiveData<String> handshakeLink =
|
||||
new MutableLiveData<>();
|
||||
private final MutableLiveEvent<Boolean> remoteLinkEntered =
|
||||
new MutableLiveEvent<>();
|
||||
private final MutableLiveData<Boolean> addContactResult =
|
||||
new MutableLiveData<>();
|
||||
@Nullable
|
||||
private String remoteHandshakeLink;
|
||||
|
||||
@Inject
|
||||
public AddContactViewModel(@NonNull Application application,
|
||||
ContactManager contactManager,
|
||||
@DatabaseExecutor Executor dbExecutor) {
|
||||
super(application);
|
||||
this.contactManager = contactManager;
|
||||
this.dbExecutor = dbExecutor;
|
||||
loadHandshakeLink();
|
||||
}
|
||||
|
||||
private void loadHandshakeLink() {
|
||||
dbExecutor.execute(() -> {
|
||||
try {
|
||||
handshakeLink.postValue(contactManager.getHandshakeLink());
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
// the UI should stay disable in this case,
|
||||
// leaving the user unable to proceed
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
LiveData<String> getHandshakeLink() {
|
||||
return handshakeLink;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getRemoteHandshakeLink() {
|
||||
return remoteHandshakeLink;
|
||||
}
|
||||
|
||||
void setRemoteHandshakeLink(String link) {
|
||||
remoteHandshakeLink = link;
|
||||
}
|
||||
|
||||
boolean isValidRemoteContactLink(@Nullable CharSequence link) {
|
||||
return link != null && LINK_REGEX.matcher(link).find();
|
||||
}
|
||||
|
||||
LiveEvent<Boolean> getRemoteLinkEntered() {
|
||||
return remoteLinkEntered;
|
||||
}
|
||||
|
||||
void onRemoteLinkEntered() {
|
||||
if (remoteHandshakeLink == null) throw new IllegalStateException();
|
||||
remoteLinkEntered.setEvent(true);
|
||||
}
|
||||
|
||||
void addContact(String nickname) {
|
||||
if (remoteHandshakeLink == null) throw new IllegalStateException();
|
||||
dbExecutor.execute(() -> {
|
||||
try {
|
||||
contactManager.addPendingContact(remoteHandshakeLink, nickname);
|
||||
addContactResult.postValue(true);
|
||||
} catch (DbException | FormatException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
addContactResult.postValue(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getAddContactResult() {
|
||||
return addContactResult;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package org.briarproject.briar.android.contact.add.remote;
|
||||
|
||||
import android.arch.lifecycle.ViewModelProvider;
|
||||
import android.arch.lifecycle.ViewModelProviders;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.TextInputEditText;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v4.app.ShareCompat.IntentBuilder;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.content.Context.CLIPBOARD_SERVICE;
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.briarproject.bramble.api.contact.ContactManager.LINK_REGEX;
|
||||
import static org.briarproject.briar.android.util.UiUtils.observeOnce;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class LinkExchangeFragment extends BaseFragment {
|
||||
|
||||
private static final String TAG = LinkExchangeFragment.class.getName();
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
|
||||
private AddContactViewModel viewModel;
|
||||
|
||||
private ClipboardManager clipboard;
|
||||
private TextInputLayout linkInputLayout;
|
||||
private TextInputEditText linkInput;
|
||||
|
||||
@Override
|
||||
public String getUniqueTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectFragment(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
if (getActivity() == null || getContext() == null) return null;
|
||||
|
||||
viewModel = ViewModelProviders.of(getActivity(), viewModelFactory)
|
||||
.get(AddContactViewModel.class);
|
||||
|
||||
View v = inflater.inflate(R.layout.fragment_link_exchange,
|
||||
container, false);
|
||||
|
||||
linkInputLayout = v.findViewById(R.id.linkInputLayout);
|
||||
linkInput = v.findViewById(R.id.linkInput);
|
||||
if (viewModel.getRemoteHandshakeLink() != null) {
|
||||
// This can happen if the link was set via an incoming Intent
|
||||
linkInput.setText(viewModel.getRemoteHandshakeLink());
|
||||
}
|
||||
|
||||
clipboard = (ClipboardManager) requireNonNull(
|
||||
getContext().getSystemService(CLIPBOARD_SERVICE));
|
||||
|
||||
Button pasteButton = v.findViewById(R.id.pasteButton);
|
||||
pasteButton.setOnClickListener(view -> {
|
||||
ClipData clipData = clipboard.getPrimaryClip();
|
||||
if (clipData != null && clipData.getItemCount() > 0)
|
||||
linkInput.setText(clipData.getItemAt(0).getText());
|
||||
});
|
||||
|
||||
observeOnce(viewModel.getHandshakeLink(), this,
|
||||
this::onHandshakeLinkLoaded);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
private void onHandshakeLinkLoaded(String link) {
|
||||
View v = requireNonNull(getView());
|
||||
|
||||
TextView linkView = v.findViewById(R.id.linkView);
|
||||
linkView.setText(link);
|
||||
|
||||
Button copyButton = v.findViewById(R.id.copyButton);
|
||||
ClipData clip = ClipData.newPlainText(
|
||||
getString(R.string.link_clip_label), link);
|
||||
copyButton.setOnClickListener(view -> {
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(getContext(), R.string.link_copied_toast,
|
||||
LENGTH_SHORT).show();
|
||||
});
|
||||
copyButton.setEnabled(true);
|
||||
|
||||
Button shareButton = v.findViewById(R.id.shareButton);
|
||||
shareButton.setOnClickListener(view ->
|
||||
IntentBuilder.from(requireActivity())
|
||||
.setText(link)
|
||||
.setType("text/plain")
|
||||
.startChooser());
|
||||
shareButton.setEnabled(true);
|
||||
|
||||
Button continueButton = v.findViewById(R.id.addButton);
|
||||
continueButton.setOnClickListener(view -> onContinueButtonClicked());
|
||||
continueButton.setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires {@link AddContactViewModel#getHandshakeLink()} to be loaded.
|
||||
*/
|
||||
@Nullable
|
||||
private String getRemoteHandshakeLinkOrNull() {
|
||||
CharSequence link = linkInput.getText();
|
||||
if (link == null || link.length() == 0) {
|
||||
linkInputLayout.setError(getString(R.string.missing_link));
|
||||
linkInput.requestFocus();
|
||||
return null;
|
||||
}
|
||||
|
||||
Matcher matcher = LINK_REGEX.matcher(link);
|
||||
if (matcher.find()) {
|
||||
String linkWithoutSchema = matcher.group(2);
|
||||
// Check also if this is our own link. This was loaded already,
|
||||
// because it enables the Continue button which is the only caller.
|
||||
if (("briar://" + linkWithoutSchema)
|
||||
.equals(viewModel.getHandshakeLink().getValue())) {
|
||||
linkInputLayout.setError(getString(R.string.own_link_error));
|
||||
linkInput.requestFocus();
|
||||
return null;
|
||||
}
|
||||
linkInputLayout.setError(null);
|
||||
return linkWithoutSchema;
|
||||
}
|
||||
linkInputLayout.setError(getString(R.string.invalid_link));
|
||||
linkInput.requestFocus();
|
||||
return null;
|
||||
}
|
||||
|
||||
private void onContinueButtonClicked() {
|
||||
String link = getRemoteHandshakeLinkOrNull();
|
||||
if (link == null) return; // invalid link
|
||||
|
||||
viewModel.setRemoteHandshakeLink(link);
|
||||
viewModel.onRemoteLinkEntered();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.briarproject.briar.android.contact.add.remote;
|
||||
|
||||
import android.arch.lifecycle.ViewModelProvider;
|
||||
import android.arch.lifecycle.ViewModelProviders;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.TextInputEditText;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.view.View.INVISIBLE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static android.widget.Toast.LENGTH_LONG;
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.bramble.util.StringUtils.utf8IsTooLong;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class NicknameFragment extends BaseFragment {
|
||||
|
||||
private static final String TAG = NicknameFragment.class.getName();
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
|
||||
private AddContactViewModel viewModel;
|
||||
|
||||
private TextInputLayout contactNameLayout;
|
||||
private TextInputEditText contactNameInput;
|
||||
private Button addButton;
|
||||
private ProgressBar progressBar;
|
||||
|
||||
@Override
|
||||
public String getUniqueTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectFragment(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
if (getActivity() == null || getContext() == null) return null;
|
||||
|
||||
View v = inflater.inflate(R.layout.fragment_nickname,
|
||||
container, false);
|
||||
|
||||
viewModel = ViewModelProviders.of(getActivity(), viewModelFactory)
|
||||
.get(AddContactViewModel.class);
|
||||
|
||||
contactNameLayout = v.findViewById(R.id.contactNameLayout);
|
||||
contactNameInput = v.findViewById(R.id.contactNameInput);
|
||||
|
||||
addButton = v.findViewById(R.id.addButton);
|
||||
addButton.setOnClickListener(view -> onAddButtonClicked());
|
||||
|
||||
progressBar = v.findViewById(R.id.progressBar);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getNicknameOrNull() {
|
||||
Editable name = contactNameInput.getText();
|
||||
if (name == null || name.toString().trim().length() == 0) {
|
||||
contactNameLayout.setError(getString(R.string.nickname_missing));
|
||||
contactNameInput.requestFocus();
|
||||
return null;
|
||||
}
|
||||
if (utf8IsTooLong(name.toString(), MAX_AUTHOR_NAME_LENGTH)) {
|
||||
contactNameLayout.setError(getString(R.string.name_too_long));
|
||||
contactNameInput.requestFocus();
|
||||
return null;
|
||||
}
|
||||
contactNameLayout.setError(null);
|
||||
return name.toString().trim();
|
||||
}
|
||||
|
||||
private void onAddButtonClicked() {
|
||||
String name = getNicknameOrNull();
|
||||
if (name == null) return; // invalid nickname
|
||||
|
||||
addButton.setVisibility(INVISIBLE);
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
|
||||
viewModel.getAddContactResult().observe(this, success -> {
|
||||
if (success == null) return;
|
||||
if (success) {
|
||||
Intent intent = new Intent(getActivity(),
|
||||
PendingContactListActivity.class);
|
||||
startActivity(intent);
|
||||
} else {
|
||||
Toast.makeText(getContext(), R.string.adding_contact_error,
|
||||
LENGTH_LONG).show();
|
||||
}
|
||||
finish();
|
||||
});
|
||||
viewModel.addContact(name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package org.briarproject.briar.android.contact.add.remote;
|
||||
|
||||
import android.arch.lifecycle.ViewModelProvider;
|
||||
import android.arch.lifecycle.ViewModelProviders;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import org.briarproject.bramble.api.contact.PendingContact;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.activity.BriarActivity;
|
||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class PendingContactListActivity extends BriarActivity
|
||||
implements PendingContactListener {
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
|
||||
private PendingContactListViewModel viewModel;
|
||||
private PendingContactListAdapter adapter;
|
||||
private BriarRecyclerView list;
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle state) {
|
||||
super.onCreate(state);
|
||||
|
||||
setContentView(R.layout.list);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
viewModel = ViewModelProviders.of(this, viewModelFactory)
|
||||
.get(PendingContactListViewModel.class);
|
||||
viewModel.getPendingContacts()
|
||||
.observe(this, this::onPendingContactsChanged);
|
||||
|
||||
adapter = new PendingContactListAdapter(this, this, PendingContact.class);
|
||||
list = findViewById(R.id.list);
|
||||
list.setEmptyText(R.string.no_pending_contacts);
|
||||
list.setLayoutManager(new LinearLayoutManager(this));
|
||||
list.setAdapter(adapter);
|
||||
list.showProgressBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
list.startPeriodicUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
list.stopPeriodicUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailedPendingContactRemoved(PendingContact pendingContact) {
|
||||
viewModel.removePendingContact(pendingContact.getId());
|
||||
}
|
||||
|
||||
private void onPendingContactsChanged(Collection<PendingContact> contacts) {
|
||||
if (contacts.isEmpty()) {
|
||||
if (adapter.isEmpty()) {
|
||||
list.showData(); // hides progress bar, shows empty text
|
||||
} else {
|
||||
// all previous contacts have been removed, so we can finish
|
||||
supportFinishAfterTransition();
|
||||
}
|
||||
} else {
|
||||
adapter.setItems(contacts);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.briarproject.briar.android.contact.add.remote;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.briarproject.bramble.api.contact.PendingContact;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.util.BriarAdapter;
|
||||
|
||||
@NotNullByDefault
|
||||
class PendingContactListAdapter extends
|
||||
BriarAdapter<PendingContact, PendingContactViewHolder> {
|
||||
|
||||
private final PendingContactListener listener;
|
||||
|
||||
PendingContactListAdapter(Context ctx, PendingContactListener listener,
|
||||
Class<PendingContact> c) {
|
||||
super(ctx, c);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingContactViewHolder onCreateViewHolder(ViewGroup viewGroup,
|
||||
int i) {
|
||||
View v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
||||
R.layout.list_item_pending_contact, viewGroup, false);
|
||||
return new PendingContactViewHolder(v, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(
|
||||
PendingContactViewHolder pendingContactViewHolder, int i) {
|
||||
pendingContactViewHolder.bind(items.get(i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(PendingContact item1, PendingContact item2) {
|
||||
return (int) (item1.getTimestamp() - item2.getTimestamp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(PendingContact item1,
|
||||
PendingContact item2) {
|
||||
return item1.getId().equals(item2.getId()) &&
|
||||
item1.getAlias().equals(item2.getAlias()) &&
|
||||
item1.getTimestamp() == item2.getTimestamp() &&
|
||||
item1.getState() == item2.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(PendingContact item1,
|
||||
PendingContact item2) {
|
||||
return item1.getId().equals(item2.getId());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package org.briarproject.briar.android.contact.add.remote;
|
||||
|
||||
import android.app.Application;
|
||||
import android.arch.lifecycle.AndroidViewModel;
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.MutableLiveData;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.contact.PendingContact;
|
||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent;
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent;
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent;
|
||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.event.EventListener;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@NotNullByDefault
|
||||
public class PendingContactListViewModel extends AndroidViewModel
|
||||
implements EventListener {
|
||||
|
||||
private final Logger LOG =
|
||||
getLogger(PendingContactListViewModel.class.getName());
|
||||
|
||||
@DatabaseExecutor
|
||||
private final Executor dbExecutor;
|
||||
private final ContactManager contactManager;
|
||||
private final EventBus eventBus;
|
||||
|
||||
private final MutableLiveData<Collection<PendingContact>> pendingContacts =
|
||||
new MutableLiveData<>();
|
||||
|
||||
@Inject
|
||||
public PendingContactListViewModel(Application application,
|
||||
@DatabaseExecutor Executor dbExecutor,
|
||||
ContactManager contactManager, EventBus eventBus) {
|
||||
super(application);
|
||||
this.dbExecutor = dbExecutor;
|
||||
this.contactManager = contactManager;
|
||||
this.eventBus = eventBus;
|
||||
this.eventBus.addListener(this);
|
||||
loadPendingContacts();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
super.onCleared();
|
||||
eventBus.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof ContactAddedRemotelyEvent ||
|
||||
e instanceof PendingContactStateChangedEvent ||
|
||||
e instanceof PendingContactRemovedEvent) {
|
||||
loadPendingContacts();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadPendingContacts() {
|
||||
dbExecutor.execute(() -> {
|
||||
try {
|
||||
pendingContacts.postValue(contactManager.getPendingContacts());
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
LiveData<Collection<PendingContact>> getPendingContacts() {
|
||||
return pendingContacts;
|
||||
}
|
||||
|
||||
void removePendingContact(PendingContactId id) {
|
||||
dbExecutor.execute(() -> {
|
||||
try {
|
||||
contactManager.removePendingContact(id);
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.briarproject.briar.android.contact.add.remote;
|
||||
|
||||
import org.briarproject.bramble.api.contact.PendingContact;
|
||||
|
||||
interface PendingContactListener {
|
||||
|
||||
void onFailedPendingContactRemoved(PendingContact pendingContact);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.briarproject.briar.android.contact.add.remote;
|
||||
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.RecyclerView.ViewHolder;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.bramble.api.contact.PendingContact;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.view.TextAvatarView;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static org.briarproject.briar.android.util.UiUtils.formatDate;
|
||||
|
||||
@NotNullByDefault
|
||||
class PendingContactViewHolder extends ViewHolder {
|
||||
|
||||
private final PendingContactListener listener;
|
||||
private final TextAvatarView avatar;
|
||||
private final TextView name;
|
||||
private final TextView time;
|
||||
private final TextView status;
|
||||
private final Button removeButton;
|
||||
|
||||
PendingContactViewHolder(View v, PendingContactListener listener) {
|
||||
super(v);
|
||||
avatar = v.findViewById(R.id.avatar);
|
||||
name = v.findViewById(R.id.name);
|
||||
time = v.findViewById(R.id.time);
|
||||
status = v.findViewById(R.id.status);
|
||||
removeButton = v.findViewById(R.id.removeButton);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void bind(PendingContact item) {
|
||||
avatar.setText(item.getAlias());
|
||||
avatar.setBackgroundBytes(item.getId().getBytes());
|
||||
name.setText(item.getAlias());
|
||||
time.setText(formatDate(time.getContext(), item.getTimestamp()));
|
||||
removeButton.setOnClickListener(v -> {
|
||||
listener.onFailedPendingContactRemoved(item);
|
||||
removeButton.setEnabled(false);
|
||||
});
|
||||
|
||||
int color = ContextCompat
|
||||
.getColor(status.getContext(), R.color.briar_green);
|
||||
int buttonVisibility = GONE;
|
||||
switch (item.getState()) {
|
||||
case WAITING_FOR_CONNECTION:
|
||||
color = ContextCompat
|
||||
.getColor(status.getContext(), R.color.briar_yellow);
|
||||
status.setText(R.string.waiting_for_contact_to_come_online);
|
||||
break;
|
||||
case CONNECTED:
|
||||
status.setText(R.string.connecting);
|
||||
break;
|
||||
case ADDING_CONTACT:
|
||||
status.setText(R.string.adding_contact);
|
||||
break;
|
||||
case FAILED:
|
||||
color = ContextCompat
|
||||
.getColor(status.getContext(), R.color.briar_red);
|
||||
status.setText(R.string.adding_contact_failed);
|
||||
buttonVisibility = VISIBLE;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
status.setTextColor(color);
|
||||
removeButton.setVisibility(buttonVisibility);
|
||||
removeButton.setEnabled(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -59,6 +59,7 @@ import org.briarproject.briar.android.conversation.ConversationVisitor.TextCache
|
||||
import org.briarproject.briar.android.forum.ForumActivity;
|
||||
import org.briarproject.briar.android.introduction.IntroductionActivity;
|
||||
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
||||
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||
import org.briarproject.briar.android.view.ImagePreview;
|
||||
import org.briarproject.briar.android.view.TextAttachmentController;
|
||||
@@ -296,10 +297,10 @@ public class ConversationActivity extends BriarActivity
|
||||
super.onActivityResult(request, result, data);
|
||||
|
||||
if (request == REQUEST_INTRODUCTION && result == RESULT_OK) {
|
||||
Snackbar snackbar = Snackbar.make(list, R.string.introduction_sent,
|
||||
Snackbar.LENGTH_SHORT);
|
||||
snackbar.getView().setBackgroundResource(R.color.briar_primary);
|
||||
snackbar.show();
|
||||
new BriarSnackbarBuilder()
|
||||
.make(list, R.string.introduction_sent,
|
||||
Snackbar.LENGTH_SHORT)
|
||||
.show();
|
||||
} else if (request == REQUEST_ATTACH_IMAGE && result == RESULT_OK) {
|
||||
// remove cast when removing FEATURE_FLAG_IMAGE_ATTACHMENTS
|
||||
((TextAttachmentController) sendController).onImageReceived(data);
|
||||
|
||||
@@ -9,7 +9,6 @@ import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentStatePagerAdapter;
|
||||
@@ -32,6 +31,7 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.activity.BriarActivity;
|
||||
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||
import org.briarproject.briar.android.view.PullDownLayout;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -308,9 +308,10 @@ public class ImageActivity extends BriarActivity
|
||||
R.string.save_image_error : R.string.save_image_success;
|
||||
int colorRes = error ?
|
||||
R.color.briar_red : R.color.briar_primary;
|
||||
Snackbar s = Snackbar.make(layout, stringRes, LENGTH_LONG);
|
||||
s.getView().setBackgroundResource(colorRes);
|
||||
s.show();
|
||||
new BriarSnackbarBuilder()
|
||||
.setBackgroundColor(colorRes)
|
||||
.make(layout, stringRes, LENGTH_LONG)
|
||||
.show();
|
||||
viewModel.onSaveStateSeen();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -27,6 +26,7 @@ import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.fragment.BaseEventFragment;
|
||||
import org.briarproject.briar.android.sharing.ForumInvitationActivity;
|
||||
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
||||
@@ -105,11 +105,9 @@ public class ForumListFragment extends BaseEventFragment implements
|
||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
list.setAdapter(adapter);
|
||||
|
||||
snackbar = Snackbar.make(list, "", LENGTH_INDEFINITE);
|
||||
snackbar.getView().setBackgroundResource(R.color.briar_primary);
|
||||
snackbar.setAction(R.string.show, this);
|
||||
snackbar.setActionTextColor(ContextCompat
|
||||
.getColor(getActivity(), R.color.briar_button_text_positive));
|
||||
snackbar = new BriarSnackbarBuilder()
|
||||
.setAction(R.string.show, this)
|
||||
.make(list, "", LENGTH_INDEFINITE);
|
||||
|
||||
return contentView;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -27,6 +26,7 @@ import org.briarproject.briar.android.privategroup.creation.CreateGroupActivity;
|
||||
import org.briarproject.briar.android.privategroup.invitation.GroupInvitationActivity;
|
||||
import org.briarproject.briar.android.privategroup.list.GroupListController.GroupListListener;
|
||||
import org.briarproject.briar.android.privategroup.list.GroupViewHolder.OnGroupRemoveClickListener;
|
||||
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||
import org.briarproject.briar.api.privategroup.GroupMessageHeader;
|
||||
|
||||
@@ -82,11 +82,9 @@ public class GroupListFragment extends BaseFragment implements
|
||||
list.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
list.setAdapter(adapter);
|
||||
|
||||
snackbar = Snackbar.make(list, "", LENGTH_INDEFINITE);
|
||||
snackbar.getView().setBackgroundResource(R.color.briar_primary);
|
||||
snackbar.setAction(R.string.show, this);
|
||||
snackbar.setActionTextColor(ContextCompat
|
||||
.getColor(getActivity(), R.color.briar_button_text_positive));
|
||||
snackbar = new BriarSnackbarBuilder()
|
||||
.setAction(R.string.show, this)
|
||||
.make(list, "", LENGTH_INDEFINITE);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.briarproject.briar.android.controller.handler.UiResultExceptionHandle
|
||||
import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener;
|
||||
import org.briarproject.briar.android.threaded.ThreadListController.ThreadListDataSource;
|
||||
import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener;
|
||||
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||
import org.briarproject.briar.android.view.KeyboardAwareLinearLayout;
|
||||
import org.briarproject.briar.android.view.TextInputView;
|
||||
@@ -41,7 +42,6 @@ import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.support.design.widget.Snackbar.make;
|
||||
import static android.support.v7.widget.RecyclerView.NO_POSITION;
|
||||
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||
|
||||
@@ -324,9 +324,9 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
|
||||
}
|
||||
|
||||
protected void displaySnackbar(@StringRes int stringId) {
|
||||
Snackbar snackbar = make(list, stringId, Snackbar.LENGTH_SHORT);
|
||||
snackbar.getView().setBackgroundResource(R.color.briar_primary);
|
||||
snackbar.show();
|
||||
new BriarSnackbarBuilder()
|
||||
.make(list, stringId, Snackbar.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void updateTextInput() {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.briarproject.briar.android.util;
|
||||
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
|
||||
import static android.support.v4.content.ContextCompat.getColor;
|
||||
|
||||
@NotNullByDefault
|
||||
public class BriarSnackbarBuilder {
|
||||
|
||||
@ColorRes
|
||||
private int backgroundResId = R.color.briar_primary;
|
||||
@StringRes
|
||||
private int actionResId;
|
||||
@Nullable
|
||||
private OnClickListener onClickListener;
|
||||
|
||||
public Snackbar make(View view, CharSequence text, int duration) {
|
||||
Snackbar s = Snackbar.make(view, text, duration);
|
||||
s.getView().setBackgroundResource(backgroundResId);
|
||||
if (onClickListener != null) {
|
||||
s.setActionTextColor(getColor(view.getContext(),
|
||||
R.color.briar_button_text_positive));
|
||||
s.setAction(actionResId, onClickListener);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public Snackbar make(View view, @StringRes int resId, int duration) {
|
||||
return make(view, view.getResources().getText(resId), duration);
|
||||
}
|
||||
|
||||
public BriarSnackbarBuilder setBackgroundColor(
|
||||
@ColorRes int backgroundResId) {
|
||||
this.backgroundResId = backgroundResId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BriarSnackbarBuilder setAction(@StringRes int actionResId,
|
||||
OnClickListener onClickListener) {
|
||||
this.actionResId = actionResId;
|
||||
this.onClickListener = onClickListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.briarproject.briar.android.viewmodel;
|
||||
|
||||
import android.arch.lifecycle.LifecycleOwner;
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Observer;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@NotNullByDefault
|
||||
public class LiveEvent<T> extends LiveData<LiveEvent.ConsumableEvent<T>> {
|
||||
|
||||
public void observeEvent(LifecycleOwner owner,
|
||||
LiveEventHandler<T> handler) {
|
||||
LiveEventObserver<T> observer = new LiveEventObserver<>(handler);
|
||||
super.observe(owner, observer);
|
||||
}
|
||||
|
||||
public static class ConsumableEvent<T> {
|
||||
private final T content;
|
||||
private boolean consumed = false;
|
||||
|
||||
public ConsumableEvent(T content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T getContentIfNotConsumed() {
|
||||
if (consumed) return null;
|
||||
else {
|
||||
consumed = true;
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
public static class LiveEventObserver<T>
|
||||
implements Observer<ConsumableEvent<T>> {
|
||||
private final LiveEventHandler<T> handler;
|
||||
|
||||
public LiveEventObserver(LiveEventHandler<T> handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(@Nullable ConsumableEvent<T> consumableEvent) {
|
||||
if (consumableEvent != null) {
|
||||
T content = consumableEvent.getContentIfNotConsumed();
|
||||
if (content != null) handler.onEventUnconsumedContent(content);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface LiveEventHandler<T> {
|
||||
void onEventUnconsumedContent(T t);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.briarproject.briar.android.viewmodel;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
public class MutableLiveEvent<T> extends LiveEvent<T> {
|
||||
|
||||
public void postEvent(T value) {
|
||||
super.postValue(new ConsumableEvent<>(value));
|
||||
}
|
||||
|
||||
public void setEvent(T value) {
|
||||
super.setValue(new ConsumableEvent<>(value));
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package org.briarproject.briar.android.viewmodel;
|
||||
import android.arch.lifecycle.ViewModel;
|
||||
import android.arch.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.briarproject.briar.android.contact.add.remote.AddContactViewModel;
|
||||
import org.briarproject.briar.android.contact.add.remote.PendingContactListViewModel;
|
||||
import org.briarproject.briar.android.conversation.ConversationViewModel;
|
||||
import org.briarproject.briar.android.conversation.ImageViewModel;
|
||||
|
||||
@@ -27,6 +29,18 @@ public abstract class ViewModelModule {
|
||||
abstract ViewModel bindImageViewModel(
|
||||
ImageViewModel imageViewModel);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(AddContactViewModel.class)
|
||||
abstract ViewModel bindAddContactViewModel(
|
||||
AddContactViewModel addContactViewModel);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(PendingContactListViewModel.class)
|
||||
abstract ViewModel bindPendingRequestsViewModel(
|
||||
PendingContactListViewModel pendingContactListViewModel);
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract ViewModelProvider.Factory bindViewModelFactory(
|
||||
|
||||
@@ -30,7 +30,7 @@ public interface AndroidNotificationManager {
|
||||
int GROUP_MESSAGE_NOTIFICATION_ID = 5;
|
||||
int FORUM_POST_NOTIFICATION_ID = 6;
|
||||
int BLOG_POST_NOTIFICATION_ID = 7;
|
||||
int INTRODUCTION_SUCCESS_NOTIFICATION_ID = 8;
|
||||
int CONTACT_ADDED_NOTIFICATION_ID = 8;
|
||||
|
||||
// Channel IDs
|
||||
String CONTACT_CHANNEL_ID = "contacts";
|
||||
@@ -48,7 +48,7 @@ public interface AndroidNotificationManager {
|
||||
String GROUP_URI = "content://org.briarproject.briar/group";
|
||||
String FORUM_URI = "content://org.briarproject.briar/forum";
|
||||
String BLOG_URI = "content://org.briarproject.briar/blog";
|
||||
String INTRODUCTION_URI = "content://org.briarproject.briar/introduction";
|
||||
String CONTACT_ADDED_URI = "content://org.briarproject.briar/contact/added";
|
||||
|
||||
// Actions for pending intents
|
||||
String ACTION_DISMISS_REMINDER = "dismissReminder";
|
||||
@@ -73,7 +73,7 @@ public interface AndroidNotificationManager {
|
||||
|
||||
void clearAllBlogPostNotifications();
|
||||
|
||||
void clearAllIntroductionNotifications();
|
||||
void clearAllContactAddedNotifications();
|
||||
|
||||
void showSignInNotification();
|
||||
|
||||
|
||||
13
briar-android/src/main/res/drawable/bubble_accent.xml
Normal file
13
briar-android/src/main/res/drawable/bubble_accent.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<corners
|
||||
android:radius="32dp"/>
|
||||
|
||||
<solid
|
||||
android:color="@color/briar_accent"/>
|
||||
|
||||
</shape>
|
||||
|
||||
13
briar-android/src/main/res/drawable/bubble_completed.xml
Normal file
13
briar-android/src/main/res/drawable/bubble_completed.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<corners
|
||||
android:radius="32dp"/>
|
||||
|
||||
<solid
|
||||
android:color="@color/briar_green"/>
|
||||
|
||||
</shape>
|
||||
|
||||
9
briar-android/src/main/res/drawable/ic_call_made.xml
Normal file
9
briar-android/src/main/res/drawable/ic_call_made.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,5v2h6.59L4,18.59 5.41,20 17,8.41V15h2V5z"/>
|
||||
</vector>
|
||||
10
briar-android/src/main/res/drawable/ic_call_received.xml
Normal file
10
briar-android/src/main/res/drawable/ic_call_received.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20,5.41L18.59,4 7,15.59V9H5v10h10v-2H8.41z"/>
|
||||
</vector>
|
||||
10
briar-android/src/main/res/drawable/ic_content_copy.xml
Normal file
10
briar-android/src/main/res/drawable/ic_content_copy.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#2A93C6"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
|
||||
</vector>
|
||||
10
briar-android/src/main/res/drawable/ic_content_paste.xml
Normal file
10
briar-android/src/main/res/drawable/ic_content_paste.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#2A93C6"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19,2h-4.18C14.4,0.84 13.3,0 12,0c-1.3,0 -2.4,0.84 -2.82,2L5,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM12,2c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM19,20L5,20L5,4h2v3h10L17,4h2v16z"/>
|
||||
</vector>
|
||||
9
briar-android/src/main/res/drawable/ic_link_menu.xml
Normal file
9
briar-android/src/main/res/drawable/ic_link_menu.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M3.9,12c0,-1.71 1.39,-3.1 3.1,-3.1h4L11,7L7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5h4v-1.9L7,15.1c-1.71,0 -3.1,-1.39 -3.1,-3.1zM8,13h8v-2L8,11v2zM17,7h-4v1.9h4c1.71,0 3.1,1.39 3.1,3.1s-1.39,3.1 -3.1,3.1h-4L13,17h4c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5z"/>
|
||||
</vector>
|
||||
9
briar-android/src/main/res/drawable/ic_nearby.xml
Normal file
9
briar-android/src/main/res/drawable/ic_nearby.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M11.1731,2.4031C9.9686,2.4471 8.7753,2.713 7.6641,3.2033 8.187,3.7263 8.3967,4.1446 8.6059,4.563 11.6391,3.4125 15.0914,4.0394 17.4971,6.445c0.7322,0.7321 1.3593,1.5692 1.6731,2.5105 0.4184,-0.2092 0.9412,-0.3134 1.4642,-0.3134h0.1045C20.2158,7.387 19.483,6.3401 18.5416,5.2942 16.5283,3.2808 13.823,2.3062 11.1731,2.4031ZM5.1695,3.2316A2.7194,2.7194 0,0 0,2.4501 5.951,2.7194 2.7194,0 0,0 5.1695,8.6704 2.7194,2.7194 0,0 0,7.8889 5.951,2.7194 2.7194,0 0,0 5.1695,3.2316ZM2.5404,8.5359C0.9715,12.1966 1.7027,16.4848 4.6313,19.4134c1.8827,1.9872 4.4972,2.9301 7.0074,2.9301 2.5102,0 5.1264,-0.9428 7.0092,-2.9301 0.9413,-0.9414 1.6724,-2.091 2.1953,-3.3461h-0.1045c-0.5229,0 -1.0458,-0.1042 -1.4642,-0.3134 -0.4184,0.9414 -0.9409,1.7783 -1.6731,2.5105 -3.2423,3.2424 -8.5771,3.2424 -11.8194,0C3.2719,15.8588 2.6451,12.4064 3.7957,9.3733 3.3773,9.1641 2.9588,8.9542 2.5404,8.5359ZM11.5944,9.3804a2.9913,2.9913 0,0 0,-2.9903 2.9903,2.9913 2.9913,0 0,0 2.9903,2.992 2.9913,2.9913 0,0 0,2.992 -2.992,2.9913 2.9913,0 0,0 -2.992,-2.9903zM20.7334,9.8035a2.7194,2.7194 0,0 0,-2.7194 2.7194,2.7194 2.7194,0 0,0 2.7194,2.7194 2.7194,2.7194 0,0 0,2.7194 -2.7194,2.7194 2.7194,0 0,0 -2.7194,-2.7194z"/>
|
||||
</vector>
|
||||
57
briar-android/src/main/res/drawable/ic_nickname.xml
Normal file
57
briar-android/src/main/res/drawable/ic_nickname.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="200dp"
|
||||
android:height="237dp"
|
||||
android:viewportHeight="178"
|
||||
android:viewportWidth="150">
|
||||
<path
|
||||
android:fillAlpha="0.25"
|
||||
android:pathData="M85.19,0.128 L3.357,0.329C2.465,0.331 1.611,0.69 0.981,1.329 0.352,1.967 -0.001,2.832 0,3.733L0.373,156.201c0.001,0.446 0.089,0.888 0.26,1.3 0.17,0.412 0.419,0.786 0.732,1.101 0.313,0.315 0.685,0.564 1.093,0.734 0.409,0.17 0.846,0.257 1.288,0.256l81.834,-0.201c0.892,-0.003 1.746,-0.363 2.375,-1.002 0.629,-0.639 0.981,-1.504 0.98,-2.405L88.554,3.516C88.551,2.617 88.196,1.755 87.565,1.12 86.935,0.485 86.081,0.128 85.19,0.128Z">
|
||||
</path>
|
||||
<path
|
||||
android:fillAlpha="0.175"
|
||||
android:fillColor="#6d6d6d"
|
||||
android:pathData="M84.282,-0.002 L4.276,0.196C2.574,0.2 1.198,1.598 1.202,3.318L1.567,154.298c0.004,1.72 1.387,3.111 3.089,3.107l80.006,-0.198c1.702,-0.004 3.078,-1.402 3.074,-3.122L87.37,3.105C87.366,1.385 85.983,-0.006 84.282,-0.002Z"/>
|
||||
<path
|
||||
android:fillAlpha="0.25"
|
||||
android:fillColor="#646464"
|
||||
android:pathData="M81.939,3.957L65.934,3.996C65.689,5.664 64.862,7.188 63.602,8.293C62.342,9.398 60.732,10.01 59.064,10.02L29.303,10.092C27.635,10.091 26.021,9.487 24.756,8.389C23.49,7.29 22.655,5.77 22.402,4.104L6.637,4.143C5.769,4.145 4.938,4.495 4.326,5.117C3.714,5.739 3.371,6.58 3.373,7.457L3.461,44.068L3.717,150.168C3.721,151.045 4.069,151.885 4.686,152.502C5.302,153.119 6.136,153.464 7.004,153.461L82.307,153.275C83.172,153.27 83.999,152.921 84.609,152.301C85.219,151.681 85.561,150.841 85.561,149.967L85.307,43.563L85.221,7.256C85.218,6.379 84.871,5.539 84.256,4.92C83.641,4.301 82.807,3.955 81.939,3.957zM52.652,5.791L34.357,6.068C34.108,6.072 33.908,6.279 33.912,6.531L33.916,6.83C33.92,7.082 34.125,7.285 34.375,7.281L52.672,7.002C52.921,6.998 53.119,6.791 53.115,6.539L53.111,6.24C53.108,5.988 52.902,5.787 52.652,5.791z"/>
|
||||
<path
|
||||
android:fillAlpha="0.25"
|
||||
android:fillColor="#dbdbdb"
|
||||
android:pathData="M57.204,6.934C57.602,6.928 57.919,6.597 57.913,6.195 57.907,5.793 57.58,5.471 57.182,5.477c-0.398,0.006 -0.716,0.337 -0.71,0.739 0.006,0.402 0.333,0.723 0.731,0.717z"/>
|
||||
<path
|
||||
android:fillAlpha="0.25"
|
||||
android:fillColor="#e0e0e0"
|
||||
android:pathData="m17.641,19.459c-4.185,0 -7.576,3.446 -7.576,7.695 0,4.25 3.392,7.695 7.576,7.695 4.185,0 7.576,-3.446 7.576,-7.695 0,-4.25 -3.392,-7.695 -7.576,-7.695zM37.523,23.637v3.234h40.117v-3.234zM37.523,30.104v3.234L77.641,33.338L77.641,30.104ZM17.641,44.088c-4.185,0 -7.576,3.444 -7.576,7.693 0,4.25 3.392,7.695 7.576,7.695 4.185,0 7.576,-3.446 7.576,-7.695 0,-4.25 -3.392,-7.693 -7.576,-7.693zM37.523,48.266L37.523,51.5h40.117v-3.234zM37.523,54.732v3.232L77.641,57.965L77.641,54.732ZM17.641,68.715c-4.185,0 -7.576,3.446 -7.576,7.695 0,4.25 3.392,7.695 7.576,7.695 4.185,0 7.576,-3.446 7.576,-7.695 0,-4.25 -3.392,-7.695 -7.576,-7.695zM37.523,72.895v3.232h40.117v-3.232zM37.523,79.361L37.523,82.594L77.641,82.594L77.641,79.361ZM17.641,93.344c-4.185,0 -7.576,3.446 -7.576,7.695 0,4.25 3.392,7.695 7.576,7.695 4.185,0 7.576,-3.445 7.576,-7.695 0,-4.25 -3.392,-7.695 -7.576,-7.695zM37.523,97.523v3.232h40.117v-3.232zM37.523,103.988v3.234h40.117v-3.234zM17.641,117.973c-4.185,0 -7.576,3.446 -7.576,7.695 0,4.25 3.392,7.693 7.576,7.693 4.185,0 7.576,-3.443 7.576,-7.693 0,-4.249 -3.392,-7.695 -7.576,-7.695zM37.523,122.15v3.234h40.117v-3.234zM37.523,128.617v3.234h40.117v-3.234z"/>
|
||||
<path
|
||||
android:fillColor="#313131"
|
||||
android:pathData="m136.95,18.407 l-80.006,0.198c-1.702,0.004 -3.078,1.402 -3.074,3.122l0.365,150.981c0.004,1.72 1.387,3.111 3.089,3.107l80.006,-0.198c1.702,-0.004 3.078,-1.402 3.074,-3.122L140.039,21.514c-0.004,-1.72 -1.387,-3.111 -3.089,-3.107z"/>
|
||||
<path
|
||||
android:fillColor="#3e3e3e"
|
||||
android:pathData="M134.609,22.357L118.6,22.395C118.356,24.062 117.528,25.587 116.268,26.691C115.008,27.796 113.398,28.408 111.73,28.418L81.969,28.492C80.301,28.491 78.689,27.886 77.424,26.787C76.158,25.689 75.323,24.168 75.07,22.502L59.305,22.541C58.437,22.543 57.604,22.894 56.992,23.516C56.38,24.137 56.037,24.98 56.039,25.857L56.129,62.469L56.748,62.467L56.129,62.471L56.383,168.57C56.385,169.447 56.733,170.287 57.348,170.906C57.963,171.524 58.796,171.871 59.664,171.869L134.967,171.684C135.835,171.682 136.665,171.331 137.277,170.709C137.889,170.088 138.232,169.246 138.23,168.369L137.973,62.219L137.975,62.219L137.889,25.656C137.887,24.779 137.541,23.939 136.926,23.32C136.311,22.702 135.477,22.356 134.609,22.357z"/>
|
||||
<path
|
||||
android:fillColor="#e0e0e0"
|
||||
android:pathData="M109.85,23.891C109.452,23.897 109.135,24.229 109.141,24.631C109.147,25.033 109.473,25.354 109.871,25.348C110.269,25.342 110.586,25.01 110.58,24.607C110.574,24.205 110.248,23.885 109.85,23.891zM105.32,24.201L87.025,24.479C86.776,24.482 86.576,24.691 86.58,24.943L86.584,25.242C86.588,25.494 86.793,25.695 87.043,25.691L105.34,25.414C105.589,25.41 105.787,25.203 105.783,24.951L105.779,24.65C105.775,24.398 105.569,24.197 105.32,24.201zM63.365,37.568L63.365,53.738L79.365,53.738L79.365,37.568L63.365,37.568zM86.748,37.568L86.748,40.801L126.865,40.801L126.865,37.568L86.748,37.568zM86.748,44.037L86.748,47.27L126.865,47.27L126.865,44.037L86.748,44.037zM71.787,112.996C67.603,112.996 64.211,116.441 64.211,120.691C64.211,124.941 67.603,128.387 71.787,128.387C75.972,128.387 79.365,124.941 79.365,120.691C79.365,116.441 75.972,112.996 71.787,112.996zM86.748,116.928L86.748,120.16L126.865,120.16L126.865,116.928L86.748,116.928zM86.748,123.393L86.748,126.627L126.865,126.627L126.865,123.393L86.748,123.393zM71.787,142.602C67.603,142.602 64.211,146.047 64.211,150.297C64.211,154.547 67.603,157.99 71.787,157.99C75.972,157.99 79.365,154.547 79.365,150.297C79.365,146.047 75.972,142.602 71.787,142.602zM86.748,145.535L86.748,148.768L126.865,148.768L126.865,145.535L86.748,145.535zM86.748,152.002L86.748,155.234L126.865,155.234L126.865,152.002L86.748,152.002z"/>
|
||||
<path
|
||||
android:fillColor="#d5d6d7"
|
||||
android:pathData="M148.744,68.665H45.619v33.583h103.125z"/>
|
||||
<path
|
||||
android:fillColor="#87c214"
|
||||
android:pathData="m97.822,50.504v5.723h17.967v-5.723zM86.748,81.104v3.232h40.117v-3.232zM86.748,87.572v3.232h40.117v-3.232z"/>
|
||||
<path
|
||||
android:fillColor="#f5f5f5"
|
||||
android:pathData="m66.865,92.314c4.185,0 7.577,-3.445 7.577,-7.695 0,-4.25 -3.392,-7.695 -7.577,-7.695 -4.185,0 -7.577,3.445 -7.577,7.695 0,4.25 3.392,7.695 7.577,7.695z"/>
|
||||
<path
|
||||
android:fillColor="#87c214"
|
||||
android:pathData="m70.13,90.006h-6.574c-0.315,0.002 -0.625,0.082 -0.904,0.231 -0.278,0.149 -0.517,0.365 -0.696,0.627 1.477,0.856 3.147,1.311 4.85,1.321 1.702,0.01 3.378,-0.427 4.864,-1.266 -0.167,-0.265 -0.393,-0.486 -0.661,-0.645 -0.268,-0.159 -0.569,-0.251 -0.879,-0.269z"/>
|
||||
<path
|
||||
android:fillColor="#333333"
|
||||
android:pathData="m66.861,80.746c-2.08,0 -3.766,1.704 -3.766,3.807 0,0.394 0.076,0.766 0.186,1.123 -0.328,0.813 -0.822,1.878 -1.158,1.709 0,0 5.07,4.425 9.545,0 -0.355,-0.613 -0.773,-1.184 -1.219,-1.732 0.105,-0.35 0.178,-0.715 0.178,-1.1 0,-2.102 -1.686,-3.807 -3.766,-3.807z"/>
|
||||
<path
|
||||
android:fillColor="#fda57d"
|
||||
android:pathData="m66.861,81.57c-1.801,0 -3.302,1.279 -3.674,2.986 -0.005,-0 -0.009,-0.006 -0.014,-0.006 -0.193,0 -0.35,0.297 -0.35,0.664 0,0.347 0.142,0.623 0.32,0.652 0.181,1.408 1.109,2.569 2.381,3.059v0.732c0,0.323 0.127,0.635 0.354,0.863 0.226,0.229 0.534,0.357 0.854,0.357h0.225c0.159,0 0.316,-0.032 0.463,-0.094 0.147,-0.061 0.28,-0.15 0.393,-0.264 0.112,-0.113 0.201,-0.248 0.262,-0.396 0.061,-0.148 0.092,-0.308 0.092,-0.469v-0.721c1.289,-0.484 2.232,-1.655 2.412,-3.076 0.168,-0.049 0.299,-0.312 0.299,-0.645 0,-0.363 -0.153,-0.656 -0.344,-0.662 -0.373,-1.705 -1.873,-2.982 -3.672,-2.982z"/>
|
||||
<path
|
||||
android:fillColor="#333333"
|
||||
android:pathData="m63.253,83.934h7.179c0,0 -0.612,-2.93 -3.328,-2.74 -2.715,0.19 -3.852,2.74 -3.852,2.74z"/>
|
||||
</vector>
|
||||
5
briar-android/src/main/res/drawable/ic_person.xml
Normal file
5
briar-android/src/main/res/drawable/ic_person.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
||||
</vector>
|
||||
10
briar-android/src/main/res/drawable/social_share_blue.xml
Normal file
10
briar-android/src/main/res/drawable/social_share_blue.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#2A93C6"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
|
||||
</vector>
|
||||
24
briar-android/src/main/res/layout/fragment_contact_list.xml
Normal file
24
briar-android/src/main/res/layout/fragment_contact_list.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.briarproject.briar.android.view.BriarRecyclerView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:scrollToEnd="false"/>
|
||||
|
||||
<io.github.kobakei.materialfabspeeddial.FabSpeedDial
|
||||
android:id="@+id/speedDial"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:fab_fabDrawable="@drawable/ic_action_add"
|
||||
app:fab_fabRippleColor="@android:color/transparent"
|
||||
app:fab_menu="@menu/contact_list_actions"
|
||||
app:fab_miniFabTextBackground="@color/briar_accent"
|
||||
app:fab_miniFabTextColor="@android:color/white"/>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
234
briar-android/src/main/res/layout/fragment_link_exchange.xml
Normal file
234
briar-android/src/main/res/layout/fragment_link_exchange.xml
Normal file
@@ -0,0 +1,234 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<android.support.constraint.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/margin_large">
|
||||
|
||||
<android.support.constraint.Guideline
|
||||
android:id="@+id/guideline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_percent="0.5"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/stepOne"
|
||||
style="@style/StepBubble"
|
||||
android:text="@string/step_1"
|
||||
app:layout_constraintBottom_toTopOf="@+id/stepOneText"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/stepOneText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/send_link_title"
|
||||
app:layout_constraintBottom_toTopOf="@+id/yourLinkIcon"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/stepOne"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/stepConnector"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="16dp"
|
||||
android:alpha="0.5"
|
||||
android:background="@color/briar_accent"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/stepOne"
|
||||
app:layout_constraintEnd_toStartOf="@+id/stepTwo"
|
||||
app:layout_constraintStart_toEndOf="@+id/stepOne"
|
||||
app:layout_constraintTop_toTopOf="@+id/stepOne"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/stepTwo"
|
||||
style="@style/StepBubble.Upcoming"
|
||||
android:text="@string/step_2"
|
||||
app:layout_constraintBottom_toTopOf="@+id/stepTwoText"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline"
|
||||
app:layout_constraintTop_toTopOf="@+id/stepOne"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:layout_constraintVertical_chainStyle="packed"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/stepTwoText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:alpha="0.5"
|
||||
android:text="@string/add_contact_choose_nickname"
|
||||
app:layout_constraintBottom_toTopOf="@+id/yourLinkIcon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
||||
app:layout_constraintTop_toBottomOf="@+id/stepTwo"/>
|
||||
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:id="@+id/yourLinkIcon"
|
||||
android:layout_width="38dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:background="@drawable/bubble_accent"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_call_made"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/stepOneText"
|
||||
app:tint="@color/briar_white"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/yourLink"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:gravity="left|start"
|
||||
android:text="@string/your_link"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/yourLinkIcon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/yourLinkIcon"
|
||||
app:layout_constraintTop_toTopOf="@+id/yourLinkIcon"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/linkView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@color/briar_white"
|
||||
android:ellipsize="end"
|
||||
android:padding="8dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/briar_primary"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="18sp"
|
||||
android:typeface="monospace"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/yourLinkIcon"
|
||||
tools:text="briar://scnsdflamslkfjgluoblmksdfbwevlewajfdlkjewwhqliafskfjhskdjhvoieiv"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/copyButton"
|
||||
style="@style/BriarButtonFlat.Positive.Tiny"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableLeft="@drawable/ic_content_copy"
|
||||
android:drawablePadding="8dp"
|
||||
android:drawableStart="@drawable/ic_content_copy"
|
||||
android:enabled="false"
|
||||
android:text="@string/copy_button"
|
||||
app:layout_constraintEnd_toStartOf="@id/shareButton"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linkView"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/shareButton"
|
||||
style="@style/BriarButtonFlat.Positive.Tiny"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableLeft="@drawable/social_share_blue"
|
||||
android:drawablePadding="8dp"
|
||||
android:drawableStart="@drawable/social_share_blue"
|
||||
android:enabled="false"
|
||||
android:text="@string/share_button"
|
||||
app:layout_constraintBottom_toBottomOf="@id/copyButton"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toEndOf="@id/copyButton"
|
||||
app:layout_constraintTop_toTopOf="@id/copyButton"/>
|
||||
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:id="@+id/linkInputIcon"
|
||||
android:layout_width="38dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/bubble_accent"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_call_received"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/copyButton"
|
||||
app:tint="@color/briar_white"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/inputLink"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:gravity="left|start"
|
||||
android:text="@string/contact_link_intro"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/linkInputIcon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/linkInputIcon"
|
||||
app:layout_constraintTop_toTopOf="@+id/linkInputIcon"/>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/linkInputLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
app:errorEnabled="true"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linkInputIcon">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
android:id="@+id/linkInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:hint="@string/contact_link_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textUri"/>
|
||||
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/pasteButton"
|
||||
style="@style/BriarButtonFlat.Positive.Tiny"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableLeft="@drawable/ic_content_paste"
|
||||
android:drawablePadding="8dp"
|
||||
android:drawableStart="@drawable/ic_content_paste"
|
||||
android:text="@string/paste_button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linkInputLayout"
|
||||
app:layout_constraintVertical_bias="0.0"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/addButton"
|
||||
style="@style/BriarButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:enabled="false"
|
||||
android:text="@string/continue_button"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pasteButton"
|
||||
app:layout_constraintVertical_bias="1.0"
|
||||
tools:enabled="true"/>
|
||||
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
</ScrollView>
|
||||
163
briar-android/src/main/res/layout/fragment_nickname.xml
Normal file
163
briar-android/src/main/res/layout/fragment_nickname.xml
Normal file
@@ -0,0 +1,163 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<android.support.constraint.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/margin_large">
|
||||
|
||||
<android.support.constraint.Guideline
|
||||
android:id="@+id/guideline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_percent="0.5"/>
|
||||
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:id="@+id/stepOne"
|
||||
style="@style/StepBubble.Completed"
|
||||
app:layout_constraintBottom_toTopOf="@+id/stepOneText"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/stepOneText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/send_link_title"
|
||||
app:layout_constraintBottom_toTopOf="@+id/imageView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/stepOne"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/stepConnector"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="16dp"
|
||||
android:background="@color/briar_accent"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/stepOne"
|
||||
app:layout_constraintEnd_toStartOf="@+id/stepTwo"
|
||||
app:layout_constraintStart_toEndOf="@+id/stepOne"
|
||||
app:layout_constraintTop_toTopOf="@+id/stepOne"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/stepTwo"
|
||||
style="@style/StepBubble"
|
||||
android:text="@string/step_2"
|
||||
app:layout_constraintBottom_toTopOf="@+id/stepTwoText"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline"
|
||||
app:layout_constraintTop_toTopOf="@+id/stepOne"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:layout_constraintVertical_chainStyle="packed"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/stepTwoText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/add_contact_choose_nickname"
|
||||
app:layout_constraintBottom_toTopOf="@+id/imageView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
||||
app:layout_constraintTop_toBottomOf="@+id/stepTwo"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:src="@drawable/ic_nickname"
|
||||
app:layout_constraintBottom_toTopOf="@+id/nicknameIcon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/stepOneText"
|
||||
tools:ignore="ContentDescription"/>
|
||||
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:id="@+id/nicknameIcon"
|
||||
android:layout_width="38dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:background="@drawable/bubble_accent"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_person"
|
||||
app:layout_constraintBottom_toTopOf="@+id/contactNameLayout"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView"
|
||||
app:tint="@color/briar_white"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/nicknameIntro"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:gravity="left|start"
|
||||
android:text="@string/nickname_intro"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/nicknameIcon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/nicknameIcon"
|
||||
app:layout_constraintTop_toTopOf="@+id/nicknameIcon"/>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/contactNameLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
app:errorEnabled="true"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/nicknameIcon">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
android:id="@+id/contactNameInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:hint="@string/add_contact_choose_a_nickname"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="text|textCapWords"/>
|
||||
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/addButton"
|
||||
style="@style/BriarButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/add_contact_button"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/contactNameLayout"
|
||||
app:layout_constraintVertical_bias="1.0"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/contactNameLayout"
|
||||
app:layout_constraintVertical_bias="1.0"/>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout
|
||||
android:id="@+id/linearLayout4"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<org.briarproject.briar.android.view.TextAvatarView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="@dimen/listitem_picture_frame_size"
|
||||
android:layout_height="@dimen/listitem_picture_frame_size"
|
||||
android:layout_marginBottom="@dimen/listitem_horizontal_margin"
|
||||
android:layout_marginLeft="@dimen/listitem_horizontal_margin"
|
||||
android:layout_marginStart="@dimen/listitem_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/listitem_horizontal_margin"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<com.vanniktech.emoji.EmojiTextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/margin_large"
|
||||
android:layout_marginLeft="@dimen/margin_large"
|
||||
android:layout_marginStart="@dimen/margin_large"
|
||||
android:layout_marginTop="@dimen/margin_large"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/text_size_medium"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/status"
|
||||
app:layout_constraintEnd_toStartOf="@+id/time"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:layout_constraintStart_toEndOf="@+id/avatar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="This is a name of a contact"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/adding_contact_failed"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toStartOf="@+id/time"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="@+id/name"
|
||||
app:layout_constraintTop_toBottomOf="@+id/name"
|
||||
tools:textColor="@color/briar_red"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/margin_large"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="@dimen/text_size_small"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/status"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/name"
|
||||
app:layout_constraintTop_toTopOf="@+id/name"
|
||||
tools:text="Dec 24"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/removeButton"
|
||||
style="@style/BriarButtonFlat.Negative"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/groups_remove"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="@+id/time"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/status"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
style="@style/Divider.ContactList"
|
||||
android:layout_width="0dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/avatar"
|
||||
app:layout_constraintTop_toBottomOf="@+id/removeButton"
|
||||
app:layout_goneMarginTop="@dimen/margin_large"/>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
@@ -4,9 +4,17 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_add_contact"
|
||||
android:icon="@drawable/ic_add_white"
|
||||
android:title="@string/add_contact_title"
|
||||
app:showAsAction="ifRoom"/>
|
||||
android:id="@+id/action_add_contact_nearby"
|
||||
android:icon="@drawable/ic_nearby"
|
||||
android:orderInCategory="3"
|
||||
android:title="@string/add_contact_nearby_title"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
</menu>
|
||||
<item
|
||||
android:id="@+id/action_add_contact_remotely"
|
||||
android:icon="@drawable/ic_link_menu"
|
||||
android:orderInCategory="2"
|
||||
android:title="@string/add_contact_remotely_title"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
</menu>
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
<string name="introduction_response_accepted_received">لقد وافق/ت %1$s على تقديمه/ها إلى %2$s.</string>
|
||||
<string name="introduction_response_declined_received">لقد رفض/ت %1$sتقديمه/ا إلى %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">ي/تقول %1$sأن %2$s قد رفض/ت التقدمة.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="zero">لا جهة اتصال تم إضافتها.</item>
|
||||
<item quantity="one">جهة اتصال تم إضافتها.</item>
|
||||
<item quantity="two">جهتيْ اتصال تم إضافتها.</item>
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
<string name="try_again_button">Tentar nuevamente</string>
|
||||
<string name="camera_error">Error de cámara</string>
|
||||
<!--Introductions-->
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Añadióse un contactu nuevu.</item>
|
||||
<item quantity="other">Añadiéronse %d contactos nuevos.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
<string name="introduction_request_answered_received">%1$ssizi %2$s-ə təqdim etmək istədi.</string>
|
||||
<string name="introduction_response_accepted_sent">%1$s-ə qəbul olundunuz</string>
|
||||
<string name="introduction_response_declined_sent">%1$s-ə girişdən imtina etdiniz</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">yeni kontaktlar əlavə edildi.</item>
|
||||
<item quantity="other">%dyeni kontaktlar əlavə edildi.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s прие представянето на %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s отказа представянето на %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s казва, че %2$s отказва представянето.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Добавен нов контакт.</item>
|
||||
<item quantity="other">%d добавени нови контакти.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
<string name="introduction_sent">Kaset eo bet ho tigoradur.</string>
|
||||
<string name="introduction_error">Ur fazi a zo c\'hoarvezet en ur ober an digoradur.</string>
|
||||
<string name="introduction_response_error">Fazi en ur respont d\'an digoradur</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Darempred nevez ouzhpennet.</item>
|
||||
<item quantity="two">%d a zarempredoù nevez ouzhpennet.</item>
|
||||
<item quantity="few">%d a zarempredoù nevez ouzhpennet.</item>
|
||||
|
||||
@@ -178,7 +178,7 @@ Un cop s\'actualitzi ja li veureu una icona diferent </string>
|
||||
<string name="introduction_response_accepted_received">%1$s ha acceptat conèixer a %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s ha refusat conèixer a %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s diu que %2$s ha refusat conèixer-lo.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">S\'ha afegit un nou contacte.</item>
|
||||
<item quantity="other">S\'han afegit %d nous contactes.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s přijal pozvání do %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s odmítl pozvání do %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s řekl, že %2$s odmítl pozvání.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Nový kontakt byl přidán.</item>
|
||||
<item quantity="few">Bylo přidáno %d nových kontaktů.</item>
|
||||
<item quantity="many">%d nových kontaktů bylo přidáno.</item>
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s hat die Kontaktempfehlung für %2$s angenommen.</string>
|
||||
<string name="introduction_response_declined_received">%1$s hat die Kontaktempfehlung von %2$s abgelehnt.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s meldet, dass %2$s die Kontaktempfehlung abgelehnt hat.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">neuer Kontakt hinzugefügt.</item>
|
||||
<item quantity="other">%d neue Kontakte hinzugefügt.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s aceptó la presentación a %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s rechazó la presentación a %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s dice que %2$s rechazó la presentación.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">nuevo contacto añadido.</item>
|
||||
<item quantity="other">%d nuevos contactos añadidos.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s erabiltzaileak %2$s erabiltzailearen aurkezpena onartu du.</string>
|
||||
<string name="introduction_response_declined_received">%1$s erabiltzaileak %2$s erabiltzailearen aurkezpena errefusatu du.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s erabiltzaileak dio %2$s erabiltzaileak aurkezpena errefusatu duela.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Kontaktu berria gehitu da.</item>
|
||||
<item quantity="other">%d kontaktu berri gehitu dira.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s معرفی به %2$s را پذیرفت.</string>
|
||||
<string name="introduction_response_declined_received">%1$s معرفی به %2$s را رد کرد.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s می گوید که %2$s دعوت نامه را رد کرد.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">مخاطب جدید افزوده شد.</item>
|
||||
<item quantity="other">%d مخاطب جدید افزوده شد.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s hyväksyi esittelyn käyttäjälle %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s kieltäytyi esittelystä käyttäjälle %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s sanoo, että %2$s on kieltäytynyt esittelystä.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Uusi yhteystieto lisätty.</item>
|
||||
<item quantity="other">%d uutta yhteystietoa lisätty.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s a accepté d’être présenté à %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s a refusé d’être présenté à %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s annonce que %2$s a refusé la présentation.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Un nouveau contact a été ajouté.</item>
|
||||
<item quantity="other">%d nouveaux contacts ont été ajoutés.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s aceptou a presentación a %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s rexeitou a presentación a %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s di que %2$srexeitou a presentación.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Novo contacto engadido.</item>
|
||||
<item quantity="other">%d novos contactos engadidos.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s הסכימו להיות מוצגים בפני %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s סירבו להיות מוצגים בפני %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s אומרים ש- %2$s סירבו להיות מוצגים בפניהם.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">נוסף איש קשר חדש.</item>
|
||||
<item quantity="two">נוספו %d אנשי קשר חדשים.</item>
|
||||
<item quantity="many">נוספו %d אנשי קשר חדשים.</item>
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s%2$s की शुरूआत स्वीकार कर ली</string>
|
||||
<string name="introduction_response_declined_received">%1$s%2$sकी शुरूआत में गिरावट आई</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$sकहते हैं कि%2$sने परिचय को अस्वीकार कर दिया</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">नया संपर्क जोड़ा।</item>
|
||||
<item quantity="other">%dनया संपर्क जोड़ा।</item>
|
||||
</plurals>
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s elfogadta a bemutatkozást %2$s számára.</string>
|
||||
<string name="introduction_response_declined_received">%1$s elutasította a bemutatkozást %2$s számára.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s alapján %2$s elutasította a bemutatkozást.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Új kapcsolat hozzáadva.</item>
|
||||
<item quantity="other">%d új kapcsolat hozzáadva.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s ha accettato l\'introduzione a %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s ha declinato l\'introduzione a %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s dice che %2$s ha declinato l\'introduzione.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Aggiunto nuovo contatto</item>
|
||||
<item quantity="other">Aggiunti %d nuovi contatti.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s го прифативте запознавањето со %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s го одбивте запознавањето со %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s вели дека %2$s го одбил запознавањето.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Нов контакт е додаден. </item>
|
||||
<item quantity="other">%d нови контакти се додадени.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s er nå bekjent %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s avslo introduksjonen med %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s sier at %2$s avslo introduksjonen.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Ny kontakt lagt til.</item>
|
||||
<item quantity="other">%d nye kontakter lagt til.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s heeft de introductie aan %2$sgeaccepteerd.</string>
|
||||
<string name="introduction_response_declined_received">%1$s heeft de introductie aan %2$s afgewezen.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s zegt dat %2$s je introductie heeft afgewezen.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Nieuw contact is toegevoegd.</item>
|
||||
<item quantity="other">%d nieuwe contacten zijn toegevoegd.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -179,7 +179,7 @@ Volètz suprimir vòstre compte e ne crear un nòu ?\n
|
||||
<string name="introduction_response_accepted_received">%1$s a acceptat d’apondre %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s a refusat d’apondre %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s anóncia que %2$s a refusat la convidacion.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Nòu contacte ajustat.</item>
|
||||
<item quantity="other">%d nòus contactes ajustats.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s zaakceptował udostępnienie kontaktu %2$s</string>
|
||||
<string name="introduction_response_declined_received">%1$s odrzucił udostępnienie kontaktu %2$s</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s mówi, że %2$s odrzucił udostępnienie kontaktu.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Nowy kontakt został dodany.</item>
|
||||
<item quantity="few">%d nowych kontaktów zostało dodanych.</item>
|
||||
<item quantity="many">%d nowych kontaktów zostało dodanych.</item>
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s aceitou ser apresentado a %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s recusou ser apresentado a %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s disse que %2$s recusou a apresentação.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Novo contato adicionado.</item>
|
||||
<item quantity="other">%d novos contatos adicionados.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s a acceptat recomandarea pentru %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s a refuzat recomandarea pentru %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s spune că %2$s a refuzat recomandarea.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Un nou contact adăugat.</item>
|
||||
<item quantity="few">%d contacte noi adăugate.</item>
|
||||
<item quantity="other">%d de contacte noi adăugate.</item>
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s принял представление %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s отказался от представления %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s сообщает, что %2$s отказался от представления.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Новый контакт добавлен.</item>
|
||||
<item quantity="few">%d новых контакта добавлено.</item>
|
||||
<item quantity="many">%d новых контактов добавлено.</item>
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s pranoi prezantimin te %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s hodhi poshtë prezantimin te %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s thotë se %2$s hodhi poshtë prezantimin.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">U shtua kontakt i ri.</item>
|
||||
<item quantity="other">U shtuan %d kontakte të rinj.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -165,7 +165,7 @@ Izaberite dugačku lozinku koju je teško pogoditi, kao četiri nasumične rije
|
||||
<string name="introduction_response_accepted_received">%1$s prihvata upoznavanje sa %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s je prihvatio-la upoznavanje sa kontaktom %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s kaže da je %2$s odbio-la upoznavanje.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Novi kontakt je dodat.</item>
|
||||
<item quantity="few">%d nova kontakta dodata.</item>
|
||||
<item quantity="other">%d novih kontakata dodato.</item>
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s, %2$s ile tanışmayı kabul etti.</string>
|
||||
<string name="introduction_response_declined_received">%1$s, %2$s ile tanışmayı reddetti.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s, %2$s kişisinin tanışmayı reddettiğini söyledi.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Yeni kişi eklendi.</item>
|
||||
<item quantity="other">%d yeni kişi eklendi.</item>
|
||||
</plurals>
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$sприйняв(-ла) запит на знайомство із %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$sвідхилив(-ла) запит на знайомство з %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s повідомляє, що %2$s відхилив(-ла) запит на знайомство.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Новий контакт додано.</item>
|
||||
<item quantity="few">%d нові контакти додано.</item>
|
||||
<item quantity="many">%d нових контактів додано.</item>
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
<string name="introduction_response_accepted_received">%1$s 已接受与 %2$s 建立联系。</string>
|
||||
<string name="introduction_response_declined_received">%1$s 已谢绝与 %2$s 建立联系。</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s 表示 %2$s 谢绝了介绍。</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="other">已添加 %d 位新联系人。</item>
|
||||
</plurals>
|
||||
<!--Private Groups-->
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<color name="briar_blue_elio_light">#3C80A9</color>
|
||||
<color name="briar_blue_light">#2A93C6</color>
|
||||
<color name="briar_blue_grey">#EBEFF2</color>
|
||||
<color name="briar_yellow">#9e9d24</color>
|
||||
<color name="briar_green">#5C940D</color>
|
||||
<color name="briar_green_light">#95D220</color>
|
||||
<color name="briar_red">#ff0000</color>
|
||||
|
||||
@@ -150,7 +150,8 @@
|
||||
<string name="dialog_message_image_support">Tap this icon to attach images.</string>
|
||||
|
||||
<!-- Adding Contacts -->
|
||||
<string name="add_contact_title">Add a Contact</string>
|
||||
|
||||
<string name="add_contact_title">Add Contact Nearby</string>
|
||||
<string name="face_to_face">You must meet up with the person you want to add as a contact.\n\nThis will prevent anyone from impersonating you or reading your messages in future.</string>
|
||||
<string name="continue_button">Continue</string>
|
||||
<string name="try_again_button">Try Again</string>
|
||||
@@ -168,7 +169,50 @@
|
||||
<string name="connection_error_explanation">Please check that you\'re both connected to the same Wi-Fi network.</string>
|
||||
<string name="connection_error_feedback">If this problem persists, please <a href="feedback">send feedback</a> to help us improve the app.</string>
|
||||
|
||||
<!-- Adding Contacts Remotely -->
|
||||
|
||||
<string name="add_contact_remotely_title_case">Add Contact at a Distance</string>
|
||||
<string name="add_contact_nearby_title">Add contact nearby</string>
|
||||
<string name="add_contact_remotely_title">Add contact at a distance</string>
|
||||
<string name="contact_name_hint">Give contact a nickname</string>
|
||||
<string name="contact_link_intro">Enter the link from your contact here</string>
|
||||
<string name="contact_link_hint">Contact\'s link</string>
|
||||
<string name="paste_button">Paste</string>
|
||||
<string name="add_contact_button">Add contact</string>
|
||||
<string name="copy_button">Copy</string>
|
||||
<string name="share_button">Share</string>
|
||||
<string name="send_link_title">Exchange links</string>
|
||||
<string name="add_contact_choose_nickname">Choose Nickname</string>
|
||||
<string name="add_contact_choose_a_nickname">Enter a nickname</string>
|
||||
<string name="nickname_intro">Give your contact a nickname. Only you can see it.</string>
|
||||
<string name="your_link">Give this link to the contact you want to add</string>
|
||||
<string name="link_clip_label">Briar link</string>
|
||||
<string name="link_copied_toast">Link copied</string>
|
||||
<string name="adding_contact_error">There was an error adding the contact.</string>
|
||||
<string name="pending_contact_requests_snackbar">There are pending contact requests</string>
|
||||
<string name="pending_contact_requests">Pending Contact Requests</string>
|
||||
<string name="no_pending_contacts">No pending contacts</string>
|
||||
<string name="add_contact_remote_connecting">Connecting…</string>
|
||||
<string name="waiting_for_contact_to_come_online">Waiting for contact to come online…\n\nDid they enter your link already?</string>
|
||||
<string name="connecting">Connecting…</string>
|
||||
<string name="adding_contact">Adding contact…</string>
|
||||
<string name="adding_contact_failed">Adding contact has failed</string>
|
||||
<string name="own_link_error">Enter your contact\'s link, not your own</string>
|
||||
<string name="nickname_missing">Please enter a nickname</string>
|
||||
<string name="invalid_link">Invalid link</string>
|
||||
<string name="intent_own_link">You opened your own link. Use the one of the contact you want to add!</string>
|
||||
<string name="missing_link">Please enter a link</string>
|
||||
<!-- This is a numeral indicating the first step in a series of screens -->
|
||||
<string name="step_1">1</string>
|
||||
<!-- This is a numeral indicating the second step in a series of screens -->
|
||||
<string name="step_2">2</string>
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">New contact added.</item>
|
||||
<item quantity="other">%d new contacts added.</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Introductions -->
|
||||
|
||||
<string name="introduction_onboarding_title">Introduce your contacts</string>
|
||||
<string name="introduction_onboarding_text">You can introduce your contacts to each other, so they don\'t need to meet in person to connect on Briar.</string>
|
||||
<string name="introduction_menu_item">Make Introduction</string>
|
||||
@@ -190,10 +234,6 @@
|
||||
<string name="introduction_response_accepted_received">%1$s accepted the introduction to %2$s.</string>
|
||||
<string name="introduction_response_declined_received">%1$s declined the introduction to %2$s.</string>
|
||||
<string name="introduction_response_declined_received_by_introducee">%1$s says that %2$s declined the introduction.</string>
|
||||
<plurals name="introduction_notification_text">
|
||||
<item quantity="one">New contact added.</item>
|
||||
<item quantity="other">%d new contacts added.</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Private Groups -->
|
||||
<string name="groups_list_empty">No groups to show</string>
|
||||
|
||||
@@ -124,4 +124,23 @@
|
||||
<item name="android:layout_margin">@dimen/margin_small</item>
|
||||
</style>
|
||||
|
||||
<style name="StepBubble">
|
||||
<item name="android:layout_width">28dp</item>
|
||||
<item name="android:layout_height">28dp</item>
|
||||
<item name="android:background">@drawable/bubble_accent</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:textColor">@color/briar_white</item>
|
||||
<item name="android:textSize">18sp</item>
|
||||
</style>
|
||||
|
||||
<style name="StepBubble.Upcoming">
|
||||
<item name="android:alpha">0.5</item>
|
||||
</style>
|
||||
|
||||
<style name="StepBubble.Completed">
|
||||
<item name="android:background">@drawable/bubble_completed</item>
|
||||
<item name="android:scaleType">center</item>
|
||||
<item name="android:src">@drawable/ic_check_white</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -88,6 +88,7 @@ dependencyVerification {
|
||||
'com.github.bumptech.glide:gifdecoder:4.9.0:gifdecoder-4.9.0.aar:7ee9402ae1c48fac9232b67e81f881c217b907b3252e49ce57bdb97937ebb270',
|
||||
'com.github.bumptech.glide:glide:4.9.0:glide-4.9.0.aar:1bf482442fce81aa9065a5e97e721039d921cc45f727a987be5f1a69f844d955',
|
||||
'com.github.chrisbanes:PhotoView:2.1.4:PhotoView-2.1.4.aar:04cb397fcb3df0757c8aed6927ebdd247930b5c78ee9acc59cd07dccdaaf3460',
|
||||
'com.github.kobakei:MaterialFabSpeedDial:1.2.1:MaterialFabSpeedDial-1.2.1.aar:e86198c3c48cd832fb209a769a9f222c2a3cc045743b110ac2391d9737e3ea02',
|
||||
'com.google.android.apps.common.testing.accessibility.framework:accessibility-test-framework:2.0:accessibility-test-framework-2.0.jar:cdf16ef8f5b8023d003ce3cc1b0d51bda737762e2dab2fedf43d1c4292353f7f',
|
||||
'com.google.android.apps.common.testing.accessibility.framework:accessibility-test-framework:2.1:accessibility-test-framework-2.1.jar:7b0aa6ed7553597ce0610684a9f7eca8021eee218f2e2f427c04a7fbf5f920bd',
|
||||
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.introduction.IntroductionRequest;
|
||||
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
|
||||
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
|
||||
import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent;
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Map;
|
||||
@@ -453,7 +453,7 @@ class IntroduceeProtocolEngine
|
||||
s.getRemote().transportProperties);
|
||||
|
||||
// Broadcast IntroductionSucceededEvent, because contact got added
|
||||
IntroductionSucceededEvent e = new IntroductionSucceededEvent(c);
|
||||
ContactAddedRemotelyEvent e = new ContactAddedRemotelyEvent(c);
|
||||
txn.attach(e);
|
||||
} catch (ContactExistsException e) {
|
||||
// Ignore this, because the other introducee might have deleted us.
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.briarproject.briar.api.introduction.IntroductionResponse;
|
||||
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
|
||||
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
|
||||
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
|
||||
import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent;
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent;
|
||||
import org.briarproject.briar.test.BriarIntegrationTest;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -1275,10 +1275,10 @@ public class IntroductionIntegrationTest
|
||||
// only broadcast for DECLINE messages in introducee role
|
||||
latestEvent = e;
|
||||
eventWaiter.resume();
|
||||
} else if (e instanceof IntroductionSucceededEvent) {
|
||||
} else if (e instanceof ContactAddedRemotelyEvent) {
|
||||
latestEvent = e;
|
||||
succeeded = true;
|
||||
Contact contact = ((IntroductionSucceededEvent) e).getContact();
|
||||
Contact contact = ((ContactAddedRemotelyEvent) e).getContact();
|
||||
eventWaiter
|
||||
.assertFalse(contact.getId().equals(contactId0From1));
|
||||
eventWaiter.resume();
|
||||
|
||||
Reference in New Issue
Block a user