mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Compare commits
45 Commits
2165-windo
...
beta-1.4.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4df523aaf8 | ||
|
|
6783eae1b1 | ||
|
|
fe58bd8f86 | ||
|
|
1a1b26d8f2 | ||
|
|
4e90641059 | ||
|
|
f7892050ea | ||
|
|
003ecdb81f | ||
|
|
9141a8bb3b | ||
|
|
7ba2af077e | ||
|
|
ce7f44de01 | ||
|
|
4a46b13e9d | ||
|
|
ae7ccdf34c | ||
|
|
88c54ed3b0 | ||
|
|
653b744a02 | ||
|
|
65e7bcb94e | ||
|
|
d6bbe59d3a | ||
|
|
98dddf3572 | ||
|
|
6d22bab5ee | ||
|
|
7ae91a984f | ||
|
|
fb50a5ba45 | ||
|
|
80bc409225 | ||
|
|
80cac277ac | ||
|
|
888aea4b37 | ||
|
|
e9d3f600fa | ||
|
|
3055338ea8 | ||
|
|
e4a7b1731a | ||
|
|
2da8c19d3e | ||
|
|
237ac50b01 | ||
|
|
73d9e05ada | ||
|
|
e14773985d | ||
|
|
8b3dae6daf | ||
|
|
065ceb8e98 | ||
|
|
6d881892c7 | ||
|
|
16b503dd7b | ||
|
|
fc5533ec6e | ||
|
|
5c153aeb6c | ||
|
|
d3beb850ef | ||
|
|
f057f0859b | ||
|
|
61ea7ff8de | ||
|
|
0fba65a722 | ||
|
|
3a191908c0 | ||
|
|
482258fc92 | ||
|
|
0cb2dcf6b7 | ||
|
|
76599a8d04 | ||
|
|
173af62dec |
@@ -104,10 +104,9 @@ mailbox integration test:
|
|||||||
rules:
|
rules:
|
||||||
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||||
when: on_success
|
when: on_success
|
||||||
allow_failure: false
|
|
||||||
- if: '$CI_COMMIT_TAG == null'
|
- if: '$CI_COMMIT_TAG == null'
|
||||||
when: manual
|
when: manual
|
||||||
allow_failure: false
|
allow_failure: true # TODO figure out how not to allow failure while leaving this optional
|
||||||
script:
|
script:
|
||||||
# start mailbox
|
# start mailbox
|
||||||
- cd /opt && git clone --depth 1 https://code.briarproject.org/briar/briar-mailbox.git briar-mailbox
|
- cd /opt && git clone --depth 1 https://code.briarproject.org/briar/briar-mailbox.git briar-mailbox
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 10404
|
versionCode 10405
|
||||||
versionName "1.4.4"
|
versionName "1.4.5"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ apply from: 'witness.gradle'
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation "com.google.dagger:dagger:$dagger_version"
|
implementation "com.google.dagger:dagger:$dagger_version"
|
||||||
implementation 'com.google.code.findbugs:jsr305:3.0.2'
|
implementation 'com.google.code.findbugs:jsr305:3.0.2'
|
||||||
|
implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version"
|
||||||
|
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
testImplementation "org.jmock:jmock:$jmock_version"
|
testImplementation "org.jmock:jmock:$jmock_version"
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ public interface FeatureFlags {
|
|||||||
|
|
||||||
boolean shouldEnableDisappearingMessages();
|
boolean shouldEnableDisappearingMessages();
|
||||||
|
|
||||||
|
boolean shouldEnableMailbox();
|
||||||
|
|
||||||
boolean shouldEnablePrivateGroupsInCore();
|
boolean shouldEnablePrivateGroupsInCore();
|
||||||
|
|
||||||
boolean shouldEnableForumsInCore();
|
boolean shouldEnableForumsInCore();
|
||||||
|
|||||||
@@ -178,6 +178,12 @@ public interface ContactManager {
|
|||||||
*/
|
*/
|
||||||
void removePendingContact(PendingContactId p) throws DbException;
|
void removePendingContact(PendingContactId p) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a {@link PendingContact}.
|
||||||
|
*/
|
||||||
|
void removePendingContact(Transaction txn, PendingContactId p)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the contact with the given ID.
|
* Returns the contact with the given ID.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public class InvalidMailboxIdException extends Exception {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
|
public class MailboxAuthToken extends MailboxId {
|
||||||
|
public MailboxAuthToken(byte[] id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link MailboxAuthToken} from the given string.
|
||||||
|
*
|
||||||
|
* @throws InvalidMailboxIdException if token is not valid.
|
||||||
|
*/
|
||||||
|
public static MailboxAuthToken fromString(@Nullable String token)
|
||||||
|
throws InvalidMailboxIdException {
|
||||||
|
return new MailboxAuthToken(bytesFromString(token));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
|
public class MailboxFileId extends MailboxId {
|
||||||
|
public MailboxFileId(byte[] id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link MailboxFileId} from the given string.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if token is not valid.
|
||||||
|
*/
|
||||||
|
public static MailboxFileId fromString(@Nullable String token)
|
||||||
|
throws InvalidMailboxIdException {
|
||||||
|
return new MailboxFileId(bytesFromString(token));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
|
public class MailboxFolderId extends MailboxId {
|
||||||
|
public MailboxFolderId(byte[] id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link MailboxFolderId} from the given string.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if token is not valid.
|
||||||
|
*/
|
||||||
|
public static MailboxFolderId fromString(@Nullable String token)
|
||||||
|
throws InvalidMailboxIdException {
|
||||||
|
return new MailboxFolderId(bytesFromString(token));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.UniqueId;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
|
public abstract class MailboxId extends UniqueId {
|
||||||
|
MailboxId(byte[] id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns valid {@link MailboxId} bytes from the given string.
|
||||||
|
*
|
||||||
|
* @throws InvalidMailboxIdException if token is not valid.
|
||||||
|
*/
|
||||||
|
static byte[] bytesFromString(@Nullable String token)
|
||||||
|
throws InvalidMailboxIdException {
|
||||||
|
if (token == null || token.length() != 64) {
|
||||||
|
throw new InvalidMailboxIdException();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return fromHexString(token);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new InvalidMailboxIdException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation expected by the mailbox API.
|
||||||
|
* Also used for serialization.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@JsonValue
|
||||||
|
public String toString() {
|
||||||
|
return toHexString(getBytes()).toLowerCase(Locale.US);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public interface MailboxManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if a mailbox is already paired.
|
||||||
|
*/
|
||||||
|
boolean isPaired(Transaction txn) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current status of the mailbox.
|
||||||
|
*/
|
||||||
|
MailboxStatus getMailboxStatus(Transaction txn) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently running pairing task,
|
||||||
|
* or null if no pairing task is running.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
MailboxPairingTask getCurrentPairingTask();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts and returns a pairing task. If a pairing task is already running,
|
||||||
|
* it will be returned and the argument will be ignored.
|
||||||
|
*
|
||||||
|
* @param qrCodePayload The ISO-8859-1 encoded bytes of the mailbox QR code.
|
||||||
|
*/
|
||||||
|
MailboxPairingTask startPairingTask(String qrCodePayload);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public abstract class MailboxPairingState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The QR code payload that was scanned by the user.
|
||||||
|
* This is null if the code should not be re-used anymore in this state.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public final String qrCodePayload;
|
||||||
|
|
||||||
|
MailboxPairingState(@Nullable String qrCodePayload) {
|
||||||
|
this.qrCodePayload = qrCodePayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class QrCodeReceived extends MailboxPairingState {
|
||||||
|
public QrCodeReceived(String qrCodePayload) {
|
||||||
|
super(qrCodePayload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Pairing extends MailboxPairingState {
|
||||||
|
public Pairing(String qrCodePayload) {
|
||||||
|
super(qrCodePayload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Paired extends MailboxPairingState {
|
||||||
|
public Paired() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InvalidQrCode extends MailboxPairingState {
|
||||||
|
public InvalidQrCode() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MailboxAlreadyPaired extends MailboxPairingState {
|
||||||
|
public MailboxAlreadyPaired() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConnectionError extends MailboxPairingState {
|
||||||
|
public ConnectionError(String qrCodePayload) {
|
||||||
|
super(qrCodePayload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UnexpectedError extends MailboxPairingState {
|
||||||
|
public UnexpectedError(String qrCodePayload) {
|
||||||
|
super(qrCodePayload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Consumer;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public interface MailboxPairingTask extends Runnable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an observer to the task. The observer will be notified on the
|
||||||
|
* event thread of the current state of the task and any subsequent state
|
||||||
|
* changes.
|
||||||
|
*/
|
||||||
|
void addObserver(Consumer<MailboxPairingState> observer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an observer from the task.
|
||||||
|
*/
|
||||||
|
void removeObserver(Consumer<MailboxPairingState> observer);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,21 +8,22 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class MailboxProperties {
|
public class MailboxProperties {
|
||||||
|
|
||||||
private final String onionAddress, authToken;
|
private final String baseUrl;
|
||||||
|
private final MailboxAuthToken authToken;
|
||||||
private final boolean owner;
|
private final boolean owner;
|
||||||
|
|
||||||
public MailboxProperties(String onionAddress, String authToken,
|
public MailboxProperties(String baseUrl, MailboxAuthToken authToken,
|
||||||
boolean owner) {
|
boolean owner) {
|
||||||
this.onionAddress = onionAddress;
|
this.baseUrl = baseUrl;
|
||||||
this.authToken = authToken;
|
this.authToken = authToken;
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOnionAddress() {
|
public String getBaseUrl() {
|
||||||
return onionAddress;
|
return baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAuthToken() {
|
public MailboxAuthToken getAuthToken() {
|
||||||
return authToken;
|
return authToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,13 +25,16 @@ import org.briarproject.bramble.api.sync.Message;
|
|||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@@ -46,8 +49,8 @@ import static org.briarproject.bramble.api.properties.TransportPropertyConstants
|
|||||||
import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH;
|
import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
|
import static org.briarproject.bramble.util.IoUtils.copyAndClose;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
|
||||||
|
|
||||||
public class TestUtils {
|
public class TestUtils {
|
||||||
|
|
||||||
@@ -211,8 +214,22 @@ public class TestUtils {
|
|||||||
getAgreementPublicKey(), verified);
|
getAgreementPublicKey(), verified);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getMailboxSecret() {
|
public static void writeBytes(File file, byte[] bytes)
|
||||||
return toHexString(getRandomBytes(32)).toLowerCase(Locale.US);
|
throws IOException {
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(file);
|
||||||
|
//noinspection TryFinallyCanBeTryWithResources
|
||||||
|
try {
|
||||||
|
outputStream.write(bytes);
|
||||||
|
} finally {
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] readBytes(File file) throws IOException {
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
FileInputStream inputStream = new FileInputStream(file);
|
||||||
|
copyAndClose(inputStream, outputStream);
|
||||||
|
return outputStream.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double getMedian(Collection<? extends Number> samples) {
|
public static double getMedian(Collection<? extends Number> samples) {
|
||||||
|
|||||||
@@ -131,7 +131,8 @@ class ContactManagerImpl implements ContactManager, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PendingContact addPendingContact(Transaction txn, String link, String alias)
|
public PendingContact addPendingContact(Transaction txn, String link,
|
||||||
|
String alias)
|
||||||
throws DbException, FormatException, GeneralSecurityException {
|
throws DbException, FormatException, GeneralSecurityException {
|
||||||
PendingContact p =
|
PendingContact p =
|
||||||
pendingContactFactory.createPendingContact(link, alias);
|
pendingContactFactory.createPendingContact(link, alias);
|
||||||
@@ -169,7 +170,8 @@ class ContactManagerImpl implements ContactManager, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Pair<PendingContact, PendingContactState>> getPendingContacts(Transaction txn)
|
public Collection<Pair<PendingContact, PendingContactState>> getPendingContacts(
|
||||||
|
Transaction txn)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
Collection<PendingContact> pendingContacts = db.getPendingContacts(txn);
|
Collection<PendingContact> pendingContacts = db.getPendingContacts(txn);
|
||||||
List<Pair<PendingContact, PendingContactState>> pairs =
|
List<Pair<PendingContact, PendingContactState>> pairs =
|
||||||
@@ -184,7 +186,13 @@ class ContactManagerImpl implements ContactManager, EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removePendingContact(PendingContactId p) throws DbException {
|
public void removePendingContact(PendingContactId p) throws DbException {
|
||||||
db.transaction(false, txn -> db.removePendingContact(txn, p));
|
db.transaction(false, txn -> removePendingContact(txn, p));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removePendingContact(Transaction txn, PendingContactId p)
|
||||||
|
throws DbException {
|
||||||
|
db.removePendingContact(txn, p);
|
||||||
states.remove(p);
|
states.remove(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,17 @@ package org.briarproject.bramble.mailbox;
|
|||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxFileId;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
interface MailboxApi {
|
interface MailboxApi {
|
||||||
@@ -19,7 +25,7 @@ interface MailboxApi {
|
|||||||
* @return the owner token
|
* @return the owner token
|
||||||
* @throws ApiException for 401 response.
|
* @throws ApiException for 401 response.
|
||||||
*/
|
*/
|
||||||
String setup(MailboxProperties properties)
|
MailboxAuthToken setup(MailboxProperties properties)
|
||||||
throws IOException, ApiException;
|
throws IOException, ApiException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,6 +37,14 @@ interface MailboxApi {
|
|||||||
boolean checkStatus(MailboxProperties properties)
|
boolean checkStatus(MailboxProperties properties)
|
||||||
throws IOException, ApiException;
|
throws IOException, ApiException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpairs Briar and the mailbox (owner only).
|
||||||
|
* Resets mailbox state to that after first install
|
||||||
|
* (e.g. removes all stored files as well).
|
||||||
|
*/
|
||||||
|
void wipeMailbox(MailboxProperties properties)
|
||||||
|
throws IOException, ApiException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new contact to the mailbox.
|
* Adds a new contact to the mailbox.
|
||||||
*
|
*
|
||||||
@@ -57,16 +71,69 @@ interface MailboxApi {
|
|||||||
Collection<ContactId> getContacts(MailboxProperties properties)
|
Collection<ContactId> getContacts(MailboxProperties properties)
|
||||||
throws IOException, ApiException;
|
throws IOException, ApiException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by contacts to send files to the owner
|
||||||
|
* and by the owner to send files to contacts.
|
||||||
|
* <p>
|
||||||
|
* The owner can add files to the contacts' inboxes
|
||||||
|
* and the contacts can add files to their own outbox.
|
||||||
|
*/
|
||||||
|
void addFile(MailboxProperties properties, MailboxFolderId folderId,
|
||||||
|
File file) throws IOException, ApiException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by owner and contacts to list their files to retrieve.
|
||||||
|
* <p>
|
||||||
|
* Returns 200 OK with the list of files in JSON.
|
||||||
|
*/
|
||||||
|
List<MailboxFile> getFiles(MailboxProperties properties,
|
||||||
|
MailboxFolderId folderId) throws IOException, ApiException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by owner and contacts to retrieve a file.
|
||||||
|
* <p>
|
||||||
|
* Returns 200 OK if successful with the files' raw bytes
|
||||||
|
* in the response body.
|
||||||
|
*
|
||||||
|
* @param file the empty file the response bytes will be written into.
|
||||||
|
*/
|
||||||
|
void getFile(MailboxProperties properties, MailboxFolderId folderId,
|
||||||
|
MailboxFileId fileId, File file) throws IOException, ApiException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by owner and contacts to delete files.
|
||||||
|
* <p>
|
||||||
|
* Returns 200 OK (no exception) if deletion was successful.
|
||||||
|
*
|
||||||
|
* @throws TolerableFailureException on 404 response,
|
||||||
|
* because file was most likely deleted already.
|
||||||
|
*/
|
||||||
|
void deleteFile(MailboxProperties properties, MailboxFolderId folderId,
|
||||||
|
MailboxFileId fileId)
|
||||||
|
throws IOException, ApiException, TolerableFailureException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all contact outboxes that have files available
|
||||||
|
* for the owner to download.
|
||||||
|
*
|
||||||
|
* @return a list of folder names
|
||||||
|
* to be used with {@link #getFiles(MailboxProperties, MailboxFolderId)}.
|
||||||
|
* @throws IllegalArgumentException if used by non-owner.
|
||||||
|
*/
|
||||||
|
List<MailboxFolderId> getFolders(MailboxProperties properties)
|
||||||
|
throws IOException, ApiException;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@JsonSerialize
|
@JsonSerialize
|
||||||
class MailboxContact {
|
class MailboxContact {
|
||||||
public final int contactId;
|
public final int contactId;
|
||||||
public final String token, inboxId, outboxId;
|
public final MailboxAuthToken token;
|
||||||
|
public final MailboxFolderId inboxId, outboxId;
|
||||||
|
|
||||||
MailboxContact(ContactId contactId,
|
MailboxContact(ContactId contactId,
|
||||||
String token,
|
MailboxAuthToken token,
|
||||||
String inboxId,
|
MailboxFolderId inboxId,
|
||||||
String outboxId) {
|
MailboxFolderId outboxId) {
|
||||||
this.contactId = contactId.getInt();
|
this.contactId = contactId.getInt();
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.inboxId = inboxId;
|
this.inboxId = inboxId;
|
||||||
@@ -74,10 +141,32 @@ interface MailboxApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonSerialize
|
||||||
|
class MailboxFile implements Comparable<MailboxFile> {
|
||||||
|
public final MailboxFileId name;
|
||||||
|
public final long time;
|
||||||
|
|
||||||
|
public MailboxFile(MailboxFileId name, long time) {
|
||||||
|
this.name = name;
|
||||||
|
this.time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@Nonnull MailboxApi.MailboxFile mailboxFile) {
|
||||||
|
//noinspection UseCompareMethod
|
||||||
|
return time < mailboxFile.time ? -1 :
|
||||||
|
(time == mailboxFile.time ? 0 : 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
class ApiException extends Exception {
|
class ApiException extends Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
class MailboxAlreadyPairedException extends ApiException {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A failure that does not need to be retried,
|
* A failure that does not need to be retried,
|
||||||
* e.g. when adding a contact that already exists.
|
* e.g. when adding a contact that already exists.
|
||||||
|
|||||||
@@ -3,15 +3,25 @@ package org.briarproject.bramble.mailbox;
|
|||||||
import com.fasterxml.jackson.core.JacksonException;
|
import com.fasterxml.jackson.core.JacksonException;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||||
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.WeakSingletonProvider;
|
import org.briarproject.bramble.api.WeakSingletonProvider;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.mailbox.InvalidMailboxIdException;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxFileId;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxId;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -26,7 +36,7 @@ import okhttp3.ResponseBody;
|
|||||||
import static com.fasterxml.jackson.databind.MapperFeature.BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES;
|
import static com.fasterxml.jackson.databind.MapperFeature.BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static okhttp3.internal.Util.EMPTY_REQUEST;
|
import static okhttp3.internal.Util.EMPTY_REQUEST;
|
||||||
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
import static org.briarproject.bramble.util.IoUtils.copyAndClose;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class MailboxApiImpl implements MailboxApi {
|
class MailboxApiImpl implements MailboxApi {
|
||||||
@@ -37,6 +47,8 @@ class MailboxApiImpl implements MailboxApi {
|
|||||||
.build();
|
.build();
|
||||||
private static final MediaType JSON =
|
private static final MediaType JSON =
|
||||||
requireNonNull(MediaType.parse("application/json; charset=utf-8"));
|
requireNonNull(MediaType.parse("application/json; charset=utf-8"));
|
||||||
|
private static final MediaType FILE =
|
||||||
|
requireNonNull(MediaType.parse("application/octet-stream"));
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
MailboxApiImpl(WeakSingletonProvider<OkHttpClient> httpClientProvider) {
|
MailboxApiImpl(WeakSingletonProvider<OkHttpClient> httpClientProvider) {
|
||||||
@@ -44,17 +56,16 @@ class MailboxApiImpl implements MailboxApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String setup(MailboxProperties properties)
|
public MailboxAuthToken setup(MailboxProperties properties)
|
||||||
throws IOException, ApiException {
|
throws IOException, ApiException {
|
||||||
if (!properties.isOwner()) throw new IllegalArgumentException();
|
if (!properties.isOwner()) throw new IllegalArgumentException();
|
||||||
Request request = getRequestBuilder(properties.getAuthToken())
|
Request request = getRequestBuilder(properties.getAuthToken())
|
||||||
.url(properties.getOnionAddress() + "/setup")
|
.url(properties.getBaseUrl() + "/setup")
|
||||||
.put(EMPTY_REQUEST)
|
.put(EMPTY_REQUEST)
|
||||||
.build();
|
.build();
|
||||||
OkHttpClient client = httpClientProvider.get();
|
OkHttpClient client = httpClientProvider.get();
|
||||||
Response response = client.newCall(request).execute();
|
Response response = client.newCall(request).execute();
|
||||||
// TODO consider throwing a special exception for the 401 case
|
if (response.code() == 401) throw new MailboxAlreadyPairedException();
|
||||||
if (response.code() == 401) throw new ApiException();
|
|
||||||
if (!response.isSuccessful()) throw new ApiException();
|
if (!response.isSuccessful()) throw new ApiException();
|
||||||
ResponseBody body = response.body();
|
ResponseBody body = response.body();
|
||||||
if (body == null) throw new ApiException();
|
if (body == null) throw new ApiException();
|
||||||
@@ -65,26 +76,12 @@ class MailboxApiImpl implements MailboxApi {
|
|||||||
throw new ApiException();
|
throw new ApiException();
|
||||||
}
|
}
|
||||||
String ownerToken = tokenNode.textValue();
|
String ownerToken = tokenNode.textValue();
|
||||||
if (ownerToken == null || !isValidToken(ownerToken)) {
|
return MailboxAuthToken.fromString(ownerToken);
|
||||||
throw new ApiException();
|
} catch (JacksonException | InvalidMailboxIdException e) {
|
||||||
}
|
|
||||||
return ownerToken;
|
|
||||||
} catch (JacksonException e) {
|
|
||||||
throw new ApiException();
|
throw new ApiException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidToken(String token) {
|
|
||||||
if (token.length() != 64) return false;
|
|
||||||
try {
|
|
||||||
// try to convert to bytes
|
|
||||||
fromHexString(token);
|
|
||||||
return true;
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkStatus(MailboxProperties properties)
|
public boolean checkStatus(MailboxProperties properties)
|
||||||
throws IOException, ApiException {
|
throws IOException, ApiException {
|
||||||
@@ -95,18 +92,27 @@ class MailboxApiImpl implements MailboxApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addContact(MailboxProperties properties, MailboxContact contact)
|
public void wipeMailbox(MailboxProperties properties)
|
||||||
throws IOException, ApiException,
|
throws IOException, ApiException {
|
||||||
TolerableFailureException {
|
|
||||||
if (!properties.isOwner()) throw new IllegalArgumentException();
|
if (!properties.isOwner()) throw new IllegalArgumentException();
|
||||||
byte[] bodyBytes = mapper.writeValueAsBytes(contact);
|
|
||||||
RequestBody body = RequestBody.create(JSON, bodyBytes);
|
|
||||||
Request request = getRequestBuilder(properties.getAuthToken())
|
Request request = getRequestBuilder(properties.getAuthToken())
|
||||||
.url(properties.getOnionAddress() + "/contacts")
|
.url(properties.getBaseUrl() + "/")
|
||||||
.post(body)
|
.delete()
|
||||||
.build();
|
.build();
|
||||||
OkHttpClient client = httpClientProvider.get();
|
OkHttpClient client = httpClientProvider.get();
|
||||||
Response response = client.newCall(request).execute();
|
Response response = client.newCall(request).execute();
|
||||||
|
if (response.code() != 204) throw new ApiException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Contact Management API (owner only) */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addContact(MailboxProperties properties, MailboxContact contact)
|
||||||
|
throws IOException, ApiException, TolerableFailureException {
|
||||||
|
if (!properties.isOwner()) throw new IllegalArgumentException();
|
||||||
|
byte[] bodyBytes = mapper.writeValueAsBytes(contact);
|
||||||
|
RequestBody body = RequestBody.create(JSON, bodyBytes);
|
||||||
|
Response response = sendPostRequest(properties, "/contacts", body);
|
||||||
if (response.code() == 409) throw new TolerableFailureException();
|
if (response.code() == 409) throw new TolerableFailureException();
|
||||||
if (!response.isSuccessful()) throw new ApiException();
|
if (!response.isSuccessful()) throw new ApiException();
|
||||||
}
|
}
|
||||||
@@ -115,7 +121,7 @@ class MailboxApiImpl implements MailboxApi {
|
|||||||
public void deleteContact(MailboxProperties properties, ContactId contactId)
|
public void deleteContact(MailboxProperties properties, ContactId contactId)
|
||||||
throws IOException, ApiException, TolerableFailureException {
|
throws IOException, ApiException, TolerableFailureException {
|
||||||
if (!properties.isOwner()) throw new IllegalArgumentException();
|
if (!properties.isOwner()) throw new IllegalArgumentException();
|
||||||
String url = properties.getOnionAddress() + "/contacts/" +
|
String url = properties.getBaseUrl() + "/contacts/" +
|
||||||
contactId.getInt();
|
contactId.getInt();
|
||||||
Request request = getRequestBuilder(properties.getAuthToken())
|
Request request = getRequestBuilder(properties.getAuthToken())
|
||||||
.delete()
|
.delete()
|
||||||
@@ -138,10 +144,7 @@ class MailboxApiImpl implements MailboxApi {
|
|||||||
if (body == null) throw new ApiException();
|
if (body == null) throw new ApiException();
|
||||||
try {
|
try {
|
||||||
JsonNode node = mapper.readTree(body.string());
|
JsonNode node = mapper.readTree(body.string());
|
||||||
JsonNode contactsNode = node.get("contacts");
|
ArrayNode contactsNode = getArray(node, "contacts");
|
||||||
if (contactsNode == null || !contactsNode.isArray()) {
|
|
||||||
throw new ApiException();
|
|
||||||
}
|
|
||||||
List<ContactId> list = new ArrayList<>();
|
List<ContactId> list = new ArrayList<>();
|
||||||
for (JsonNode contactNode : contactsNode) {
|
for (JsonNode contactNode : contactsNode) {
|
||||||
if (!contactNode.isNumber()) throw new ApiException();
|
if (!contactNode.isNumber()) throw new ApiException();
|
||||||
@@ -155,18 +158,144 @@ class MailboxApiImpl implements MailboxApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* File Management (owner and contacts) */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addFile(MailboxProperties properties, MailboxFolderId folderId,
|
||||||
|
File file) throws IOException, ApiException {
|
||||||
|
String path = "/files/" + folderId;
|
||||||
|
RequestBody body = RequestBody.create(FILE, file);
|
||||||
|
Response response = sendPostRequest(properties, path, body);
|
||||||
|
if (response.code() != 200) throw new ApiException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MailboxFile> getFiles(MailboxProperties properties,
|
||||||
|
MailboxFolderId folderId) throws IOException, ApiException {
|
||||||
|
String path = "/files/" + folderId;
|
||||||
|
Response response = sendGetRequest(properties, path);
|
||||||
|
if (response.code() != 200) throw new ApiException();
|
||||||
|
|
||||||
|
ResponseBody body = response.body();
|
||||||
|
if (body == null) throw new ApiException();
|
||||||
|
try {
|
||||||
|
JsonNode node = mapper.readTree(body.string());
|
||||||
|
ArrayNode filesNode = getArray(node, "files");
|
||||||
|
List<MailboxFile> list = new ArrayList<>();
|
||||||
|
for (JsonNode fileNode : filesNode) {
|
||||||
|
if (!fileNode.isObject()) throw new ApiException();
|
||||||
|
ObjectNode objectNode = (ObjectNode) fileNode;
|
||||||
|
JsonNode nameNode = objectNode.get("name");
|
||||||
|
JsonNode timeNode = objectNode.get("time");
|
||||||
|
if (nameNode == null || !nameNode.isTextual()) {
|
||||||
|
throw new ApiException();
|
||||||
|
}
|
||||||
|
if (timeNode == null || !timeNode.isNumber()) {
|
||||||
|
throw new ApiException();
|
||||||
|
}
|
||||||
|
String name = nameNode.asText();
|
||||||
|
long time = timeNode.asLong();
|
||||||
|
if (time < 1) throw new ApiException();
|
||||||
|
list.add(new MailboxFile(MailboxFileId.fromString(name), time));
|
||||||
|
}
|
||||||
|
Collections.sort(list);
|
||||||
|
return list;
|
||||||
|
} catch (JacksonException | InvalidMailboxIdException e) {
|
||||||
|
throw new ApiException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getFile(MailboxProperties properties, MailboxFolderId folderId,
|
||||||
|
MailboxFileId fileId, File file) throws IOException, ApiException {
|
||||||
|
String path = "/files/" + folderId + "/" + fileId;
|
||||||
|
Response response = sendGetRequest(properties, path);
|
||||||
|
if (response.code() != 200) throw new ApiException();
|
||||||
|
|
||||||
|
ResponseBody body = response.body();
|
||||||
|
if (body == null) throw new ApiException();
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(file);
|
||||||
|
copyAndClose(body.byteStream(), outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteFile(MailboxProperties properties,
|
||||||
|
MailboxFolderId folderId, MailboxFileId fileId)
|
||||||
|
throws IOException, ApiException, TolerableFailureException {
|
||||||
|
String path = "/files/" + folderId + "/" + fileId;
|
||||||
|
Request request = getRequestBuilder(properties.getAuthToken())
|
||||||
|
.delete()
|
||||||
|
.url(properties.getBaseUrl() + path)
|
||||||
|
.build();
|
||||||
|
OkHttpClient client = httpClientProvider.get();
|
||||||
|
Response response = client.newCall(request).execute();
|
||||||
|
if (response.code() == 404) throw new TolerableFailureException();
|
||||||
|
if (response.code() != 200) throw new ApiException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MailboxFolderId> getFolders(MailboxProperties properties)
|
||||||
|
throws IOException, ApiException {
|
||||||
|
if (!properties.isOwner()) throw new IllegalArgumentException();
|
||||||
|
Response response = sendGetRequest(properties, "/folders");
|
||||||
|
if (response.code() != 200) throw new ApiException();
|
||||||
|
|
||||||
|
ResponseBody body = response.body();
|
||||||
|
if (body == null) throw new ApiException();
|
||||||
|
try {
|
||||||
|
JsonNode node = mapper.readTree(body.string());
|
||||||
|
ArrayNode filesNode = getArray(node, "folders");
|
||||||
|
List<MailboxFolderId> list = new ArrayList<>();
|
||||||
|
for (JsonNode fileNode : filesNode) {
|
||||||
|
if (!fileNode.isObject()) throw new ApiException();
|
||||||
|
ObjectNode objectNode = (ObjectNode) fileNode;
|
||||||
|
JsonNode idNode = objectNode.get("id");
|
||||||
|
if (idNode == null || !idNode.isTextual()) {
|
||||||
|
throw new ApiException();
|
||||||
|
}
|
||||||
|
String id = idNode.asText();
|
||||||
|
list.add(MailboxFolderId.fromString(id));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
} catch (JacksonException | InvalidMailboxIdException e) {
|
||||||
|
throw new ApiException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper Functions */
|
||||||
|
|
||||||
private Response sendGetRequest(MailboxProperties properties, String path)
|
private Response sendGetRequest(MailboxProperties properties, String path)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Request request = getRequestBuilder(properties.getAuthToken())
|
Request request = getRequestBuilder(properties.getAuthToken())
|
||||||
.url(properties.getOnionAddress() + path)
|
.url(properties.getBaseUrl() + path)
|
||||||
.build();
|
.build();
|
||||||
OkHttpClient client = httpClientProvider.get();
|
OkHttpClient client = httpClientProvider.get();
|
||||||
return client.newCall(request).execute();
|
return client.newCall(request).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Request.Builder getRequestBuilder(String token) {
|
private Response sendPostRequest(MailboxProperties properties, String path,
|
||||||
|
RequestBody body) throws IOException {
|
||||||
|
Request request = getRequestBuilder(properties.getAuthToken())
|
||||||
|
.url(properties.getBaseUrl() + path)
|
||||||
|
.post(body)
|
||||||
|
.build();
|
||||||
|
OkHttpClient client = httpClientProvider.get();
|
||||||
|
return client.newCall(request).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Request.Builder getRequestBuilder(MailboxId token) {
|
||||||
return new Request.Builder()
|
return new Request.Builder()
|
||||||
.addHeader("Authorization", "Bearer " + token);
|
.addHeader("Authorization", "Bearer " + token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* JSON helpers */
|
||||||
|
|
||||||
|
private ArrayNode getArray(JsonNode node, String name) throws ApiException {
|
||||||
|
JsonNode arrayNode = node.get(name);
|
||||||
|
if (arrayNode == null || !arrayNode.isArray()) {
|
||||||
|
throw new ApiException();
|
||||||
|
}
|
||||||
|
return (ArrayNode) arrayNode;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxManager;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
class MailboxManagerImpl implements MailboxManager {
|
||||||
|
|
||||||
|
private final Executor ioExecutor;
|
||||||
|
private final MailboxSettingsManager mailboxSettingsManager;
|
||||||
|
private final MailboxPairingTaskFactory pairingTaskFactory;
|
||||||
|
private final Object lock = new Object();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private MailboxPairingTask pairingTask = null;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MailboxManagerImpl(
|
||||||
|
@IoExecutor Executor ioExecutor,
|
||||||
|
MailboxSettingsManager mailboxSettingsManager,
|
||||||
|
MailboxPairingTaskFactory pairingTaskFactory) {
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
|
this.mailboxSettingsManager = mailboxSettingsManager;
|
||||||
|
this.pairingTaskFactory = pairingTaskFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPaired(Transaction txn) throws DbException {
|
||||||
|
return mailboxSettingsManager.getOwnMailboxProperties(txn) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MailboxStatus getMailboxStatus(Transaction txn) throws DbException {
|
||||||
|
return mailboxSettingsManager.getOwnMailboxStatus(txn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public MailboxPairingTask getCurrentPairingTask() {
|
||||||
|
synchronized (lock) {
|
||||||
|
return pairingTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MailboxPairingTask startPairingTask(String payload) {
|
||||||
|
MailboxPairingTask created;
|
||||||
|
synchronized (lock) {
|
||||||
|
if (pairingTask != null) return pairingTask;
|
||||||
|
created = pairingTaskFactory.createPairingTask(payload);
|
||||||
|
pairingTask = created;
|
||||||
|
}
|
||||||
|
ioExecutor.execute(() -> {
|
||||||
|
created.run();
|
||||||
|
synchronized (lock) {
|
||||||
|
// remove task after it finished
|
||||||
|
pairingTask = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,16 +1,36 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
public class MailboxModule {
|
public class MailboxModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
MailboxManager providesMailboxManager(MailboxManagerImpl mailboxManager) {
|
||||||
|
return mailboxManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
MailboxPairingTaskFactory provideMailboxPairingTaskFactory(
|
||||||
|
MailboxPairingTaskFactoryImpl mailboxPairingTaskFactory) {
|
||||||
|
return mailboxPairingTaskFactory;
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
MailboxSettingsManager provideMailboxSettingsManager(
|
MailboxSettingsManager provideMailboxSettingsManager(
|
||||||
MailboxSettingsManagerImpl mailboxSettingsManager) {
|
MailboxSettingsManagerImpl mailboxSettingsManager) {
|
||||||
return mailboxSettingsManager;
|
return mailboxSettingsManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
MailboxApi providesMailboxApi(MailboxApiImpl mailboxApi) {
|
||||||
|
return mailboxApi;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
interface MailboxPairingTaskFactory {
|
||||||
|
|
||||||
|
MailboxPairingTask createPairingTask(String qrCodePayload);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
|
import org.briarproject.bramble.api.event.EventExecutor;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
class MailboxPairingTaskFactoryImpl implements MailboxPairingTaskFactory {
|
||||||
|
|
||||||
|
private final Executor eventExecutor;
|
||||||
|
private final TransactionManager db;
|
||||||
|
private final CryptoComponent crypto;
|
||||||
|
private final Clock clock;
|
||||||
|
private final MailboxApi api;
|
||||||
|
private final MailboxSettingsManager mailboxSettingsManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MailboxPairingTaskFactoryImpl(
|
||||||
|
@EventExecutor Executor eventExecutor,
|
||||||
|
TransactionManager db,
|
||||||
|
CryptoComponent crypto,
|
||||||
|
Clock clock,
|
||||||
|
MailboxApi api,
|
||||||
|
MailboxSettingsManager mailboxSettingsManager) {
|
||||||
|
this.eventExecutor = eventExecutor;
|
||||||
|
this.db = db;
|
||||||
|
this.crypto = crypto;
|
||||||
|
this.clock = clock;
|
||||||
|
this.api = api;
|
||||||
|
this.mailboxSettingsManager = mailboxSettingsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MailboxPairingTask createPairingTask(String qrCodePayload) {
|
||||||
|
return new MailboxPairingTaskImpl(qrCodePayload, eventExecutor, db,
|
||||||
|
crypto, clock, api, mailboxSettingsManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Consumer;
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
|
import org.briarproject.bramble.api.event.EventExecutor;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||||
|
import org.briarproject.bramble.mailbox.MailboxApi.MailboxAlreadyPairedException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
|
class MailboxPairingTaskImpl implements MailboxPairingTask {
|
||||||
|
|
||||||
|
private final static Logger LOG =
|
||||||
|
getLogger(MailboxPairingTaskImpl.class.getName());
|
||||||
|
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
|
||||||
|
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
||||||
|
private static final int VERSION_REQUIRED = 32;
|
||||||
|
|
||||||
|
private final String payload;
|
||||||
|
private final Executor eventExecutor;
|
||||||
|
private final TransactionManager db;
|
||||||
|
private final CryptoComponent crypto;
|
||||||
|
private final Clock clock;
|
||||||
|
private final MailboxApi api;
|
||||||
|
private final MailboxSettingsManager mailboxSettingsManager;
|
||||||
|
|
||||||
|
private final Object lock = new Object();
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private final List<Consumer<MailboxPairingState>> observers =
|
||||||
|
new ArrayList<>();
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private MailboxPairingState state;
|
||||||
|
|
||||||
|
MailboxPairingTaskImpl(
|
||||||
|
String payload,
|
||||||
|
@EventExecutor Executor eventExecutor,
|
||||||
|
TransactionManager db,
|
||||||
|
CryptoComponent crypto,
|
||||||
|
Clock clock,
|
||||||
|
MailboxApi api,
|
||||||
|
MailboxSettingsManager mailboxSettingsManager) {
|
||||||
|
this.payload = payload;
|
||||||
|
this.eventExecutor = eventExecutor;
|
||||||
|
this.db = db;
|
||||||
|
this.crypto = crypto;
|
||||||
|
this.clock = clock;
|
||||||
|
this.api = api;
|
||||||
|
this.mailboxSettingsManager = mailboxSettingsManager;
|
||||||
|
state = new MailboxPairingState.QrCodeReceived(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addObserver(Consumer<MailboxPairingState> o) {
|
||||||
|
MailboxPairingState state;
|
||||||
|
synchronized (lock) {
|
||||||
|
observers.add(o);
|
||||||
|
state = this.state;
|
||||||
|
eventExecutor.execute(() -> o.accept(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeObserver(Consumer<MailboxPairingState> o) {
|
||||||
|
synchronized (lock) {
|
||||||
|
observers.remove(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
pairMailbox();
|
||||||
|
} catch (FormatException e) {
|
||||||
|
onMailboxError(e, new MailboxPairingState.InvalidQrCode());
|
||||||
|
} catch (MailboxAlreadyPairedException e) {
|
||||||
|
onMailboxError(e, new MailboxPairingState.MailboxAlreadyPaired());
|
||||||
|
} catch (IOException e) {
|
||||||
|
onMailboxError(e, new MailboxPairingState.ConnectionError(payload));
|
||||||
|
} catch (ApiException | DbException e) {
|
||||||
|
onMailboxError(e, new MailboxPairingState.UnexpectedError(payload));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pairMailbox() throws IOException, ApiException, DbException {
|
||||||
|
MailboxProperties mailboxProperties = decodeQrCodePayload(payload);
|
||||||
|
setState(new MailboxPairingState.Pairing(payload));
|
||||||
|
MailboxAuthToken ownerToken = api.setup(mailboxProperties);
|
||||||
|
MailboxProperties ownerProperties = new MailboxProperties(
|
||||||
|
mailboxProperties.getBaseUrl(), ownerToken, true);
|
||||||
|
long time = clock.currentTimeMillis();
|
||||||
|
db.transaction(false, txn -> {
|
||||||
|
mailboxSettingsManager
|
||||||
|
.setOwnMailboxProperties(txn, ownerProperties);
|
||||||
|
mailboxSettingsManager.recordSuccessfulConnection(txn, time);
|
||||||
|
});
|
||||||
|
setState(new MailboxPairingState.Paired());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onMailboxError(Exception e, MailboxPairingState state) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
setState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setState(MailboxPairingState state) {
|
||||||
|
synchronized (lock) {
|
||||||
|
this.state = state;
|
||||||
|
notifyObservers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private void notifyObservers() {
|
||||||
|
List<Consumer<MailboxPairingState>> observers =
|
||||||
|
new ArrayList<>(this.observers);
|
||||||
|
MailboxPairingState state = this.state;
|
||||||
|
eventExecutor.execute(() -> {
|
||||||
|
for (Consumer<MailboxPairingState> o : observers) o.accept(state);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private MailboxProperties decodeQrCodePayload(String payload)
|
||||||
|
throws FormatException {
|
||||||
|
byte[] bytes = payload.getBytes(ISO_8859_1);
|
||||||
|
if (bytes.length != 65) {
|
||||||
|
if (LOG.isLoggable(WARNING)) {
|
||||||
|
LOG.warning("QR code length is not 65: " + bytes.length);
|
||||||
|
}
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
int version = bytes[0] & 0xFF;
|
||||||
|
if (version != VERSION_REQUIRED) {
|
||||||
|
if (LOG.isLoggable(WARNING)) {
|
||||||
|
LOG.warning("QR code has not version " + VERSION_REQUIRED +
|
||||||
|
": " + version);
|
||||||
|
}
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
LOG.info("QR code is valid");
|
||||||
|
byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33);
|
||||||
|
String onionAddress = crypto.encodeOnionAddress(onionPubKey);
|
||||||
|
String baseUrl = "http://" + onionAddress + ".onion";
|
||||||
|
byte[] tokenBytes = Arrays.copyOfRange(bytes, 33, 65);
|
||||||
|
MailboxAuthToken setupToken = new MailboxAuthToken(tokenBytes);
|
||||||
|
return new MailboxProperties(baseUrl, setupToken, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ package org.briarproject.bramble.mailbox;
|
|||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
|
import org.briarproject.bramble.api.mailbox.InvalidMailboxIdException;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
@@ -43,15 +45,20 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager {
|
|||||||
String onion = s.get(SETTINGS_KEY_ONION);
|
String onion = s.get(SETTINGS_KEY_ONION);
|
||||||
String token = s.get(SETTINGS_KEY_TOKEN);
|
String token = s.get(SETTINGS_KEY_TOKEN);
|
||||||
if (isNullOrEmpty(onion) || isNullOrEmpty(token)) return null;
|
if (isNullOrEmpty(onion) || isNullOrEmpty(token)) return null;
|
||||||
return new MailboxProperties(onion, token, true);
|
try {
|
||||||
|
MailboxAuthToken tokenId = MailboxAuthToken.fromString(token);
|
||||||
|
return new MailboxProperties(onion, tokenId, true);
|
||||||
|
} catch (InvalidMailboxIdException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOwnMailboxProperties(Transaction txn, MailboxProperties p)
|
public void setOwnMailboxProperties(Transaction txn, MailboxProperties p)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
Settings s = new Settings();
|
Settings s = new Settings();
|
||||||
s.put(SETTINGS_KEY_ONION, p.getOnionAddress());
|
s.put(SETTINGS_KEY_ONION, p.getBaseUrl());
|
||||||
s.put(SETTINGS_KEY_TOKEN, p.getAuthToken());
|
s.put(SETTINGS_KEY_TOKEN, p.getAuthToken().toString());
|
||||||
settingsManager.mergeSettings(txn, s, SETTINGS_NAMESPACE);
|
settingsManager.mergeSettings(txn, s, SETTINGS_NAMESPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.file;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.file.RemovableDriveTask;
|
import org.briarproject.bramble.api.plugin.file.RemovableDriveTask;
|
||||||
|
|
||||||
|
@Deprecated // We can simply remove tasks when they finish
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
interface RemovableDriveTaskRegistry {
|
interface RemovableDriveTaskRegistry {
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ d Bridge obfs4 45.145.95.6:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=T
|
|||||||
d Bridge obfs4 51.222.13.177:80 5EDAC3B810E12B01F6FD8050D2FD3E277B289A08 cert=2uplIpLQ0q9+0qMFrK5pkaYRDOe460LL9WHBvatgkuRr/SL31wBOEupaMMJ6koRE6Ld0ew iat-mode=0
|
d Bridge obfs4 51.222.13.177:80 5EDAC3B810E12B01F6FD8050D2FD3E277B289A08 cert=2uplIpLQ0q9+0qMFrK5pkaYRDOe460LL9WHBvatgkuRr/SL31wBOEupaMMJ6koRE6Ld0ew iat-mode=0
|
||||||
d Bridge obfs4 185.100.85.3:443 5B403DFE34F4872EB027059CECAE30B0C864B3A2 cert=bWUdFUe8io9U6JkSLoGAvSAUDcB779/shovCYmYAQb/pW/iEAMZtO/lCd94OokOF909TPA iat-mode=2
|
d Bridge obfs4 185.100.85.3:443 5B403DFE34F4872EB027059CECAE30B0C864B3A2 cert=bWUdFUe8io9U6JkSLoGAvSAUDcB779/shovCYmYAQb/pW/iEAMZtO/lCd94OokOF909TPA iat-mode=2
|
||||||
n Bridge obfs4 46.226.107.197:10300 A38FD6BDFD902882F5F5B9B7CCC95602A20B0BC4 cert=t8tA9q2AeGlmp/dO6oW9bkY5RqqmvqjArCEM9wjJoDnk6XtnaejkF0JTA7VamdyOzcvuBg iat-mode=0
|
n Bridge obfs4 46.226.107.197:10300 A38FD6BDFD902882F5F5B9B7CCC95602A20B0BC4 cert=t8tA9q2AeGlmp/dO6oW9bkY5RqqmvqjArCEM9wjJoDnk6XtnaejkF0JTA7VamdyOzcvuBg iat-mode=0
|
||||||
n Bridge obfs4 74.104.165.202:9002 EF432018A6AA5D970B2F84E39CD30A147030141C cert=PhppfUusY85dHGvWtGTybZ1fED4DtbHmALkNMIOIYrAz1B4xN7/2a5gyiZe1epju1BOHVg iat-mode=0
|
|
||||||
n Bridge obfs4 23.88.49.56:443 1CDA1660823AE2565D7F50DE8EB99DFDDE96074B cert=4bwNXedHutVD0ZqCm6ph90Vik9dRY4n9qnBHiLiqQOSsIvui4iHwuMFQK6oqiK8tyhVcDw iat-mode=0
|
n Bridge obfs4 23.88.49.56:443 1CDA1660823AE2565D7F50DE8EB99DFDDE96074B cert=4bwNXedHutVD0ZqCm6ph90Vik9dRY4n9qnBHiLiqQOSsIvui4iHwuMFQK6oqiK8tyhVcDw iat-mode=0
|
||||||
n Bridge obfs4 185.65.206.101:443 8A3E001D4C5105ED41060597DEEB21FF19CDC4D3 cert=Nd6XZ+f00sGKL1u6USmyvfqR34HN/pt7jEVbgMpXPF/yyGaLBiXRH/x0SIjX5TceYnd+Dg iat-mode=0
|
n Bridge obfs4 185.181.11.86:443 A961609729E7FDF520B4E81F1F1B8FA1045285C3 cert=e5faG9Zk4Ni+e7z2YgGfevyKPQlMvkVGi4ublSsHYjaBovKeNXpOhbeFxzbZZoAzxAoGUQ iat-mode=0
|
||||||
|
n Bridge obfs4 85.242.211.221:8042 A36A938DD7FDB8BACC846BA326EE0BA0D89A9252 cert=1AN6Pt1eFca3Y/WYD2TGAU3Al9cO4eouXE9SX63s66Z/ks3tVmgQ5GeXi1B5DOvx6Il7Zw iat-mode=0
|
||||||
|
n Bridge obfs4 185.161.70.200:9003 7A81D0CD19870DFA3FD13C5DE232D8ADD026DC40 cert=aIcWxyZS3JcWsowlD9hcw9fttA44Bq/W2laFjVWlhuXqrIlAAwrXvq1O9lm9XrkV8GG/ZA iat-mode=0
|
||||||
|
n Bridge obfs4 172.105.22.69:80 CBD17B33192A879433AB37C9E142541BD3459ABD cert=rk5YmpKypLsjlS4tjkYaZNBweYMa5tWQRhZ8Q2WRleNOgrhSceKo59BA8kp6kVfaMPXnSw iat-mode=0
|
||||||
|
n Bridge obfs4 46.128.93.192:7346 5D28B8E1D117B8720D56A8513CF32509DCA1D84F cert=ED6tZP50eF0vno09F5gFvoWTMdcWFEX2FtwXOUYRevjzKg30/y701f61Vycnh6HO9gkaMw iat-mode=0
|
||||||
m Bridge meek_lite 192.0.2.2:2 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com
|
m Bridge meek_lite 192.0.2.2:2 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com
|
||||||
@@ -1,15 +1,26 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.WeakSingletonProvider;
|
import org.briarproject.bramble.api.WeakSingletonProvider;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxFileId;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxId;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||||
import org.briarproject.bramble.mailbox.MailboxApi.MailboxContact;
|
import org.briarproject.bramble.mailbox.MailboxApi.MailboxContact;
|
||||||
|
import org.briarproject.bramble.mailbox.MailboxApi.MailboxFile;
|
||||||
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@@ -19,12 +30,17 @@ import okhttp3.OkHttpClient;
|
|||||||
import okhttp3.mockwebserver.MockResponse;
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
import okhttp3.mockwebserver.MockWebServer;
|
import okhttp3.mockwebserver.MockWebServer;
|
||||||
import okhttp3.mockwebserver.RecordedRequest;
|
import okhttp3.mockwebserver.RecordedRequest;
|
||||||
|
import okio.Buffer;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMailboxSecret;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.readBytes;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.writeBytes;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -33,6 +49,9 @@ import static org.junit.Assert.assertTrue;
|
|||||||
|
|
||||||
public class MailboxApiTest extends BrambleTestCase {
|
public class MailboxApiTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TemporaryFolder folder = new TemporaryFolder();
|
||||||
|
|
||||||
private final OkHttpClient client = new OkHttpClient.Builder()
|
private final OkHttpClient client = new OkHttpClient.Builder()
|
||||||
.socketFactory(SocketFactory.getDefault())
|
.socketFactory(SocketFactory.getDefault())
|
||||||
.connectTimeout(60_000, MILLISECONDS)
|
.connectTimeout(60_000, MILLISECONDS)
|
||||||
@@ -47,12 +66,15 @@ public class MailboxApiTest extends BrambleTestCase {
|
|||||||
};
|
};
|
||||||
private final MailboxApiImpl api = new MailboxApiImpl(httpClientProvider);
|
private final MailboxApiImpl api = new MailboxApiImpl(httpClientProvider);
|
||||||
|
|
||||||
private final String token = getMailboxSecret();
|
private final MailboxAuthToken token = new MailboxAuthToken(getRandomId());
|
||||||
private final String token2 = getMailboxSecret();
|
private final MailboxAuthToken token2 = new MailboxAuthToken(getRandomId());
|
||||||
private final ContactId contactId = getContactId();
|
private final ContactId contactId = getContactId();
|
||||||
private final String contactToken = getMailboxSecret();
|
private final MailboxAuthToken contactToken =
|
||||||
private final String contactInboxId = getMailboxSecret();
|
new MailboxAuthToken(getRandomId());
|
||||||
private final String contactOutboxId = getMailboxSecret();
|
private final MailboxFolderId contactInboxId =
|
||||||
|
new MailboxFolderId(getRandomId());
|
||||||
|
private final MailboxFolderId contactOutboxId =
|
||||||
|
new MailboxFolderId(getRandomId());
|
||||||
private final MailboxContact mailboxContact = new MailboxContact(
|
private final MailboxContact mailboxContact = new MailboxContact(
|
||||||
contactId, contactToken, contactInboxId, contactOutboxId);
|
contactId, contactToken, contactInboxId, contactOutboxId);
|
||||||
|
|
||||||
@@ -178,6 +200,53 @@ public class MailboxApiTest extends BrambleTestCase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWipe() throws Exception {
|
||||||
|
MockWebServer server = new MockWebServer();
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(204));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(200));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(401));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(500));
|
||||||
|
server.start();
|
||||||
|
String baseUrl = getBaseUrl(server);
|
||||||
|
MailboxProperties properties =
|
||||||
|
new MailboxProperties(baseUrl, token, true);
|
||||||
|
MailboxProperties properties2 =
|
||||||
|
new MailboxProperties(baseUrl, token2, true);
|
||||||
|
|
||||||
|
api.wipeMailbox(properties);
|
||||||
|
RecordedRequest request1 = server.takeRequest();
|
||||||
|
assertEquals("/", request1.getPath());
|
||||||
|
assertEquals("DELETE", request1.getMethod());
|
||||||
|
assertToken(request1, token);
|
||||||
|
|
||||||
|
assertThrows(ApiException.class, () -> api.wipeMailbox(properties2));
|
||||||
|
RecordedRequest request2 = server.takeRequest();
|
||||||
|
assertEquals("/", request2.getPath());
|
||||||
|
assertEquals("DELETE", request2.getMethod());
|
||||||
|
assertToken(request2, token2);
|
||||||
|
|
||||||
|
assertThrows(ApiException.class, () -> api.wipeMailbox(properties));
|
||||||
|
RecordedRequest request3 = server.takeRequest();
|
||||||
|
assertEquals("/", request3.getPath());
|
||||||
|
assertEquals("DELETE", request3.getMethod());
|
||||||
|
assertToken(request3, token);
|
||||||
|
|
||||||
|
assertThrows(ApiException.class, () -> api.wipeMailbox(properties));
|
||||||
|
RecordedRequest request4 = server.takeRequest();
|
||||||
|
assertEquals("/", request4.getPath());
|
||||||
|
assertEquals("DELETE", request4.getMethod());
|
||||||
|
assertToken(request4, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWipeOnlyForOwner() {
|
||||||
|
MailboxProperties properties =
|
||||||
|
new MailboxProperties("", token, false);
|
||||||
|
assertThrows(IllegalArgumentException.class, () ->
|
||||||
|
api.wipeMailbox(properties));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddContact() throws Exception {
|
public void testAddContact() throws Exception {
|
||||||
MockWebServer server = new MockWebServer();
|
MockWebServer server = new MockWebServer();
|
||||||
@@ -370,12 +439,362 @@ public class MailboxApiTest extends BrambleTestCase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddFile() throws Exception {
|
||||||
|
File file = folder.newFile();
|
||||||
|
byte[] bytes = getRandomBytes(1337);
|
||||||
|
writeBytes(file, bytes);
|
||||||
|
|
||||||
|
MockWebServer server = new MockWebServer();
|
||||||
|
server.enqueue(new MockResponse());
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(401));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(500));
|
||||||
|
server.start();
|
||||||
|
String baseUrl = getBaseUrl(server);
|
||||||
|
MailboxProperties properties =
|
||||||
|
new MailboxProperties(baseUrl, token, true);
|
||||||
|
|
||||||
|
// file gets uploaded as expected
|
||||||
|
api.addFile(properties, contactInboxId, file);
|
||||||
|
RecordedRequest request1 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request1.getPath());
|
||||||
|
assertEquals("POST", request1.getMethod());
|
||||||
|
assertToken(request1, token);
|
||||||
|
assertArrayEquals(bytes, request1.getBody().readByteArray());
|
||||||
|
|
||||||
|
// request is not successful
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.addFile(properties, contactInboxId, file));
|
||||||
|
RecordedRequest request2 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request2.getPath());
|
||||||
|
assertEquals("POST", request1.getMethod());
|
||||||
|
assertToken(request2, token);
|
||||||
|
|
||||||
|
// server error
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.addFile(properties, contactInboxId, file));
|
||||||
|
RecordedRequest request3 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request3.getPath());
|
||||||
|
assertEquals("POST", request1.getMethod());
|
||||||
|
assertToken(request3, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFiles() throws Exception {
|
||||||
|
MailboxFile mailboxFile1 =
|
||||||
|
new MailboxFile(new MailboxFileId(getRandomId()), 1337);
|
||||||
|
MailboxFile mailboxFile2 =
|
||||||
|
new MailboxFile(new MailboxFileId(getRandomId()),
|
||||||
|
System.currentTimeMillis());
|
||||||
|
String fileResponse1 =
|
||||||
|
new ObjectMapper().writeValueAsString(mailboxFile1);
|
||||||
|
String fileResponse2 =
|
||||||
|
new ObjectMapper().writeValueAsString(mailboxFile2);
|
||||||
|
String validResponse1 = "{\"files\": [" + fileResponse1 + "] }";
|
||||||
|
String validResponse2 = "{\"files\": [" + fileResponse1 + ", " +
|
||||||
|
fileResponse2 + "] }";
|
||||||
|
String invalidResponse1 = "{\"files\":\"bar\"}";
|
||||||
|
String invalidResponse2 = "{\"files\":{\"foo\":\"bar\"}}";
|
||||||
|
String invalidResponse3 = "{\"files\": [" + fileResponse1 + ", 1] }";
|
||||||
|
String invalidResponse4 = "{\"contacts\": [ 1, 2 ] }";
|
||||||
|
|
||||||
|
MockWebServer server = new MockWebServer();
|
||||||
|
server.enqueue(new MockResponse().setBody(validResponse1));
|
||||||
|
server.enqueue(new MockResponse().setBody(validResponse2));
|
||||||
|
server.enqueue(new MockResponse());
|
||||||
|
server.enqueue(new MockResponse().setBody(invalidResponse1));
|
||||||
|
server.enqueue(new MockResponse().setBody(invalidResponse2));
|
||||||
|
server.enqueue(new MockResponse().setBody(invalidResponse3));
|
||||||
|
server.enqueue(new MockResponse().setBody(invalidResponse4));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(401));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(500));
|
||||||
|
server.start();
|
||||||
|
String baseUrl = getBaseUrl(server);
|
||||||
|
MailboxProperties properties =
|
||||||
|
new MailboxProperties(baseUrl, token, true);
|
||||||
|
|
||||||
|
// valid response with one file
|
||||||
|
List<MailboxFile> received1 = api.getFiles(properties, contactInboxId);
|
||||||
|
assertEquals(1, received1.size());
|
||||||
|
assertEquals(mailboxFile1.name, received1.get(0).name);
|
||||||
|
assertEquals(mailboxFile1.time, received1.get(0).time);
|
||||||
|
RecordedRequest request1 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request1.getPath());
|
||||||
|
assertEquals("GET", request1.getMethod());
|
||||||
|
assertToken(request1, token);
|
||||||
|
|
||||||
|
// valid response with two files
|
||||||
|
List<MailboxFile> received2 = api.getFiles(properties, contactInboxId);
|
||||||
|
assertEquals(2, received2.size());
|
||||||
|
assertEquals(mailboxFile1.name, received2.get(0).name);
|
||||||
|
assertEquals(mailboxFile1.time, received2.get(0).time);
|
||||||
|
assertEquals(mailboxFile2.name, received2.get(1).name);
|
||||||
|
assertEquals(mailboxFile2.time, received2.get(1).time);
|
||||||
|
RecordedRequest request2 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request1.getPath());
|
||||||
|
assertEquals("GET", request2.getMethod());
|
||||||
|
assertToken(request2, token);
|
||||||
|
|
||||||
|
// empty body
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.getFiles(properties, contactInboxId));
|
||||||
|
RecordedRequest request3 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request3.getPath());
|
||||||
|
assertEquals("GET", request3.getMethod());
|
||||||
|
assertToken(request3, token);
|
||||||
|
|
||||||
|
// invalid response: string instead of list
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.getFiles(properties, contactInboxId));
|
||||||
|
RecordedRequest request4 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request4.getPath());
|
||||||
|
assertEquals("GET", request4.getMethod());
|
||||||
|
assertToken(request4, token);
|
||||||
|
|
||||||
|
// invalid response: object instead of list
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.getFiles(properties, contactInboxId));
|
||||||
|
RecordedRequest request5 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request5.getPath());
|
||||||
|
assertEquals("GET", request5.getMethod());
|
||||||
|
assertToken(request5, token);
|
||||||
|
|
||||||
|
// invalid response: list with non-objects
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.getFiles(properties, contactInboxId));
|
||||||
|
RecordedRequest request6 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request6.getPath());
|
||||||
|
assertEquals("GET", request6.getMethod());
|
||||||
|
assertToken(request6, token);
|
||||||
|
|
||||||
|
// no files key in root object
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.getFiles(properties, contactInboxId));
|
||||||
|
RecordedRequest request7 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request7.getPath());
|
||||||
|
assertEquals("GET", request7.getMethod());
|
||||||
|
assertToken(request7, token);
|
||||||
|
|
||||||
|
// 401 not authorized
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.getFiles(properties, contactInboxId));
|
||||||
|
RecordedRequest request8 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request8.getPath());
|
||||||
|
assertEquals("GET", request8.getMethod());
|
||||||
|
assertToken(request8, token);
|
||||||
|
|
||||||
|
// 500 internal server error
|
||||||
|
assertThrows(ApiException.class,
|
||||||
|
() -> api.getFiles(properties, contactInboxId));
|
||||||
|
RecordedRequest request9 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactInboxId, request9.getPath());
|
||||||
|
assertEquals("GET", request9.getMethod());
|
||||||
|
assertToken(request9, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFile() throws Exception {
|
||||||
|
MailboxFileId name = new MailboxFileId(getRandomId());
|
||||||
|
File file1 = folder.newFile();
|
||||||
|
File file2 = folder.newFile();
|
||||||
|
File file3 = folder.newFile();
|
||||||
|
byte[] bytes = getRandomBytes(1337);
|
||||||
|
|
||||||
|
MockWebServer server = new MockWebServer();
|
||||||
|
server.enqueue(new MockResponse().setBody(new Buffer().write(bytes)));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(401));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(500));
|
||||||
|
server.start();
|
||||||
|
String baseUrl = getBaseUrl(server);
|
||||||
|
MailboxProperties properties =
|
||||||
|
new MailboxProperties(baseUrl, token, true);
|
||||||
|
|
||||||
|
// file gets downloaded as expected
|
||||||
|
api.getFile(properties, contactOutboxId, name, file1);
|
||||||
|
RecordedRequest request1 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactOutboxId + "/" + name,
|
||||||
|
request1.getPath());
|
||||||
|
assertEquals("GET", request1.getMethod());
|
||||||
|
assertToken(request1, token);
|
||||||
|
assertArrayEquals(bytes, readBytes(file1));
|
||||||
|
|
||||||
|
// request is not successful
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.getFile(properties, contactOutboxId, name, file2));
|
||||||
|
RecordedRequest request2 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactOutboxId + "/" + name,
|
||||||
|
request2.getPath());
|
||||||
|
assertEquals("GET", request1.getMethod());
|
||||||
|
assertToken(request2, token);
|
||||||
|
assertEquals(0, readBytes(file2).length);
|
||||||
|
|
||||||
|
// server error
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.getFile(properties, contactOutboxId, name, file3));
|
||||||
|
RecordedRequest request3 = server.takeRequest();
|
||||||
|
assertEquals("/files/" + contactOutboxId + "/" + name,
|
||||||
|
request3.getPath());
|
||||||
|
assertEquals("GET", request1.getMethod());
|
||||||
|
assertToken(request3, token);
|
||||||
|
assertEquals(0, readBytes(file3).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteFile() throws Exception {
|
||||||
|
MailboxFileId name = new MailboxFileId(getRandomId());
|
||||||
|
|
||||||
|
MockWebServer server = new MockWebServer();
|
||||||
|
server.enqueue(new MockResponse());
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(205));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(401));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(404));
|
||||||
|
server.start();
|
||||||
|
String baseUrl = getBaseUrl(server);
|
||||||
|
MailboxProperties properties =
|
||||||
|
new MailboxProperties(baseUrl, token, true);
|
||||||
|
|
||||||
|
// file gets deleted as expected
|
||||||
|
api.deleteFile(properties, contactInboxId, name);
|
||||||
|
RecordedRequest request1 = server.takeRequest();
|
||||||
|
assertEquals("DELETE", request1.getMethod());
|
||||||
|
assertEquals("/files/" + contactInboxId + "/" + name,
|
||||||
|
request1.getPath());
|
||||||
|
assertToken(request1, token);
|
||||||
|
|
||||||
|
// request is not returning 200
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.deleteFile(properties, contactInboxId, name));
|
||||||
|
RecordedRequest request2 = server.takeRequest();
|
||||||
|
assertEquals("DELETE", request2.getMethod());
|
||||||
|
assertEquals("/files/" + contactInboxId + "/" + name,
|
||||||
|
request2.getPath());
|
||||||
|
assertToken(request2, token);
|
||||||
|
|
||||||
|
// request is not authorized
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.deleteFile(properties, contactInboxId, name));
|
||||||
|
RecordedRequest request3 = server.takeRequest();
|
||||||
|
assertEquals("DELETE", request3.getMethod());
|
||||||
|
assertEquals("/files/" + contactInboxId + "/" + name,
|
||||||
|
request3.getPath());
|
||||||
|
assertToken(request3, token);
|
||||||
|
|
||||||
|
// file not found is tolerable
|
||||||
|
assertThrows(TolerableFailureException.class, () ->
|
||||||
|
api.deleteFile(properties, contactInboxId, name));
|
||||||
|
RecordedRequest request4 = server.takeRequest();
|
||||||
|
assertEquals("DELETE", request4.getMethod());
|
||||||
|
assertEquals("/files/" + contactInboxId + "/" + name,
|
||||||
|
request4.getPath());
|
||||||
|
assertToken(request4, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFolders() throws Exception {
|
||||||
|
MailboxFolderId id1 = new MailboxFolderId(getRandomId());
|
||||||
|
MailboxFolderId id2 = new MailboxFolderId(getRandomId());
|
||||||
|
String validResponse1 = "{\"folders\": [ {\"id\": \"" + id1 + "\"} ] }";
|
||||||
|
String validResponse2 = "{\"folders\": [ {\"id\": \"" + id1 + "\"}, " +
|
||||||
|
"{ \"id\": \"" + id2 + "\"} ] }";
|
||||||
|
String invalidResponse1 = "{\"folders\":\"bar\"}";
|
||||||
|
String invalidResponse2 = "{\"folders\":{\"foo\":\"bar\"}}";
|
||||||
|
String invalidResponse3 =
|
||||||
|
"{\"folders\": [ {\"id\": \"" + id1 + "\", 1] }";
|
||||||
|
String invalidResponse4 = "{\"files\": [ 1, 2 ] }";
|
||||||
|
|
||||||
|
MockWebServer server = new MockWebServer();
|
||||||
|
server.enqueue(new MockResponse().setBody(validResponse1));
|
||||||
|
server.enqueue(new MockResponse().setBody(validResponse2));
|
||||||
|
server.enqueue(new MockResponse());
|
||||||
|
server.enqueue(new MockResponse().setBody(invalidResponse1));
|
||||||
|
server.enqueue(new MockResponse().setBody(invalidResponse2));
|
||||||
|
server.enqueue(new MockResponse().setBody(invalidResponse3));
|
||||||
|
server.enqueue(new MockResponse().setBody(invalidResponse4));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(401));
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(500));
|
||||||
|
server.start();
|
||||||
|
String baseUrl = getBaseUrl(server);
|
||||||
|
MailboxProperties properties =
|
||||||
|
new MailboxProperties(baseUrl, token, true);
|
||||||
|
|
||||||
|
// valid response with one folders
|
||||||
|
assertEquals(singletonList(id1), api.getFolders(properties));
|
||||||
|
RecordedRequest request1 = server.takeRequest();
|
||||||
|
assertEquals("/folders", request1.getPath());
|
||||||
|
assertEquals("GET", request1.getMethod());
|
||||||
|
assertToken(request1, token);
|
||||||
|
|
||||||
|
// valid response with two folders
|
||||||
|
assertEquals(Arrays.asList(id1, id2), api.getFolders(properties));
|
||||||
|
RecordedRequest request2 = server.takeRequest();
|
||||||
|
assertEquals("/folders", request1.getPath());
|
||||||
|
assertEquals("GET", request2.getMethod());
|
||||||
|
assertToken(request2, token);
|
||||||
|
|
||||||
|
// empty body
|
||||||
|
assertThrows(ApiException.class, () -> api.getFolders(properties));
|
||||||
|
RecordedRequest request3 = server.takeRequest();
|
||||||
|
assertEquals("/folders", request3.getPath());
|
||||||
|
assertEquals("GET", request3.getMethod());
|
||||||
|
assertToken(request3, token);
|
||||||
|
|
||||||
|
// invalid response: string instead of list
|
||||||
|
assertThrows(ApiException.class, () -> api.getFolders(properties));
|
||||||
|
RecordedRequest request4 = server.takeRequest();
|
||||||
|
assertEquals("/folders", request4.getPath());
|
||||||
|
assertEquals("GET", request4.getMethod());
|
||||||
|
assertToken(request4, token);
|
||||||
|
|
||||||
|
// invalid response: object instead of list
|
||||||
|
assertThrows(ApiException.class, () -> api.getFolders(properties));
|
||||||
|
RecordedRequest request5 = server.takeRequest();
|
||||||
|
assertEquals("/folders", request5.getPath());
|
||||||
|
assertEquals("GET", request5.getMethod());
|
||||||
|
assertToken(request5, token);
|
||||||
|
|
||||||
|
// invalid response: list with non-objects
|
||||||
|
assertThrows(ApiException.class, () -> api.getFolders(properties));
|
||||||
|
RecordedRequest request6 = server.takeRequest();
|
||||||
|
assertEquals("/folders", request6.getPath());
|
||||||
|
assertEquals("GET", request6.getMethod());
|
||||||
|
assertToken(request6, token);
|
||||||
|
|
||||||
|
// no folders key in root object
|
||||||
|
assertThrows(ApiException.class, () -> api.getFolders(properties));
|
||||||
|
RecordedRequest request7 = server.takeRequest();
|
||||||
|
assertEquals("/folders", request7.getPath());
|
||||||
|
assertEquals("GET", request7.getMethod());
|
||||||
|
assertToken(request7, token);
|
||||||
|
|
||||||
|
// 401 not authorized
|
||||||
|
assertThrows(ApiException.class, () -> api.getFolders(properties));
|
||||||
|
RecordedRequest request8 = server.takeRequest();
|
||||||
|
assertEquals("/folders", request8.getPath());
|
||||||
|
assertEquals("GET", request8.getMethod());
|
||||||
|
assertToken(request8, token);
|
||||||
|
|
||||||
|
// 500 internal server error
|
||||||
|
assertThrows(ApiException.class, () -> api.getFolders(properties));
|
||||||
|
RecordedRequest request9 = server.takeRequest();
|
||||||
|
assertEquals("/folders", request9.getPath());
|
||||||
|
assertEquals("GET", request9.getMethod());
|
||||||
|
assertToken(request9, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFoldersOnlyForOwner() {
|
||||||
|
MailboxProperties properties =
|
||||||
|
new MailboxProperties("", token, false);
|
||||||
|
assertThrows(IllegalArgumentException.class, () ->
|
||||||
|
api.getFolders(properties));
|
||||||
|
}
|
||||||
|
|
||||||
private String getBaseUrl(MockWebServer server) {
|
private String getBaseUrl(MockWebServer server) {
|
||||||
String baseUrl = server.url("").toString();
|
String baseUrl = server.url("").toString();
|
||||||
return baseUrl.substring(0, baseUrl.length() - 1);
|
return baseUrl.substring(0, baseUrl.length() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertToken(RecordedRequest request, String token) {
|
private void assertToken(RecordedRequest request, MailboxId token) {
|
||||||
assertNotNull(request.getHeader("Authorization"));
|
assertNotNull(request.getHeader("Authorization"));
|
||||||
assertEquals("Bearer " + token, request.getHeader("Authorization"));
|
assertEquals("Bearer " + token, request.getHeader("Authorization"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,27 @@ package org.briarproject.bramble.mailbox;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.WeakSingletonProvider;
|
import org.briarproject.bramble.api.WeakSingletonProvider;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.mailbox.InvalidMailboxIdException;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxFileId;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||||
import org.briarproject.bramble.mailbox.MailboxApi.MailboxContact;
|
import org.briarproject.bramble.mailbox.MailboxApi.MailboxContact;
|
||||||
|
import org.briarproject.bramble.mailbox.MailboxApi.MailboxFile;
|
||||||
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
@@ -22,8 +32,12 @@ import okhttp3.OkHttpClient;
|
|||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMailboxSecret;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled;
|
import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.readBytes;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.writeBytes;
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -31,15 +45,27 @@ import static org.junit.Assume.assumeTrue;
|
|||||||
|
|
||||||
public class MailboxIntegrationTest extends BrambleTestCase {
|
public class MailboxIntegrationTest extends BrambleTestCase {
|
||||||
|
|
||||||
private final static String URL_BASE = "http://127.0.0.1:8000";
|
@Rule
|
||||||
private final static String SETUP_TOKEN =
|
public TemporaryFolder folder = new TemporaryFolder();
|
||||||
"54686973206973206120736574757020746f6b656e20666f722042726961722e";
|
|
||||||
|
|
||||||
private final OkHttpClient client = new OkHttpClient.Builder()
|
private final static String URL_BASE = "http://127.0.0.1:8000";
|
||||||
|
private final static MailboxAuthToken SETUP_TOKEN;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
SETUP_TOKEN = MailboxAuthToken.fromString(
|
||||||
|
"54686973206973206120736574757020746f6b656e20666f722042726961722e");
|
||||||
|
} catch (InvalidMailboxIdException e) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final OkHttpClient client = new OkHttpClient.Builder()
|
||||||
.socketFactory(SocketFactory.getDefault())
|
.socketFactory(SocketFactory.getDefault())
|
||||||
.connectTimeout(60_000, MILLISECONDS)
|
.connectTimeout(60_000, MILLISECONDS)
|
||||||
.build();
|
.build();
|
||||||
private final WeakSingletonProvider<OkHttpClient> httpClientProvider =
|
private static final WeakSingletonProvider<OkHttpClient>
|
||||||
|
httpClientProvider =
|
||||||
new WeakSingletonProvider<OkHttpClient>() {
|
new WeakSingletonProvider<OkHttpClient>() {
|
||||||
@Override
|
@Override
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@@ -47,7 +73,8 @@ public class MailboxIntegrationTest extends BrambleTestCase {
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private final MailboxApiImpl api = new MailboxApiImpl(httpClientProvider);
|
private final static MailboxApiImpl api =
|
||||||
|
new MailboxApiImpl(httpClientProvider);
|
||||||
// needs to be static to keep values across different tests
|
// needs to be static to keep values across different tests
|
||||||
private static MailboxProperties ownerProperties;
|
private static MailboxProperties ownerProperties;
|
||||||
|
|
||||||
@@ -64,10 +91,27 @@ public class MailboxIntegrationTest extends BrambleTestCase {
|
|||||||
if (ownerProperties != null) return;
|
if (ownerProperties != null) return;
|
||||||
MailboxProperties setupProperties =
|
MailboxProperties setupProperties =
|
||||||
new MailboxProperties(URL_BASE, SETUP_TOKEN, true);
|
new MailboxProperties(URL_BASE, SETUP_TOKEN, true);
|
||||||
String ownerToken = api.setup(setupProperties);
|
MailboxAuthToken ownerToken = api.setup(setupProperties);
|
||||||
ownerProperties = new MailboxProperties(URL_BASE, ownerToken, true);
|
ownerProperties = new MailboxProperties(URL_BASE, ownerToken, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
// we can't test wiping as a regular test as it stops the mailbox
|
||||||
|
public static void wipe() throws IOException, ApiException {
|
||||||
|
if (!isOptionalTestEnabled(MailboxIntegrationTest.class)) return;
|
||||||
|
|
||||||
|
api.wipeMailbox(ownerProperties);
|
||||||
|
|
||||||
|
// check doesn't work anymore
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.checkStatus(ownerProperties));
|
||||||
|
|
||||||
|
// new setup doesn't work as mailbox is stopping
|
||||||
|
MailboxProperties setupProperties =
|
||||||
|
new MailboxProperties(URL_BASE, SETUP_TOKEN, true);
|
||||||
|
assertThrows(ApiException.class, () -> api.setup(setupProperties));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStatus() throws Exception {
|
public void testStatus() throws Exception {
|
||||||
assertTrue(api.checkStatus(ownerProperties));
|
assertTrue(api.checkStatus(ownerProperties));
|
||||||
@@ -101,9 +145,128 @@ public class MailboxIntegrationTest extends BrambleTestCase {
|
|||||||
() -> api.deleteContact(ownerProperties, contactId2));
|
() -> api.deleteContact(ownerProperties, contactId2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFileManagementApi() throws Exception {
|
||||||
|
// add contact, so we can leave each other files
|
||||||
|
ContactId contactId = new ContactId(1);
|
||||||
|
MailboxContact contact = getMailboxContact(contactId);
|
||||||
|
MailboxProperties contactProperties = new MailboxProperties(
|
||||||
|
ownerProperties.getBaseUrl(), contact.token, false);
|
||||||
|
api.addContact(ownerProperties, contact);
|
||||||
|
|
||||||
|
// upload a file for our contact
|
||||||
|
File file1 = folder.newFile();
|
||||||
|
byte[] bytes1 = getRandomBytes(2048);
|
||||||
|
writeBytes(file1, bytes1);
|
||||||
|
api.addFile(ownerProperties, contact.inboxId, file1);
|
||||||
|
|
||||||
|
// contact checks files
|
||||||
|
List<MailboxFile> files1 =
|
||||||
|
api.getFiles(contactProperties, contact.inboxId);
|
||||||
|
assertEquals(1, files1.size());
|
||||||
|
MailboxFileId fileName1 = files1.get(0).name;
|
||||||
|
|
||||||
|
// owner can't check files
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.getFiles(ownerProperties, contact.inboxId));
|
||||||
|
|
||||||
|
// contact downloads file
|
||||||
|
File file1downloaded = folder.newFile();
|
||||||
|
api.getFile(contactProperties, contact.inboxId, fileName1,
|
||||||
|
file1downloaded);
|
||||||
|
assertArrayEquals(bytes1, readBytes(file1downloaded));
|
||||||
|
|
||||||
|
// owner can't download file, even if knowing name
|
||||||
|
File file1forbidden = folder.newFile();
|
||||||
|
assertThrows(ApiException.class, () -> api.getFile(ownerProperties,
|
||||||
|
contact.inboxId, fileName1, file1forbidden));
|
||||||
|
assertEquals(0, file1forbidden.length());
|
||||||
|
|
||||||
|
// owner can't delete file
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.deleteFile(ownerProperties, contact.inboxId, fileName1));
|
||||||
|
|
||||||
|
// contact deletes file
|
||||||
|
api.deleteFile(contactProperties, contact.inboxId, fileName1);
|
||||||
|
assertEquals(0,
|
||||||
|
api.getFiles(contactProperties, contact.inboxId).size());
|
||||||
|
|
||||||
|
// contact uploads two files for the owner
|
||||||
|
File file2 = folder.newFile();
|
||||||
|
File file3 = folder.newFile();
|
||||||
|
byte[] bytes2 = getRandomBytes(2048);
|
||||||
|
byte[] bytes3 = getRandomBytes(1024);
|
||||||
|
writeBytes(file2, bytes2);
|
||||||
|
writeBytes(file3, bytes3);
|
||||||
|
api.addFile(contactProperties, contact.outboxId, file2);
|
||||||
|
api.addFile(contactProperties, contact.outboxId, file3);
|
||||||
|
|
||||||
|
// owner checks folders with available files
|
||||||
|
List<MailboxFolderId> folders = api.getFolders(ownerProperties);
|
||||||
|
assertEquals(singletonList(contact.outboxId), folders);
|
||||||
|
|
||||||
|
// owner lists files in contact's outbox
|
||||||
|
List<MailboxFile> files2 =
|
||||||
|
api.getFiles(ownerProperties, contact.outboxId);
|
||||||
|
assertEquals(2, files2.size());
|
||||||
|
MailboxFileId file2name = files2.get(0).name;
|
||||||
|
MailboxFileId file3name = files2.get(1).name;
|
||||||
|
|
||||||
|
// contact can't list files in contact's outbox
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.getFiles(contactProperties, contact.outboxId));
|
||||||
|
|
||||||
|
// owner downloads both files from contact's outbox
|
||||||
|
File file2downloaded = folder.newFile();
|
||||||
|
File file3downloaded = folder.newFile();
|
||||||
|
api.getFile(ownerProperties, contact.outboxId, file2name,
|
||||||
|
file2downloaded);
|
||||||
|
api.getFile(ownerProperties, contact.outboxId, file3name,
|
||||||
|
file3downloaded);
|
||||||
|
byte[] downloadedBytes2 = readBytes(file2downloaded);
|
||||||
|
byte[] downloadedBytes3 = readBytes(file3downloaded);
|
||||||
|
// file order is preserved (sorted by time),
|
||||||
|
// so we know what file is which
|
||||||
|
assertArrayEquals(bytes2, downloadedBytes2);
|
||||||
|
assertArrayEquals(bytes3, downloadedBytes3);
|
||||||
|
|
||||||
|
// contact can't download files again, even if knowing name
|
||||||
|
File file2forbidden = folder.newFile();
|
||||||
|
File file3forbidden = folder.newFile();
|
||||||
|
assertThrows(ApiException.class, () -> api.getFile(contactProperties,
|
||||||
|
contact.outboxId, file2name, file2forbidden));
|
||||||
|
assertThrows(ApiException.class, () -> api.getFile(contactProperties,
|
||||||
|
contact.outboxId, file3name, file3forbidden));
|
||||||
|
assertEquals(0, file1forbidden.length());
|
||||||
|
assertEquals(0, file2forbidden.length());
|
||||||
|
|
||||||
|
// contact can't delete files in outbox
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.deleteFile(contactProperties, contact.outboxId, file2name));
|
||||||
|
assertThrows(ApiException.class, () ->
|
||||||
|
api.deleteFile(contactProperties, contact.outboxId, file3name));
|
||||||
|
|
||||||
|
// owner deletes files
|
||||||
|
api.deleteFile(ownerProperties, contact.outboxId, file2name);
|
||||||
|
api.deleteFile(ownerProperties, contact.outboxId, file3name);
|
||||||
|
assertEquals(emptyList(),
|
||||||
|
api.getFiles(ownerProperties, contact.outboxId));
|
||||||
|
assertEquals(emptyList(), api.getFolders(ownerProperties));
|
||||||
|
|
||||||
|
// deleting a non-existent file is tolerable
|
||||||
|
assertThrows(TolerableFailureException.class, () ->
|
||||||
|
api.deleteFile(ownerProperties, contact.outboxId, file3name));
|
||||||
|
|
||||||
|
// owner deletes contact again to leave clean state for other tests
|
||||||
|
api.deleteContact(ownerProperties, contactId);
|
||||||
|
assertEquals(emptyList(), api.getContacts(ownerProperties));
|
||||||
|
}
|
||||||
|
|
||||||
private MailboxContact getMailboxContact(ContactId contactId) {
|
private MailboxContact getMailboxContact(ContactId contactId) {
|
||||||
return new MailboxContact(contactId, getMailboxSecret(),
|
MailboxAuthToken authToken = new MailboxAuthToken(getRandomId());
|
||||||
getMailboxSecret(), getMailboxSecret());
|
MailboxFolderId inboxId = new MailboxFolderId(getRandomId());
|
||||||
|
MailboxFolderId outboxId = new MailboxFolderId(getRandomId());
|
||||||
|
return new MailboxContact(contactId, authToken, inboxId, outboxId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
|
import org.briarproject.bramble.test.DbExpectations;
|
||||||
|
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||||
|
import org.briarproject.bramble.test.PredicateMatcher;
|
||||||
|
import org.jmock.Expectations;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
|
private final Executor executor = new ImmediateExecutor();
|
||||||
|
private final TransactionManager db =
|
||||||
|
context.mock(TransactionManager.class);
|
||||||
|
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
|
private final Clock clock = context.mock(Clock.class);
|
||||||
|
private final MailboxApi api = context.mock(MailboxApi.class);
|
||||||
|
private final MailboxSettingsManager mailboxSettingsManager =
|
||||||
|
context.mock(MailboxSettingsManager.class);
|
||||||
|
private final MailboxPairingTaskFactory factory =
|
||||||
|
new MailboxPairingTaskFactoryImpl(executor, db, crypto, clock, api,
|
||||||
|
mailboxSettingsManager);
|
||||||
|
|
||||||
|
private final String onion = getRandomString(56);
|
||||||
|
private final byte[] onionBytes = getRandomBytes(32);
|
||||||
|
private final String onionAddress = "http://" + onion + ".onion";
|
||||||
|
private final MailboxAuthToken setupToken =
|
||||||
|
new MailboxAuthToken(getRandomId());
|
||||||
|
private final MailboxAuthToken ownerToken =
|
||||||
|
new MailboxAuthToken(getRandomId());
|
||||||
|
private final String validPayload = getValidPayload();
|
||||||
|
private final long time = System.currentTimeMillis();
|
||||||
|
private final MailboxProperties setupProperties =
|
||||||
|
new MailboxProperties(onionAddress, setupToken, true);
|
||||||
|
private final MailboxProperties ownerProperties =
|
||||||
|
new MailboxProperties(onionAddress, ownerToken, true);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitialQrCodeReceivedState() {
|
||||||
|
MailboxPairingTask task =
|
||||||
|
factory.createPairingTask(getRandomString(42));
|
||||||
|
task.addObserver(state ->
|
||||||
|
assertTrue(state instanceof MailboxPairingState.QrCodeReceived)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidQrCode() {
|
||||||
|
MailboxPairingTask task1 =
|
||||||
|
factory.createPairingTask(getRandomString(42));
|
||||||
|
task1.run();
|
||||||
|
task1.addObserver(state ->
|
||||||
|
assertTrue(state instanceof MailboxPairingState.InvalidQrCode)
|
||||||
|
);
|
||||||
|
|
||||||
|
String goodLength = "00" + getRandomString(63);
|
||||||
|
MailboxPairingTask task2 = factory.createPairingTask(goodLength);
|
||||||
|
task2.run();
|
||||||
|
task2.addObserver(state ->
|
||||||
|
assertTrue(state instanceof MailboxPairingState.InvalidQrCode)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSuccessfulPairing() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(crypto).encodeOnionAddress(onionBytes);
|
||||||
|
will(returnValue(onion));
|
||||||
|
oneOf(api).setup(with(matches(setupProperties)));
|
||||||
|
will(returnValue(ownerToken));
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(time));
|
||||||
|
}});
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
context.checking(new DbExpectations() {{
|
||||||
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
|
oneOf(mailboxSettingsManager).setOwnMailboxProperties(
|
||||||
|
with(txn), with(matches(ownerProperties)));
|
||||||
|
oneOf(mailboxSettingsManager).recordSuccessfulConnection(txn, time);
|
||||||
|
}});
|
||||||
|
|
||||||
|
AtomicInteger i = new AtomicInteger(0);
|
||||||
|
MailboxPairingTask task = factory.createPairingTask(validPayload);
|
||||||
|
task.addObserver(state -> {
|
||||||
|
if (i.get() == 0) {
|
||||||
|
assertEquals(MailboxPairingState.QrCodeReceived.class,
|
||||||
|
state.getClass());
|
||||||
|
} else if (i.get() == 1) {
|
||||||
|
assertEquals(MailboxPairingState.Pairing.class,
|
||||||
|
state.getClass());
|
||||||
|
} else if (i.get() == 2) {
|
||||||
|
assertEquals(MailboxPairingState.Paired.class,
|
||||||
|
state.getClass());
|
||||||
|
} else fail("Unexpected change of state " + state.getClass());
|
||||||
|
i.getAndIncrement();
|
||||||
|
});
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAlreadyPaired() throws Exception {
|
||||||
|
testApiException(new MailboxApi.MailboxAlreadyPairedException(),
|
||||||
|
MailboxPairingState.MailboxAlreadyPaired.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMailboxApiException() throws Exception {
|
||||||
|
testApiException(new MailboxApi.ApiException(),
|
||||||
|
MailboxPairingState.UnexpectedError.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApiIOException() throws Exception {
|
||||||
|
testApiException(new IOException(),
|
||||||
|
MailboxPairingState.ConnectionError.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testApiException(Exception e,
|
||||||
|
Class<? extends MailboxPairingState> s) throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(crypto).encodeOnionAddress(onionBytes);
|
||||||
|
will(returnValue(onion));
|
||||||
|
oneOf(api).setup(with(matches(setupProperties)));
|
||||||
|
will(throwException(e));
|
||||||
|
}});
|
||||||
|
|
||||||
|
MailboxPairingTask task = factory.createPairingTask(validPayload);
|
||||||
|
task.run();
|
||||||
|
task.addObserver(state -> assertEquals(state.getClass(), s));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDbException() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(crypto).encodeOnionAddress(onionBytes);
|
||||||
|
will(returnValue(onion));
|
||||||
|
oneOf(api).setup(with(matches(setupProperties)));
|
||||||
|
will(returnValue(ownerToken));
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(time));
|
||||||
|
}});
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
context.checking(new DbExpectations() {{
|
||||||
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
|
oneOf(mailboxSettingsManager).setOwnMailboxProperties(
|
||||||
|
with(txn), with(matches(ownerProperties)));
|
||||||
|
will(throwException(new DbException()));
|
||||||
|
}});
|
||||||
|
|
||||||
|
MailboxPairingTask task = factory.createPairingTask(validPayload);
|
||||||
|
task.run();
|
||||||
|
task.addObserver(state -> assertEquals(state.getClass(),
|
||||||
|
MailboxPairingState.UnexpectedError.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getValidPayload() {
|
||||||
|
byte[] payloadBytes = ByteBuffer.allocate(65)
|
||||||
|
.put((byte) 32) // 1
|
||||||
|
.put(onionBytes) // 32
|
||||||
|
.put(setupToken.getBytes()) // 32
|
||||||
|
.array();
|
||||||
|
//noinspection CharsetObjectCanBeUsed
|
||||||
|
return new String(payloadBytes, Charset.forName("ISO-8859-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PredicateMatcher<MailboxProperties> matches(MailboxProperties p2) {
|
||||||
|
return new PredicateMatcher<>(MailboxProperties.class, p1 ->
|
||||||
|
p1.getAuthToken().equals(p2.getAuthToken()) &&
|
||||||
|
p1.getBaseUrl().equals(p2.getBaseUrl()) &&
|
||||||
|
p1.isOwner() == p2.isOwner());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.mailbox;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
@@ -20,6 +21,7 @@ import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTIN
|
|||||||
import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_KEY_TOKEN;
|
import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_KEY_TOKEN;
|
||||||
import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_NAMESPACE;
|
import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_NAMESPACE;
|
||||||
import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_UPLOADS_NAMESPACE;
|
import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_UPLOADS_NAMESPACE;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -35,7 +37,7 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
new MailboxSettingsManagerImpl(settingsManager);
|
new MailboxSettingsManagerImpl(settingsManager);
|
||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
private final String onion = getRandomString(64);
|
private final String onion = getRandomString(64);
|
||||||
private final String token = getRandomString(64);
|
private final MailboxAuthToken token = new MailboxAuthToken(getRandomId());
|
||||||
private final ContactId contactId1 = new ContactId(random.nextInt());
|
private final ContactId contactId1 = new ContactId(random.nextInt());
|
||||||
private final ContactId contactId2 = new ContactId(random.nextInt());
|
private final ContactId contactId2 = new ContactId(random.nextInt());
|
||||||
private final ContactId contactId3 = new ContactId(random.nextInt());
|
private final ContactId contactId3 = new ContactId(random.nextInt());
|
||||||
@@ -62,7 +64,7 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
Settings settings = new Settings();
|
Settings settings = new Settings();
|
||||||
settings.put(SETTINGS_KEY_ONION, onion);
|
settings.put(SETTINGS_KEY_ONION, onion);
|
||||||
settings.put(SETTINGS_KEY_TOKEN, token);
|
settings.put(SETTINGS_KEY_TOKEN, token.toString());
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(settingsManager).getSettings(txn, SETTINGS_NAMESPACE);
|
oneOf(settingsManager).getSettings(txn, SETTINGS_NAMESPACE);
|
||||||
@@ -71,7 +73,7 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
MailboxProperties properties = manager.getOwnMailboxProperties(txn);
|
MailboxProperties properties = manager.getOwnMailboxProperties(txn);
|
||||||
assertNotNull(properties);
|
assertNotNull(properties);
|
||||||
assertEquals(onion, properties.getOnionAddress());
|
assertEquals(onion, properties.getBaseUrl());
|
||||||
assertEquals(token, properties.getAuthToken());
|
assertEquals(token, properties.getAuthToken());
|
||||||
assertTrue(properties.isOwner());
|
assertTrue(properties.isOwner());
|
||||||
}
|
}
|
||||||
@@ -81,7 +83,7 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
Settings expectedSettings = new Settings();
|
Settings expectedSettings = new Settings();
|
||||||
expectedSettings.put(SETTINGS_KEY_ONION, onion);
|
expectedSettings.put(SETTINGS_KEY_ONION, onion);
|
||||||
expectedSettings.put(SETTINGS_KEY_TOKEN, token);
|
expectedSettings.put(SETTINGS_KEY_TOKEN, token.toString());
|
||||||
MailboxProperties properties =
|
MailboxProperties properties =
|
||||||
new MailboxProperties(onion, token, true);
|
new MailboxProperties(onion, token, true);
|
||||||
|
|
||||||
@@ -180,7 +182,7 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
Settings settings = new Settings();
|
Settings settings = new Settings();
|
||||||
settings.put(String.valueOf(contactId1.getInt()), onion);
|
settings.put(String.valueOf(contactId1.getInt()), onion);
|
||||||
settings.put(String.valueOf(contactId2.getInt()), token);
|
settings.put(String.valueOf(contactId2.getInt()), token.toString());
|
||||||
settings.put(String.valueOf(contactId3.getInt()), "");
|
settings.put(String.valueOf(contactId3.getInt()), "");
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -192,7 +194,8 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
String filename1 = manager.getPendingUpload(txn, contactId1);
|
String filename1 = manager.getPendingUpload(txn, contactId1);
|
||||||
assertEquals(onion, filename1);
|
assertEquals(onion, filename1);
|
||||||
String filename2 = manager.getPendingUpload(txn, contactId2);
|
String filename2 = manager.getPendingUpload(txn, contactId2);
|
||||||
assertEquals(token, filename2);
|
assertNotNull(filename2);
|
||||||
|
assertEquals(token.toString(), filename2);
|
||||||
String filename3 = manager.getPendingUpload(txn, contactId3);
|
String filename3 = manager.getPendingUpload(txn, contactId3);
|
||||||
assertNull(filename3);
|
assertNull(filename3);
|
||||||
String filename4 =
|
String filename4 =
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ public class TestFeatureFlagModule {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldEnableMailbox() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldEnablePrivateGroupsInCore() {
|
public boolean shouldEnablePrivateGroupsInCore() {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
16
briar-android/artwork/ic_mailbox.svg
Normal file
16
briar-android/artwork/ic_mailbox.svg
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" version="1.1" id="svg4"
|
||||||
|
sodipodi:docname="ic_mailbox.svg" inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs id="defs8" />
|
||||||
|
<sodipodi:namedview id="namedview6" pagecolor="#7d7d7d" bordercolor="#666666" borderopacity="1.0"
|
||||||
|
inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:pagecheckerboard="0"
|
||||||
|
showgrid="false" inkscape:zoom="9.0780032" inkscape:cx="22.086355" inkscape:cy="10.850404"
|
||||||
|
inkscape:window-width="1920" inkscape:window-height="928" inkscape:window-x="0"
|
||||||
|
inkscape:window-y="108" inkscape:window-maximized="1" inkscape:current-layer="svg4" />
|
||||||
|
<path
|
||||||
|
d="m 5.0781637,2.0000001 c -0.5245356,0 -1.0278314,0.2105185 -1.3987365,0.5847785 C 3.3085215,2.9590375 3.1,3.4663153 3.1,3.9956004 V 16.767666 c 0,0.529289 0.2085215,1.037692 0.5794272,1.411969 0.3709051,0.37423 0.8742009,0.583635 1.3987365,0.583635 H 15.850874 l 3.588966,3.026135 C 20.019297,22.277986 20.9,21.862034 20.9,21.100087 V 3.9956004 C 20.9,3.4663153 20.691473,2.9590375 20.32057,2.5847786 19.949681,2.2105186 19.44635,2.0000001 18.921831,2.0000001 Z M 6.2648311,5.19273 H 17.73517 v 5.65018 h -4.00732 v 1.954238 h 1.465946 c 0.26433,0 0.396594,0.32267 0.209762,0.511253 l -3.160194,3.188138 c -0.11588,0.116871 -0.303625,0.116871 -0.419503,0 L 8.6636588,13.308401 C 8.4767702,13.119818 8.6091068,12.797148 8.8734113,12.797148 H 10.339359 V 10.84291 H 6.2648311 Z"
|
||||||
|
fill="white" id="path2" style="fill:#ffffff;stroke:none;stroke-width:0.590769" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
105
briar-android/artwork/mailbox_onboarding_dark.svg
Normal file
105
briar-android/artwork/mailbox_onboarding_dark.svg
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<svg width="250" height="199" viewBox="0 0 250 199" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M95.4363 100.233C95.4363 93.5233 100.876 88.084 107.585 88.084H130.365C137.074 88.084 142.514 93.5233 142.514 100.233V123.012C142.514 129.722 137.074 135.161 130.365 135.161H107.585C100.876 135.161 95.4363 129.722 95.4363 123.012V100.233Z"
|
||||||
|
fill="#15212D" />
|
||||||
|
<path
|
||||||
|
d="M102.336 10.2609C102.336 4.59395 106.93 0 112.597 0H131.836C137.503 0 142.097 4.59395 142.097 10.2609V29.5C142.097 35.1669 137.503 39.7609 131.836 39.7609H112.597C106.93 39.7609 102.336 35.1669 102.336 29.5V10.2609Z"
|
||||||
|
fill="#15212D" />
|
||||||
|
<path
|
||||||
|
d="M34.8184 148.09C34.8184 143.427 38.5986 139.646 43.2618 139.646H59.0933C63.7565 139.646 67.5368 143.427 67.5368 148.09V163.921C67.5368 168.585 63.7565 172.365 59.0933 172.365H43.2618C38.5986 172.365 34.8184 168.585 34.8184 163.921V148.09Z"
|
||||||
|
fill="#15212D" />
|
||||||
|
<path
|
||||||
|
d="M110.024 186.044C110.024 183.557 112.04 181.541 114.527 181.541H122.971C125.458 181.541 127.475 183.557 127.475 186.044V194.488C127.475 196.976 125.458 198.992 122.971 198.992H114.527C112.04 198.992 110.024 196.976 110.024 194.488V186.044Z"
|
||||||
|
fill="#15212D" />
|
||||||
|
<path
|
||||||
|
d="M173.713 141.6C173.713 134.89 179.152 129.451 185.862 129.451H208.641C215.351 129.451 220.79 134.89 220.79 141.6V164.38C220.79 171.089 215.351 176.528 208.641 176.528H185.862C179.152 176.528 173.713 171.089 173.713 164.38V141.6Z"
|
||||||
|
fill="#15212D" />
|
||||||
|
<path
|
||||||
|
d="M232.049 95.4156C232.049 92.9284 234.065 90.9121 236.553 90.9121H244.997C247.484 90.9121 249.5 92.9284 249.5 95.4156V103.86C249.5 106.347 247.484 108.363 244.997 108.363H236.553C234.065 108.363 232.049 106.347 232.049 103.86V95.4156Z"
|
||||||
|
fill="#15212D" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M120.481 84.2273V45.2676H122.481V84.2273H120.481Z" fill="#657D99" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M117.685 176.101L117.685 139.646H119.685L119.685 176.101H117.685Z" fill="#657D99" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M3.27959 108.445L4.0457 106.598C4.3381 106.719 4.66032 106.787 5.00345 106.787H7.11444V108.787H5.00345C4.39282 108.787 3.81058 108.665 3.27959 108.445ZM11.3364 108.787V106.787H13.4474C13.7905 106.787 14.1128 106.719 14.4052 106.598L15.1713 108.445C14.6403 108.665 14.058 108.787 13.4474 108.787H11.3364ZM17.9509 97.9504H15.9509V95.8394C15.9509 95.4963 15.8829 95.174 15.7617 94.8816L17.6091 94.1155C17.8293 94.6465 17.9509 95.2288 17.9509 95.8394V97.9504ZM7.11444 91.3359H5.00345C4.39282 91.3359 3.81058 91.4575 3.27959 91.6777L4.0457 93.5251C4.3381 93.4039 4.66032 93.3359 5.00345 93.3359H7.11444V91.3359ZM0.500008 102.172H2.50001V104.283C2.50001 104.626 2.56793 104.949 2.68918 105.241L0.841732 106.007C0.621538 105.476 0.500008 104.894 0.500008 104.283V102.172ZM0.500008 97.9504H2.50001V95.8394C2.50001 95.4963 2.56793 95.174 2.68918 94.8816L0.841731 94.1155C0.621538 94.6465 0.500008 95.2288 0.500008 95.8394V97.9504ZM11.3364 91.3359V93.3359H13.4474C13.7905 93.3359 14.1128 93.4039 14.4052 93.5251L15.1713 91.6777C14.6403 91.4575 14.058 91.3359 13.4474 91.3359H11.3364ZM17.9509 102.172H15.9509V104.283C15.9509 104.626 15.8829 104.949 15.7617 105.241L17.6091 106.007C17.8293 105.476 17.9509 104.894 17.9509 104.283V102.172Z"
|
||||||
|
fill="#657D99" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M41.1771 64.5169V62.6484H43.1771V64.5169H41.1771ZM41.1771 71.9908V68.2538H43.1771V71.9908H41.1771ZM41.1771 79.4647V75.7277H43.1771V79.4647H41.1771ZM41.1771 86.9385V83.2016H43.1771V86.9385H41.1771ZM41.1771 94.4124V90.6755H43.1771V94.4124H41.1771ZM41.1771 99.0178V98.1493H43.1771V99.0178H44.9095V101.018H39.681V99.0178H41.1771ZM24.7048 101.018H22.2087V99.0178H24.7048V101.018ZM34.6889 101.018H29.6969V99.0178H34.6889V101.018ZM52.1068 101.018H50.3744V99.0178H54.8543V101.018H54.1068V102.148H52.1068V101.018ZM61.8442 101.018H58.3493V99.0178H61.8442V101.018ZM67.0867 101.018H65.3392V99.0178H67.0867C68.0476 99.0178 68.9663 99.2092 69.8048 99.557L69.0387 101.404C68.4388 101.156 67.7801 101.018 67.0867 101.018ZM72.187 106.118C72.187 105.425 72.0492 104.766 71.8004 104.166L73.6478 103.4C73.9955 104.239 74.187 105.157 74.187 106.118C74.187 106.812 74.3248 107.47 74.5736 108.07L72.7261 108.836C72.3784 107.998 72.187 107.079 72.187 106.118ZM52.1068 110.668V106.408H54.1068V110.668H52.1068ZM79.2873 113.218C78.3264 113.218 77.4077 113.027 76.5691 112.679L77.3352 110.832C77.9352 111.081 78.5939 111.218 79.2873 111.218H81.5905V113.218H79.2873ZM88.5 113.218H86.1968V111.218H88.5V113.218ZM52.1068 119.188V114.928H54.1068V119.188H52.1068ZM52.1068 127.709V123.449H54.1068V127.709H52.1068ZM52.1068 134.099V131.969H54.1068V134.099H52.1068Z"
|
||||||
|
fill="#74B816" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M105.214 134.93L105.602 132.968C106.242 133.095 106.905 133.161 107.585 133.161H109.484V135.161H107.585C106.774 135.161 105.981 135.082 105.214 134.93ZM128.466 135.161V133.161H130.365C131.045 133.161 131.708 133.095 132.347 132.968L132.736 134.93C131.969 135.082 131.176 135.161 130.365 135.161H128.466ZM137.115 133.115L136.002 131.453C137.11 130.712 138.064 129.757 138.805 128.65L140.467 129.762C139.58 131.087 138.44 132.228 137.115 133.115ZM142.514 102.131H140.514V100.233C140.514 99.5526 140.447 98.8898 140.32 98.2501L142.282 97.8619C142.434 98.6288 142.514 99.4216 142.514 100.233V102.131ZM140.467 93.4828L138.805 94.5954C138.064 93.4878 137.11 92.5338 136.002 91.7922L137.115 90.1303C138.44 91.0173 139.58 92.1579 140.467 93.4828ZM109.484 88.084H107.585C106.774 88.084 105.981 88.1635 105.214 88.3152L105.602 90.2772C106.242 90.1507 106.905 90.084 107.585 90.084H109.484V88.084ZM100.835 90.1303L101.948 91.7922C100.84 92.5338 99.8861 93.4878 99.1445 94.5954L97.4826 93.4828C98.3696 92.1579 99.5102 91.0173 100.835 90.1303ZM95.4363 121.114H97.4363V123.012C97.4363 123.693 97.503 124.355 97.6295 124.995L95.6675 125.383C95.5158 124.616 95.4363 123.824 95.4363 123.012V121.114ZM97.4826 129.762L99.1445 128.65C99.8861 129.757 100.84 130.712 101.948 131.453L100.835 133.115C99.5102 132.228 98.3696 131.087 97.4826 129.762ZM95.4363 117.317H97.4363V113.521H95.4363V117.317ZM95.4363 109.724H97.4363V105.928H95.4363V109.724ZM95.4363 102.131H97.4363V100.233C97.4363 99.5526 97.503 98.8898 97.6295 98.2501L95.6675 97.8619C95.5158 98.6288 95.4363 99.4216 95.4363 100.233V102.131ZM113.28 88.084V90.084H117.077V88.084H113.28ZM120.873 88.084V90.084H124.67V88.084H120.873ZM128.466 88.084V90.084H130.365C131.045 90.084 131.708 90.1507 132.347 90.2772L132.736 88.3152C131.969 88.1635 131.176 88.084 130.365 88.084H128.466ZM142.514 105.928H140.514V109.724H142.514V105.928ZM142.514 113.521H140.514V117.317H142.514V113.521ZM142.514 121.114H140.514V123.012C140.514 123.693 140.447 124.355 140.32 124.995L142.282 125.383C142.434 124.616 142.514 123.824 142.514 123.012V121.114ZM124.67 135.161V133.161H120.873V135.161H124.67ZM117.077 135.161V133.161H113.28V135.161H117.077Z"
|
||||||
|
fill="#74B816" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M188.618 86.5389V84.6738H190.618V86.5389H188.618ZM188.618 93.9991V90.269H190.618V93.9991H188.618ZM188.618 97.7293H190.618V98.5943H191.517V100.594H190.618V101.183H188.618V97.7293ZM199.112 100.594H195.315V98.5943H199.112V100.594ZM206.707 100.594H202.91V98.5943H206.707V100.594ZM214.303 100.594H210.505V98.5943H214.303V100.594ZM221.898 100.594H218.1V98.5943H221.898V100.594ZM227.595 100.594H225.696V98.5943H227.595V100.594ZM188.618 107.537V104.36H190.618V107.537H188.618ZM188.618 111.303V110.715H190.618V111.359C190.865 111.387 191.109 111.425 191.35 111.472L190.962 113.434C190.528 113.349 190.079 113.303 189.618 113.303H187.737V111.303H188.618ZM153.881 113.303H152V111.303H153.881V113.303ZM161.405 113.303H157.643V111.303H161.405V113.303ZM168.928 113.303H165.166V111.303H168.928V113.303ZM176.452 113.303H172.69V111.303H176.452V113.303ZM183.975 113.303H180.214V111.303H183.975V113.303ZM195.34 116.361C194.837 115.611 194.19 114.964 193.44 114.462L194.552 112.8C195.52 113.448 196.353 114.281 197.001 115.249L195.34 116.361ZM196.498 120.183C196.498 119.722 196.453 119.273 196.367 118.839L198.329 118.451C198.44 119.012 198.498 119.591 198.498 120.183V121.203H196.498V120.183ZM196.498 124.261V123.242H198.498V124.261H196.498Z"
|
||||||
|
fill="#74B816" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M183.491 176.297L183.879 174.335C184.519 174.462 185.182 174.528 185.862 174.528H187.76V176.528H185.862C185.051 176.528 184.258 176.449 183.491 176.297ZM206.743 176.528V174.528H208.641C209.322 174.528 209.985 174.462 210.624 174.335L211.012 176.297C210.246 176.449 209.453 176.528 208.641 176.528H206.743ZM215.392 174.482L214.279 172.82C215.387 172.079 216.341 171.125 217.082 170.017L218.744 171.13C217.857 172.455 216.717 173.595 215.392 174.482ZM220.79 143.498H218.79V141.6C218.79 140.92 218.724 140.257 218.597 139.617L220.559 139.229C220.711 139.996 220.79 140.789 220.79 141.6V143.498ZM218.744 134.85L217.082 135.963C216.341 134.855 215.387 133.901 214.279 133.159L215.392 131.497C216.717 132.384 217.857 133.525 218.744 134.85ZM187.76 129.451H185.862C185.051 129.451 184.258 129.531 183.491 129.682L183.879 131.644C184.519 131.518 185.182 131.451 185.862 131.451H187.76V129.451ZM179.112 131.497L180.225 133.159C179.117 133.901 178.163 134.855 177.421 135.963L175.759 134.85C176.646 133.525 177.787 132.384 179.112 131.497ZM173.713 162.481H175.713V164.38C175.713 165.06 175.78 165.723 175.906 166.362L173.944 166.751C173.793 165.984 173.713 165.191 173.713 164.38V162.481ZM175.759 171.13L177.421 170.017C178.163 171.125 179.117 172.079 180.225 172.82L179.112 174.482C177.787 173.595 176.646 172.455 175.759 171.13ZM173.713 158.685H175.713V154.888H173.713V158.685ZM173.713 151.092H175.713V147.295H173.713V151.092ZM173.713 143.498H175.713V141.6C175.713 140.92 175.78 140.257 175.906 139.617L173.944 139.229C173.793 139.996 173.713 140.789 173.713 141.6V143.498ZM191.557 129.451V131.451H195.354V129.451H191.557ZM199.15 129.451V131.451H202.947V129.451H199.15ZM206.743 129.451V131.451H208.641C209.322 131.451 209.985 131.518 210.624 131.644L211.012 129.682C210.246 129.531 209.453 129.451 208.641 129.451H206.743ZM220.79 147.295H218.79V151.092H220.79V147.295ZM220.79 154.888H218.79V158.685H220.79V154.888ZM220.79 162.481H218.79V164.38C218.79 165.06 218.724 165.723 218.597 166.362L220.559 166.751C220.711 165.984 220.79 165.191 220.79 164.38V162.481ZM202.947 176.528V174.528H199.15V176.528H202.947ZM195.354 176.528V174.528H191.557V176.528H195.354Z"
|
||||||
|
fill="#74B816" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M110.594 39.5656L110.982 37.6036C111.503 37.7066 112.042 37.7609 112.597 37.7609H115.001V39.7609H112.597C111.911 39.7609 111.242 39.6937 110.594 39.5656ZM129.431 39.7609V37.7609H131.836C132.39 37.7609 132.93 37.7066 133.45 37.6036L133.838 39.5656C133.191 39.6937 132.521 39.7609 131.836 39.7609H129.431ZM137.537 38.0326L136.424 36.3706C137.326 35.767 138.103 34.9902 138.706 34.0885L140.368 35.2011C139.619 36.3201 138.656 37.2835 137.537 38.0326ZM142.097 12.6658H140.097V10.2609C140.097 9.7066 140.042 9.167 139.939 8.64647L141.901 8.25834C142.029 8.90601 142.097 9.57559 142.097 10.2609V12.6658ZM140.368 4.55977L138.706 5.67241C138.103 4.77069 137.326 3.99391 136.424 3.39022L137.537 1.72828C138.656 2.47741 139.619 3.44081 140.368 4.55977ZM115.001 0H112.597C111.911 0 111.242 0.0671774 110.594 0.195306L110.982 2.15728C111.503 2.05431 112.042 2 112.597 2H115.001V0ZM106.895 1.72829L108.008 3.39022C107.106 3.99391 106.33 4.77069 105.726 5.67241L104.064 4.55977C104.813 3.44081 105.777 2.47741 106.895 1.72829ZM102.336 27.0951H104.336V29.5C104.336 30.0543 104.39 30.5939 104.493 31.1144L102.531 31.5025C102.403 30.8549 102.336 30.1853 102.336 29.5V27.0951ZM104.064 35.2011L105.726 34.0885C106.33 34.9902 107.106 35.767 108.008 36.3706L106.895 38.0326C105.777 37.2835 104.813 36.3201 104.064 35.2011ZM102.336 22.2853H104.336V17.4755H102.336V22.2853ZM102.336 12.6658H104.336V10.2609C104.336 9.7066 104.39 9.167 104.493 8.64647L102.531 8.25834C102.403 8.90601 102.336 9.57559 102.336 10.2609V12.6658ZM119.811 0V2H124.621V0H119.811ZM129.431 0V2H131.836C132.39 2 132.93 2.05431 133.45 2.15728L133.838 0.195306C133.191 0.0671773 132.521 0 131.836 0H129.431ZM142.097 17.4755H140.097V22.2853H142.097V17.4755ZM142.097 27.0951H140.097V29.5C140.097 30.0543 140.042 30.5939 139.939 31.1144L141.901 31.5025C142.029 30.8549 142.097 30.1853 142.097 29.5V27.0951ZM124.621 39.7609V37.7609H119.811V39.7609H124.621Z"
|
||||||
|
fill="#435B77" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M40.0298 171.724L40.7959 169.877C41.5528 170.191 42.3845 170.365 43.2618 170.365H45.2408V172.365H43.2618C42.117 172.365 41.0253 172.137 40.0298 171.724ZM57.1144 172.365V170.365H59.0933C59.9707 170.365 60.8023 170.191 61.5593 169.877L62.3254 171.724C61.3298 172.137 60.2382 172.365 59.0933 172.365H57.1144ZM67.5368 150.069H65.5368V148.09C65.5368 147.213 65.3625 146.381 65.0486 145.624L66.8961 144.858C67.3089 145.853 67.5368 146.945 67.5368 148.09V150.069ZM45.2408 139.646H43.2618C42.117 139.646 41.0253 139.874 40.0298 140.287L40.7959 142.135C41.5528 141.821 42.3845 141.646 43.2618 141.646H45.2408V139.646ZM34.8184 161.943H36.8184V163.921C36.8184 164.799 36.9926 165.63 37.3065 166.387L35.4591 167.153C35.0462 166.158 34.8184 165.066 34.8184 163.921V161.943ZM34.8184 157.985H36.8184V154.027H34.8184V157.985ZM34.8184 150.069H36.8184V148.09C36.8184 147.213 36.9926 146.381 37.3065 145.624L35.4591 144.858C35.0462 145.853 34.8184 146.945 34.8184 148.09V150.069ZM49.1986 139.646V141.646H53.1565V139.646H49.1986ZM57.1144 139.646V141.646H59.0933C59.9707 141.646 60.8023 141.821 61.5593 142.135L62.3254 140.287C61.3298 139.874 60.2382 139.646 59.0933 139.646H57.1144ZM67.5368 154.027H65.5368V157.985H67.5368V154.027ZM67.5368 161.943H65.5368V163.921C65.5368 164.799 65.3625 165.63 65.0486 166.387L66.8961 167.154C67.3089 166.158 67.5368 165.066 67.5368 163.921V161.943ZM53.1565 172.365V170.365H49.1986V172.365H53.1565Z"
|
||||||
|
fill="#435B77" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M112.803 198.65L113.569 196.803C113.862 196.924 114.184 196.992 114.527 196.992H116.638V198.992H114.527C113.917 198.992 113.334 198.87 112.803 198.65ZM120.86 198.992V196.992H122.971C123.314 196.992 123.636 196.924 123.929 196.803L124.695 198.65C124.164 198.87 123.582 198.992 122.971 198.992H120.86ZM127.475 188.155H125.475V186.044C125.475 185.701 125.407 185.379 125.285 185.087L127.133 184.321C127.353 184.852 127.475 185.434 127.475 186.044V188.155ZM116.638 181.541H114.527C113.917 181.541 113.334 181.663 112.803 181.883L113.569 183.73C113.862 183.609 114.184 183.541 114.527 183.541H116.638V181.541ZM110.024 192.377H112.024V194.488C112.024 194.832 112.092 195.154 112.213 195.446L110.365 196.212C110.145 195.681 110.024 195.099 110.024 194.488V192.377ZM110.024 188.155H112.024V186.044C112.024 185.701 112.092 185.379 112.213 185.087L110.365 184.321C110.145 184.852 110.024 185.434 110.024 186.044V188.155ZM120.86 181.541V183.541H122.971C123.314 183.541 123.636 183.609 123.929 183.73L124.695 181.883C124.164 181.663 123.582 181.541 122.971 181.541H120.86ZM127.475 192.377H125.475V194.488C125.475 194.832 125.407 195.154 125.285 195.446L127.133 196.212C127.353 195.681 127.475 195.099 127.475 194.488V192.377Z"
|
||||||
|
fill="#435B77" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M178.996 79.8234L179.762 77.976C180.48 78.2737 181.269 78.4391 182.101 78.4391H184.003V80.4391H182.101C181.001 80.4391 179.952 80.2201 178.996 79.8234ZM195.412 80.4391V78.4391H197.314C198.146 78.4391 198.935 78.2737 199.653 77.976L200.419 79.8234C199.463 80.2201 198.414 80.4391 197.314 80.4391H195.412ZM205.427 59.0149H203.427V57.1133C203.427 56.2807 203.262 55.4918 202.964 54.7737L204.811 54.0076C205.208 54.9643 205.427 56.0132 205.427 57.1133V59.0149ZM184.003 49H182.101C181.001 49 179.952 49.2189 178.996 49.6156L179.762 51.4631C180.48 51.1653 181.269 51 182.101 51H184.003V49ZM173.988 70.4242H175.988V72.3258C175.988 73.1584 176.153 73.9473 176.451 74.6653L174.604 75.4315C174.207 74.4748 173.988 73.4259 173.988 72.3258V70.4242ZM173.988 66.6211H175.988V62.818H173.988V66.6211ZM173.988 59.0149H175.988V57.1133C175.988 56.2807 176.153 55.4918 176.451 54.7737L174.604 54.0076C174.207 54.9643 173.988 56.0132 173.988 57.1133V59.0149ZM187.806 49V51H191.609V49H187.806ZM195.412 49V51H197.314C198.146 51 198.935 51.1653 199.653 51.4631L200.419 49.6156C199.463 49.2189 198.414 49 197.314 49H195.412ZM205.427 62.818H203.427V66.6211H205.427V62.818ZM205.427 70.4242H203.427V72.3258C203.427 73.1584 203.262 73.9473 202.964 74.6653L204.811 75.4315C205.208 74.4748 205.427 73.4259 205.427 72.3258V70.4242ZM191.609 80.4391V78.4391H187.806V80.4391H191.609Z"
|
||||||
|
fill="#657D99" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M234.829 108.021L235.595 106.174C235.887 106.295 236.209 106.363 236.553 106.363H238.664V108.363H236.553C235.942 108.363 235.36 108.241 234.829 108.021ZM242.886 108.363V106.363H244.997C245.34 106.363 245.662 106.295 245.954 106.174L246.72 108.021C246.189 108.241 245.607 108.363 244.997 108.363H242.886ZM249.5 97.5265H247.5V95.4156C247.5 95.0724 247.432 94.7502 247.311 94.4578L249.158 93.6917C249.378 94.2227 249.5 94.8049 249.5 95.4156V97.5265ZM238.664 90.9121H236.553C235.942 90.9121 235.36 91.0336 234.829 91.2538L235.595 93.1013C235.887 92.98 236.209 92.9121 236.553 92.9121H238.664V90.9121ZM232.049 101.749H234.049V103.86C234.049 104.203 234.117 104.525 234.238 104.817L232.391 105.583C232.171 105.052 232.049 104.47 232.049 103.86V101.749ZM232.049 97.5265H234.049V95.4156C234.049 95.0724 234.117 94.7502 234.238 94.4578L232.391 93.6917C232.171 94.2227 232.049 94.8049 232.049 95.4156V97.5265ZM242.886 90.9121V92.9121H244.997C245.34 92.9121 245.662 92.98 245.954 93.1013L246.72 91.2538C246.189 91.0336 245.607 90.9121 244.997 90.9121H242.886ZM249.5 101.749H247.5V103.86C247.5 104.203 247.432 104.525 247.311 104.817L249.158 105.583C249.378 105.052 249.5 104.47 249.5 103.86V101.749Z"
|
||||||
|
fill="#435B77" />
|
||||||
|
<path
|
||||||
|
d="M29.8254 34.377V53.6604C29.8254 55.2256 31.1003 56.5166 32.6817 56.5166H34.021C35.5863 56.5166 36.8772 55.2256 36.8772 53.6604V34.377H29.8254Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M36.8611 25.0827V21.4519C36.8611 19.8866 35.5863 18.5957 34.021 18.5957H32.6817C31.1164 18.5957 29.8254 19.8866 29.8254 21.4519V25.0827H36.8611Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M52.5136 40.7353V21.4519C52.5136 19.8866 51.2388 18.5957 49.6735 18.5957H48.3342C46.7689 18.5957 45.478 19.8866 45.478 21.4519V40.7353H52.5136Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M45.478 50.0293V53.6601C45.478 55.2253 46.7689 56.5163 48.3342 56.5163H49.6735C51.2388 56.5163 52.5298 55.2253 52.5298 53.6601V50.0293H45.478Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M28.6957 41.8652H25.065C23.4997 41.8652 22.2087 43.14 22.2087 44.7214V46.0608C22.2087 47.6261 23.4836 48.917 25.065 48.917H28.6957V41.8652Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M57.2738 41.8652H37.9903V48.917H57.2738C58.839 48.917 60.13 47.6261 60.13 46.0608V44.7214C60.13 43.14 58.839 41.8652 57.2738 41.8652Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M44.3484 26.2129H25.065C23.4997 26.2129 22.2087 27.4877 22.2087 29.0691V30.4084C22.2087 31.9737 23.4836 33.2647 25.065 33.2647H44.3484V26.2129Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M57.2738 26.2128H53.6431V33.2646H57.2738C58.8391 33.2646 60.1301 31.9898 60.1301 30.4084V29.069C60.1301 27.4876 58.8391 26.2128 57.2738 26.2128Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M108.864 99.4959H129.086C129.852 99.4959 130.587 99.8008 131.129 100.343C131.671 100.886 131.975 101.622 131.975 102.39L131.975 127.191C131.975 128.296 130.688 128.899 129.841 128.191L124.6 123.804H108.864C108.098 123.804 107.363 123.499 106.821 122.956C106.279 122.413 105.975 121.677 105.975 120.91V102.39C105.975 101.622 106.279 100.886 106.821 100.343C107.363 99.8008 108.098 99.4959 108.864 99.4959ZM116.549 112.318H110.597V104.126H127.353V112.318H121.499V115.152H123.64C124.026 115.152 124.22 115.619 123.947 115.893L119.331 120.517C119.161 120.686 118.887 120.686 118.718 120.517L114.102 115.893C113.829 115.619 114.022 115.152 114.408 115.152H116.549V112.318Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M190.408 151.152V162.299C190.408 163.204 191.145 163.95 192.059 163.95H192.833C193.738 163.95 194.484 163.204 194.484 162.299V151.152H190.408Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M194.475 145.779V143.68C194.475 142.775 193.738 142.029 192.833 142.029H192.059C191.154 142.029 190.408 142.775 190.408 143.68V145.779H194.475Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M203.523 154.827V143.68C203.523 142.775 202.786 142.029 201.881 142.029H201.107C200.202 142.029 199.456 142.775 199.456 143.68V154.827H203.523Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M199.456 160.201V162.3C199.456 163.204 200.202 163.951 201.107 163.951H201.881C202.786 163.951 203.533 163.204 203.533 162.3V160.201H199.456Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M189.755 155.48H187.656C186.751 155.48 186.005 156.217 186.005 157.131V157.905C186.005 158.81 186.742 159.556 187.656 159.556H189.755V155.48Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M206.275 155.48H195.128V159.556H206.275C207.18 159.556 207.926 158.81 207.926 157.905V157.131C207.926 156.217 207.18 155.48 206.275 155.48Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M198.803 146.433H187.656C186.751 146.433 186.005 147.17 186.005 148.084V148.859C186.005 149.763 186.742 150.51 187.656 150.51H198.803V146.433Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M206.275 146.433H204.176V150.51H206.275C207.18 150.51 207.926 149.773 207.926 148.859V148.084C207.926 147.17 207.18 146.433 206.275 146.433Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 21 KiB |
105
briar-android/artwork/mailbox_onboarding_light.svg
Normal file
105
briar-android/artwork/mailbox_onboarding_light.svg
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<svg width="250" height="200" viewBox="0 0 250 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M95.4363 100.737C95.4363 94.0273 100.876 88.588 107.585 88.588H130.365C137.074 88.588 142.514 94.0273 142.514 100.737V123.516C142.514 130.226 137.074 135.665 130.365 135.665H107.585C100.876 135.665 95.4363 130.226 95.4363 123.516V100.737Z"
|
||||||
|
fill="#F6FAFE" />
|
||||||
|
<path
|
||||||
|
d="M102.336 10.7649C102.336 5.09801 106.93 0.504059 112.597 0.504059H131.836C137.503 0.504059 142.097 5.09801 142.097 10.7649V30.0041C142.097 35.671 137.503 40.2649 131.836 40.2649H112.597C106.93 40.2649 102.336 35.671 102.336 30.0041V10.7649Z"
|
||||||
|
fill="#F6FAFE" />
|
||||||
|
<path
|
||||||
|
d="M34.8184 148.594C34.8184 143.931 38.5986 140.151 43.2618 140.151H59.0933C63.7565 140.151 67.5368 143.931 67.5368 148.594V164.426C67.5368 169.089 63.7565 172.869 59.0933 172.869H43.2618C38.5986 172.869 34.8184 169.089 34.8184 164.426V148.594Z"
|
||||||
|
fill="#F6FAFE" />
|
||||||
|
<path
|
||||||
|
d="M110.024 186.549C110.024 184.061 112.04 182.045 114.527 182.045H122.971C125.458 182.045 127.475 184.061 127.475 186.549V194.992C127.475 197.48 125.458 199.496 122.971 199.496H114.527C112.04 199.496 110.024 197.48 110.024 194.992V186.549Z"
|
||||||
|
fill="#F6FAFE" />
|
||||||
|
<path
|
||||||
|
d="M173.713 142.104C173.713 135.395 179.152 129.955 185.862 129.955H208.641C215.351 129.955 220.79 135.395 220.79 142.104V164.884C220.79 171.593 215.351 177.033 208.641 177.033H185.862C179.152 177.033 173.713 171.593 173.713 164.884V142.104Z"
|
||||||
|
fill="#F6FAFE" />
|
||||||
|
<path
|
||||||
|
d="M232.049 95.9196C232.049 93.4324 234.065 91.4162 236.553 91.4162H244.997C247.484 91.4162 249.5 93.4324 249.5 95.9196V104.364C249.5 106.851 247.484 108.867 244.997 108.867H236.553C234.065 108.867 232.049 106.851 232.049 104.364V95.9196Z"
|
||||||
|
fill="#F6FAFE" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M120.481 84.7314V45.7716H122.481V84.7314H120.481Z" fill="#657D99" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M117.685 176.605L117.685 140.151H119.685L119.685 176.605H117.685Z" fill="#657D99" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M3.27959 108.949L4.0457 107.102C4.3381 107.223 4.66032 107.291 5.00345 107.291H7.11444V109.291H5.00345C4.39282 109.291 3.81058 109.169 3.27959 108.949ZM11.3364 109.291V107.291H13.4474C13.7905 107.291 14.1128 107.223 14.4052 107.102L15.1713 108.949C14.6403 109.169 14.058 109.291 13.4474 109.291H11.3364ZM17.9509 98.4544H15.9509V96.3434C15.9509 96.0003 15.8829 95.6781 15.7617 95.3857L17.6091 94.6196C17.8293 95.1506 17.9509 95.7328 17.9509 96.3434V98.4544ZM7.11444 91.84H5.00345C4.39282 91.84 3.81058 91.9615 3.27959 92.1817L4.0457 94.0292C4.3381 93.9079 4.66032 93.84 5.00345 93.84H7.11444V91.84ZM0.500008 102.676H2.50001V104.787C2.50001 105.131 2.56793 105.453 2.68918 105.745L0.841732 106.511C0.621538 105.98 0.500008 105.398 0.500008 104.787V102.676ZM0.500008 98.4544H2.50001V96.3434C2.50001 96.0003 2.56793 95.6781 2.68918 95.3857L0.841731 94.6196C0.621538 95.1506 0.500008 95.7328 0.500008 96.3434V98.4544ZM11.3364 91.84V93.84H13.4474C13.7905 93.84 14.1128 93.9079 14.4052 94.0292L15.1713 92.1817C14.6403 91.9615 14.058 91.84 13.4474 91.84H11.3364ZM17.9509 102.676H15.9509V104.787C15.9509 105.131 15.8829 105.453 15.7617 105.745L17.6091 106.511C17.8293 105.98 17.9509 105.398 17.9509 104.787V102.676Z"
|
||||||
|
fill="#657D99" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M41.1771 65.021V63.1525H43.1771V65.021H41.1771ZM41.1771 72.4948V68.7579H43.1771V72.4948H41.1771ZM41.1771 79.9687V76.2318H43.1771V79.9687H41.1771ZM41.1771 87.4426V83.7057H43.1771V87.4426H41.1771ZM41.1771 94.9165V91.1795H43.1771V94.9165H41.1771ZM41.1771 99.5219V98.6534H43.1771V99.5219H44.9095V101.522H39.681V99.5219H41.1771ZM24.7048 101.522H22.2087V99.5219H24.7048V101.522ZM34.6889 101.522H29.6969V99.5219H34.6889V101.522ZM52.1068 101.522H50.3744V99.5219H54.8543V101.522H54.1068V102.652H52.1068V101.522ZM61.8442 101.522H58.3493V99.5219H61.8442V101.522ZM67.0867 101.522H65.3392V99.5219H67.0867C68.0476 99.5219 68.9663 99.7133 69.8048 100.061L69.0387 101.908C68.4388 101.66 67.7801 101.522 67.0867 101.522ZM72.187 106.622C72.187 105.929 72.0492 105.27 71.8004 104.67L73.6478 103.904C73.9955 104.743 74.187 105.661 74.187 106.622C74.187 107.316 74.3248 107.974 74.5736 108.574L72.7261 109.34C72.3784 108.502 72.187 107.583 72.187 106.622ZM52.1068 111.172V106.912H54.1068V111.172H52.1068ZM79.2873 113.722C78.3264 113.722 77.4077 113.531 76.5691 113.183L77.3352 111.336C77.9352 111.585 78.5939 111.722 79.2873 111.722H81.5905V113.722H79.2873ZM88.5 113.722H86.1968V111.722H88.5V113.722ZM52.1068 119.692V115.432H54.1068V119.692H52.1068ZM52.1068 128.213V123.953H54.1068V128.213H52.1068ZM52.1068 134.603V132.473H54.1068V134.603H52.1068Z"
|
||||||
|
fill="#74B816" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M105.214 135.434L105.602 133.472C106.242 133.599 106.905 133.665 107.585 133.665H109.484V135.665H107.585C106.774 135.665 105.981 135.586 105.214 135.434ZM128.466 135.665V133.665H130.365C131.045 133.665 131.708 133.599 132.347 133.472L132.736 135.434C131.969 135.586 131.176 135.665 130.365 135.665H128.466ZM137.115 133.619L136.002 131.957C137.11 131.216 138.064 130.262 138.805 129.154L140.467 130.267C139.58 131.591 138.44 132.732 137.115 133.619ZM142.514 102.635H140.514V100.737C140.514 100.057 140.447 99.3939 140.32 98.7541L142.282 98.366C142.434 99.1329 142.514 99.9257 142.514 100.737V102.635ZM140.467 93.9869L138.805 95.0995C138.064 93.9919 137.11 93.0378 136.002 92.2963L137.115 90.6344C138.44 91.5213 139.58 92.662 140.467 93.9869ZM109.484 88.588H107.585C106.774 88.588 105.981 88.6676 105.214 88.8193L105.602 90.7813C106.242 90.6547 106.905 90.588 107.585 90.588H109.484V88.588ZM100.835 90.6344L101.948 92.2963C100.84 93.0378 99.8861 93.9919 99.1445 95.0995L97.4826 93.9869C98.3696 92.662 99.5102 91.5213 100.835 90.6344ZM95.4363 121.618H97.4363V123.516C97.4363 124.197 97.503 124.86 97.6295 125.499L95.6675 125.887C95.5158 125.121 95.4363 124.328 95.4363 123.516V121.618ZM97.4826 130.267L99.1445 129.154C99.8861 130.262 100.84 131.216 101.948 131.957L100.835 133.619C99.5102 132.732 98.3696 131.591 97.4826 130.267ZM95.4363 117.822H97.4363V114.025H95.4363V117.822ZM95.4363 110.228H97.4363V106.432H95.4363V110.228ZM95.4363 102.635H97.4363V100.737C97.4363 100.057 97.503 99.3939 97.6295 98.7541L95.6675 98.366C95.5158 99.1329 95.4363 99.9257 95.4363 100.737V102.635ZM113.28 88.588V90.588H117.077V88.588H113.28ZM120.873 88.588V90.588H124.67V88.588H120.873ZM128.466 88.588V90.588H130.365C131.045 90.588 131.708 90.6547 132.347 90.7813L132.736 88.8193C131.969 88.6676 131.176 88.588 130.365 88.588H128.466ZM142.514 106.432H140.514V110.228H142.514V106.432ZM142.514 114.025H140.514V117.822H142.514V114.025ZM142.514 121.618H140.514V123.516C140.514 124.197 140.447 124.86 140.32 125.499L142.282 125.887C142.434 125.121 142.514 124.328 142.514 123.516V121.618ZM124.67 135.665V133.665H120.873V135.665H124.67ZM117.077 135.665V133.665H113.28V135.665H117.077Z"
|
||||||
|
fill="#74B816" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M188.618 87.0429V85.1779H190.618V87.0429H188.618ZM188.618 94.5032V90.7731H190.618V94.5032H188.618ZM188.618 98.2333H190.618V99.0984H191.517V101.098H190.618V101.687H188.618V98.2333ZM199.112 101.098H195.315V99.0984H199.112V101.098ZM206.707 101.098H202.91V99.0984H206.707V101.098ZM214.303 101.098H210.505V99.0984H214.303V101.098ZM221.898 101.098H218.1V99.0984H221.898V101.098ZM227.595 101.098H225.696V99.0984H227.595V101.098ZM188.618 108.042V104.864H190.618V108.042H188.618ZM188.618 111.807V111.219H190.618V111.863C190.865 111.891 191.109 111.929 191.35 111.976L190.962 113.938C190.528 113.853 190.079 113.807 189.618 113.807H187.737V111.807H188.618ZM153.881 113.807H152V111.807H153.881V113.807ZM161.405 113.807H157.643V111.807H161.405V113.807ZM168.928 113.807H165.166V111.807H168.928V113.807ZM176.452 113.807H172.69V111.807H176.452V113.807ZM183.975 113.807H180.214V111.807H183.975V113.807ZM195.34 116.865C194.837 116.115 194.19 115.468 193.44 114.966L194.552 113.304C195.52 113.952 196.353 114.785 197.001 115.753L195.34 116.865ZM196.498 120.687C196.498 120.226 196.453 119.777 196.367 119.343L198.329 118.955C198.44 119.516 198.498 120.095 198.498 120.687V121.707H196.498V120.687ZM196.498 124.765V123.746H198.498V124.765H196.498Z"
|
||||||
|
fill="#74B816" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M183.491 176.801L183.879 174.839C184.519 174.966 185.182 175.033 185.862 175.033H187.76V177.033H185.862C185.051 177.033 184.258 176.953 183.491 176.801ZM206.743 177.033V175.033H208.641C209.322 175.033 209.985 174.966 210.624 174.839L211.012 176.801C210.246 176.953 209.453 177.033 208.641 177.033H206.743ZM215.392 174.986L214.279 173.324C215.387 172.583 216.341 171.629 217.082 170.521L218.744 171.634C217.857 172.959 216.717 174.099 215.392 174.986ZM220.79 144.002H218.79V142.104C218.79 141.424 218.724 140.761 218.597 140.121L220.559 139.733C220.711 140.5 220.79 141.293 220.79 142.104V144.002ZM218.744 135.354L217.082 136.467C216.341 135.359 215.387 134.405 214.279 133.663L215.392 132.002C216.717 132.889 217.857 134.029 218.744 135.354ZM187.76 129.955H185.862C185.051 129.955 184.258 130.035 183.491 130.186L183.879 132.148C184.519 132.022 185.182 131.955 185.862 131.955H187.76V129.955ZM179.112 132.002L180.225 133.663C179.117 134.405 178.163 135.359 177.421 136.467L175.759 135.354C176.646 134.029 177.787 132.889 179.112 132.002ZM173.713 162.985H175.713V164.884C175.713 165.564 175.78 166.227 175.906 166.866L173.944 167.255C173.793 166.488 173.713 165.695 173.713 164.884V162.985ZM175.759 171.634L177.421 170.521C178.163 171.629 179.117 172.583 180.225 173.324L179.112 174.986C177.787 174.099 176.646 172.959 175.759 171.634ZM173.713 159.189H175.713V155.392H173.713V159.189ZM173.713 151.596H175.713V147.799H173.713V151.596ZM173.713 144.002H175.713V142.104C175.713 141.424 175.78 140.761 175.906 140.121L173.944 139.733C173.793 140.5 173.713 141.293 173.713 142.104V144.002ZM191.557 129.955V131.955H195.354V129.955H191.557ZM199.15 129.955V131.955H202.947V129.955H199.15ZM206.743 129.955V131.955H208.641C209.322 131.955 209.985 132.022 210.624 132.148L211.012 130.186C210.246 130.035 209.453 129.955 208.641 129.955H206.743ZM220.79 147.799H218.79V151.596H220.79V147.799ZM220.79 155.392H218.79V159.189H220.79V155.392ZM220.79 162.985H218.79V164.884C218.79 165.564 218.724 166.227 218.597 166.866L220.559 167.255C220.711 166.488 220.79 165.695 220.79 164.884V162.985ZM202.947 177.033V175.033H199.15V177.033H202.947ZM195.354 177.033V175.033H191.557V177.033H195.354Z"
|
||||||
|
fill="#74B816" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M110.594 40.0696L110.982 38.1076C111.503 38.2106 112.042 38.2649 112.597 38.2649H115.001V40.2649H112.597C111.911 40.2649 111.242 40.1978 110.594 40.0696ZM129.431 40.2649V38.2649H131.836C132.39 38.2649 132.93 38.2106 133.45 38.1076L133.838 40.0696C133.191 40.1978 132.521 40.2649 131.836 40.2649H129.431ZM137.537 38.5366L136.424 36.8747C137.326 36.271 138.103 35.4942 138.706 34.5925L140.368 35.7052C139.619 36.8241 138.656 37.7875 137.537 38.5366ZM142.097 13.1698H140.097V10.7649C140.097 10.2107 140.042 9.67106 139.939 9.15053L141.901 8.76239C142.029 9.41006 142.097 10.0797 142.097 10.7649V13.1698ZM140.368 5.06383L138.706 6.17647C138.103 5.27474 137.326 4.49797 136.424 3.89428L137.537 2.23234C138.656 2.98147 139.619 3.94486 140.368 5.06383ZM115.001 0.504059H112.597C111.911 0.504059 111.242 0.571236 110.594 0.699365L110.982 2.66134C111.503 2.55836 112.042 2.50406 112.597 2.50406H115.001V0.504059ZM106.895 2.23235L108.008 3.89428C107.106 4.49797 106.33 5.27475 105.726 6.17647L104.064 5.06383C104.813 3.94487 105.777 2.98147 106.895 2.23235ZM102.336 27.5992H104.336V30.0041C104.336 30.5583 104.39 31.0979 104.493 31.6185L102.531 32.0066C102.403 31.3589 102.336 30.6893 102.336 30.0041V27.5992ZM104.064 35.7052L105.726 34.5925C106.33 35.4942 107.106 36.271 108.008 36.8747L106.895 38.5366C105.777 37.7875 104.813 36.8241 104.064 35.7052ZM102.336 22.7894H104.336V17.9796H102.336V22.7894ZM102.336 13.1698H104.336V10.7649C104.336 10.2107 104.39 9.67106 104.493 9.15053L102.531 8.7624C102.403 9.41007 102.336 10.0797 102.336 10.7649V13.1698ZM119.811 0.504059V2.50406H124.621V0.504059H119.811ZM129.431 0.504059V2.50406H131.836C132.39 2.50406 132.93 2.55836 133.45 2.66134L133.838 0.699365C133.191 0.571236 132.521 0.504059 131.836 0.504059H129.431ZM142.097 17.9796H140.097V22.7894H142.097V17.9796ZM142.097 27.5992H140.097V30.0041C140.097 30.5583 140.042 31.0979 139.939 31.6185L141.901 32.0066C142.029 31.3589 142.097 30.6893 142.097 30.0041V27.5992ZM124.621 40.2649V38.2649H119.811V40.2649H124.621Z"
|
||||||
|
fill="#435B77" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M40.0298 172.228L40.7959 170.381C41.5528 170.695 42.3845 170.869 43.2618 170.869H45.2408V172.869H43.2618C42.117 172.869 41.0253 172.641 40.0298 172.228ZM57.1144 172.869V170.869H59.0933C59.9707 170.869 60.8023 170.695 61.5593 170.381L62.3254 172.228C61.3298 172.641 60.2382 172.869 59.0933 172.869H57.1144ZM67.5368 150.573H65.5368V148.594C65.5368 147.717 65.3625 146.885 65.0486 146.128L66.8961 145.362C67.3089 146.358 67.5368 147.449 67.5368 148.594V150.573ZM45.2408 140.151H43.2618C42.117 140.151 41.0253 140.378 40.0298 140.791L40.7959 142.639C41.5528 142.325 42.3845 142.151 43.2618 142.151H45.2408V140.151ZM34.8184 162.447H36.8184V164.426C36.8184 165.303 36.9926 166.134 37.3065 166.891L35.4591 167.658C35.0462 166.662 34.8184 165.57 34.8184 164.426V162.447ZM34.8184 158.489H36.8184V154.531H34.8184V158.489ZM34.8184 150.573H36.8184V148.594C36.8184 147.717 36.9926 146.885 37.3065 146.128L35.4591 145.362C35.0462 146.358 34.8184 147.449 34.8184 148.594V150.573ZM49.1986 140.151V142.151H53.1565V140.151H49.1986ZM57.1144 140.151V142.151H59.0933C59.9707 142.151 60.8023 142.325 61.5593 142.639L62.3254 140.791C61.3298 140.378 60.2382 140.151 59.0933 140.151H57.1144ZM67.5368 154.531H65.5368V158.489H67.5368V154.531ZM67.5368 162.447H65.5368V164.426C65.5368 165.303 65.3625 166.134 65.0486 166.891L66.8961 167.658C67.3089 166.662 67.5368 165.57 67.5368 164.426V162.447ZM53.1565 172.869V170.869H49.1986V172.869H53.1565Z"
|
||||||
|
fill="#435B77" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M112.803 199.154L113.569 197.307C113.862 197.428 114.184 197.496 114.527 197.496H116.638V199.496H114.527C113.917 199.496 113.334 199.374 112.803 199.154ZM120.86 199.496V197.496H122.971C123.314 197.496 123.636 197.428 123.929 197.307L124.695 199.154C124.164 199.374 123.582 199.496 122.971 199.496H120.86ZM127.475 188.66H125.475V186.549C125.475 186.205 125.407 185.883 125.285 185.591L127.133 184.825C127.353 185.356 127.475 185.938 127.475 186.549V188.66ZM116.638 182.045H114.527C113.917 182.045 113.334 182.167 112.803 182.387L113.569 184.234C113.862 184.113 114.184 184.045 114.527 184.045H116.638V182.045ZM110.024 192.881H112.024V194.992C112.024 195.336 112.092 195.658 112.213 195.95L110.365 196.716C110.145 196.185 110.024 195.603 110.024 194.992V192.881ZM110.024 188.66H112.024V186.549C112.024 186.205 112.092 185.883 112.213 185.591L110.365 184.825C110.145 185.356 110.024 185.938 110.024 186.549V188.66ZM120.86 182.045V184.045H122.971C123.314 184.045 123.636 184.113 123.929 184.234L124.695 182.387C124.164 182.167 123.582 182.045 122.971 182.045H120.86ZM127.475 192.881H125.475V194.992C125.475 195.336 125.407 195.658 125.285 195.95L127.133 196.716C127.353 196.185 127.475 195.603 127.475 194.992V192.881Z"
|
||||||
|
fill="#435B77" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M178.996 80.3275L179.762 78.4801C180.48 78.7778 181.269 78.9431 182.101 78.9431H184.003V80.9431H182.101C181.001 80.9431 179.952 80.7242 178.996 80.3275ZM195.412 80.9431V78.9431H197.314C198.146 78.9431 198.935 78.7778 199.653 78.4801L200.419 80.3275C199.463 80.7242 198.414 80.9431 197.314 80.9431H195.412ZM205.427 59.5189H203.427V57.6174C203.427 56.7848 203.262 55.9958 202.964 55.2778L204.811 54.5117C205.208 55.4683 205.427 56.5173 205.427 57.6174V59.5189ZM184.003 49.5041H182.101C181.001 49.5041 179.952 49.723 178.996 50.1197L179.762 51.9672C180.48 51.6694 181.269 51.5041 182.101 51.5041H184.003V49.5041ZM173.988 70.9283H175.988V72.8298C175.988 73.6624 176.153 74.4514 176.451 75.1694L174.604 75.9355C174.207 74.9789 173.988 73.9299 173.988 72.8298V70.9283ZM173.988 67.1252H175.988V63.322H173.988V67.1252ZM173.988 59.5189H175.988V57.6174C175.988 56.7848 176.153 55.9958 176.451 55.2778L174.604 54.5117C174.207 55.4683 173.988 56.5173 173.988 57.6174V59.5189ZM187.806 49.5041V51.5041H191.609V49.5041H187.806ZM195.412 49.5041V51.5041H197.314C198.146 51.5041 198.935 51.6694 199.653 51.9672L200.419 50.1197C199.463 49.723 198.414 49.5041 197.314 49.5041H195.412ZM205.427 63.322H203.427V67.1252H205.427V63.322ZM205.427 70.9283H203.427V72.8298C203.427 73.6624 203.262 74.4514 202.964 75.1694L204.811 75.9355C205.208 74.9789 205.427 73.9299 205.427 72.8298V70.9283ZM191.609 80.9431V78.9431H187.806V80.9431H191.609Z"
|
||||||
|
fill="#657D99" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M234.829 108.525L235.595 106.678C235.887 106.799 236.209 106.867 236.553 106.867H238.664V108.867H236.553C235.942 108.867 235.36 108.745 234.829 108.525ZM242.886 108.867V106.867H244.997C245.34 106.867 245.662 106.799 245.954 106.678L246.72 108.525C246.189 108.745 245.607 108.867 244.997 108.867H242.886ZM249.5 98.0306H247.5V95.9196C247.5 95.5765 247.432 95.2543 247.311 94.9619L249.158 94.1957C249.378 94.7267 249.5 95.309 249.5 95.9196V98.0306ZM238.664 91.4162H236.553C235.942 91.4162 235.36 91.5377 234.829 91.7579L235.595 93.6053C235.887 93.4841 236.209 93.4162 236.553 93.4162H238.664V91.4162ZM232.049 102.253H234.049V104.364C234.049 104.707 234.117 105.029 234.238 105.321L232.391 106.087C232.171 105.556 232.049 104.974 232.049 104.364V102.253ZM232.049 98.0306H234.049V95.9196C234.049 95.5765 234.117 95.2543 234.238 94.9619L232.391 94.1957C232.171 94.7267 232.049 95.309 232.049 95.9196V98.0306ZM242.886 91.4162V93.4162H244.997C245.34 93.4162 245.662 93.4841 245.954 93.6053L246.72 91.7579C246.189 91.5377 245.607 91.4162 244.997 91.4162H242.886ZM249.5 102.253H247.5V104.364C247.5 104.707 247.432 105.029 247.311 105.321L249.158 106.087C249.378 105.556 249.5 104.974 249.5 104.364V102.253Z"
|
||||||
|
fill="#435B77" />
|
||||||
|
<path
|
||||||
|
d="M29.8254 34.881V54.1644C29.8254 55.7297 31.1003 57.0206 32.6817 57.0206H34.021C35.5863 57.0206 36.8772 55.7297 36.8772 54.1644V34.881H29.8254Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M36.8611 25.5867V21.956C36.8611 20.3907 35.5863 19.0998 34.021 19.0998H32.6817C31.1164 19.0998 29.8254 20.3907 29.8254 21.956V25.5867H36.8611Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M52.5136 41.2394V21.956C52.5136 20.3907 51.2388 19.0998 49.6735 19.0998H48.3342C46.7689 19.0998 45.478 20.3907 45.478 21.956V41.2394H52.5136Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M45.478 50.5334V54.1641C45.478 55.7294 46.7689 57.0203 48.3342 57.0203H49.6735C51.2388 57.0203 52.5298 55.7294 52.5298 54.1641V50.5334H45.478Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M28.6957 42.3693H25.065C23.4997 42.3693 22.2087 43.6441 22.2087 45.2255V46.5648C22.2087 48.1301 23.4836 49.4211 25.065 49.4211H28.6957V42.3693Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M57.2738 42.3693H37.9903V49.4211H57.2738C58.839 49.4211 60.13 48.1301 60.13 46.5648V45.2255C60.13 43.6441 58.839 42.3693 57.2738 42.3693Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M44.3484 26.7169H25.065C23.4997 26.7169 22.2087 27.9918 22.2087 29.5732V30.9125C22.2087 32.4778 23.4836 33.7687 25.065 33.7687H44.3484V26.7169Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M57.2738 26.7169H53.6431V33.7687H57.2738C58.8391 33.7687 60.1301 32.4938 60.1301 30.9124V29.5731C60.1301 27.9917 58.8391 26.7169 57.2738 26.7169Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M108.864 100H129.086C129.852 100 130.587 100.305 131.129 100.848C131.671 101.39 131.975 102.126 131.975 102.894L131.975 127.695C131.975 128.8 130.688 129.403 129.841 128.695L124.6 124.308H108.864C108.098 124.308 107.363 124.003 106.821 123.46C106.279 122.917 105.975 122.181 105.975 121.414V102.894C105.975 102.126 106.279 101.39 106.821 100.848C107.363 100.305 108.098 100 108.864 100ZM116.549 112.823H110.597V104.63H127.353V112.823H121.499V115.656H123.64C124.026 115.656 124.22 116.123 123.947 116.397L119.331 121.021C119.161 121.19 118.887 121.19 118.718 121.021L114.102 116.397C113.829 116.123 114.022 115.656 114.408 115.656H116.549V112.823Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M190.408 151.656V162.803C190.408 163.708 191.145 164.454 192.059 164.454H192.833C193.738 164.454 194.484 163.708 194.484 162.803V151.656H190.408Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M194.475 146.283V144.184C194.475 143.279 193.738 142.533 192.833 142.533H192.059C191.154 142.533 190.408 143.279 190.408 144.184V146.283H194.475Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M203.523 155.331V144.184C203.523 143.279 202.786 142.533 201.881 142.533H201.107C200.202 142.533 199.456 143.279 199.456 144.184V155.331H203.523Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M199.456 160.705V162.804C199.456 163.709 200.202 164.455 201.107 164.455H201.881C202.786 164.455 203.533 163.709 203.533 162.804V160.705H199.456Z"
|
||||||
|
fill="#82C91E" />
|
||||||
|
<path
|
||||||
|
d="M189.755 155.984H187.656C186.751 155.984 186.005 156.721 186.005 157.635V158.409C186.005 159.314 186.742 160.061 187.656 160.061H189.755V155.984Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M206.275 155.984H195.128V160.061H206.275C207.18 160.061 207.926 159.314 207.926 158.409V157.635C207.926 156.721 207.18 155.984 206.275 155.984Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M198.803 146.937H187.656C186.751 146.937 186.005 147.674 186.005 148.588V149.363C186.005 150.267 186.742 151.014 187.656 151.014H198.803V146.937Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
<path
|
||||||
|
d="M206.275 146.937H204.176V151.014H206.275C207.18 151.014 207.926 150.277 207.926 149.363V148.588C207.926 147.674 207.18 146.937 206.275 146.937Z"
|
||||||
|
fill="#95DE2D" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 21 KiB |
@@ -26,8 +26,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 10404
|
versionCode 10405
|
||||||
versionName "1.4.4"
|
versionName "1.4.5"
|
||||||
applicationId "org.briarproject.briar.android"
|
applicationId "org.briarproject.briar.android"
|
||||||
|
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
|
|||||||
@@ -477,6 +477,17 @@
|
|||||||
android:value="org.briarproject.briar.android.conversation.ConversationActivity" />
|
android:value="org.briarproject.briar.android.conversation.ConversationActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".android.mailbox.MailboxActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/mailbox_settings_title"
|
||||||
|
android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity"
|
||||||
|
android:theme="@style/BriarTheme">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value="org.briarproject.briar.android.settings.SettingsActivity" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ import org.briarproject.briar.android.hotspot.ManualHotspotFragment;
|
|||||||
import org.briarproject.briar.android.hotspot.QrHotspotFragment;
|
import org.briarproject.briar.android.hotspot.QrHotspotFragment;
|
||||||
import org.briarproject.briar.android.logging.CachingLogHandler;
|
import org.briarproject.briar.android.logging.CachingLogHandler;
|
||||||
import org.briarproject.briar.android.login.SignInReminderReceiver;
|
import org.briarproject.briar.android.login.SignInReminderReceiver;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxScanFragment;
|
||||||
|
import org.briarproject.briar.android.mailbox.OfflineFragment;
|
||||||
|
import org.briarproject.briar.android.mailbox.SetupDownloadFragment;
|
||||||
import org.briarproject.briar.android.removabledrive.ChooserFragment;
|
import org.briarproject.briar.android.removabledrive.ChooserFragment;
|
||||||
import org.briarproject.briar.android.removabledrive.ReceiveFragment;
|
import org.briarproject.briar.android.removabledrive.ReceiveFragment;
|
||||||
import org.briarproject.briar.android.removabledrive.SendFragment;
|
import org.briarproject.briar.android.removabledrive.SendFragment;
|
||||||
@@ -239,4 +242,10 @@ public interface AndroidComponent
|
|||||||
void inject(ReceiveFragment receiveFragment);
|
void inject(ReceiveFragment receiveFragment);
|
||||||
|
|
||||||
void inject(BluetoothIntroFragment bluetoothIntroFragment);
|
void inject(BluetoothIntroFragment bluetoothIntroFragment);
|
||||||
|
|
||||||
|
void inject(SetupDownloadFragment setupDownloadFragment);
|
||||||
|
|
||||||
|
void inject(MailboxScanFragment mailboxScanFragment);
|
||||||
|
|
||||||
|
void inject(OfflineFragment offlineFragment);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
|
|||||||
import org.briarproject.bramble.plugin.tor.AndroidTorPluginFactory;
|
import org.briarproject.bramble.plugin.tor.AndroidTorPluginFactory;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
import org.briarproject.briar.BuildConfig;
|
||||||
import org.briarproject.briar.android.account.DozeHelperModule;
|
import org.briarproject.briar.android.account.DozeHelperModule;
|
||||||
import org.briarproject.briar.android.account.LockManagerImpl;
|
import org.briarproject.briar.android.account.LockManagerImpl;
|
||||||
import org.briarproject.briar.android.account.SetupModule;
|
import org.briarproject.briar.android.account.SetupModule;
|
||||||
@@ -340,6 +341,11 @@ public class AppModule {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldEnableMailbox() {
|
||||||
|
return BuildConfig.DEBUG;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldEnablePrivateGroupsInCore() {
|
public boolean shouldEnablePrivateGroupsInCore() {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import org.briarproject.briar.android.login.ChangePasswordActivity;
|
|||||||
import org.briarproject.briar.android.login.OpenDatabaseFragment;
|
import org.briarproject.briar.android.login.OpenDatabaseFragment;
|
||||||
import org.briarproject.briar.android.login.PasswordFragment;
|
import org.briarproject.briar.android.login.PasswordFragment;
|
||||||
import org.briarproject.briar.android.login.StartupActivity;
|
import org.briarproject.briar.android.login.StartupActivity;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxActivity;
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||||
import org.briarproject.briar.android.navdrawer.TransportsActivity;
|
import org.briarproject.briar.android.navdrawer.TransportsActivity;
|
||||||
import org.briarproject.briar.android.panic.PanicPreferencesActivity;
|
import org.briarproject.briar.android.panic.PanicPreferencesActivity;
|
||||||
@@ -250,4 +251,6 @@ public interface ActivityComponent {
|
|||||||
void inject(RssFeedDeleteFeedDialogFragment fragment);
|
void inject(RssFeedDeleteFeedDialogFragment fragment);
|
||||||
|
|
||||||
void inject(ConnectViaBluetoothActivity connectViaBluetoothActivity);
|
void inject(ConnectViaBluetoothActivity connectViaBluetoothActivity);
|
||||||
|
|
||||||
|
void inject(MailboxActivity mailboxActivity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,12 +181,6 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||||||
showFragment(getSupportFragmentManager(), f, f.getUniqueTag());
|
showFragment(getSupportFragmentManager(), f, f.getUniqueTag());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isFragmentAdded(String fragmentTag) {
|
|
||||||
FragmentManager fm = getSupportFragmentManager();
|
|
||||||
Fragment f = fm.findFragmentByTag(fragmentTag);
|
|
||||||
return f != null && f.isAdded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean showScreenFilterWarning() {
|
private boolean showScreenFilterWarning() {
|
||||||
if (((BriarApplication) getApplication()).isInstrumentationTest()) {
|
if (((BriarApplication) getApplication()).isInstrumentationTest()) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -3,11 +3,10 @@ package org.briarproject.briar.android.contact.add.nearby;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.util.Permission;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
@@ -17,16 +16,13 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
|||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale;
|
import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale;
|
||||||
import static androidx.core.content.ContextCompat.checkSelfPermission;
|
import static androidx.core.content.ContextCompat.checkSelfPermission;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.getGoToSettingsListener;
|
|
||||||
import static org.briarproject.briar.android.util.UiUtils.isLocationEnabled;
|
import static org.briarproject.briar.android.util.UiUtils.isLocationEnabled;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.showDenialDialog;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.showLocationDialog;
|
import static org.briarproject.briar.android.util.UiUtils.showLocationDialog;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.showRationale;
|
||||||
|
|
||||||
class AddNearbyContactPermissionManager {
|
class AddNearbyContactPermissionManager {
|
||||||
|
|
||||||
private enum Permission {
|
|
||||||
UNKNOWN, GRANTED, SHOW_RATIONALE, PERMANENTLY_DENIED
|
|
||||||
}
|
|
||||||
|
|
||||||
private Permission cameraPermission = Permission.UNKNOWN;
|
private Permission cameraPermission = Permission.UNKNOWN;
|
||||||
private Permission locationPermission = Permission.UNKNOWN;
|
private Permission locationPermission = Permission.UNKNOWN;
|
||||||
|
|
||||||
@@ -68,27 +64,30 @@ class AddNearbyContactPermissionManager {
|
|||||||
// If an essential permission has been permanently denied, ask the
|
// If an essential permission has been permanently denied, ask the
|
||||||
// user to change the setting
|
// user to change the setting
|
||||||
if (cameraPermission == Permission.PERMANENTLY_DENIED) {
|
if (cameraPermission == Permission.PERMANENTLY_DENIED) {
|
||||||
showDenialDialog(R.string.permission_camera_title,
|
showDenialDialog(ctx, R.string.permission_camera_title,
|
||||||
R.string.permission_camera_denied_body);
|
R.string.permission_camera_denied_body);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isBluetoothSupported &&
|
if (isBluetoothSupported &&
|
||||||
locationPermission == Permission.PERMANENTLY_DENIED) {
|
locationPermission == Permission.PERMANENTLY_DENIED) {
|
||||||
showDenialDialog(R.string.permission_location_title,
|
showDenialDialog(ctx, R.string.permission_location_title,
|
||||||
R.string.permission_location_denied_body);
|
R.string.permission_location_denied_body);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Should we show the rationale for one or both permissions?
|
// Should we show the rationale for one or both permissions?
|
||||||
if (cameraPermission == Permission.SHOW_RATIONALE &&
|
if (cameraPermission == Permission.SHOW_RATIONALE &&
|
||||||
locationPermission == Permission.SHOW_RATIONALE) {
|
locationPermission == Permission.SHOW_RATIONALE) {
|
||||||
showRationale(R.string.permission_camera_location_title,
|
showRationale(ctx, R.string.permission_camera_location_title,
|
||||||
R.string.permission_camera_location_request_body);
|
R.string.permission_camera_location_request_body,
|
||||||
|
this::requestPermissions);
|
||||||
} else if (cameraPermission == Permission.SHOW_RATIONALE) {
|
} else if (cameraPermission == Permission.SHOW_RATIONALE) {
|
||||||
showRationale(R.string.permission_camera_title,
|
showRationale(ctx, R.string.permission_camera_title,
|
||||||
R.string.permission_camera_request_body);
|
R.string.permission_camera_request_body,
|
||||||
|
this::requestPermissions);
|
||||||
} else if (locationPermission == Permission.SHOW_RATIONALE) {
|
} else if (locationPermission == Permission.SHOW_RATIONALE) {
|
||||||
showRationale(R.string.permission_location_title,
|
showRationale(ctx, R.string.permission_location_title,
|
||||||
R.string.permission_location_request_body);
|
R.string.permission_location_request_body,
|
||||||
|
this::requestPermissions);
|
||||||
} else if (locationEnabled) {
|
} else if (locationEnabled) {
|
||||||
requestPermissions();
|
requestPermissions();
|
||||||
} else {
|
} else {
|
||||||
@@ -97,27 +96,6 @@ class AddNearbyContactPermissionManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showDenialDialog(@StringRes int title, @StringRes int body) {
|
|
||||||
AlertDialog.Builder builder =
|
|
||||||
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
|
|
||||||
builder.setTitle(title);
|
|
||||||
builder.setMessage(body);
|
|
||||||
builder.setPositiveButton(R.string.ok, getGoToSettingsListener(ctx));
|
|
||||||
builder.setNegativeButton(R.string.cancel,
|
|
||||||
(dialog, which) -> ctx.supportFinishAfterTransition());
|
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showRationale(@StringRes int title, @StringRes int body) {
|
|
||||||
AlertDialog.Builder builder =
|
|
||||||
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
|
|
||||||
builder.setTitle(title);
|
|
||||||
builder.setMessage(body);
|
|
||||||
builder.setNeutralButton(R.string.continue_button,
|
|
||||||
(dialog, which) -> requestPermissions());
|
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void requestPermissions() {
|
private void requestPermissions() {
|
||||||
String[] permissions;
|
String[] permissions;
|
||||||
if (isBluetoothSupported) {
|
if (isBluetoothSupported) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.util.Permission;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -19,10 +20,6 @@ import static org.briarproject.briar.android.util.UiUtils.showLocationDialog;
|
|||||||
|
|
||||||
class BluetoothConditionManager {
|
class BluetoothConditionManager {
|
||||||
|
|
||||||
private enum Permission {
|
|
||||||
UNKNOWN, GRANTED, SHOW_RATIONALE, PERMANENTLY_DENIED
|
|
||||||
}
|
|
||||||
|
|
||||||
private Permission locationPermission = Permission.UNKNOWN;
|
private Permission locationPermission = Permission.UNKNOWN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.briar.android.fragment;
|
package org.briarproject.briar.android.fragment;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -16,6 +17,7 @@ import org.briarproject.briar.R;
|
|||||||
import androidx.activity.OnBackPressedCallback;
|
import androidx.activity.OnBackPressedCallback;
|
||||||
import androidx.annotation.ColorRes;
|
import androidx.annotation.ColorRes;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
@@ -93,11 +95,6 @@ public class FinalFragment extends Fragment {
|
|||||||
|
|
||||||
AppCompatActivity a = (AppCompatActivity) requireActivity();
|
AppCompatActivity a = (AppCompatActivity) requireActivity();
|
||||||
a.setTitle(args.getInt(ARG_TITLE));
|
a.setTitle(args.getInt(ARG_TITLE));
|
||||||
ActionBar actionBar = a.getSupportActionBar();
|
|
||||||
if (actionBar != null) {
|
|
||||||
actionBar.setDisplayHomeAsUpEnabled(false);
|
|
||||||
actionBar.setHomeButtonEnabled(false);
|
|
||||||
}
|
|
||||||
a.getOnBackPressedDispatcher().addCallback(
|
a.getOnBackPressedDispatcher().addCallback(
|
||||||
getViewLifecycleOwner(), new OnBackPressedCallback(true) {
|
getViewLifecycleOwner(), new OnBackPressedCallback(true) {
|
||||||
@Override
|
@Override
|
||||||
@@ -108,6 +105,18 @@ public class FinalFragment extends Fragment {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(@NonNull Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
// onAttach(Activity) is deprecated, we are told to cast the context
|
||||||
|
AppCompatActivity a = (AppCompatActivity) context;
|
||||||
|
ActionBar actionBar = a.getSupportActionBar();
|
||||||
|
if (shouldHideActionBarBackButton() && actionBar != null) {
|
||||||
|
actionBar.setDisplayHomeAsUpEnabled(false);
|
||||||
|
actionBar.setHomeButtonEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
@@ -115,6 +124,17 @@ public class FinalFragment extends Fragment {
|
|||||||
scrollView.post(() -> scrollView.fullScroll(FOCUS_DOWN));
|
scrollView.post(() -> scrollView.fullScroll(FOCUS_DOWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetach() {
|
||||||
|
AppCompatActivity a = (AppCompatActivity) requireActivity();
|
||||||
|
ActionBar actionBar = a.getSupportActionBar();
|
||||||
|
if (shouldHideActionBarBackButton() && actionBar != null) {
|
||||||
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
|
actionBar.setHomeButtonEnabled(true);
|
||||||
|
}
|
||||||
|
super.onDetach();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the action that the system back button
|
* This is the action that the system back button
|
||||||
* and the button at the bottom will perform.
|
* and the button at the bottom will perform.
|
||||||
@@ -123,4 +143,13 @@ public class FinalFragment extends Fragment {
|
|||||||
requireActivity().supportFinishAfterTransition();
|
requireActivity().supportFinishAfterTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If you are overriding {@link #onBackButtonPressed()}
|
||||||
|
* and are no longer finishing the fragment, return false here.
|
||||||
|
* Otherwise the ActionBar back button will be missing in your activity.
|
||||||
|
*/
|
||||||
|
protected boolean shouldHideActionBarBackButton() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,7 @@ import static android.content.Context.WIFI_SERVICE;
|
|||||||
*/
|
*/
|
||||||
abstract class AbstractConditionManager {
|
abstract class AbstractConditionManager {
|
||||||
|
|
||||||
enum Permission {
|
final Consumer<Boolean> permissionUpdateCallback;
|
||||||
UNKNOWN, GRANTED, SHOW_RATIONALE, PERMANENTLY_DENIED
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final Consumer<Boolean> permissionUpdateCallback;
|
|
||||||
protected FragmentActivity ctx;
|
protected FragmentActivity ctx;
|
||||||
WifiManager wifiManager;
|
WifiManager wifiManager;
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.content.Intent;
|
|||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.util.Permission;
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
|||||||
@@ -56,13 +56,9 @@ public class HotspotActivity extends BriarActivity
|
|||||||
if (hotspotState instanceof HotspotStarted) {
|
if (hotspotState instanceof HotspotStarted) {
|
||||||
HotspotStarted started = (HotspotStarted) hotspotState;
|
HotspotStarted started = (HotspotStarted) hotspotState;
|
||||||
String tag = HotspotFragment.TAG;
|
String tag = HotspotFragment.TAG;
|
||||||
// check if fragment is already added
|
if (started.wasNotYetConsumed()) {
|
||||||
// to not lose state on configuration changes
|
started.consume();
|
||||||
if (fm.findFragmentByTag(tag) == null) {
|
showFragment(fm, new HotspotFragment(), tag);
|
||||||
if (started.wasNotYetConsumed()) {
|
|
||||||
started.consume();
|
|
||||||
showFragment(fm, new HotspotFragment(), tag);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (hotspotState instanceof HotspotError) {
|
} else if (hotspotState instanceof HotspotError) {
|
||||||
HotspotError error = (HotspotError) hotspotState;
|
HotspotError error = (HotspotError) hotspotState;
|
||||||
@@ -116,10 +112,8 @@ public class HotspotActivity extends BriarActivity
|
|||||||
private void showErrorFragment(String error) {
|
private void showErrorFragment(String error) {
|
||||||
FragmentManager fm = getSupportFragmentManager();
|
FragmentManager fm = getSupportFragmentManager();
|
||||||
String tag = HotspotErrorFragment.TAG;
|
String tag = HotspotErrorFragment.TAG;
|
||||||
if (fm.findFragmentByTag(tag) == null) {
|
Fragment f = HotspotErrorFragment.newInstance(error);
|
||||||
Fragment f = HotspotErrorFragment.newInstance(error);
|
showFragment(fm, f, tag, false);
|
||||||
showFragment(fm, f, tag, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -85,16 +85,10 @@ public class StartupActivity extends BaseActivity implements
|
|||||||
if (state == SIGNED_OUT) {
|
if (state == SIGNED_OUT) {
|
||||||
// Configuration changes such as screen rotation
|
// Configuration changes such as screen rotation
|
||||||
// can cause this to get called again.
|
// can cause this to get called again.
|
||||||
// Don't replace the fragment in that case to not lose view state.
|
showInitialFragment(new PasswordFragment());
|
||||||
if (!isFragmentAdded(PasswordFragment.TAG)) {
|
|
||||||
showInitialFragment(new PasswordFragment());
|
|
||||||
}
|
|
||||||
} else if (state == SIGNED_IN || state == STARTING) {
|
} else if (state == SIGNED_IN || state == STARTING) {
|
||||||
startService(new Intent(this, BriarService.class));
|
startService(new Intent(this, BriarService.class));
|
||||||
// Only show OpenDatabaseFragment if not already visible.
|
showNextFragment(new OpenDatabaseFragment());
|
||||||
if (!isFragmentAdded(OpenDatabaseFragment.TAG)) {
|
|
||||||
showNextFragment(new OpenDatabaseFragment());
|
|
||||||
}
|
|
||||||
} else if (state == STARTED) {
|
} else if (state == STARTED) {
|
||||||
setResult(RESULT_OK);
|
setResult(RESULT_OK);
|
||||||
supportFinishAfterTransition();
|
supportFinishAfterTransition();
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.util.Permission;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import androidx.core.util.Consumer;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.CAMERA;
|
||||||
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale;
|
||||||
|
import static androidx.core.content.ContextCompat.checkSelfPermission;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.showDenialDialog;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.showRationale;
|
||||||
|
|
||||||
|
class CameraPermissionManager {
|
||||||
|
|
||||||
|
private Permission cameraPermission = Permission.UNKNOWN;
|
||||||
|
|
||||||
|
private final FragmentActivity ctx;
|
||||||
|
private final Consumer<String[]> requestPermissions;
|
||||||
|
|
||||||
|
CameraPermissionManager(FragmentActivity ctx,
|
||||||
|
Consumer<String[]> requestPermissions) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.requestPermissions = requestPermissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetPermissions() {
|
||||||
|
cameraPermission = Permission.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean areEssentialPermissionsGranted(Context ctx) {
|
||||||
|
return checkSelfPermission(ctx, CAMERA) == PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean areEssentialPermissionsGranted() {
|
||||||
|
return cameraPermission == Permission.GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean checkPermissions() {
|
||||||
|
if (areEssentialPermissionsGranted()) return true;
|
||||||
|
// If an essential permission has been permanently denied, ask the
|
||||||
|
// user to change the setting
|
||||||
|
if (cameraPermission == Permission.PERMANENTLY_DENIED) {
|
||||||
|
showDenialDialog(ctx, R.string.permission_camera_title,
|
||||||
|
R.string.permission_camera_qr_denied_body);
|
||||||
|
} else if (cameraPermission == Permission.SHOW_RATIONALE) {
|
||||||
|
showRationale(ctx, R.string.permission_camera_title,
|
||||||
|
R.string.permission_camera_request_body,
|
||||||
|
this::requestPermissions);
|
||||||
|
} else {
|
||||||
|
requestPermissions();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestPermissions() {
|
||||||
|
String[] permissions = new String[] {CAMERA};
|
||||||
|
requestPermissions.accept(permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onRequestPermissionResult(Map<String, Boolean> result) {
|
||||||
|
if (gotPermission(result)) {
|
||||||
|
cameraPermission = Permission.GRANTED;
|
||||||
|
} else if (shouldShowRequestPermissionRationale(ctx, CAMERA)) {
|
||||||
|
cameraPermission = Permission.SHOW_RATIONALE;
|
||||||
|
} else {
|
||||||
|
cameraPermission = Permission.PERMANENTLY_DENIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean gotPermission(Map<String, Boolean> result) {
|
||||||
|
Boolean permissionResult = result.get(CAMERA);
|
||||||
|
return permissionResult == null ? areEssentialPermissionsGranted(ctx) :
|
||||||
|
permissionResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.fragment.FinalFragment;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
public class ErrorFragment extends FinalFragment {
|
||||||
|
|
||||||
|
public static ErrorFragment newInstance(@StringRes int title,
|
||||||
|
@StringRes int text) {
|
||||||
|
ErrorFragment f = new ErrorFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putInt(ARG_TITLE, title);
|
||||||
|
args.putInt(ARG_ICON, R.drawable.alerts_and_states_error);
|
||||||
|
args.putInt(ARG_ICON_TINT, R.color.briar_red_500);
|
||||||
|
args.putInt(ARG_TEXT, text);
|
||||||
|
f.setArguments(args);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
View v = super.onCreateView(inflater, container, savedInstanceState);
|
||||||
|
buttonView.setText(R.string.try_again_button);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onBackButtonPressed() {
|
||||||
|
requireActivity().getSupportFragmentManager().popBackStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldHideActionBarBackButton() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
|
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 javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import static android.view.View.INVISIBLE;
|
||||||
|
import static android.view.View.VISIBLE;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
public class MailboxActivity extends BriarActivity {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
|
private MailboxViewModel viewModel;
|
||||||
|
private ProgressBar progressBar;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void injectActivity(ActivityComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
|
||||||
|
viewModel = new ViewModelProvider(this, viewModelFactory)
|
||||||
|
.get(MailboxViewModel.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_mailbox);
|
||||||
|
|
||||||
|
progressBar = findViewById(R.id.progressBar);
|
||||||
|
if (viewModel.getState().getValue() == null) {
|
||||||
|
progressBar.setVisibility(VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.getState().observeEvent(this, state -> {
|
||||||
|
if (state instanceof MailboxState.NotSetup) {
|
||||||
|
onNotSetup();
|
||||||
|
} else if (state instanceof MailboxState.ScanningQrCode) {
|
||||||
|
onScanningQrCode();
|
||||||
|
} else if (state instanceof MailboxState.SettingUp) {
|
||||||
|
onCodeScanned();
|
||||||
|
} else if (state instanceof MailboxState.QrCodeWrong) {
|
||||||
|
onQrCodeWrong();
|
||||||
|
} else if (state instanceof MailboxState.OfflineInSetup) {
|
||||||
|
onOffline();
|
||||||
|
} else if (state instanceof MailboxState.IsSetup) {
|
||||||
|
onIsSetup(((MailboxState.IsSetup) state).mailboxStatus);
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Unknown state: " + state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
if (item.getItemId() == android.R.id.home) {
|
||||||
|
onBackPressed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
if (viewModel.getState()
|
||||||
|
.getLastValue() instanceof MailboxState.SettingUp) {
|
||||||
|
// don't go back in flow if we are already setting up mailbox
|
||||||
|
supportFinishAfterTransition();
|
||||||
|
} else {
|
||||||
|
super.onBackPressed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onNotSetup() {
|
||||||
|
progressBar.setVisibility(INVISIBLE);
|
||||||
|
getSupportFragmentManager().beginTransaction()
|
||||||
|
.replace(R.id.fragmentContainer, new SetupIntroFragment(),
|
||||||
|
SetupIntroFragment.TAG)
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onScanningQrCode() {
|
||||||
|
showFragment(getSupportFragmentManager(), new MailboxScanFragment(),
|
||||||
|
MailboxScanFragment.TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onCodeScanned() {
|
||||||
|
showFragment(getSupportFragmentManager(),
|
||||||
|
new MailboxConnectingFragment(),
|
||||||
|
MailboxConnectingFragment.TAG, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onQrCodeWrong() {
|
||||||
|
Fragment f = ErrorFragment.newInstance(
|
||||||
|
R.string.mailbox_setup_qr_code_wrong_title,
|
||||||
|
R.string.mailbox_setup_qr_code_wrong_description);
|
||||||
|
showFragment(getSupportFragmentManager(), f, ErrorFragment.TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onOffline() {
|
||||||
|
showFragment(getSupportFragmentManager(), new OfflineFragment(),
|
||||||
|
OfflineFragment.TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onIsSetup(MailboxStatus mailboxStatus) {
|
||||||
|
// TODO
|
||||||
|
Toast.makeText(this, "NOT IMPLEMENTED", Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
public class MailboxConnectingFragment extends Fragment {
|
||||||
|
|
||||||
|
static final String TAG = MailboxConnectingFragment.class.getName();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.fragment_mailbox_connecting,
|
||||||
|
container, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
requireActivity().setTitle(R.string.mailbox_setup_title);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -12,8 +12,7 @@ public interface MailboxModule {
|
|||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@ViewModelKey(MailboxPairViewModel.class)
|
@ViewModelKey(MailboxViewModel.class)
|
||||||
ViewModel bindMailboxViewModel(
|
ViewModel bindMailboxViewModel(MailboxViewModel mailboxViewModel);
|
||||||
MailboxPairViewModel mailboxPairViewModel);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
package org.briarproject.briar.android.mailbox;
|
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
|
|
||||||
import com.google.zxing.Result;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
|
||||||
import org.briarproject.bramble.api.db.TransactionManager;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
import org.briarproject.briar.android.qrcode.QrCodeDecoder;
|
|
||||||
import org.briarproject.briar.android.viewmodel.DbViewModel;
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.annotation.UiThread;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
|
||||||
|
|
||||||
@UiThread
|
|
||||||
@NotNullByDefault
|
|
||||||
class MailboxPairViewModel extends DbViewModel
|
|
||||||
implements QrCodeDecoder.ResultCallback {
|
|
||||||
private static final Logger LOG =
|
|
||||||
getLogger(MailboxPairViewModel.class.getName());
|
|
||||||
|
|
||||||
private static final int VERSION_REQUIRED = 32;
|
|
||||||
|
|
||||||
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
|
|
||||||
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
|
||||||
|
|
||||||
private final CryptoComponent crypto;
|
|
||||||
private final QrCodeDecoder qrCodeDecoder;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private String onionAddress = null;
|
|
||||||
@Nullable
|
|
||||||
private String setupToken = null;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
MailboxPairViewModel(
|
|
||||||
Application app,
|
|
||||||
@DatabaseExecutor Executor dbExecutor,
|
|
||||||
LifecycleManager lifecycleManager,
|
|
||||||
TransactionManager db,
|
|
||||||
AndroidExecutor androidExecutor,
|
|
||||||
@IoExecutor Executor ioExecutor,
|
|
||||||
CryptoComponent crypto) {
|
|
||||||
super(app, dbExecutor, lifecycleManager, db, androidExecutor);
|
|
||||||
this.crypto = crypto;
|
|
||||||
qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onQrCodeDecoded(Result result) {
|
|
||||||
LOG.info("Got result from decoder");
|
|
||||||
byte[] bytes = result.getText().getBytes(ISO_8859_1);
|
|
||||||
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("QR code length in bytes: " + bytes.length);
|
|
||||||
if (bytes.length != 65) {
|
|
||||||
LOG.info("QR code has wrong length");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("QR code version: " + bytes[0]);
|
|
||||||
if (bytes[0] != VERSION_REQUIRED) {
|
|
||||||
LOG.info("QR code has wrong version");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33);
|
|
||||||
onionAddress = crypto.encodeOnionAddress(onionPubKey);
|
|
||||||
setupToken = StringUtils.toHexString(Arrays.copyOfRange(bytes, 33, 65))
|
|
||||||
.toLowerCase();
|
|
||||||
LOG.info("QR code is valid");
|
|
||||||
}
|
|
||||||
|
|
||||||
QrCodeDecoder getQrCodeDecoder() {
|
|
||||||
return qrCodeDecoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
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.qrcode.CameraException;
|
||||||
|
import org.briarproject.briar.android.qrcode.CameraView;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.annotation.UiThread;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import static android.widget.Toast.LENGTH_LONG;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
public class MailboxScanFragment extends Fragment {
|
||||||
|
|
||||||
|
static final String TAG = MailboxScanFragment.class.getName();
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(TAG);
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
|
private MailboxViewModel viewModel;
|
||||||
|
|
||||||
|
private CameraView cameraView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
FragmentActivity activity = requireActivity();
|
||||||
|
getAndroidComponent(activity).inject(this);
|
||||||
|
viewModel = new ViewModelProvider(activity, viewModelFactory)
|
||||||
|
.get(MailboxViewModel.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.fragment_mailbox_scan, container,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
cameraView = view.findViewById(R.id.camera_view);
|
||||||
|
cameraView.setPreviewConsumer(viewModel.getQrCodeDecoder());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
requireActivity().setTitle(R.string.mailbox_setup_button_scan);
|
||||||
|
try {
|
||||||
|
cameraView.start();
|
||||||
|
} catch (CameraException e) {
|
||||||
|
logCameraExceptionAndFinish(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
try {
|
||||||
|
cameraView.stop();
|
||||||
|
} catch (CameraException e) {
|
||||||
|
logCameraExceptionAndFinish(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void logCameraExceptionAndFinish(CameraException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
Toast.makeText(requireContext(), R.string.camera_error,
|
||||||
|
LENGTH_LONG).show();
|
||||||
|
requireActivity().getSupportFragmentManager().popBackStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
class MailboxState {
|
||||||
|
|
||||||
|
static class NotSetup extends MailboxState {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ScanningQrCode extends MailboxState {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SettingUp extends MailboxState {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class QrCodeWrong extends MailboxState {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class OfflineInSetup extends MailboxState {
|
||||||
|
@Nullable
|
||||||
|
final MailboxProperties mailboxProperties;
|
||||||
|
|
||||||
|
OfflineInSetup(@Nullable MailboxProperties mailboxProperties) {
|
||||||
|
this.mailboxProperties = mailboxProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
OfflineInSetup() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class IsSetup extends MailboxState {
|
||||||
|
final MailboxStatus mailboxStatus;
|
||||||
|
|
||||||
|
IsSetup(MailboxStatus mailboxStatus) {
|
||||||
|
this.mailboxStatus = mailboxStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
|
import com.google.zxing.Result;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
|
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||||
|
import org.briarproject.bramble.api.plugin.TorConstants;
|
||||||
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.NotSetup;
|
||||||
|
import org.briarproject.briar.android.qrcode.QrCodeDecoder;
|
||||||
|
import org.briarproject.briar.android.viewmodel.DbViewModel;
|
||||||
|
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
||||||
|
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
class MailboxViewModel extends DbViewModel
|
||||||
|
implements QrCodeDecoder.ResultCallback {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
getLogger(MailboxViewModel.class.getName());
|
||||||
|
|
||||||
|
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
|
||||||
|
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
||||||
|
private static final int VERSION_REQUIRED = 32;
|
||||||
|
|
||||||
|
private final CryptoComponent crypto;
|
||||||
|
private final QrCodeDecoder qrCodeDecoder;
|
||||||
|
private final PluginManager pluginManager;
|
||||||
|
private final MailboxSettingsManager mailboxSettingsManager;
|
||||||
|
|
||||||
|
private final MutableLiveEvent<MailboxState> state =
|
||||||
|
new MutableLiveEvent<>();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MailboxViewModel(
|
||||||
|
Application app,
|
||||||
|
@DatabaseExecutor Executor dbExecutor,
|
||||||
|
LifecycleManager lifecycleManager,
|
||||||
|
TransactionManager db,
|
||||||
|
AndroidExecutor androidExecutor,
|
||||||
|
@IoExecutor Executor ioExecutor,
|
||||||
|
CryptoComponent crypto,
|
||||||
|
PluginManager pluginManager,
|
||||||
|
MailboxSettingsManager mailboxSettingsManager) {
|
||||||
|
super(app, dbExecutor, lifecycleManager, db, androidExecutor);
|
||||||
|
this.crypto = crypto;
|
||||||
|
this.pluginManager = pluginManager;
|
||||||
|
this.mailboxSettingsManager = mailboxSettingsManager;
|
||||||
|
qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this);
|
||||||
|
checkIfSetup();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void checkIfSetup() {
|
||||||
|
runOnDbThread(true, txn -> {
|
||||||
|
MailboxProperties props =
|
||||||
|
mailboxSettingsManager.getOwnMailboxProperties(txn);
|
||||||
|
if (props == null) state.postEvent(new NotSetup());
|
||||||
|
else {
|
||||||
|
MailboxStatus mailboxStatus =
|
||||||
|
mailboxSettingsManager.getOwnMailboxStatus(txn);
|
||||||
|
state.postEvent(new MailboxState.IsSetup(mailboxStatus));
|
||||||
|
}
|
||||||
|
}, this::handleException);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
void onScanButtonClicked() {
|
||||||
|
if (isTorActive()) {
|
||||||
|
state.setEvent(new MailboxState.ScanningQrCode());
|
||||||
|
} else {
|
||||||
|
state.setEvent(new MailboxState.OfflineInSetup());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@IoExecutor
|
||||||
|
public void onQrCodeDecoded(Result result) {
|
||||||
|
LOG.info("Got result from decoder");
|
||||||
|
MailboxProperties properties;
|
||||||
|
try {
|
||||||
|
properties = decodeQrCode(result.getText());
|
||||||
|
} catch (FormatException e) {
|
||||||
|
state.postEvent(new MailboxState.QrCodeWrong());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onMailboxPropertiesReceived(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@IoExecutor
|
||||||
|
// TODO move this into core #2168
|
||||||
|
private MailboxProperties decodeQrCode(String payload)
|
||||||
|
throws FormatException {
|
||||||
|
byte[] bytes = payload.getBytes(ISO_8859_1);
|
||||||
|
if (bytes.length != 65) {
|
||||||
|
if (LOG.isLoggable(WARNING)) {
|
||||||
|
LOG.warning("QR code length is not 65: " + bytes.length);
|
||||||
|
}
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
int version = bytes[0] & 0xFF;
|
||||||
|
if (version != VERSION_REQUIRED) {
|
||||||
|
if (LOG.isLoggable(WARNING)) {
|
||||||
|
LOG.warning("QR code has not version " + VERSION_REQUIRED +
|
||||||
|
": " + version);
|
||||||
|
}
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
LOG.info("QR code is valid");
|
||||||
|
byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33);
|
||||||
|
String onionAddress = crypto.encodeOnionAddress(onionPubKey);
|
||||||
|
byte[] tokenBytes = Arrays.copyOfRange(bytes, 33, 65);
|
||||||
|
MailboxAuthToken setupToken = new MailboxAuthToken(tokenBytes);
|
||||||
|
return new MailboxProperties(onionAddress, setupToken, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onMailboxPropertiesReceived(MailboxProperties properties) {
|
||||||
|
if (isTorActive()) {
|
||||||
|
// TODO pass props to core #2168
|
||||||
|
state.postEvent(new MailboxState.SettingUp());
|
||||||
|
} else {
|
||||||
|
state.postEvent(new MailboxState.OfflineInSetup(properties));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO ideally also move this into core #2168
|
||||||
|
private boolean isTorActive() {
|
||||||
|
Plugin plugin = pluginManager.getPlugin(TorConstants.ID);
|
||||||
|
return plugin != null && plugin.getState() == ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
void tryAgainWhenOffline() {
|
||||||
|
MailboxState.OfflineInSetup offline =
|
||||||
|
(MailboxState.OfflineInSetup) requireNonNull(
|
||||||
|
state.getLastValue());
|
||||||
|
if (offline.mailboxProperties == null) {
|
||||||
|
onScanButtonClicked();
|
||||||
|
} else {
|
||||||
|
onMailboxPropertiesReceived(offline.mailboxProperties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
QrCodeDecoder getQrCodeDecoder() {
|
||||||
|
return qrCodeDecoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
LiveEvent<MailboxState> getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.navdrawer.TransportsActivity;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.widget.NestedScrollView;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import static android.view.View.FOCUS_DOWN;
|
||||||
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
public class OfflineFragment extends Fragment {
|
||||||
|
|
||||||
|
public static final String TAG = OfflineFragment.class.getName();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
|
private MailboxViewModel viewModel;
|
||||||
|
|
||||||
|
private NestedScrollView scrollView;
|
||||||
|
protected Button buttonView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
FragmentActivity activity = requireActivity();
|
||||||
|
getAndroidComponent(activity).inject(this);
|
||||||
|
viewModel = new ViewModelProvider(activity, viewModelFactory)
|
||||||
|
.get(MailboxViewModel.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
View v = inflater
|
||||||
|
.inflate(R.layout.fragment_offline, container, false);
|
||||||
|
|
||||||
|
scrollView = (NestedScrollView) v;
|
||||||
|
Button checkButton = v.findViewById(R.id.checkButton);
|
||||||
|
checkButton.setOnClickListener(view -> {
|
||||||
|
Intent i = new Intent(requireContext(), TransportsActivity.class);
|
||||||
|
startActivity(i);
|
||||||
|
});
|
||||||
|
buttonView = v.findViewById(R.id.button);
|
||||||
|
buttonView.setOnClickListener(view -> {
|
||||||
|
getParentFragmentManager().popBackStackImmediate();
|
||||||
|
viewModel.tryAgainWhenOffline();
|
||||||
|
});
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
// Scroll down in case the screen is small, so the button is visible
|
||||||
|
scrollView.post(() -> scrollView.fullScroll(FOCUS_DOWN));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import static android.view.View.FOCUS_DOWN;
|
||||||
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
public class SetupDownloadFragment extends Fragment {
|
||||||
|
|
||||||
|
static final String TAG = SetupDownloadFragment.class.getName();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
|
private MailboxViewModel viewModel;
|
||||||
|
|
||||||
|
private CameraPermissionManager permissionManager;
|
||||||
|
private ScrollView scrollView;
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<String[]> permissionLauncher =
|
||||||
|
registerForActivityResult(new RequestMultiplePermissions(), r -> {
|
||||||
|
permissionManager.onRequestPermissionResult(r);
|
||||||
|
if (permissionManager.checkPermissions()) {
|
||||||
|
scanCode();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
FragmentActivity activity = requireActivity();
|
||||||
|
getAndroidComponent(activity).inject(this);
|
||||||
|
viewModel = new ViewModelProvider(activity, viewModelFactory)
|
||||||
|
.get(MailboxViewModel.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
View v = inflater.inflate(R.layout.fragment_mailbox_setup_download,
|
||||||
|
container, false);
|
||||||
|
scrollView = v.findViewById(R.id.scrollView);
|
||||||
|
|
||||||
|
permissionManager = new CameraPermissionManager(requireActivity(),
|
||||||
|
permissionLauncher::launch);
|
||||||
|
|
||||||
|
Button scanButton = v.findViewById(R.id.scanButton);
|
||||||
|
scanButton.setOnClickListener(view -> {
|
||||||
|
if (permissionManager.checkPermissions()) {
|
||||||
|
scanCode();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
requireActivity().setTitle(R.string.mailbox_setup_title);
|
||||||
|
// Scroll down in case the screen is small, so the button is visible
|
||||||
|
scrollView.post(() -> scrollView.fullScroll(FOCUS_DOWN));
|
||||||
|
// Permissions may have been granted manually while we were stopped
|
||||||
|
permissionManager.resetPermissions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scanCode() {
|
||||||
|
viewModel.onScanButtonClicked();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
|
import static android.view.View.FOCUS_DOWN;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
public class SetupIntroFragment extends Fragment {
|
||||||
|
|
||||||
|
static final String TAG = SetupIntroFragment.class.getName();
|
||||||
|
|
||||||
|
private ScrollView scrollView;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
View v = inflater.inflate(R.layout.fragment_mailbox_setup_intro,
|
||||||
|
container, false);
|
||||||
|
scrollView = v.findViewById(R.id.scrollView);
|
||||||
|
Button button = v.findViewById(R.id.continueButton);
|
||||||
|
button.setOnClickListener(view -> {
|
||||||
|
FragmentManager fm = getParentFragmentManager();
|
||||||
|
Fragment f = new SetupDownloadFragment();
|
||||||
|
showFragment(fm, f, SetupDownloadFragment.TAG);
|
||||||
|
});
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
requireActivity().setTitle(R.string.mailbox_setup_title);
|
||||||
|
// Scroll down in case the screen is small, so the button is visible
|
||||||
|
scrollView.post(() -> scrollView.fullScroll(FOCUS_DOWN));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.briar.android.settings;
|
package org.briarproject.briar.android.settings;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -8,6 +9,7 @@ import android.view.View;
|
|||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxActivity;
|
||||||
import org.briarproject.briar.android.util.ActivityLaunchers.GetImageAdvanced;
|
import org.briarproject.briar.android.util.ActivityLaunchers.GetImageAdvanced;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -36,7 +38,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||||||
private static final String PREF_KEY_FEEDBACK = "pref_key_send_feedback";
|
private static final String PREF_KEY_FEEDBACK = "pref_key_send_feedback";
|
||||||
private static final String PREF_KEY_DEV = "pref_key_dev";
|
private static final String PREF_KEY_DEV = "pref_key_dev";
|
||||||
private static final String PREF_KEY_EXPLODE = "pref_key_explode";
|
private static final String PREF_KEY_EXPLODE = "pref_key_explode";
|
||||||
private static final String PREF_KEY_SHARE_APP = "pref_key_share_app";
|
private static final String PREF_KEY_MAILBOX = "pref_key_mailbox";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ViewModelProvider.Factory viewModelFactory;
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
@@ -70,6 +72,18 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||||||
prefAvatar.setVisible(false);
|
prefAvatar.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Preference prefMailbox =
|
||||||
|
requireNonNull(findPreference(PREF_KEY_MAILBOX));
|
||||||
|
if (viewModel.shouldEnableMailbox()) {
|
||||||
|
prefMailbox.setOnPreferenceClickListener(preference -> {
|
||||||
|
Intent i = new Intent(requireContext(), MailboxActivity.class);
|
||||||
|
startActivity(i);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
prefMailbox.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
Preference prefFeedback =
|
Preference prefFeedback =
|
||||||
requireNonNull(findPreference(PREF_KEY_FEEDBACK));
|
requireNonNull(findPreference(PREF_KEY_FEEDBACK));
|
||||||
prefFeedback.setOnPreferenceClickListener(preference -> {
|
prefFeedback.setOnPreferenceClickListener(preference -> {
|
||||||
|
|||||||
@@ -161,6 +161,10 @@ class SettingsViewModel extends DbViewModel implements EventListener {
|
|||||||
return featureFlags.shouldEnableProfilePictures();
|
return featureFlags.shouldEnableProfilePictures();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean shouldEnableMailbox() {
|
||||||
|
return featureFlags.shouldEnableMailbox();
|
||||||
|
}
|
||||||
|
|
||||||
private void loadOwnIdentityInfo() {
|
private void loadOwnIdentityInfo() {
|
||||||
runOnDbThread(() -> {
|
runOnDbThread(() -> {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.briarproject.briar.android.util;
|
||||||
|
|
||||||
|
public enum Permission {
|
||||||
|
UNKNOWN, GRANTED, SHOW_RATIONALE, PERMANENTLY_DENIED
|
||||||
|
}
|
||||||
@@ -52,6 +52,7 @@ import androidx.annotation.ColorRes;
|
|||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
@@ -146,6 +147,10 @@ public class UiUtils {
|
|||||||
|
|
||||||
public static void showFragment(FragmentManager fm, Fragment f,
|
public static void showFragment(FragmentManager fm, Fragment f,
|
||||||
@Nullable String tag, boolean addToBackStack) {
|
@Nullable String tag, boolean addToBackStack) {
|
||||||
|
// don't re-add same (already added/visible) fragment again
|
||||||
|
Fragment fragment = fm.findFragmentByTag(tag);
|
||||||
|
if (fragment != null && fragment.isAdded()) return;
|
||||||
|
|
||||||
FragmentTransaction ta = fm.beginTransaction()
|
FragmentTransaction ta = fm.beginTransaction()
|
||||||
.setCustomAnimations(R.anim.step_next_in,
|
.setCustomAnimations(R.anim.step_next_in,
|
||||||
R.anim.step_previous_out, R.anim.step_previous_in,
|
R.anim.step_previous_out, R.anim.step_previous_in,
|
||||||
@@ -574,4 +579,26 @@ public class UiUtils {
|
|||||||
SOFT_INPUT_STATE_HIDDEN);
|
SOFT_INPUT_STATE_HIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void showDenialDialog(FragmentActivity ctx,
|
||||||
|
@StringRes int title, @StringRes int body) {
|
||||||
|
AlertDialog.Builder builder =
|
||||||
|
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
|
||||||
|
builder.setTitle(title);
|
||||||
|
builder.setMessage(body);
|
||||||
|
builder.setPositiveButton(R.string.ok, getGoToSettingsListener(ctx));
|
||||||
|
builder.setNegativeButton(R.string.cancel,
|
||||||
|
(dialog, which) -> ctx.supportFinishAfterTransition());
|
||||||
|
builder.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showRationale(FragmentActivity ctx, @StringRes int title,
|
||||||
|
@StringRes int body, Runnable requestPermissions) {
|
||||||
|
AlertDialog.Builder builder =
|
||||||
|
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
|
||||||
|
builder.setTitle(title);
|
||||||
|
builder.setMessage(body);
|
||||||
|
builder.setNeutralButton(R.string.continue_button,
|
||||||
|
(dialog, which) -> requestPermissions.run());
|
||||||
|
builder.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="200dp"
|
||||||
|
android:height="160dp"
|
||||||
|
android:viewportWidth="250"
|
||||||
|
android:viewportHeight="200">
|
||||||
|
<path
|
||||||
|
android:fillColor="#15212D"
|
||||||
|
android:pathData="M95.436,100.233C95.436,93.523 100.876,88.084 107.585,88.084H130.365C137.074,88.084 142.514,93.523 142.514,100.233V123.012C142.514,129.722 137.074,135.161 130.365,135.161H107.585C100.876,135.161 95.436,129.722 95.436,123.012V100.233Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#15212D"
|
||||||
|
android:pathData="M102.336,10.261C102.336,4.594 106.93,0 112.597,0H131.836C137.503,0 142.097,4.594 142.097,10.261V29.5C142.097,35.167 137.503,39.761 131.836,39.761H112.597C106.93,39.761 102.336,35.167 102.336,29.5V10.261Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#15212D"
|
||||||
|
android:pathData="M34.818,148.09C34.818,143.427 38.599,139.646 43.262,139.646H59.093C63.757,139.646 67.537,143.427 67.537,148.09V163.921C67.537,168.585 63.757,172.365 59.093,172.365H43.262C38.599,172.365 34.818,168.585 34.818,163.921V148.09Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#15212D"
|
||||||
|
android:pathData="M110.024,186.044C110.024,183.557 112.04,181.541 114.527,181.541H122.971C125.458,181.541 127.475,183.557 127.475,186.044V194.488C127.475,196.976 125.458,198.992 122.971,198.992H114.527C112.04,198.992 110.024,196.976 110.024,194.488V186.044Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#15212D"
|
||||||
|
android:pathData="M173.713,141.6C173.713,134.89 179.152,129.451 185.862,129.451H208.641C215.351,129.451 220.79,134.89 220.79,141.6V164.38C220.79,171.089 215.351,176.528 208.641,176.528H185.862C179.152,176.528 173.713,171.089 173.713,164.38V141.6Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#15212D"
|
||||||
|
android:pathData="M232.049,95.416C232.049,92.928 234.065,90.912 236.553,90.912H244.997C247.484,90.912 249.5,92.928 249.5,95.416V103.86C249.5,106.347 247.484,108.363 244.997,108.363H236.553C234.065,108.363 232.049,106.347 232.049,103.86V95.416Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#657D99"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M120.481,84.227V45.268H122.481V84.227H120.481Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#657D99"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M117.685,176.101L117.685,139.646H119.685L119.685,176.101H117.685Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#657D99"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M3.28,108.445L4.046,106.598C4.338,106.719 4.66,106.787 5.003,106.787H7.114V108.787H5.003C4.393,108.787 3.811,108.665 3.28,108.445ZM11.336,108.787V106.787H13.447C13.79,106.787 14.113,106.719 14.405,106.598L15.171,108.445C14.64,108.665 14.058,108.787 13.447,108.787H11.336ZM17.951,97.95H15.951V95.839C15.951,95.496 15.883,95.174 15.762,94.882L17.609,94.116C17.829,94.646 17.951,95.229 17.951,95.839V97.95ZM7.114,91.336H5.003C4.393,91.336 3.811,91.457 3.28,91.678L4.046,93.525C4.338,93.404 4.66,93.336 5.003,93.336H7.114V91.336ZM0.5,102.172H2.5V104.283C2.5,104.626 2.568,104.949 2.689,105.241L0.842,106.007C0.622,105.476 0.5,104.894 0.5,104.283V102.172ZM0.5,97.95H2.5V95.839C2.5,95.496 2.568,95.174 2.689,94.882L0.842,94.116C0.622,94.646 0.5,95.229 0.5,95.839V97.95ZM11.336,91.336V93.336H13.447C13.79,93.336 14.113,93.404 14.405,93.525L15.171,91.678C14.64,91.457 14.058,91.336 13.447,91.336H11.336ZM17.951,102.172H15.951V104.283C15.951,104.626 15.883,104.949 15.762,105.241L17.609,106.007C17.829,105.476 17.951,104.894 17.951,104.283V102.172Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#74B816"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M41.177,64.517V62.648H43.177V64.517H41.177ZM41.177,71.991V68.254H43.177V71.991H41.177ZM41.177,79.465V75.728H43.177V79.465H41.177ZM41.177,86.938V83.202H43.177V86.938H41.177ZM41.177,94.412V90.675H43.177V94.412H41.177ZM41.177,99.018V98.149H43.177V99.018H44.91V101.018H39.681V99.018H41.177ZM24.705,101.018H22.209V99.018H24.705V101.018ZM34.689,101.018H29.697V99.018H34.689V101.018ZM52.107,101.018H50.374V99.018H54.854V101.018H54.107V102.148H52.107V101.018ZM61.844,101.018H58.349V99.018H61.844V101.018ZM67.087,101.018H65.339V99.018H67.087C68.048,99.018 68.966,99.209 69.805,99.557L69.039,101.404C68.439,101.156 67.78,101.018 67.087,101.018ZM72.187,106.118C72.187,105.425 72.049,104.766 71.8,104.166L73.648,103.4C73.995,104.239 74.187,105.157 74.187,106.118C74.187,106.812 74.325,107.47 74.574,108.07L72.726,108.836C72.378,107.998 72.187,107.079 72.187,106.118ZM52.107,110.668V106.408H54.107V110.668H52.107ZM79.287,113.218C78.326,113.218 77.408,113.027 76.569,112.679L77.335,110.832C77.935,111.081 78.594,111.218 79.287,111.218H81.59V113.218H79.287ZM88.5,113.218H86.197V111.218H88.5V113.218ZM52.107,119.188V114.928H54.107V119.188H52.107ZM52.107,127.709V123.449H54.107V127.709H52.107ZM52.107,134.099V131.969H54.107V134.099H52.107Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#74B816"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M105.214,134.93L105.602,132.968C106.242,133.095 106.905,133.161 107.585,133.161H109.484V135.161H107.585C106.774,135.161 105.981,135.082 105.214,134.93ZM128.466,135.161V133.161H130.365C131.045,133.161 131.708,133.095 132.347,132.968L132.736,134.93C131.969,135.082 131.176,135.161 130.365,135.161H128.466ZM137.115,133.115L136.002,131.453C137.11,130.712 138.064,129.757 138.805,128.65L140.467,129.762C139.58,131.087 138.44,132.228 137.115,133.115ZM142.514,102.131H140.514V100.233C140.514,99.553 140.447,98.89 140.32,98.25L142.282,97.862C142.434,98.629 142.514,99.422 142.514,100.233V102.131ZM140.467,93.483L138.805,94.595C138.064,93.488 137.11,92.534 136.002,91.792L137.115,90.13C138.44,91.017 139.58,92.158 140.467,93.483ZM109.484,88.084H107.585C106.774,88.084 105.981,88.163 105.214,88.315L105.602,90.277C106.242,90.151 106.905,90.084 107.585,90.084H109.484V88.084ZM100.835,90.13L101.948,91.792C100.84,92.534 99.886,93.488 99.145,94.595L97.483,93.483C98.37,92.158 99.51,91.017 100.835,90.13ZM95.436,121.114H97.436V123.012C97.436,123.693 97.503,124.355 97.63,124.995L95.668,125.383C95.516,124.616 95.436,123.824 95.436,123.012V121.114ZM97.483,129.762L99.145,128.65C99.886,129.757 100.84,130.712 101.948,131.453L100.835,133.115C99.51,132.228 98.37,131.087 97.483,129.762ZM95.436,117.317H97.436V113.521H95.436V117.317ZM95.436,109.724H97.436V105.928H95.436V109.724ZM95.436,102.131H97.436V100.233C97.436,99.553 97.503,98.89 97.63,98.25L95.668,97.862C95.516,98.629 95.436,99.422 95.436,100.233V102.131ZM113.28,88.084V90.084H117.077V88.084H113.28ZM120.873,88.084V90.084H124.67V88.084H120.873ZM128.466,88.084V90.084H130.365C131.045,90.084 131.708,90.151 132.347,90.277L132.736,88.315C131.969,88.163 131.176,88.084 130.365,88.084H128.466ZM142.514,105.928H140.514V109.724H142.514V105.928ZM142.514,113.521H140.514V117.317H142.514V113.521ZM142.514,121.114H140.514V123.012C140.514,123.693 140.447,124.355 140.32,124.995L142.282,125.383C142.434,124.616 142.514,123.824 142.514,123.012V121.114ZM124.67,135.161V133.161H120.873V135.161H124.67ZM117.077,135.161V133.161H113.28V135.161H117.077Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#74B816"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M188.618,86.539V84.674H190.618V86.539H188.618ZM188.618,93.999V90.269H190.618V93.999H188.618ZM188.618,97.729H190.618V98.594H191.517V100.594H190.618V101.183H188.618V97.729ZM199.112,100.594H195.315V98.594H199.112V100.594ZM206.707,100.594H202.91V98.594H206.707V100.594ZM214.303,100.594H210.505V98.594H214.303V100.594ZM221.898,100.594H218.1V98.594H221.898V100.594ZM227.595,100.594H225.696V98.594H227.595V100.594ZM188.618,107.537V104.36H190.618V107.537H188.618ZM188.618,111.303V110.715H190.618V111.359C190.865,111.387 191.109,111.425 191.35,111.472L190.962,113.434C190.528,113.349 190.079,113.303 189.618,113.303H187.737V111.303H188.618ZM153.881,113.303H152V111.303H153.881V113.303ZM161.405,113.303H157.643V111.303H161.405V113.303ZM168.928,113.303H165.166V111.303H168.928V113.303ZM176.452,113.303H172.69V111.303H176.452V113.303ZM183.975,113.303H180.214V111.303H183.975V113.303ZM195.34,116.361C194.837,115.611 194.19,114.964 193.44,114.462L194.552,112.8C195.52,113.448 196.353,114.281 197.001,115.249L195.34,116.361ZM196.498,120.183C196.498,119.722 196.453,119.273 196.367,118.839L198.329,118.451C198.44,119.012 198.498,119.591 198.498,120.183V121.203H196.498V120.183ZM196.498,124.261V123.242H198.498V124.261H196.498Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#74B816"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M183.491,176.297L183.879,174.335C184.519,174.462 185.182,174.528 185.862,174.528H187.76V176.528H185.862C185.051,176.528 184.258,176.449 183.491,176.297ZM206.743,176.528V174.528H208.641C209.322,174.528 209.985,174.462 210.624,174.335L211.012,176.297C210.246,176.449 209.453,176.528 208.641,176.528H206.743ZM215.392,174.482L214.279,172.82C215.387,172.079 216.341,171.125 217.082,170.017L218.744,171.13C217.857,172.455 216.717,173.595 215.392,174.482ZM220.79,143.498H218.79V141.6C218.79,140.92 218.724,140.257 218.597,139.617L220.559,139.229C220.711,139.996 220.79,140.789 220.79,141.6V143.498ZM218.744,134.85L217.082,135.963C216.341,134.855 215.387,133.901 214.279,133.159L215.392,131.497C216.717,132.384 217.857,133.525 218.744,134.85ZM187.76,129.451H185.862C185.051,129.451 184.258,129.531 183.491,129.682L183.879,131.644C184.519,131.518 185.182,131.451 185.862,131.451H187.76V129.451ZM179.112,131.497L180.225,133.159C179.117,133.901 178.163,134.855 177.421,135.963L175.759,134.85C176.646,133.525 177.787,132.384 179.112,131.497ZM173.713,162.481H175.713V164.38C175.713,165.06 175.78,165.723 175.906,166.362L173.944,166.751C173.793,165.984 173.713,165.191 173.713,164.38V162.481ZM175.759,171.13L177.421,170.017C178.163,171.125 179.117,172.079 180.225,172.82L179.112,174.482C177.787,173.595 176.646,172.455 175.759,171.13ZM173.713,158.685H175.713V154.888H173.713V158.685ZM173.713,151.092H175.713V147.295H173.713V151.092ZM173.713,143.498H175.713V141.6C175.713,140.92 175.78,140.257 175.906,139.617L173.944,139.229C173.793,139.996 173.713,140.789 173.713,141.6V143.498ZM191.557,129.451V131.451H195.354V129.451H191.557ZM199.15,129.451V131.451H202.947V129.451H199.15ZM206.743,129.451V131.451H208.641C209.322,131.451 209.985,131.518 210.624,131.644L211.012,129.682C210.246,129.531 209.453,129.451 208.641,129.451H206.743ZM220.79,147.295H218.79V151.092H220.79V147.295ZM220.79,154.888H218.79V158.685H220.79V154.888ZM220.79,162.481H218.79V164.38C218.79,165.06 218.724,165.723 218.597,166.362L220.559,166.751C220.711,165.984 220.79,165.191 220.79,164.38V162.481ZM202.947,176.528V174.528H199.15V176.528H202.947ZM195.354,176.528V174.528H191.557V176.528H195.354Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#435B77"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M110.594,39.566L110.982,37.604C111.503,37.707 112.042,37.761 112.597,37.761H115.001V39.761H112.597C111.911,39.761 111.242,39.694 110.594,39.566ZM129.431,39.761V37.761H131.836C132.39,37.761 132.93,37.707 133.45,37.604L133.838,39.566C133.191,39.694 132.521,39.761 131.836,39.761H129.431ZM137.537,38.033L136.424,36.371C137.326,35.767 138.103,34.99 138.706,34.089L140.368,35.201C139.619,36.32 138.656,37.284 137.537,38.033ZM142.097,12.666H140.097V10.261C140.097,9.707 140.042,9.167 139.939,8.646L141.901,8.258C142.029,8.906 142.097,9.576 142.097,10.261V12.666ZM140.368,4.56L138.706,5.672C138.103,4.771 137.326,3.994 136.424,3.39L137.537,1.728C138.656,2.477 139.619,3.441 140.368,4.56ZM115.001,0H112.597C111.911,0 111.242,0.067 110.594,0.195L110.982,2.157C111.503,2.054 112.042,2 112.597,2H115.001V0ZM106.895,1.728L108.008,3.39C107.106,3.994 106.33,4.771 105.726,5.672L104.064,4.56C104.813,3.441 105.777,2.477 106.895,1.728ZM102.336,27.095H104.336V29.5C104.336,30.054 104.39,30.594 104.493,31.114L102.531,31.503C102.403,30.855 102.336,30.185 102.336,29.5V27.095ZM104.064,35.201L105.726,34.089C106.33,34.99 107.106,35.767 108.008,36.371L106.895,38.033C105.777,37.284 104.813,36.32 104.064,35.201ZM102.336,22.285H104.336V17.476H102.336V22.285ZM102.336,12.666H104.336V10.261C104.336,9.707 104.39,9.167 104.493,8.646L102.531,8.258C102.403,8.906 102.336,9.576 102.336,10.261V12.666ZM119.811,0V2H124.621V0H119.811ZM129.431,0V2H131.836C132.39,2 132.93,2.054 133.45,2.157L133.838,0.195C133.191,0.067 132.521,0 131.836,0H129.431ZM142.097,17.476H140.097V22.285H142.097V17.476ZM142.097,27.095H140.097V29.5C140.097,30.054 140.042,30.594 139.939,31.114L141.901,31.503C142.029,30.855 142.097,30.185 142.097,29.5V27.095ZM124.621,39.761V37.761H119.811V39.761H124.621Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#435B77"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M40.03,171.724L40.796,169.877C41.553,170.191 42.384,170.365 43.262,170.365H45.241V172.365H43.262C42.117,172.365 41.025,172.137 40.03,171.724ZM57.114,172.365V170.365H59.093C59.971,170.365 60.802,170.191 61.559,169.877L62.325,171.724C61.33,172.137 60.238,172.365 59.093,172.365H57.114ZM67.537,150.069H65.537V148.09C65.537,147.213 65.363,146.381 65.049,145.624L66.896,144.858C67.309,145.853 67.537,146.945 67.537,148.09V150.069ZM45.241,139.646H43.262C42.117,139.646 41.025,139.874 40.03,140.287L40.796,142.135C41.553,141.821 42.384,141.646 43.262,141.646H45.241V139.646ZM34.818,161.943H36.818V163.921C36.818,164.799 36.993,165.63 37.306,166.387L35.459,167.153C35.046,166.158 34.818,165.066 34.818,163.921V161.943ZM34.818,157.985H36.818V154.027H34.818V157.985ZM34.818,150.069H36.818V148.09C36.818,147.213 36.993,146.381 37.306,145.624L35.459,144.858C35.046,145.853 34.818,146.945 34.818,148.09V150.069ZM49.199,139.646V141.646H53.157V139.646H49.199ZM57.114,139.646V141.646H59.093C59.971,141.646 60.802,141.821 61.559,142.135L62.325,140.287C61.33,139.874 60.238,139.646 59.093,139.646H57.114ZM67.537,154.027H65.537V157.985H67.537V154.027ZM67.537,161.943H65.537V163.921C65.537,164.799 65.363,165.63 65.049,166.387L66.896,167.154C67.309,166.158 67.537,165.066 67.537,163.921V161.943ZM53.157,172.365V170.365H49.199V172.365H53.157Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#435B77"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M112.803,198.65L113.569,196.803C113.862,196.924 114.184,196.992 114.527,196.992H116.638V198.992H114.527C113.917,198.992 113.334,198.87 112.803,198.65ZM120.86,198.992V196.992H122.971C123.314,196.992 123.636,196.924 123.929,196.803L124.695,198.65C124.164,198.87 123.582,198.992 122.971,198.992H120.86ZM127.475,188.155H125.475V186.044C125.475,185.701 125.407,185.379 125.285,185.087L127.133,184.321C127.353,184.852 127.475,185.434 127.475,186.044V188.155ZM116.638,181.541H114.527C113.917,181.541 113.334,181.663 112.803,181.883L113.569,183.73C113.862,183.609 114.184,183.541 114.527,183.541H116.638V181.541ZM110.024,192.377H112.024V194.488C112.024,194.832 112.092,195.154 112.213,195.446L110.365,196.212C110.145,195.681 110.024,195.099 110.024,194.488V192.377ZM110.024,188.155H112.024V186.044C112.024,185.701 112.092,185.379 112.213,185.087L110.365,184.321C110.145,184.852 110.024,185.434 110.024,186.044V188.155ZM120.86,181.541V183.541H122.971C123.314,183.541 123.636,183.609 123.929,183.73L124.695,181.883C124.164,181.663 123.582,181.541 122.971,181.541H120.86ZM127.475,192.377H125.475V194.488C125.475,194.832 125.407,195.154 125.285,195.446L127.133,196.212C127.353,195.681 127.475,195.099 127.475,194.488V192.377Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#657D99"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M178.996,79.823L179.762,77.976C180.48,78.274 181.269,78.439 182.101,78.439H184.003V80.439H182.101C181.001,80.439 179.952,80.22 178.996,79.823ZM195.412,80.439V78.439H197.314C198.146,78.439 198.935,78.274 199.653,77.976L200.419,79.823C199.463,80.22 198.414,80.439 197.314,80.439H195.412ZM205.427,59.015H203.427V57.113C203.427,56.281 203.262,55.492 202.964,54.774L204.811,54.008C205.208,54.964 205.427,56.013 205.427,57.113V59.015ZM184.003,49H182.101C181.001,49 179.952,49.219 178.996,49.616L179.762,51.463C180.48,51.165 181.269,51 182.101,51H184.003V49ZM173.988,70.424H175.988V72.326C175.988,73.158 176.153,73.947 176.451,74.665L174.604,75.432C174.207,74.475 173.988,73.426 173.988,72.326V70.424ZM173.988,66.621H175.988V62.818H173.988V66.621ZM173.988,59.015H175.988V57.113C175.988,56.281 176.153,55.492 176.451,54.774L174.604,54.008C174.207,54.964 173.988,56.013 173.988,57.113V59.015ZM187.806,49V51H191.609V49H187.806ZM195.412,49V51H197.314C198.146,51 198.935,51.165 199.653,51.463L200.419,49.616C199.463,49.219 198.414,49 197.314,49H195.412ZM205.427,62.818H203.427V66.621H205.427V62.818ZM205.427,70.424H203.427V72.326C203.427,73.158 203.262,73.947 202.964,74.665L204.811,75.432C205.208,74.475 205.427,73.426 205.427,72.326V70.424ZM191.609,80.439V78.439H187.806V80.439H191.609Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#435B77"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M234.829,108.021L235.595,106.174C235.887,106.295 236.209,106.363 236.553,106.363H238.664V108.363H236.553C235.942,108.363 235.36,108.241 234.829,108.021ZM242.886,108.363V106.363H244.997C245.34,106.363 245.662,106.295 245.954,106.174L246.72,108.021C246.189,108.241 245.607,108.363 244.997,108.363H242.886ZM249.5,97.526H247.5V95.416C247.5,95.072 247.432,94.75 247.311,94.458L249.158,93.692C249.378,94.223 249.5,94.805 249.5,95.416V97.526ZM238.664,90.912H236.553C235.942,90.912 235.36,91.034 234.829,91.254L235.595,93.101C235.887,92.98 236.209,92.912 236.553,92.912H238.664V90.912ZM232.049,101.749H234.049V103.86C234.049,104.203 234.117,104.525 234.238,104.817L232.391,105.583C232.171,105.052 232.049,104.47 232.049,103.86V101.749ZM232.049,97.526H234.049V95.416C234.049,95.072 234.117,94.75 234.238,94.458L232.391,93.692C232.171,94.223 232.049,94.805 232.049,95.416V97.526ZM242.886,90.912V92.912H244.997C245.34,92.912 245.662,92.98 245.954,93.101L246.72,91.254C246.189,91.034 245.607,90.912 244.997,90.912H242.886ZM249.5,101.749H247.5V103.86C247.5,104.203 247.432,104.525 247.311,104.817L249.158,105.583C249.378,105.052 249.5,104.47 249.5,103.86V101.749Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M29.825,34.377V53.66C29.825,55.226 31.1,56.517 32.682,56.517H34.021C35.586,56.517 36.877,55.226 36.877,53.66V34.377H29.825Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M36.861,25.083V21.452C36.861,19.887 35.586,18.596 34.021,18.596H32.682C31.116,18.596 29.825,19.887 29.825,21.452V25.083H36.861Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M52.514,40.735V21.452C52.514,19.887 51.239,18.596 49.674,18.596H48.334C46.769,18.596 45.478,19.887 45.478,21.452V40.735H52.514Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M45.478,50.029V53.66C45.478,55.225 46.769,56.516 48.334,56.516H49.674C51.239,56.516 52.53,55.225 52.53,53.66V50.029H45.478Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M28.696,41.865H25.065C23.5,41.865 22.209,43.14 22.209,44.721V46.061C22.209,47.626 23.484,48.917 25.065,48.917H28.696V41.865Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M57.274,41.865H37.99V48.917H57.274C58.839,48.917 60.13,47.626 60.13,46.061V44.721C60.13,43.14 58.839,41.865 57.274,41.865Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M44.348,26.213H25.065C23.5,26.213 22.209,27.488 22.209,29.069V30.408C22.209,31.974 23.484,33.265 25.065,33.265H44.348V26.213Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M57.274,26.213H53.643V33.265H57.274C58.839,33.265 60.13,31.99 60.13,30.408V29.069C60.13,27.488 58.839,26.213 57.274,26.213Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M108.864,99.496H129.086C129.852,99.496 130.587,99.801 131.129,100.343C131.671,100.886 131.975,101.622 131.975,102.39L131.975,127.191C131.975,128.296 130.688,128.899 129.841,128.191L124.6,123.804H108.864C108.098,123.804 107.363,123.499 106.821,122.956C106.279,122.413 105.975,121.677 105.975,120.91V102.39C105.975,101.622 106.279,100.886 106.821,100.343C107.363,99.801 108.098,99.496 108.864,99.496ZM116.549,112.318H110.597V104.126H127.353V112.318H121.499V115.152H123.64C124.026,115.152 124.22,115.619 123.947,115.893L119.331,120.517C119.161,120.686 118.887,120.686 118.718,120.517L114.102,115.893C113.829,115.619 114.022,115.152 114.408,115.152H116.549V112.318Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M190.408,151.152V162.299C190.408,163.204 191.145,163.95 192.059,163.95H192.833C193.738,163.95 194.484,163.204 194.484,162.299V151.152H190.408Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M194.475,145.779V143.68C194.475,142.775 193.738,142.029 192.833,142.029H192.059C191.154,142.029 190.408,142.775 190.408,143.68V145.779H194.475Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M203.523,154.827V143.68C203.523,142.775 202.786,142.029 201.881,142.029H201.107C200.202,142.029 199.456,142.775 199.456,143.68V154.827H203.523Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M199.456,160.201V162.3C199.456,163.204 200.202,163.951 201.107,163.951H201.881C202.786,163.951 203.533,163.204 203.533,162.3V160.201H199.456Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M189.755,155.48H187.656C186.751,155.48 186.005,156.217 186.005,157.131V157.905C186.005,158.81 186.742,159.556 187.656,159.556H189.755V155.48Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M206.275,155.48H195.128V159.556H206.275C207.18,159.556 207.926,158.81 207.926,157.905V157.131C207.926,156.217 207.18,155.48 206.275,155.48Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M198.803,146.433H187.656C186.751,146.433 186.005,147.17 186.005,148.084V148.859C186.005,149.763 186.742,150.51 187.656,150.51H198.803V146.433Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M206.275,146.433H204.176V150.51H206.275C207.18,150.51 207.926,149.773 207.926,148.859V148.084C207.926,147.17 207.18,146.433 206.275,146.433Z" />
|
||||||
|
</vector>
|
||||||
14
briar-android/src/main/res/drawable/border_qr_scanner.xml
Normal file
14
briar-android/src/main/res/drawable/border_qr_scanner.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:dither="true"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<corners android:radius="32dp" />
|
||||||
|
|
||||||
|
<solid android:color="@android:color/transparent" />
|
||||||
|
|
||||||
|
<stroke
|
||||||
|
android:width="4dp"
|
||||||
|
android:color="#ffffff" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
12
briar-android/src/main/res/drawable/ic_mailbox.xml
Normal file
12
briar-android/src/main/res/drawable/ic_mailbox.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?android:attr/textColorPrimary"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
tools:ignore="NewApi">
|
||||||
|
<path
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:pathData="m5.0782,2c-0.5245,0 -1.0278,0.2105 -1.3987,0.5848C3.3085,2.959 3.1,3.4663 3.1,3.9956V16.7677c0,0.5293 0.2085,1.0377 0.5794,1.412 0.3709,0.3742 0.8742,0.5836 1.3987,0.5836H15.8509l3.589,3.0261C20.0193,22.278 20.9,21.862 20.9,21.1001V3.9956C20.9,3.4663 20.6915,2.959 20.3206,2.5848 19.9497,2.2105 19.4464,2 18.9218,2ZM6.2648,5.1927H17.7352v5.6502h-4.0073v1.9542h1.4659c0.2643,0 0.3966,0.3227 0.2098,0.5113l-3.1602,3.1881c-0.1159,0.1169 -0.3036,0.1169 -0.4195,0L8.6637,13.3084C8.4768,13.1198 8.6091,12.7971 8.8734,12.7971H10.3394V10.8429H6.2648Z" />
|
||||||
|
</vector>
|
||||||
124
briar-android/src/main/res/drawable/ic_mailbox_onboarding.xml
Normal file
124
briar-android/src/main/res/drawable/ic_mailbox_onboarding.xml
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="200dp"
|
||||||
|
android:height="160dp"
|
||||||
|
android:viewportWidth="250"
|
||||||
|
android:viewportHeight="200">
|
||||||
|
<path
|
||||||
|
android:fillColor="#F6FAFE"
|
||||||
|
android:pathData="M95.436,100.737C95.436,94.027 100.876,88.588 107.585,88.588H130.365C137.074,88.588 142.514,94.027 142.514,100.737V123.516C142.514,130.226 137.074,135.665 130.365,135.665H107.585C100.876,135.665 95.436,130.226 95.436,123.516V100.737Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#F6FAFE"
|
||||||
|
android:pathData="M102.336,10.765C102.336,5.098 106.93,0.504 112.597,0.504H131.836C137.503,0.504 142.097,5.098 142.097,10.765V30.004C142.097,35.671 137.503,40.265 131.836,40.265H112.597C106.93,40.265 102.336,35.671 102.336,30.004V10.765Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#F6FAFE"
|
||||||
|
android:pathData="M34.818,148.594C34.818,143.931 38.599,140.151 43.262,140.151H59.093C63.757,140.151 67.537,143.931 67.537,148.594V164.426C67.537,169.089 63.757,172.869 59.093,172.869H43.262C38.599,172.869 34.818,169.089 34.818,164.426V148.594Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#F6FAFE"
|
||||||
|
android:pathData="M110.024,186.549C110.024,184.061 112.04,182.045 114.527,182.045H122.971C125.458,182.045 127.475,184.061 127.475,186.549V194.992C127.475,197.48 125.458,199.496 122.971,199.496H114.527C112.04,199.496 110.024,197.48 110.024,194.992V186.549Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#F6FAFE"
|
||||||
|
android:pathData="M173.713,142.104C173.713,135.395 179.152,129.955 185.862,129.955H208.641C215.351,129.955 220.79,135.395 220.79,142.104V164.884C220.79,171.593 215.351,177.033 208.641,177.033H185.862C179.152,177.033 173.713,171.593 173.713,164.884V142.104Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#F6FAFE"
|
||||||
|
android:pathData="M232.049,95.92C232.049,93.432 234.065,91.416 236.553,91.416H244.997C247.484,91.416 249.5,93.432 249.5,95.92V104.364C249.5,106.851 247.484,108.867 244.997,108.867H236.553C234.065,108.867 232.049,106.851 232.049,104.364V95.92Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#657D99"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M120.481,84.731V45.772H122.481V84.731H120.481Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#657D99"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M117.685,176.605L117.685,140.151H119.685L119.685,176.605H117.685Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#657D99"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M3.28,108.949L4.046,107.102C4.338,107.223 4.66,107.291 5.003,107.291H7.114V109.291H5.003C4.393,109.291 3.811,109.169 3.28,108.949ZM11.336,109.291V107.291H13.447C13.79,107.291 14.113,107.223 14.405,107.102L15.171,108.949C14.64,109.169 14.058,109.291 13.447,109.291H11.336ZM17.951,98.454H15.951V96.343C15.951,96 15.883,95.678 15.762,95.386L17.609,94.62C17.829,95.151 17.951,95.733 17.951,96.343V98.454ZM7.114,91.84H5.003C4.393,91.84 3.811,91.962 3.28,92.182L4.046,94.029C4.338,93.908 4.66,93.84 5.003,93.84H7.114V91.84ZM0.5,102.676H2.5V104.787C2.5,105.131 2.568,105.453 2.689,105.745L0.842,106.511C0.622,105.98 0.5,105.398 0.5,104.787V102.676ZM0.5,98.454H2.5V96.343C2.5,96 2.568,95.678 2.689,95.386L0.842,94.62C0.622,95.151 0.5,95.733 0.5,96.343V98.454ZM11.336,91.84V93.84H13.447C13.79,93.84 14.113,93.908 14.405,94.029L15.171,92.182C14.64,91.962 14.058,91.84 13.447,91.84H11.336ZM17.951,102.676H15.951V104.787C15.951,105.131 15.883,105.453 15.762,105.745L17.609,106.511C17.829,105.98 17.951,105.398 17.951,104.787V102.676Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#74B816"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M41.177,65.021V63.153H43.177V65.021H41.177ZM41.177,72.495V68.758H43.177V72.495H41.177ZM41.177,79.969V76.232H43.177V79.969H41.177ZM41.177,87.443V83.706H43.177V87.443H41.177ZM41.177,94.916V91.179H43.177V94.916H41.177ZM41.177,99.522V98.653H43.177V99.522H44.91V101.522H39.681V99.522H41.177ZM24.705,101.522H22.209V99.522H24.705V101.522ZM34.689,101.522H29.697V99.522H34.689V101.522ZM52.107,101.522H50.374V99.522H54.854V101.522H54.107V102.652H52.107V101.522ZM61.844,101.522H58.349V99.522H61.844V101.522ZM67.087,101.522H65.339V99.522H67.087C68.048,99.522 68.966,99.713 69.805,100.061L69.039,101.908C68.439,101.66 67.78,101.522 67.087,101.522ZM72.187,106.622C72.187,105.929 72.049,105.27 71.8,104.67L73.648,103.904C73.995,104.743 74.187,105.661 74.187,106.622C74.187,107.316 74.325,107.974 74.574,108.574L72.726,109.34C72.378,108.502 72.187,107.583 72.187,106.622ZM52.107,111.172V106.912H54.107V111.172H52.107ZM79.287,113.722C78.326,113.722 77.408,113.531 76.569,113.183L77.335,111.336C77.935,111.585 78.594,111.722 79.287,111.722H81.59V113.722H79.287ZM88.5,113.722H86.197V111.722H88.5V113.722ZM52.107,119.692V115.432H54.107V119.692H52.107ZM52.107,128.213V123.953H54.107V128.213H52.107ZM52.107,134.603V132.473H54.107V134.603H52.107Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#74B816"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M105.214,135.434L105.602,133.472C106.242,133.599 106.905,133.665 107.585,133.665H109.484V135.665H107.585C106.774,135.665 105.981,135.586 105.214,135.434ZM128.466,135.665V133.665H130.365C131.045,133.665 131.708,133.599 132.347,133.472L132.736,135.434C131.969,135.586 131.176,135.665 130.365,135.665H128.466ZM137.115,133.619L136.002,131.957C137.11,131.216 138.064,130.262 138.805,129.154L140.467,130.267C139.58,131.591 138.44,132.732 137.115,133.619ZM142.514,102.635H140.514V100.737C140.514,100.057 140.447,99.394 140.32,98.754L142.282,98.366C142.434,99.133 142.514,99.926 142.514,100.737V102.635ZM140.467,93.987L138.805,95.1C138.064,93.992 137.11,93.038 136.002,92.296L137.115,90.634C138.44,91.521 139.58,92.662 140.467,93.987ZM109.484,88.588H107.585C106.774,88.588 105.981,88.668 105.214,88.819L105.602,90.781C106.242,90.655 106.905,90.588 107.585,90.588H109.484V88.588ZM100.835,90.634L101.948,92.296C100.84,93.038 99.886,93.992 99.145,95.1L97.483,93.987C98.37,92.662 99.51,91.521 100.835,90.634ZM95.436,121.618H97.436V123.516C97.436,124.197 97.503,124.86 97.63,125.499L95.668,125.887C95.516,125.121 95.436,124.328 95.436,123.516V121.618ZM97.483,130.267L99.145,129.154C99.886,130.262 100.84,131.216 101.948,131.957L100.835,133.619C99.51,132.732 98.37,131.591 97.483,130.267ZM95.436,117.822H97.436V114.025H95.436V117.822ZM95.436,110.228H97.436V106.432H95.436V110.228ZM95.436,102.635H97.436V100.737C97.436,100.057 97.503,99.394 97.63,98.754L95.668,98.366C95.516,99.133 95.436,99.926 95.436,100.737V102.635ZM113.28,88.588V90.588H117.077V88.588H113.28ZM120.873,88.588V90.588H124.67V88.588H120.873ZM128.466,88.588V90.588H130.365C131.045,90.588 131.708,90.655 132.347,90.781L132.736,88.819C131.969,88.668 131.176,88.588 130.365,88.588H128.466ZM142.514,106.432H140.514V110.228H142.514V106.432ZM142.514,114.025H140.514V117.822H142.514V114.025ZM142.514,121.618H140.514V123.516C140.514,124.197 140.447,124.86 140.32,125.499L142.282,125.887C142.434,125.121 142.514,124.328 142.514,123.516V121.618ZM124.67,135.665V133.665H120.873V135.665H124.67ZM117.077,135.665V133.665H113.28V135.665H117.077Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#74B816"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M188.618,87.043V85.178H190.618V87.043H188.618ZM188.618,94.503V90.773H190.618V94.503H188.618ZM188.618,98.233H190.618V99.098H191.517V101.098H190.618V101.687H188.618V98.233ZM199.112,101.098H195.315V99.098H199.112V101.098ZM206.707,101.098H202.91V99.098H206.707V101.098ZM214.303,101.098H210.505V99.098H214.303V101.098ZM221.898,101.098H218.1V99.098H221.898V101.098ZM227.595,101.098H225.696V99.098H227.595V101.098ZM188.618,108.042V104.864H190.618V108.042H188.618ZM188.618,111.807V111.219H190.618V111.863C190.865,111.891 191.109,111.929 191.35,111.976L190.962,113.938C190.528,113.853 190.079,113.807 189.618,113.807H187.737V111.807H188.618ZM153.881,113.807H152V111.807H153.881V113.807ZM161.405,113.807H157.643V111.807H161.405V113.807ZM168.928,113.807H165.166V111.807H168.928V113.807ZM176.452,113.807H172.69V111.807H176.452V113.807ZM183.975,113.807H180.214V111.807H183.975V113.807ZM195.34,116.865C194.837,116.115 194.19,115.468 193.44,114.966L194.552,113.304C195.52,113.952 196.353,114.785 197.001,115.753L195.34,116.865ZM196.498,120.687C196.498,120.226 196.453,119.777 196.367,119.343L198.329,118.955C198.44,119.516 198.498,120.095 198.498,120.687V121.707H196.498V120.687ZM196.498,124.765V123.746H198.498V124.765H196.498Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#74B816"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M183.491,176.801L183.879,174.839C184.519,174.966 185.182,175.033 185.862,175.033H187.76V177.033H185.862C185.051,177.033 184.258,176.953 183.491,176.801ZM206.743,177.033V175.033H208.641C209.322,175.033 209.985,174.966 210.624,174.839L211.012,176.801C210.246,176.953 209.453,177.033 208.641,177.033H206.743ZM215.392,174.986L214.279,173.324C215.387,172.583 216.341,171.629 217.082,170.521L218.744,171.634C217.857,172.959 216.717,174.099 215.392,174.986ZM220.79,144.002H218.79V142.104C218.79,141.424 218.724,140.761 218.597,140.121L220.559,139.733C220.711,140.5 220.79,141.293 220.79,142.104V144.002ZM218.744,135.354L217.082,136.467C216.341,135.359 215.387,134.405 214.279,133.663L215.392,132.002C216.717,132.889 217.857,134.029 218.744,135.354ZM187.76,129.955H185.862C185.051,129.955 184.258,130.035 183.491,130.186L183.879,132.148C184.519,132.022 185.182,131.955 185.862,131.955H187.76V129.955ZM179.112,132.002L180.225,133.663C179.117,134.405 178.163,135.359 177.421,136.467L175.759,135.354C176.646,134.029 177.787,132.889 179.112,132.002ZM173.713,162.985H175.713V164.884C175.713,165.564 175.78,166.227 175.906,166.866L173.944,167.255C173.793,166.488 173.713,165.695 173.713,164.884V162.985ZM175.759,171.634L177.421,170.521C178.163,171.629 179.117,172.583 180.225,173.324L179.112,174.986C177.787,174.099 176.646,172.959 175.759,171.634ZM173.713,159.189H175.713V155.392H173.713V159.189ZM173.713,151.596H175.713V147.799H173.713V151.596ZM173.713,144.002H175.713V142.104C175.713,141.424 175.78,140.761 175.906,140.121L173.944,139.733C173.793,140.5 173.713,141.293 173.713,142.104V144.002ZM191.557,129.955V131.955H195.354V129.955H191.557ZM199.15,129.955V131.955H202.947V129.955H199.15ZM206.743,129.955V131.955H208.641C209.322,131.955 209.985,132.022 210.624,132.148L211.012,130.186C210.246,130.035 209.453,129.955 208.641,129.955H206.743ZM220.79,147.799H218.79V151.596H220.79V147.799ZM220.79,155.392H218.79V159.189H220.79V155.392ZM220.79,162.985H218.79V164.884C218.79,165.564 218.724,166.227 218.597,166.866L220.559,167.255C220.711,166.488 220.79,165.695 220.79,164.884V162.985ZM202.947,177.033V175.033H199.15V177.033H202.947ZM195.354,177.033V175.033H191.557V177.033H195.354Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#435B77"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M110.594,40.07L110.982,38.108C111.503,38.211 112.042,38.265 112.597,38.265H115.001V40.265H112.597C111.911,40.265 111.242,40.198 110.594,40.07ZM129.431,40.265V38.265H131.836C132.39,38.265 132.93,38.211 133.45,38.108L133.838,40.07C133.191,40.198 132.521,40.265 131.836,40.265H129.431ZM137.537,38.537L136.424,36.875C137.326,36.271 138.103,35.494 138.706,34.592L140.368,35.705C139.619,36.824 138.656,37.787 137.537,38.537ZM142.097,13.17H140.097V10.765C140.097,10.211 140.042,9.671 139.939,9.151L141.901,8.762C142.029,9.41 142.097,10.08 142.097,10.765V13.17ZM140.368,5.064L138.706,6.176C138.103,5.275 137.326,4.498 136.424,3.894L137.537,2.232C138.656,2.981 139.619,3.945 140.368,5.064ZM115.001,0.504H112.597C111.911,0.504 111.242,0.571 110.594,0.699L110.982,2.661C111.503,2.558 112.042,2.504 112.597,2.504H115.001V0.504ZM106.895,2.232L108.008,3.894C107.106,4.498 106.33,5.275 105.726,6.176L104.064,5.064C104.813,3.945 105.777,2.981 106.895,2.232ZM102.336,27.599H104.336V30.004C104.336,30.558 104.39,31.098 104.493,31.618L102.531,32.007C102.403,31.359 102.336,30.689 102.336,30.004V27.599ZM104.064,35.705L105.726,34.592C106.33,35.494 107.106,36.271 108.008,36.875L106.895,38.537C105.777,37.787 104.813,36.824 104.064,35.705ZM102.336,22.789H104.336V17.98H102.336V22.789ZM102.336,13.17H104.336V10.765C104.336,10.211 104.39,9.671 104.493,9.151L102.531,8.762C102.403,9.41 102.336,10.08 102.336,10.765V13.17ZM119.811,0.504V2.504H124.621V0.504H119.811ZM129.431,0.504V2.504H131.836C132.39,2.504 132.93,2.558 133.45,2.661L133.838,0.699C133.191,0.571 132.521,0.504 131.836,0.504H129.431ZM142.097,17.98H140.097V22.789H142.097V17.98ZM142.097,27.599H140.097V30.004C140.097,30.558 140.042,31.098 139.939,31.618L141.901,32.007C142.029,31.359 142.097,30.689 142.097,30.004V27.599ZM124.621,40.265V38.265H119.811V40.265H124.621Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#435B77"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M40.03,172.228L40.796,170.381C41.553,170.695 42.384,170.869 43.262,170.869H45.241V172.869H43.262C42.117,172.869 41.025,172.641 40.03,172.228ZM57.114,172.869V170.869H59.093C59.971,170.869 60.802,170.695 61.559,170.381L62.325,172.228C61.33,172.641 60.238,172.869 59.093,172.869H57.114ZM67.537,150.573H65.537V148.594C65.537,147.717 65.363,146.885 65.049,146.128L66.896,145.362C67.309,146.358 67.537,147.449 67.537,148.594V150.573ZM45.241,140.151H43.262C42.117,140.151 41.025,140.378 40.03,140.791L40.796,142.639C41.553,142.325 42.384,142.151 43.262,142.151H45.241V140.151ZM34.818,162.447H36.818V164.426C36.818,165.303 36.993,166.134 37.306,166.891L35.459,167.658C35.046,166.662 34.818,165.57 34.818,164.426V162.447ZM34.818,158.489H36.818V154.531H34.818V158.489ZM34.818,150.573H36.818V148.594C36.818,147.717 36.993,146.885 37.306,146.128L35.459,145.362C35.046,146.358 34.818,147.449 34.818,148.594V150.573ZM49.199,140.151V142.151H53.157V140.151H49.199ZM57.114,140.151V142.151H59.093C59.971,142.151 60.802,142.325 61.559,142.639L62.325,140.791C61.33,140.378 60.238,140.151 59.093,140.151H57.114ZM67.537,154.531H65.537V158.489H67.537V154.531ZM67.537,162.447H65.537V164.426C65.537,165.303 65.363,166.134 65.049,166.891L66.896,167.658C67.309,166.662 67.537,165.57 67.537,164.426V162.447ZM53.157,172.869V170.869H49.199V172.869H53.157Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#435B77"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M112.803,199.154L113.569,197.307C113.862,197.428 114.184,197.496 114.527,197.496H116.638V199.496H114.527C113.917,199.496 113.334,199.374 112.803,199.154ZM120.86,199.496V197.496H122.971C123.314,197.496 123.636,197.428 123.929,197.307L124.695,199.154C124.164,199.374 123.582,199.496 122.971,199.496H120.86ZM127.475,188.66H125.475V186.549C125.475,186.205 125.407,185.883 125.285,185.591L127.133,184.825C127.353,185.356 127.475,185.938 127.475,186.549V188.66ZM116.638,182.045H114.527C113.917,182.045 113.334,182.167 112.803,182.387L113.569,184.234C113.862,184.113 114.184,184.045 114.527,184.045H116.638V182.045ZM110.024,192.881H112.024V194.992C112.024,195.336 112.092,195.658 112.213,195.95L110.365,196.716C110.145,196.185 110.024,195.603 110.024,194.992V192.881ZM110.024,188.66H112.024V186.549C112.024,186.205 112.092,185.883 112.213,185.591L110.365,184.825C110.145,185.356 110.024,185.938 110.024,186.549V188.66ZM120.86,182.045V184.045H122.971C123.314,184.045 123.636,184.113 123.929,184.234L124.695,182.387C124.164,182.167 123.582,182.045 122.971,182.045H120.86ZM127.475,192.881H125.475V194.992C125.475,195.336 125.407,195.658 125.285,195.95L127.133,196.716C127.353,196.185 127.475,195.603 127.475,194.992V192.881Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#657D99"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M178.996,80.327L179.762,78.48C180.48,78.778 181.269,78.943 182.101,78.943H184.003V80.943H182.101C181.001,80.943 179.952,80.724 178.996,80.327ZM195.412,80.943V78.943H197.314C198.146,78.943 198.935,78.778 199.653,78.48L200.419,80.327C199.463,80.724 198.414,80.943 197.314,80.943H195.412ZM205.427,59.519H203.427V57.617C203.427,56.785 203.262,55.996 202.964,55.278L204.811,54.512C205.208,55.468 205.427,56.517 205.427,57.617V59.519ZM184.003,49.504H182.101C181.001,49.504 179.952,49.723 178.996,50.12L179.762,51.967C180.48,51.669 181.269,51.504 182.101,51.504H184.003V49.504ZM173.988,70.928H175.988V72.83C175.988,73.662 176.153,74.451 176.451,75.169L174.604,75.936C174.207,74.979 173.988,73.93 173.988,72.83V70.928ZM173.988,67.125H175.988V63.322H173.988V67.125ZM173.988,59.519H175.988V57.617C175.988,56.785 176.153,55.996 176.451,55.278L174.604,54.512C174.207,55.468 173.988,56.517 173.988,57.617V59.519ZM187.806,49.504V51.504H191.609V49.504H187.806ZM195.412,49.504V51.504H197.314C198.146,51.504 198.935,51.669 199.653,51.967L200.419,50.12C199.463,49.723 198.414,49.504 197.314,49.504H195.412ZM205.427,63.322H203.427V67.125H205.427V63.322ZM205.427,70.928H203.427V72.83C203.427,73.662 203.262,74.451 202.964,75.169L204.811,75.936C205.208,74.979 205.427,73.93 205.427,72.83V70.928ZM191.609,80.943V78.943H187.806V80.943H191.609Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#435B77"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M234.829,108.525L235.595,106.678C235.887,106.799 236.209,106.867 236.553,106.867H238.664V108.867H236.553C235.942,108.867 235.36,108.745 234.829,108.525ZM242.886,108.867V106.867H244.997C245.34,106.867 245.662,106.799 245.954,106.678L246.72,108.525C246.189,108.745 245.607,108.867 244.997,108.867H242.886ZM249.5,98.031H247.5V95.92C247.5,95.576 247.432,95.254 247.311,94.962L249.158,94.196C249.378,94.727 249.5,95.309 249.5,95.92V98.031ZM238.664,91.416H236.553C235.942,91.416 235.36,91.538 234.829,91.758L235.595,93.605C235.887,93.484 236.209,93.416 236.553,93.416H238.664V91.416ZM232.049,102.253H234.049V104.364C234.049,104.707 234.117,105.029 234.238,105.321L232.391,106.087C232.171,105.556 232.049,104.974 232.049,104.364V102.253ZM232.049,98.031H234.049V95.92C234.049,95.576 234.117,95.254 234.238,94.962L232.391,94.196C232.171,94.727 232.049,95.309 232.049,95.92V98.031ZM242.886,91.416V93.416H244.997C245.34,93.416 245.662,93.484 245.954,93.605L246.72,91.758C246.189,91.538 245.607,91.416 244.997,91.416H242.886ZM249.5,102.253H247.5V104.364C247.5,104.707 247.432,105.029 247.311,105.321L249.158,106.087C249.378,105.556 249.5,104.974 249.5,104.364V102.253Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M29.825,34.881V54.164C29.825,55.73 31.1,57.021 32.682,57.021H34.021C35.586,57.021 36.877,55.73 36.877,54.164V34.881H29.825Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M36.861,25.587V21.956C36.861,20.391 35.586,19.1 34.021,19.1H32.682C31.116,19.1 29.825,20.391 29.825,21.956V25.587H36.861Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M52.514,41.239V21.956C52.514,20.391 51.239,19.1 49.674,19.1H48.334C46.769,19.1 45.478,20.391 45.478,21.956V41.239H52.514Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M45.478,50.533V54.164C45.478,55.729 46.769,57.02 48.334,57.02H49.674C51.239,57.02 52.53,55.729 52.53,54.164V50.533H45.478Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M28.696,42.369H25.065C23.5,42.369 22.209,43.644 22.209,45.225V46.565C22.209,48.13 23.484,49.421 25.065,49.421H28.696V42.369Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M57.274,42.369H37.99V49.421H57.274C58.839,49.421 60.13,48.13 60.13,46.565V45.225C60.13,43.644 58.839,42.369 57.274,42.369Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M44.348,26.717H25.065C23.5,26.717 22.209,27.992 22.209,29.573V30.913C22.209,32.478 23.484,33.769 25.065,33.769H44.348V26.717Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M57.274,26.717H53.643V33.769H57.274C58.839,33.769 60.13,32.494 60.13,30.912V29.573C60.13,27.992 58.839,26.717 57.274,26.717Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M108.864,100H129.086C129.852,100 130.587,100.305 131.129,100.848C131.671,101.39 131.975,102.126 131.975,102.894L131.975,127.695C131.975,128.8 130.688,129.403 129.841,128.695L124.6,124.308H108.864C108.098,124.308 107.363,124.003 106.821,123.46C106.279,122.917 105.975,122.181 105.975,121.414V102.894C105.975,102.126 106.279,101.39 106.821,100.848C107.363,100.305 108.098,100 108.864,100ZM116.549,112.823H110.597V104.63H127.353V112.823H121.499V115.656H123.64C124.026,115.656 124.22,116.123 123.947,116.397L119.331,121.021C119.161,121.19 118.887,121.19 118.718,121.021L114.102,116.397C113.829,116.123 114.022,115.656 114.408,115.656H116.549V112.823Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M190.408,151.656V162.803C190.408,163.708 191.145,164.454 192.059,164.454H192.833C193.738,164.454 194.484,163.708 194.484,162.803V151.656H190.408Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M194.475,146.283V144.184C194.475,143.279 193.738,142.533 192.833,142.533H192.059C191.154,142.533 190.408,143.279 190.408,144.184V146.283H194.475Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M203.523,155.331V144.184C203.523,143.279 202.786,142.533 201.881,142.533H201.107C200.202,142.533 199.456,143.279 199.456,144.184V155.331H203.523Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#82C91E"
|
||||||
|
android:pathData="M199.456,160.705V162.804C199.456,163.709 200.202,164.455 201.107,164.455H201.881C202.786,164.455 203.533,163.709 203.533,162.804V160.705H199.456Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M189.755,155.984H187.656C186.751,155.984 186.005,156.721 186.005,157.635V158.409C186.005,159.314 186.742,160.061 187.656,160.061H189.755V155.984Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M206.275,155.984H195.128V160.061H206.275C207.18,160.061 207.926,159.314 207.926,158.409V157.635C207.926,156.721 207.18,155.984 206.275,155.984Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M198.803,146.937H187.656C186.751,146.937 186.005,147.674 186.005,148.588V149.363C186.005,150.267 186.742,151.014 187.656,151.014H198.803V146.937Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#95DE2D"
|
||||||
|
android:pathData="M206.275,146.937H204.176V151.014H206.275C207.18,151.014 207.926,150.277 207.926,149.363V148.588C207.926,147.674 207.18,146.937 206.275,146.937Z" />
|
||||||
|
</vector>
|
||||||
17
briar-android/src/main/res/layout/activity_mailbox.xml
Normal file
17
briar-android/src/main/res/layout/activity_mailbox.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/fragmentContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
style="?android:progressBarStyleLarge"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="invisible"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout 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">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
style="?android:attr/progressBarStyleLarge"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/textView"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView"
|
||||||
|
style="@style/TextAppearance.AppCompat.Large"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:text="@string/mailbox_setup_connecting"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/progressBar" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
27
briar-android/src/main/res/layout/fragment_mailbox_scan.xml
Normal file
27
briar-android/src/main/res/layout/fragment_mailbox_scan.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout 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.qrcode.CameraView
|
||||||
|
android:id="@+id/camera_view"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:background="@drawable/border_qr_scanner"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1,1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<?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:id="@+id/scrollView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fillViewport="true"
|
||||||
|
tools:context=".android.mailbox.MailboxActivity">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="@dimen/hero_rect_width"
|
||||||
|
android:layout_height="@dimen/hero_rect_width"
|
||||||
|
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/introView"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0.25"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
app:srcCompat="@drawable/ic_mailbox"
|
||||||
|
app:tint="@color/briar_brand_green"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/introView"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginBottom="@dimen/margin_large"
|
||||||
|
android:text="@string/mailbox_setup_intro"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/scanButton"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/scanButton"
|
||||||
|
style="@style/BriarButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/margin_large"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:text="@string/mailbox_setup_button_scan"
|
||||||
|
app:drawableLeftCompat="@drawable/ic_qr_code"
|
||||||
|
app:drawableStartCompat="@drawable/ic_qr_code"
|
||||||
|
app:drawableTint="@color/button_text"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?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:id="@+id/scrollView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fillViewport="true"
|
||||||
|
tools:context=".android.mailbox.MailboxActivity">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/introView"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0.25"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
app:srcCompat="@drawable/ic_mailbox_onboarding"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/introView"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginBottom="@dimen/margin_large"
|
||||||
|
android:text="@string/mailbox_setup_intro"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/continueButton"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/continueButton"
|
||||||
|
style="@style/BriarButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/margin_large"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:text="@string/continue_button"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
81
briar-android/src/main/res/layout/fragment_offline.xml
Normal file
81
briar-android/src/main/res/layout/fragment_offline.xml
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.core.widget.NestedScrollView 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">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iconView"
|
||||||
|
android:layout_width="@dimen/hero_square"
|
||||||
|
android:layout_height="@dimen/hero_square"
|
||||||
|
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/titleView"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0.25"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
app:srcCompat="@drawable/transport_tor"
|
||||||
|
app:tint="@color/briar_red_500"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/titleView"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/offline"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/textView"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/iconView" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginBottom="@dimen/margin_large"
|
||||||
|
android:text="@string/tor_offline_description"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/checkButton"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/titleView" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/checkButton"
|
||||||
|
style="@style/BriarButtonFlat.Neutral"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/margin_large"
|
||||||
|
android:text="@string/tor_offline_button_check"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/button"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button"
|
||||||
|
style="@style/BriarButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/margin_large"
|
||||||
|
android:text="@string/try_again_button"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
@@ -50,10 +50,16 @@
|
|||||||
<item quantity="one">Това е тестова версия на Briar. Вашият акаунт ще бъде изтече след %d ден и не може да бъде подновена.</item>
|
<item quantity="one">Това е тестова версия на Briar. Вашият акаунт ще бъде изтече след %d ден и не може да бъде подновена.</item>
|
||||||
<item quantity="other">Това е изпитателно издание на Briar. Валидността на профила ще изтече след %d дена и не може да бъде подновена.</item>
|
<item quantity="other">Това е изпитателно издание на Briar. Валидността на профила ще изтече след %d дена и не може да бъде подновена.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
<plurals name="old_android_expiry_warning">
|
||||||
|
<item quantity="one">Android 4 не се поддържа. Briar ще спре да работи на %s (след %d ден). Инсталирайте Briar на друго устройство и създайте нов профил.</item>
|
||||||
|
<item quantity="other">Android 4 не се поддържа. Briar ще спре да работи на %s (след %d дни). Инсталирайте Briar на друго устройство и създайте нов профил.</item>
|
||||||
|
</plurals>
|
||||||
<string name="expiry_date_reached">Софтуерът е с изтекъл срок.\nБлагодарим за изпитването!</string>
|
<string name="expiry_date_reached">Софтуерът е с изтекъл срок.\nБлагодарим за изпитването!</string>
|
||||||
<string name="download_briar">За да продължите да използвате Briar изтеглете последното издание.</string>
|
<string name="download_briar">За да продължите да използвате Briar изтеглете последното издание.</string>
|
||||||
<string name="create_new_account">Ще трябва да създадете нов профил, но ще можете да използвате същия прякор.</string>
|
<string name="create_new_account">Ще трябва да създадете нов профил, но ще можете да използвате същия прякор.</string>
|
||||||
<string name="download_briar_button">Изтегляне</string>
|
<string name="download_briar_button">Изтегляне</string>
|
||||||
|
<string name="old_android_expiry_date_reached">Briar не работи на Android 4.\nИнсталирайте Briar на друго устройство.</string>
|
||||||
|
<string name="old_android_delete_account">За да премахнете профила от устройството докоснете бутона отдолу.</string>
|
||||||
<string name="delete_account_button">Премахване на профил</string>
|
<string name="delete_account_button">Премахване на профил</string>
|
||||||
<string name="startup_open_database">Хранилището се дешифрира…</string>
|
<string name="startup_open_database">Хранилището се дешифрира…</string>
|
||||||
<string name="startup_migrate_database">Хранилището се обновява…</string>
|
<string name="startup_migrate_database">Хранилището се обновява…</string>
|
||||||
@@ -419,8 +425,8 @@
|
|||||||
<string name="forum_invitation_response_accepted_sent">Приехте поканата от %s за членство във форум.</string>
|
<string name="forum_invitation_response_accepted_sent">Приехте поканата от %s за членство във форум.</string>
|
||||||
<string name="forum_invitation_response_declined_sent">Отказахте поканата на %s за членство във форум.</string>
|
<string name="forum_invitation_response_declined_sent">Отказахте поканата на %s за членство във форум.</string>
|
||||||
<string name="forum_invitation_response_declined_auto">Поканата от %s за членство във форум е отказана автоматично.</string>
|
<string name="forum_invitation_response_declined_auto">Поканата от %s за членство във форум е отказана автоматично.</string>
|
||||||
<string name="forum_invitation_response_accepted_received">%s прие поканата във форум.</string>
|
<string name="forum_invitation_response_accepted_received">%s прие поканата за форум.</string>
|
||||||
<string name="forum_invitation_response_declined_received">%s отказа поканата във форум.</string>
|
<string name="forum_invitation_response_declined_received">%s отказа поканата за форум.</string>
|
||||||
<string name="sharing_status">Състояние на споделяне</string>
|
<string name="sharing_status">Състояние на споделяне</string>
|
||||||
<string name="sharing_status_forum">Всеки участник във форума може да го сподели с контактите си. Споделяте този форум със следните контакти. Възможно е да има и други, които не можете да видите.</string>
|
<string name="sharing_status_forum">Всеки участник във форума може да го сподели с контактите си. Споделяте този форум със следните контакти. Възможно е да има и други, които не можете да видите.</string>
|
||||||
<string name="shared_with">Споделено с %1$d (на линия %2$d)</string>
|
<string name="shared_with">Споделено с %1$d (на линия %2$d)</string>
|
||||||
@@ -569,6 +575,12 @@
|
|||||||
<string name="notify_sound_setting_disabled">Няма</string>
|
<string name="notify_sound_setting_disabled">Няма</string>
|
||||||
<string name="choose_ringtone_title">Избор на тон за звънене</string>
|
<string name="choose_ringtone_title">Избор на тон за звънене</string>
|
||||||
<string name="cannot_load_ringtone">Тонът за звънене не може да бъде зареден</string>
|
<string name="cannot_load_ringtone">Тонът за звънене не може да бъде зареден</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_settings_title">Пощенска кутия</string>
|
||||||
|
<string name="mailbox_setup_title">Настройка като пощенска кутия</string>
|
||||||
|
<string name="mailbox_setup_intro">Пощенската кутия ви дава възможност да получавате съобщения от контактите ви докато сте извън мрежа. Кутията ще получава съобщенията и ще ги пази до като дойдете на линия.\n\nИнсталирайте приложението Birar Mailbox на резервно устройство. Включете го в захранване и с достъп до безжична мрежа, така че да е винаги на линия.</string>
|
||||||
|
<string name="mailbox_setup_connecting">Свързване…</string>
|
||||||
|
<string name="tor_offline_title">Извън линия</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Изчезващи съобщения</string>
|
<string name="disappearing_messages_title">Изчезващи съобщения</string>
|
||||||
<string name="disappearing_messages_explanation_long">При включване, тази настройка прави бъдещите съобщения в този разговор да изчезват след 7\u00A0дни.
|
<string name="disappearing_messages_explanation_long">При включване, тази настройка прави бъдещите съобщения в този разговор да изчезват след 7\u00A0дни.
|
||||||
@@ -649,7 +661,7 @@
|
|||||||
<string name="transports_help_text">Briar може да се свърже с контактите ви през интернет, Wi-Fi или Bluetooth.\n\nЗа повече поверителност цялата връзка към интернет се пренасочва през мрежата на Tor.\n\nАко даден контакт може да бъде достъпен чрез няколко метода Briar ги използва успоредно.</string>
|
<string name="transports_help_text">Briar може да се свърже с контактите ви през интернет, Wi-Fi или Bluetooth.\n\nЗа повече поверителност цялата връзка към интернет се пренасочва през мрежата на Tor.\n\nАко даден контакт може да бъде достъпен чрез няколко метода Briar ги използва успоредно.</string>
|
||||||
<!--Share app offline-->
|
<!--Share app offline-->
|
||||||
<string name="hotspot_title">Споделяне на приложението извън мрежа</string>
|
<string name="hotspot_title">Споделяне на приложението извън мрежа</string>
|
||||||
<string name="hotspot_intro">Споделете приложението с някого наблизо без използване на интернет, а с през Wi-Fi на устройствата.
|
<string name="hotspot_intro">Споделете приложението с някого наблизо без използване на интернет, а през Wi-Fi на устройствата.
|
||||||
\n\nВашето устройство ще създаде безжична точка за достъп. Хората наблизо биха могли да се свържат към нея и да изтеглят Briar от вашето устройство.</string>
|
\n\nВашето устройство ще създаде безжична точка за достъп. Хората наблизо биха могли да се свържат към нея и да изтеглят Briar от вашето устройство.</string>
|
||||||
<string name="hotspot_button_start_sharing">Включване на безжична точка</string>
|
<string name="hotspot_button_start_sharing">Включване на безжична точка</string>
|
||||||
<string name="hotspot_button_stop_sharing">Спиране на безжична точка</string>
|
<string name="hotspot_button_stop_sharing">Спиране на безжична точка</string>
|
||||||
@@ -686,7 +698,13 @@
|
|||||||
<string name="website_troubleshooting_title">Отстраняване на неизправности</string>
|
<string name="website_troubleshooting_title">Отстраняване на неизправности</string>
|
||||||
<string name="website_troubleshooting_1">Ако не можете да изтеглите приложението пробвайте с друг мрежов четец.</string>
|
<string name="website_troubleshooting_1">Ако не можете да изтеглите приложението пробвайте с друг мрежов четец.</string>
|
||||||
<string name="hotspot_help_wifi_title">Проблеми при свързване чрез Wi-Fi:</string>
|
<string name="hotspot_help_wifi_title">Проблеми при свързване чрез Wi-Fi:</string>
|
||||||
|
<string name="hotspot_help_wifi_1">Изключете и включете Wi-Fi и на двете устройства, и опитайте отново.</string>
|
||||||
|
<string name="hotspot_help_wifi_2">Ако устройството се оплаква, че безжичната мрежа няма достъп до интернет, останете свързани въпреки това.</string>
|
||||||
|
<string name="hotspot_help_wifi_3">Рестартирайте устройството, което създава безжичната точка за достъп, отворете Briar и го споделете отново.</string>
|
||||||
<string name="hotspot_help_site_title">Проблеми при посещаване на страницата:</string>
|
<string name="hotspot_help_site_title">Проблеми при посещаване на страницата:</string>
|
||||||
|
<string name="hotspot_help_site_1">Уверете се, че въвеждате адреса точно, както е показан. Дори малка грешка може да доведе до неуспех.</string>
|
||||||
|
<string name="hotspot_help_site_2">Уверете се, че устройството е свързано с правилната мрежа на Wi-Fi (вижте по-горе) докато отваряте страницата.</string>
|
||||||
|
<string name="hotspot_help_site_3">Ако имате инсталирано приложение за защитна стена се уверете, че не спира достъпа.</string>
|
||||||
<string name="hotspot_help_fallback_title">Нищо не става?</string>
|
<string name="hotspot_help_fallback_title">Нищо не става?</string>
|
||||||
<string name="hotspot_help_fallback_intro">Запазете приложението като файл на APK и го споделете по друг начин. След като бъде получен от другото устройство може да бъде използван за инсталиране на Briar.
|
<string name="hotspot_help_fallback_intro">Запазете приложението като файл на APK и го споделете по друг начин. След като бъде получен от другото устройство може да бъде използван за инсталиране на Briar.
|
||||||
\n\nЗабележка: За да го споделите чрез Bluetooth може да се наложи първо да го преименувате, така че да завършва на .zip.</string>
|
\n\nЗабележка: За да го споделите чрез Bluetooth може да се наложи първо да го преименувате, така че да завършва на .zip.</string>
|
||||||
|
|||||||
@@ -160,7 +160,7 @@
|
|||||||
<string name="image_attach_error_invalid_mime_type">El format de la imatge no s\'admet: %s</string>
|
<string name="image_attach_error_invalid_mime_type">El format de la imatge no s\'admet: %s</string>
|
||||||
<string name="set_contact_alias">Canvia el nom del contacte</string>
|
<string name="set_contact_alias">Canvia el nom del contacte</string>
|
||||||
<string name="set_contact_alias_hint">Nom del contacte</string>
|
<string name="set_contact_alias_hint">Nom del contacte</string>
|
||||||
<string name="menu_item_disappearing_messages">Missatges fonedissos</string>
|
<string name="menu_item_disappearing_messages">Missatges efímers</string>
|
||||||
<!--The first placeholder will show a duration like "7 days". The second placeholder at the end will add "Tap to learn more."-->
|
<!--The first placeholder will show a duration like "7 days". The second placeholder at the end will add "Tap to learn more."-->
|
||||||
<string name="auto_delete_msg_you_enabled">Els vostres missatges es faran fonedissos en %1$s. %2$s</string>
|
<string name="auto_delete_msg_you_enabled">Els vostres missatges es faran fonedissos en %1$s. %2$s</string>
|
||||||
<!--The placeholder at the end will add "Tap to learn more."-->
|
<!--The placeholder at the end will add "Tap to learn more."-->
|
||||||
@@ -559,8 +559,11 @@ Així que l\'actualitzi li veureu una icona diferent .</string>
|
|||||||
<string name="notify_sound_setting_disabled">Cap</string>
|
<string name="notify_sound_setting_disabled">Cap</string>
|
||||||
<string name="choose_ringtone_title">Trieu el so d\'avís</string>
|
<string name="choose_ringtone_title">Trieu el so d\'avís</string>
|
||||||
<string name="cannot_load_ringtone">No s\'ha pogut carregar el so d\'avís</string>
|
<string name="cannot_load_ringtone">No s\'ha pogut carregar el so d\'avís</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_setup_connecting">S\'està connectant...</string>
|
||||||
|
<string name="tor_offline_title">Fora de línia</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Missatges fonedissos</string>
|
<string name="disappearing_messages_title">Missatges efímers</string>
|
||||||
<string name="learn_more">Més informació</string>
|
<string name="learn_more">Més informació</string>
|
||||||
<!--Settings Actions-->
|
<!--Settings Actions-->
|
||||||
<string name="pref_category_actions">Accions</string>
|
<string name="pref_category_actions">Accions</string>
|
||||||
|
|||||||
@@ -575,6 +575,22 @@
|
|||||||
<string name="notify_sound_setting_disabled">Keine</string>
|
<string name="notify_sound_setting_disabled">Keine</string>
|
||||||
<string name="choose_ringtone_title">Klingelton auswählen</string>
|
<string name="choose_ringtone_title">Klingelton auswählen</string>
|
||||||
<string name="cannot_load_ringtone">Klingelton kann nicht geladen werden</string>
|
<string name="cannot_load_ringtone">Klingelton kann nicht geladen werden</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_settings_title">Mailbox</string>
|
||||||
|
<string name="mailbox_setup_title">Mailbox-Einrichtung</string>
|
||||||
|
<string name="mailbox_setup_intro">Eine Mailbox ermöglicht es deinen Kontakten, dir Nachrichten zu senden, während du offline bist. Die Mailbox empfängt deine Nachrichten und speichert sie, bis du wieder online bist.\n
|
||||||
|
\nDu kannst die Briar Mailbox-App auf einem Ersatzgerät installieren. Sorge dafür, dass es mit Strom und WLAN verbunden ist, damit es immer online ist.</string>
|
||||||
|
<string name="mailbox_setup_download">Installiere zunächst die Mailbox-App auf einem anderen Gerät, indem du bei Google Play nach \"Briar Mailbox\" suchst oder dort, wo du Briar heruntergeladen hast.\n
|
||||||
|
\nVerbinde dann deine Mailbox mit Briar, indem du den angezeigten QR-Code der Mailbox-App scannst.</string>
|
||||||
|
<string name="mailbox_setup_download_link">Download-Link teilen</string>
|
||||||
|
<string name="mailbox_setup_button_scan">Mailbox QR-Code scannen</string>
|
||||||
|
<string name="permission_camera_qr_denied_body">Du hast den Zugriff auf die Kamera verweigert, aber das Scannen eines QR-Codes erfordert die Verwendung der Kamera.\n\nBitte gewähre den Zugriff.</string>
|
||||||
|
<string name="mailbox_setup_connecting">Verbinde…</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_title">Falscher QR-Code</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_description">Der gescannte Code ist ungültig. Bitte öffne die Briar Mailbox-App auf deinem Mailbox-Gerät und scanne den dort angezeigten QR-Code.</string>
|
||||||
|
<string name="tor_offline_title">Offline</string>
|
||||||
|
<string name="tor_offline_description">Stelle sicher, dass das Gerät online ist und Verbindungen zum Internet zugelassen sind.\n\nWarte anschließend, bis das Globussymbol in den Verbindungseinstellungen grün wird.</string>
|
||||||
|
<string name="tor_offline_button_check">Verbindungseinstellungen prüfen</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Selbstlöschende Nachrichten</string>
|
<string name="disappearing_messages_title">Selbstlöschende Nachrichten</string>
|
||||||
<string name="disappearing_messages_explanation_long">Wenn diese Einstellung aktiviert ist, werden neue
|
<string name="disappearing_messages_explanation_long">Wenn diese Einstellung aktiviert ist, werden neue
|
||||||
|
|||||||
@@ -50,10 +50,16 @@
|
|||||||
<item quantity="one">Esta es una versión de prueba de Briar. Su cuenta expirará en %d día y no podrá ser renovada.</item>
|
<item quantity="one">Esta es una versión de prueba de Briar. Su cuenta expirará en %d día y no podrá ser renovada.</item>
|
||||||
<item quantity="other">Esta es una versión de prueba de Briar. Tu cuenta expirará en %d días y no podrá ser renovada.</item>
|
<item quantity="other">Esta es una versión de prueba de Briar. Tu cuenta expirará en %d días y no podrá ser renovada.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
<plurals name="old_android_expiry_warning">
|
||||||
|
<item quantity="one">Android 4 ya no es soportado. Briar dejará de funcionar sobre %s (en %d días). Por favor, instala Briar en un dispositivo más nuevo y crea una cuenta nueva.</item>
|
||||||
|
<item quantity="other">Android 4 ya no es soportado. Briar dejará de funcionar sobre %s (en %d días). Por favor, instala Briar en un dispositivo más nuevo y crea una cuenta nueva.</item>
|
||||||
|
</plurals>
|
||||||
<string name="expiry_date_reached">Este programa ha caducado.\n¡Gracias por probarlo!</string>
|
<string name="expiry_date_reached">Este programa ha caducado.\n¡Gracias por probarlo!</string>
|
||||||
<string name="download_briar">Para continuar usando Briar, por favor descarga la versión mas reciente.</string>
|
<string name="download_briar">Para continuar usando Briar, por favor descarga la versión mas reciente.</string>
|
||||||
<string name="create_new_account">Necesitarás crear una nueva cuenta, pero puedes usar el mismo nombre de usuario.</string>
|
<string name="create_new_account">Necesitarás crear una nueva cuenta, pero puedes usar el mismo nombre de usuario.</string>
|
||||||
<string name="download_briar_button">Descargar la última versión.</string>
|
<string name="download_briar_button">Descargar la última versión.</string>
|
||||||
|
<string name="old_android_expiry_date_reached">Briar ya no funciona sobre Android 4.\nPor favor, instala Briar en un dispositivo más nuevo.</string>
|
||||||
|
<string name="old_android_delete_account">Puedes pulsar el botón de abajo para borrar tu cuenta de este dispositivo.</string>
|
||||||
<string name="delete_account_button">Borrar cuenta</string>
|
<string name="delete_account_button">Borrar cuenta</string>
|
||||||
<string name="startup_open_database">Descifrando la base de datos...</string>
|
<string name="startup_open_database">Descifrando la base de datos...</string>
|
||||||
<string name="startup_migrate_database">Actualizando la base de datos...</string>
|
<string name="startup_migrate_database">Actualizando la base de datos...</string>
|
||||||
@@ -569,6 +575,22 @@
|
|||||||
<string name="notify_sound_setting_disabled">Ninguno</string>
|
<string name="notify_sound_setting_disabled">Ninguno</string>
|
||||||
<string name="choose_ringtone_title">Elegir tono de notificación</string>
|
<string name="choose_ringtone_title">Elegir tono de notificación</string>
|
||||||
<string name="cannot_load_ringtone">No se puede cargar el tono de notificación</string>
|
<string name="cannot_load_ringtone">No se puede cargar el tono de notificación</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_settings_title">Buzón</string>
|
||||||
|
<string name="mailbox_setup_title">Configuración del buzón</string>
|
||||||
|
<string name="mailbox_setup_intro">Un Buzón les permite a tus contactos enviarte mensajes mientras estás fuera de línea. El Buzón recibirá tus mensajes y los almacenará hasta que estés en línea.\n
|
||||||
|
\nPuedes instalar la aplicación Buzón de Briar en un dispositivo sobrante. Mantenlo conectado al suministro eléctrico y el Wi-Fi, de manera que siempre esté en línea.</string>
|
||||||
|
<string name="mailbox_setup_download">Primero, instala la aplicación Buzón en otro dispositivo, buscando \"Buzón de Briar\" en Google Play o desde donde hayas descargado Briar.\n
|
||||||
|
\nLuego vincula tu Buzón con Briar escaneando el código QR mostrado por la aplicación Buzón.</string>
|
||||||
|
<string name="mailbox_setup_download_link">Compartir enlace de descarga</string>
|
||||||
|
<string name="mailbox_setup_button_scan">Escanear código QR de Buzón</string>
|
||||||
|
<string name="permission_camera_qr_denied_body">Has denegado el acceso a la cámara, pero para escanear un código QR se requiere el uso de la cámara.\n\nPor favor considera conceder el acceso.</string>
|
||||||
|
<string name="mailbox_setup_connecting">Conectando...</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_title">Código QR erróneo</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_description">El código escaneado no es válido. Por favor abre la aplicación Buzón de Briar en tu dispositivo de buzón y escanea el código QR que presenta.</string>
|
||||||
|
<string name="tor_offline_title">Desconectado</string>
|
||||||
|
<string name="tor_offline_description">Asegúrate de que este dispositivo esté en línea y las conexiones a Internet estén permitidas.\n\nLuego, espera a que el ícono de un globo en las configuraciones de conexión se torne verde.</string>
|
||||||
|
<string name="tor_offline_button_check">Comprobar configuración de conexión</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Mensajes con caducidad</string>
|
<string name="disappearing_messages_title">Mensajes con caducidad</string>
|
||||||
<string name="disappearing_messages_explanation_long">Activar este ajuste hará que los nuevos
|
<string name="disappearing_messages_explanation_long">Activar este ajuste hará que los nuevos
|
||||||
|
|||||||
@@ -611,6 +611,22 @@
|
|||||||
<string name="notify_sound_setting_disabled">هیچکدام</string>
|
<string name="notify_sound_setting_disabled">هیچکدام</string>
|
||||||
<string name="choose_ringtone_title">انتخاب رینگتون</string>
|
<string name="choose_ringtone_title">انتخاب رینگتون</string>
|
||||||
<string name="cannot_load_ringtone">ناتوانی در بارگذاری رینگتون</string>
|
<string name="cannot_load_ringtone">ناتوانی در بارگذاری رینگتون</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_settings_title">Mailbox</string>
|
||||||
|
<string name="mailbox_setup_title">راهاندازی Mailbox</string>
|
||||||
|
<string name="mailbox_setup_intro">Mailbox به مخاطبین شما امکان میدهد در زمانی که آفلاین هستید، برای شما پیام ارسال کنند. Mailbox پیامهای شما را دریافت میکند و آنها را تا زمانی که آنلاین شوید نگهداری میکند.\n
|
||||||
|
شما میتوانید برنامه Briar Mailbox را روی دستگاه دیگری نصب کنید. آن را به برق و Wi-Fi متصل نگه دارید تا همیشه آنلاین باشد. </string>
|
||||||
|
<string name="mailbox_setup_download">ابتدا، با جستجوی «Briar Mailbox» در Google Play یا هر جایی که Briar را دانلود کردهاید، برنامه Mailbox را روی دستگاه دیگری نصب کنید.\n
|
||||||
|
\nسپس با اسکن کد QR نمایش داده شده توسط برنامه Mailbox، صندوق پستی خود را با Briar پیوند دهید. </string>
|
||||||
|
<string name="mailbox_setup_download_link">اشتراک لینک دانلود</string>
|
||||||
|
<string name="mailbox_setup_button_scan">اسکن کد QR Mailbox</string>
|
||||||
|
<string name="permission_camera_qr_denied_body">شما دسترسی به دوربین را رد کردهاید، اما اسکن کد QR مستلزم استفاده از دوربین است.\n\nلطفا دسترسی به دوربین را بدهید.</string>
|
||||||
|
<string name="mailbox_setup_connecting">در حال اتصال...</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_title">کد QR اشتباه است</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_description">کد اسکن شده نامعتبر است. لطفا برنامه Briar Mailbox را در دستگاه صندوق پستی خود باز کنید و کد QR ارائه شده را اسکن کنید.</string>
|
||||||
|
<string name="tor_offline_title">آفلاین</string>
|
||||||
|
<string name="tor_offline_description">مطمئن شوید که این دستگاه آنلاین است و اجازه اتصال به اینترنت را دارد.\n\nسپس منتظر بمانید تا نماد کره زمین در تنظیمات اتصال سبز شود.</string>
|
||||||
|
<string name="tor_offline_button_check">تنظیمات اتصال را بررسی کنید</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">پیامهای ناپدید شونده</string>
|
<string name="disappearing_messages_title">پیامهای ناپدید شونده</string>
|
||||||
<string name="disappearing_messages_explanation_long">روشن کردن این تنظیمات موجب خواهد شد تا پیامهای جدید
|
<string name="disappearing_messages_explanation_long">روشن کردن این تنظیمات موجب خواهد شد تا پیامهای جدید
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<string name="setup_name_explanation">Votre pseudonyme sera affiché à côté de tout contenu que vous publierez. Vous pourrez le modifier après avoir créé votre compte.</string>
|
<string name="setup_name_explanation">Votre pseudonyme sera affiché à côté de tout contenu que vous publierez. Vous pourrez le modifier après avoir créé votre compte.</string>
|
||||||
<string name="setup_next">Suivant</string>
|
<string name="setup_next">Suivant</string>
|
||||||
<string name="setup_password_intro">Choisir un mot de passe</string>
|
<string name="setup_password_intro">Choisir un mot de passe</string>
|
||||||
<string name="setup_password_explanation">Votre compte Briar est enregistré chiffré sur votre appareil et non dans le nuage. Si vous désinstallez Briar ou oubliez votre mot de passe, il n’existe aucune façon de récupérer votre compte.\n\nChoisissez un mot de passe long qui sera difficile à deviner, par exemple quatre mots au hasard ou dix lettres, chiffres et symboles au hasard.</string>
|
<string name="setup_password_explanation">Votre compte Briar est enregistré chiffré sur votre appareil et non dans le nuage. Si vous oubliez votre mot de passe ou désinstallez Briar, votre compte ne peut pas être récupéré.\n\nChoisissez un mot de passe long qui sera difficile à deviner, par exemple quatre mots au hasard ou dix lettres, chiffres et symboles au hasard.</string>
|
||||||
<string name="setup_doze_title">Connexions d’arrière-plan</string>
|
<string name="setup_doze_title">Connexions d’arrière-plan</string>
|
||||||
<string name="setup_doze_intro">Pour recevoir des messages, Briar a besoin de rester connectée en arrière-plan.</string>
|
<string name="setup_doze_intro">Pour recevoir des messages, Briar a besoin de rester connectée en arrière-plan.</string>
|
||||||
<string name="setup_doze_explanation">Pour recevoir des messages, Briar a besoin de rester connectée en arrière-plan. Veuillez désactiver les optimisations de la batterie afin que Briar puisse rester connectée.</string>
|
<string name="setup_doze_explanation">Pour recevoir des messages, Briar a besoin de rester connectée en arrière-plan. Veuillez désactiver les optimisations de la batterie afin que Briar puisse rester connectée.</string>
|
||||||
@@ -45,10 +45,10 @@
|
|||||||
<string name="startup_failed_db_error">Briar n’a pas pu ouvrir la base de données qui comprend votre compte, vos contacts et messages.\n\nVeuillez mettre l’appli à jour vers la version la plus récente et réessayer, ou créer un nouveau compte en choisissant « J’ai oublié mon mot de passe » à l’invite de mot de passe.</string>
|
<string name="startup_failed_db_error">Briar n’a pas pu ouvrir la base de données qui comprend votre compte, vos contacts et messages.\n\nVeuillez mettre l’appli à jour vers la version la plus récente et réessayer, ou créer un nouveau compte en choisissant « J’ai oublié mon mot de passe » à l’invite de mot de passe.</string>
|
||||||
<string name="startup_failed_data_too_old_error">Votre compte a été créé avec une ancienne version de cette appli et ne peut pas être ouvert avec cette version.\n\nVous devez soit réinstaller l’ancienne version, soit créer un nouveau compte en choisissant « J’ai oublié mon mot de passe » à l’invite de mot de passe.</string>
|
<string name="startup_failed_data_too_old_error">Votre compte a été créé avec une ancienne version de cette appli et ne peut pas être ouvert avec cette version.\n\nVous devez soit réinstaller l’ancienne version, soit créer un nouveau compte en choisissant « J’ai oublié mon mot de passe » à l’invite de mot de passe.</string>
|
||||||
<string name="startup_failed_data_too_new_error">Votre compte a été créé avec une version plus récente de cette appli et ne peut être ouvert avec cette version.\n\nVeuillez mettre l’appli à jour vers la version la plus récente et réessayer.</string>
|
<string name="startup_failed_data_too_new_error">Votre compte a été créé avec une version plus récente de cette appli et ne peut être ouvert avec cette version.\n\nVeuillez mettre l’appli à jour vers la version la plus récente et réessayer.</string>
|
||||||
<string name="startup_failed_service_error">Briar n\'a pas pu lancer un composant essentiel.\n\nVeuillez mettre l’appli à jour vers la version la plus récente et réessayer.</string>
|
<string name="startup_failed_service_error">Briar n’a pas pu lancer un composant essentiel.\n\nVeuillez mettre l’appli à jour vers la version la plus récente et réessayer.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Ceci est une version de test de Briar. Votre compte arrivera à expiration dans %d jour et ne peut pas être renouvelé.</item>
|
<item quantity="one">Ceci est une version d’essai de Briar. Votre compte arrivera à expiration dans %d jour et ne peut pas être renouvelé.</item>
|
||||||
<item quantity="other">Ceci est une version de test de Briar. Votre compte arrivera à expiration dans %d jours et ne pourra pas être renouvelé.</item>
|
<item quantity="other">Ceci est une version d’essai de Briar. Votre compte arrivera à expiration dans %d jours et ne pourra pas être renouvelé.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="expiry_date_reached">Ce logiciel est arrivé à expiration.\nMerci de l’avoir testé !</string>
|
<string name="expiry_date_reached">Ce logiciel est arrivé à expiration.\nMerci de l’avoir testé !</string>
|
||||||
<string name="download_briar">Pour continuer à utiliser Briar, veuillez télécharger la dernière version.</string>
|
<string name="download_briar">Pour continuer à utiliser Briar, veuillez télécharger la dernière version.</string>
|
||||||
@@ -234,7 +234,7 @@
|
|||||||
<string name="connecting_to_device">Connexion à l’appareil\u2026</string>
|
<string name="connecting_to_device">Connexion à l’appareil\u2026</string>
|
||||||
<string name="authenticating_with_device">Autentification avec l’appareil\u2026</string>
|
<string name="authenticating_with_device">Autentification avec l’appareil\u2026</string>
|
||||||
<string name="connection_error_title">Impossible de se connecter à votre contact</string>
|
<string name="connection_error_title">Impossible de se connecter à votre contact</string>
|
||||||
<string name="connection_error_feedback">Si le problème persiste, veuillez nous <a href="feedback">envoyer une rétroaction</a> pour nous aider à améliorer l\'appli.</string>
|
<string name="connection_error_feedback">Si le problème persiste, veuillez nous <a href="feedback">envoyer une rétroaction</a> pour nous aider à améliorer l’appli.</string>
|
||||||
<!--Adding Contacts Remotely-->
|
<!--Adding Contacts Remotely-->
|
||||||
<string name="add_contact_remotely_title_case">Ajouter un contact éloigné</string>
|
<string name="add_contact_remotely_title_case">Ajouter un contact éloigné</string>
|
||||||
<string name="add_contact_nearby_title">Ajouter un contact à proximité</string>
|
<string name="add_contact_nearby_title">Ajouter un contact à proximité</string>
|
||||||
@@ -337,7 +337,7 @@
|
|||||||
<string name="groups_create_group_button">Créer un groupe</string>
|
<string name="groups_create_group_button">Créer un groupe</string>
|
||||||
<string name="groups_create_group_invitation_button">Envoyer une invitation</string>
|
<string name="groups_create_group_invitation_button">Envoyer une invitation</string>
|
||||||
<string name="groups_create_group_hint">Choisissez un nom pour votre groupe privé</string>
|
<string name="groups_create_group_hint">Choisissez un nom pour votre groupe privé</string>
|
||||||
<string name="groups_invitation_sent">L’invitation de groupe a été envoyée</string>
|
<string name="groups_invitation_sent">L’invitation au groupe a été envoyée</string>
|
||||||
<string name="groups_member_list">Liste des participants</string>
|
<string name="groups_member_list">Liste des participants</string>
|
||||||
<string name="groups_invite_members">Inviter des participants</string>
|
<string name="groups_invite_members">Inviter des participants</string>
|
||||||
<string name="groups_member_created_you">Vous avez créé le groupe</string>
|
<string name="groups_member_created_you">Vous avez créé le groupe</string>
|
||||||
@@ -354,20 +354,20 @@
|
|||||||
<string name="groups_dissolved_dialog_title">Le groupe a été dissous</string>
|
<string name="groups_dissolved_dialog_title">Le groupe a été dissous</string>
|
||||||
<string name="groups_dissolved_dialog_message">Le créateur de ce groupe l’a dissous.\n\nVous ne pouvez plus écrire de messages au groupe et ne recevrez peut-être pas tous ceux qui y ont été publiés.</string>
|
<string name="groups_dissolved_dialog_message">Le créateur de ce groupe l’a dissous.\n\nVous ne pouvez plus écrire de messages au groupe et ne recevrez peut-être pas tous ceux qui y ont été publiés.</string>
|
||||||
<!--Private Group Invitations-->
|
<!--Private Group Invitations-->
|
||||||
<string name="groups_invitations_title">Invitations de groupe</string>
|
<string name="groups_invitations_title">Invitations au groupe</string>
|
||||||
<string name="groups_invitations_invitation_sent">Vous avez invité %1$s à se joindre au groupe « %2$s ».</string>
|
<string name="groups_invitations_invitation_sent">Vous avez invité %1$s à se joindre au groupe « %2$s ».</string>
|
||||||
<string name="groups_invitations_invitation_received">%1$s vous a invité à vous joindre au groupe « %2$s ».</string>
|
<string name="groups_invitations_invitation_received">%1$s vous a invité à vous joindre au groupe « %2$s ».</string>
|
||||||
<string name="groups_invitations_joined">S’est joint au groupe</string>
|
<string name="groups_invitations_joined">S’est joint au groupe</string>
|
||||||
<string name="groups_invitations_declined">L’invitation de groupe a été refusée</string>
|
<string name="groups_invitations_declined">L’invitation au groupe a été refusée</string>
|
||||||
<plurals name="groups_invitations_open">
|
<plurals name="groups_invitations_open">
|
||||||
<item quantity="one">%d invitation de groupe en attente</item>
|
<item quantity="one">%d invitation au groupe en attente</item>
|
||||||
<item quantity="other">%d invitations de groupe en attente</item>
|
<item quantity="other">%d invitations au groupe en attente</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="groups_invitations_response_accepted_sent">Vous avez accepté l’invitation de groupe de %s.</string>
|
<string name="groups_invitations_response_accepted_sent">Vous avez accepté l’invitation au groupe de %s.</string>
|
||||||
<string name="groups_invitations_response_declined_sent">Vous avez refusé l’invitation de groupe de %s.</string>
|
<string name="groups_invitations_response_declined_sent">Vous avez refusé l’invitation au groupe de %s.</string>
|
||||||
<string name="groups_invitations_response_declined_auto">L’invitation au groupe provenant de %s a été refusée automatiquement.</string>
|
<string name="groups_invitations_response_declined_auto">L’invitation au groupe provenant de %s a été refusée automatiquement.</string>
|
||||||
<string name="groups_invitations_response_accepted_received">%s a accepté l’invitation de groupe.</string>
|
<string name="groups_invitations_response_accepted_received">%s a accepté l’invitation au groupe.</string>
|
||||||
<string name="groups_invitations_response_declined_received">%s a refusé l’invitation de groupe.</string>
|
<string name="groups_invitations_response_declined_received">%s a refusé l’invitation au groupe.</string>
|
||||||
<string name="sharing_status_groups">Seul le créateur peut inviter de nouveaux participants. Voici la liste des membres actuels du groupe.</string>
|
<string name="sharing_status_groups">Seul le créateur peut inviter de nouveaux participants. Voici la liste des membres actuels du groupe.</string>
|
||||||
<!--Private Groups Revealing Contacts-->
|
<!--Private Groups Revealing Contacts-->
|
||||||
<string name="groups_reveal_contacts">Dévoiler les contacts</string>
|
<string name="groups_reveal_contacts">Dévoiler les contacts</string>
|
||||||
@@ -567,6 +567,9 @@
|
|||||||
<string name="notify_sound_setting_disabled">Aucun</string>
|
<string name="notify_sound_setting_disabled">Aucun</string>
|
||||||
<string name="choose_ringtone_title">Choisir une sonnerie</string>
|
<string name="choose_ringtone_title">Choisir une sonnerie</string>
|
||||||
<string name="cannot_load_ringtone">Impossible de charger la sonnerie</string>
|
<string name="cannot_load_ringtone">Impossible de charger la sonnerie</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_setup_connecting">Connexion…</string>
|
||||||
|
<string name="tor_offline_title">Hors ligne</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Messages éphémères</string>
|
<string name="disappearing_messages_title">Messages éphémères</string>
|
||||||
<string name="disappearing_messages_explanation_long">L’activation de ce paramètre fera disparaître
|
<string name="disappearing_messages_explanation_long">L’activation de ce paramètre fera disparaître
|
||||||
@@ -675,6 +678,7 @@ copies des messages que vous envoyez.
|
|||||||
<string name="website_troubleshooting_title">Dépannage</string>
|
<string name="website_troubleshooting_title">Dépannage</string>
|
||||||
<!--error handling-->
|
<!--error handling-->
|
||||||
<!--Transfer Data via Removable Drives-->
|
<!--Transfer Data via Removable Drives-->
|
||||||
|
<string name="removable_drive_menu_title">Se connecter par un lecteur amovible</string>
|
||||||
<string name="removable_drive_success_receive_title">L’importation est réussie</string>
|
<string name="removable_drive_success_receive_title">L’importation est réussie</string>
|
||||||
<!--Screenshots-->
|
<!--Screenshots-->
|
||||||
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
|
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
|
||||||
|
|||||||
@@ -550,6 +550,9 @@
|
|||||||
<string name="notify_sound_setting_disabled">Ningún</string>
|
<string name="notify_sound_setting_disabled">Ningún</string>
|
||||||
<string name="choose_ringtone_title">Escolle ton</string>
|
<string name="choose_ringtone_title">Escolle ton</string>
|
||||||
<string name="cannot_load_ringtone">Non se cargou o ton</string>
|
<string name="cannot_load_ringtone">Non se cargou o ton</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_setup_connecting">Conectando...</string>
|
||||||
|
<string name="tor_offline_title">Desconectado</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Mensaxes efémeras</string>
|
<string name="disappearing_messages_title">Mensaxes efémeras</string>
|
||||||
<string name="disappearing_messages_explanation_long">Ao activar esta función farás que as novas
|
<string name="disappearing_messages_explanation_long">Ao activar esta función farás que as novas
|
||||||
|
|||||||
@@ -567,6 +567,9 @@ Vigyázat: Ez végleg törli az identitásait, kapcsolatait és üzeneteit</stri
|
|||||||
<string name="notify_sound_setting_disabled">Egyik sem</string>
|
<string name="notify_sound_setting_disabled">Egyik sem</string>
|
||||||
<string name="choose_ringtone_title">Csengőhang választása</string>
|
<string name="choose_ringtone_title">Csengőhang választása</string>
|
||||||
<string name="cannot_load_ringtone">Sikertelen a csengőhang betöltése</string>
|
<string name="cannot_load_ringtone">Sikertelen a csengőhang betöltése</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_setup_connecting">Csatlakozás...</string>
|
||||||
|
<string name="tor_offline_title">Offline</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Eltűnő üzenetek</string>
|
<string name="disappearing_messages_title">Eltűnő üzenetek</string>
|
||||||
<string name="disappearing_messages_explanation_long">Bekapcsolva ezt beállítást az új
|
<string name="disappearing_messages_explanation_long">Bekapcsolva ezt beállítást az új
|
||||||
|
|||||||
@@ -575,6 +575,9 @@
|
|||||||
<string name="notify_sound_setting_disabled">Ekkert</string>
|
<string name="notify_sound_setting_disabled">Ekkert</string>
|
||||||
<string name="choose_ringtone_title">Veldu hringitón</string>
|
<string name="choose_ringtone_title">Veldu hringitón</string>
|
||||||
<string name="cannot_load_ringtone">Get ekki hlaðið inn hringitóni</string>
|
<string name="cannot_load_ringtone">Get ekki hlaðið inn hringitóni</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_setup_connecting">Tengist…</string>
|
||||||
|
<string name="tor_offline_title">Ónettengt</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Sjálfeyðandi skilaboð</string>
|
<string name="disappearing_messages_title">Sjálfeyðandi skilaboð</string>
|
||||||
<string name="disappearing_messages_explanation_long">Ef kveikt er á þessari stillingu munu ný
|
<string name="disappearing_messages_explanation_long">Ef kveikt er á þessari stillingu munu ný
|
||||||
|
|||||||
@@ -575,6 +575,9 @@
|
|||||||
<string name="notify_sound_setting_disabled">Nessuno</string>
|
<string name="notify_sound_setting_disabled">Nessuno</string>
|
||||||
<string name="choose_ringtone_title">Scegli suoneria</string>
|
<string name="choose_ringtone_title">Scegli suoneria</string>
|
||||||
<string name="cannot_load_ringtone">Impossibile caricare la suoneria</string>
|
<string name="cannot_load_ringtone">Impossibile caricare la suoneria</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_setup_connecting">Connessione in corso...</string>
|
||||||
|
<string name="tor_offline_title">Offline</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Messaggi dissolventi</string>
|
<string name="disappearing_messages_title">Messaggi dissolventi</string>
|
||||||
<string name="disappearing_messages_explanation_long">L\'attivazione di questa impostazione farà sparire
|
<string name="disappearing_messages_explanation_long">L\'attivazione di questa impostazione farà sparire
|
||||||
|
|||||||
@@ -540,6 +540,9 @@
|
|||||||
<string name="notify_sound_setting_disabled">なし</string>
|
<string name="notify_sound_setting_disabled">なし</string>
|
||||||
<string name="choose_ringtone_title">着信音を選択</string>
|
<string name="choose_ringtone_title">着信音を選択</string>
|
||||||
<string name="cannot_load_ringtone">着信音を読み込めません</string>
|
<string name="cannot_load_ringtone">着信音を読み込めません</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_setup_connecting">接続中…</string>
|
||||||
|
<string name="tor_offline_title">オフライン</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">消えたメッセージ</string>
|
<string name="disappearing_messages_title">消えたメッセージ</string>
|
||||||
<string name="learn_more">詳細情報</string>
|
<string name="learn_more">詳細情報</string>
|
||||||
|
|||||||
@@ -603,6 +603,9 @@
|
|||||||
<string name="notify_sound_setting_disabled">Nėra</string>
|
<string name="notify_sound_setting_disabled">Nėra</string>
|
||||||
<string name="choose_ringtone_title">Pasirinkite skambėjimo melodiją</string>
|
<string name="choose_ringtone_title">Pasirinkite skambėjimo melodiją</string>
|
||||||
<string name="cannot_load_ringtone">Nepavyksta įkelti skambučio melodijos</string>
|
<string name="cannot_load_ringtone">Nepavyksta įkelti skambučio melodijos</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_setup_connecting">Jungiamasi…</string>
|
||||||
|
<string name="tor_offline_title">Nepasiekiama</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Išnykstančios žinutės</string>
|
<string name="disappearing_messages_title">Išnykstančios žinutės</string>
|
||||||
<string name="disappearing_messages_explanation_long">Įjungus šį nustatymą, naujos žinutės
|
<string name="disappearing_messages_explanation_long">Įjungus šį nustatymą, naujos žinutės
|
||||||
|
|||||||
@@ -1,45 +1,45 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
<!--Setup-->
|
<!--Setup-->
|
||||||
<string name="setup_title">Briar မှ ကြိုဆိုပါသည်</string>
|
<string name="setup_title">Briar မှ ကြိုဆိုပါတယ်</string>
|
||||||
<string name="setup_name_explanation">သင့်နာမည်ပြောင်သည် သင်တင်ထားသမျှ၏ဘေးတွင် ပေါ်နေပါလိမ့်မည်။ သို့ပါ၍ သင့်နာမည်ပြောင်အား အကောင့်ဖွင့်ပြီးနောက် ပြောင်း၍မရတော့ပါ။</string>
|
<string name="setup_name_explanation">သင့်နာမည်ပြောင်သည် သင်တင်ထားသမျှ၏ ဘေးတွင် ပေါ်နေပါလိမ့်မည်။ သို့ပါ၍ သင့်နာမည်ပြောင်အား အကောင့်ဖွင့်ပြီးနောက် ပြောင်း၍ မရတော့ပါ။</string>
|
||||||
<string name="setup_next">ရှေ့သို့</string>
|
<string name="setup_next">ရှေ့သို့</string>
|
||||||
<string name="setup_password_intro">စကားဝှက်တစ်ခု ရွေးပါ</string>
|
<string name="setup_password_intro">စကားဝှက်တစ်ခု ရွေးပါ</string>
|
||||||
<string name="setup_password_explanation">သင့် Briar အကောင့်ကို ကလောက်တွင်မဟုတ်ဘဲ သင့်ကိရိယာတွင်သာ လျှို့ဝှက်ကုဒ်ပြောင်းသိမ်းဆည်းထားပါသည်။ သင့်စကားဝှက်ကို မေ့သွားလျှင် (သို့) Briar ကို ဖြုတ်လိုက်လျှင် သင့်အကောင့်ကို မည်သည့်နည်းနှင့်မျှ ပြန်မရယူနိုင်ပါ။\n\nကြုံရာစကားလုံးလေးလုံး (သို့) ကြုံရာအက္ခရာဆယ်လုံး၊ နံပါတ်များနှင့် သင်္ကေတများကဲ့သို့ ခန့်မှန်းရခက်သည့် ရှည်လျားသောစကားဝှက်ကို ရွေးချယ်ပါ။</string>
|
<string name="setup_password_explanation">သင့် Briar အကောင့်ကို ကလောက်တွင်မဟုတ်ဘဲ သင့်ကိရိယာတွင်သာ လျှို့ဝှက်ကုဒ်ပြောင်း သိမ်းဆည်းထားပါသည်။ သင့်စကားဝှက်ကို မေ့သွားလျှင် (သို့) Briar ကို ဖြုတ်လိုက်လျှင် သင့်အကောင့်ကို မည်သည့်နည်းနှင့်မျှ ပြန်မရယူနိုင်ပါ။\n\nကြုံရာစကားလုံးလေးလုံး (သို့) ကြုံရာအက္ခရာဆယ်လုံး၊ နံပါတ်များနှင့် သင်္ကေတများကဲ့သို့ ခန့်မှန်းရခက်သည့် ရှည်လျားသောစကားဝှက်ကို ရွေးချယ်ပါ။</string>
|
||||||
<string name="setup_doze_title">နောက်ခံချိတ်ဆက်မှုများ</string>
|
<string name="setup_doze_title">နောက်ခံ ချိတ်ဆက်မှုများ</string>
|
||||||
<string name="setup_doze_intro">မက်ဆေ့ချ်များလက်ခံရယူနိုင်ရန် Briar သည် နောက်ခံချိတ်ဆက်နေရန် လိုအပ်သည်။</string>
|
<string name="setup_doze_intro">မက်ဆေ့ချ်များ လက်ခံရယူနိုင်ရန် Briar သည် နောက်ခံ၌ ချိတ်ဆက်နေရန် လိုအပ်သည်။</string>
|
||||||
<string name="setup_doze_explanation">မက်ဆေ့ချ်များလက်ခံရယူနိုင်ရန် Briar သည် နောက်ခံချိတ်ဆက်နေရန် လိုအပ်သည်။ Briar အနေဖြင့် ချိတ်ဆက်မှုမပြတ်ရှိနေစေရန် ဘတ္ထရီအားအကောင်းဆုံးထိန်းညှိခြင်းကို ကျေးဇူးပြု၍ ပိတ်ထားပေးပါ။</string>
|
<string name="setup_doze_explanation">မက်ဆေ့ချ်များ လက်ခံရယူနိုင်ရန် Briar သည် နောက်ခံ၌ ချိတ်ဆက်နေရန် လိုအပ်သည်။ Briar အနေဖြင့် ချိတ်ဆက်မှု မပြတ်ရှိနေစေရန် ဘတ္ထရီအား အကောင်းဆုံး ထိန်းညှိခြင်းကို ကျေးဇူးပြု၍ ပိတ်ထားပေးပါ။</string>
|
||||||
<string name="setup_doze_button">ချိတ်ဆက်မှုများ ခွင့်ပြုမည်</string>
|
<string name="setup_doze_button">ချိတ်ဆက်မှုများကို ခွင့်ပြုပါ</string>
|
||||||
<string name="choose_nickname">သင့်နာမည်ပြောင်ကို ရွေးပါ</string>
|
<string name="choose_nickname">သင့်နာမည်ပြောင်ကို ရွေးပါ</string>
|
||||||
<string name="choose_password">သင့်စကားဝှက်ကို ရွေးပါ</string>
|
<string name="choose_password">သင့်စကားဝှက်ကို ရွေးပါ</string>
|
||||||
<string name="confirm_password">သင့်စကားဝှက်ကို အတည်ပြုပါ</string>
|
<string name="confirm_password">သင့်စကားဝှက်ကို အတည်ပြုပါ</string>
|
||||||
<string name="name_too_long">နာမည်ရှည်လွန်းသည်</string>
|
<string name="name_too_long">နာမည် ရှည်လွန်းတယ်</string>
|
||||||
<string name="password_too_weak">စကားဝှက်က အားနည်းလွန်းသည်</string>
|
<string name="password_too_weak">စကားဝှက်က အားနည်းလွန်းတယ်</string>
|
||||||
<string name="passwords_do_not_match">စကားဝှက်ကိုက်ညီမှုမရှိပါ</string>
|
<string name="passwords_do_not_match">စကားဝှက်များ မတူကြပါ</string>
|
||||||
<string name="create_account_button">အကောင့်ဖွင့်မည်</string>
|
<string name="create_account_button">အကောင့်ဖွင့်ပါ</string>
|
||||||
<string name="more_info">ပိုမိုသိရှိရန်</string>
|
<string name="more_info">ပိုမိုသိရှိရန်</string>
|
||||||
<string name="don_t_ask_again">ထပ်မမေးပါနှင့်</string>
|
<string name="don_t_ask_again">ထပ်မမေးပါနဲ့</string>
|
||||||
<string name="setup_huawei_text">အောက်ပါခလုတ်ကိုနှိပ်၍ \"ကာကွယ်မှုပေးထားသောအက်ပ်များ\" စခရင်တွင် Briar ကို ကာကွယ်ထားကြောင်း သေချာစေပါ။</string>
|
<string name="setup_huawei_text">အောက်ပါခလုတ်ကိုနှိပ်၍ \"ကာကွယ်မှုပေးထားသောအက်ပ်များ\" စခရင်တွင် Briar ကို ကာကွယ်ထားကြောင်း သေချာစေပါ။</string>
|
||||||
<string name="setup_huawei_button">Briar ကို ကာကွယ်မည်</string>
|
<string name="setup_huawei_button">Briar ကို ကာကွယ်ပါ</string>
|
||||||
<string name="setup_huawei_help">ကာကွယ်မှုပေးထားသောအက်ပ်များစာရင်းတွင် ထည့်မထားလျှင် Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
<string name="setup_huawei_help">ကာကွယ်မှုပေးထားသောအက်ပ်များစာရင်းတွင် ထည့်မထားလျှင် Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
||||||
<string name="setup_huawei_app_launch_text">အောက်ပါခလုတ်ကိုနှိပ်ပြီး \"အက်ပ်စတင်ခြင်း\" စခရင်ကို ဖွင့်၍ Briar ကို \"ကိုယ်တိုင်စီမံမည်\" ဟု သတ်မှတ်ပါ။</string>
|
<string name="setup_huawei_app_launch_text">အောက်ပါခလုတ်ကိုနှိပ်ပြီး \"အက်ပ်စတင်ခြင်း\" စခရင်ကို ဖွင့်၍ Briar ကို \"ကိုယ်တိုင်စီမံမည်\" ဟု သတ်မှတ်ပါ။</string>
|
||||||
<string name="setup_huawei_app_launch_button">ဘတ္ထရီဆက်တင်များကို ဖွင့်မည်</string>
|
<string name="setup_huawei_app_launch_button">ဘတ္ထရီဆက်တင်များကို ဖွင့်ပါ</string>
|
||||||
<string name="setup_huawei_app_launch_help">\"အက်ပ်စတင်ခြင်း\" စခရင်တွင် \"ကိုယ်တိုင်စီမံမည်\" ဟု သတ်မှတ်မထားလျှင် Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
<string name="setup_huawei_app_launch_help">\"အက်ပ်စတင်ခြင်း\" စခရင်တွင် \"ကိုယ်တိုင်စီမံမည်\" ဟု သတ်မှတ်မထားလျှင် Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
||||||
<string name="setup_xiaomi_text">ဖွင့်ထားသောအက်ပ်များစာရင်းတွင် Briar ကို လော့ခ်ချထားမှ နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်။</string>
|
<string name="setup_xiaomi_text">ဖွင့်ထားသောအက်ပ်များစာရင်းတွင် Briar ကို လော့ခ်ချထားမှ နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်။</string>
|
||||||
<string name="setup_xiaomi_button">Briar ကို ကာကွယ်ထားမည်</string>
|
<string name="setup_xiaomi_button">Briar ကို ကာကွယ်ပါ</string>
|
||||||
<string name="setup_xiaomi_help">ဖွင့်ထားသောအက်ပ်များစာရင်းတွင် လော့ခ်ချမထားပါက Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
<string name="setup_xiaomi_help">ဖွင့်ထားသောအက်ပ်များစာရင်းတွင် လော့ခ်ချမထားပါက Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
||||||
<string name="setup_xiaomi_dialog_body_old">၁။ ဖွင့်ထားသောအက်ပ်များစာရင်း (တစ်နည်းအားဖြင့် အက်ပ်ပြောင်းရာ) ကို ဖွင့်ပါ\n\n၂။ သော့ခလောက်အိုင်ကွန်ပေါ်လာရန် Briar ပုံပေါ်မှ ပွတ်ဆွဲချပါ\n\n၃။ သော့ခတ်မထားပါက သော့ခတ်ရန်နှိပ်လိုက်ပါ</string>
|
<string name="setup_xiaomi_dialog_body_old">၁။ ဖွင့်ထားသောအက်ပ်များစာရင်း (တစ်နည်းအားဖြင့် အက်ပ်ပြောင်းရာ) ကို ဖွင့်ပါ\n\n၂။ သော့ခလောက်အိုင်ကွန်ပေါ်လာရန် Briar ပုံပေါ်မှ ပွတ်ဆွဲချပါ\n\n၃။ သော့ခတ်မထားပါက သော့ခတ်ရန်နှိပ်လိုက်ပါ</string>
|
||||||
<string name="setup_xiaomi_dialog_body_new">၁။ ဖွင့်ထားသောအက်ပ်များစာရင်း (တစ်နည်းအားဖြင့် အက်ပ်ပြောင်းရာ) ကို ဖွင့်ပါ\n\n၂။ သော့ခလောက်ခလုတ်ပေါ်လာသည်အထိ Briar ပုံကို နှိပ်ထားပါ\n\n၃။ သော့ခတ်မထားပါက သော့ခတ်ရန်နှိပ်လိုက်ပါ</string>
|
<string name="setup_xiaomi_dialog_body_new">၁။ ဖွင့်ထားသောအက်ပ်များစာရင်း (တစ်နည်းအားဖြင့် အက်ပ်ပြောင်းရာ) ကို ဖွင့်ပါ\n\n၂။ သော့ခလောက်ခလုတ်ပေါ်လာသည်အထိ Briar ပုံကို နှိပ်ထားပါ\n\n၃။ သော့ခတ်မထားပါက သော့ခတ်ရန်နှိပ်လိုက်ပါ</string>
|
||||||
<string name="warning_dozed">%s ကို နောက်ကွယ်တွင် ဖွင့်မထားနိုင်ပါ</string>
|
<string name="warning_dozed">%s ကို နောက်ကွယ်တွင် ဖွင့်မထားနိုင်ပါ</string>
|
||||||
<!--Login-->
|
<!--Login-->
|
||||||
<string name="enter_password">စကားဝှက်</string>
|
<string name="enter_password">စကားဝှက်</string>
|
||||||
<string name="try_again">စကားဝှက်မှားနေသည်၊ ထပ်စမ်းကြည့်ပါ</string>
|
<string name="try_again">စကားဝှက်မှားနေတယ်၊ ထပ်စမ်းကြည့်ပါ</string>
|
||||||
<string name="dialog_title_cannot_check_password">စကားဝှက်ကို စစ်ဆေး၍မရပါ</string>
|
<string name="dialog_title_cannot_check_password">စကားဝှက်ကို စစ်ဆေး၍မရပါ</string>
|
||||||
<string name="dialog_message_cannot_check_password">Briar က သင့်စကားဝှက်ကို မစစ်ဆေးနိုင်ပါ။ ဤပြဿနာကို ဖြေရှင်းရန် သင့်ကိရိယာကို ပိတ်၍ပြန်ဖွင့်ကြည့်ပါ။</string>
|
<string name="dialog_message_cannot_check_password">Briar က သင့်စကားဝှက်ကို မစစ်ဆေးနိုင်ပါ။ ဤပြဿနာကို ဖြေရှင်းရန် သင့်ကိရိယာကို ပိတ်၍ပြန်ဖွင့်ကြည့်ပါ။</string>
|
||||||
<string name="sign_in_button">အကောင့်ဝင်မည်</string>
|
<string name="sign_in_button">အကောင့်ဝင်ပါ</string>
|
||||||
<string name="forgotten_password">ကျွန်ုပ်၏စကားဝှက်ကို မေ့သွားပါသည်</string>
|
<string name="forgotten_password">ကျွန်ုပ်၏စကားဝှက်ကို မေ့သွားပါတယ်</string>
|
||||||
<string name="dialog_title_lost_password">စကားဝှက်ပျောက်ဆုံး</string>
|
<string name="dialog_title_lost_password">စကားဝှက်ပျောက်ဆုံး</string>
|
||||||
<string name="dialog_message_lost_password">သင့် Briar အကောင့်ကို ကလောက်တွင်မဟုတ်ဘဲ သင့်ကိရိယာတွင်သာ လျှို့ဝှက်ကုဒ်ပြောင်းသိမ်းဆည်းထားသောကြောင့် သင့်စကားဝှက်ကို ပြန်လည်သတ်မှတ်မပေးနိုင်ပါ။ သင့်အကောင့်ကို ဖျက်ပစ်ပြီး အသစ်ပြန်ဖွင့်ချင်ပါသလား။\n\nသတိ - သင့်ကိုယ်ပိုင်အချက်အလက်များ၊ အဆက်အသွယ်များနှင့် မက်ဆေ့ချ်များအားလုံး အပြီးပျက်သွားပါလိမ့်မည်။</string>
|
<string name="dialog_message_lost_password">သင့် Briar အကောင့်ကို ကလောက်တွင်မဟုတ်ဘဲ သင့်ကိရိယာတွင်သာ လျှို့ဝှက်ကုဒ်ပြောင်း သိမ်းဆည်းထားသောကြောင့် သင့်စကားဝှက်ကို ပြန်လည်သတ်မှတ်မပေးနိုင်ပါ။ သင့်အကောင့်ကို ဖျက်ပစ်ပြီး အသစ်ပြန်ဖွင့်ချင်ပါသလား။ \n\nသတိ - သင့်ကိုယ်ပိုင်အချက်အလက်များ၊ အဆက်အသွယ်များနှင့် မက်ဆေ့ချ်များအားလုံး အပြီး ပျက်သွားပါလိမ့်မည်။</string>
|
||||||
<string name="startup_failed_activity_title">Briar မစတင်နိုင်ပါ</string>
|
<string name="startup_failed_activity_title">Briar မစတင်နိုင်ပါ</string>
|
||||||
<string name="startup_failed_clock_error">သင့်ကိရိယာ၏နာရီသည် မှားနေပါသဖြင့် Briar မစတင်နိုင်ပါ။\n\nသင့်ကိရိယာ၏နာရီကို အချိန်မှန်အောင်တိုက်ပြီး ပြန်စမ်းကြည့်ပါ။</string>
|
<string name="startup_failed_clock_error">သင့်ကိရိယာ၏နာရီသည် မှားနေပါသဖြင့် Briar မစတင်နိုင်ပါ။\n\nသင့်ကိရိယာ၏နာရီကို အချိန်မှန်အောင်တိုက်ပြီး ပြန်စမ်းကြည့်ပါ။</string>
|
||||||
<string name="startup_failed_db_error">Briar သည် သင့်အကောင့်၊ သင့်အဆက်အသွယ်များနှင့် သင့်မက်ဆေ့ချ်များပါရှိသော အချက်အလက်အစုကို မဖွင့်နိုင်ပါ။\n\nအက်ပ်နောက်ဆုံးဗားရှင်းသို့ အဆင့်မြှင့်ပြီး ထပ်စမ်းကြည့်ပါ (သို့) စကားဝှက်တောင်းသည့်နေရာတွင် \'ကျွန်ုပ်၏စကားဝှက်ကို မေ့သွားပါသည်\' ကို ရွေးချယ်ပြီး အကောင့်အသစ်တစ်ခု ဖွင့်နိုင်ပါသည်။</string>
|
<string name="startup_failed_db_error">Briar သည် သင့်အကောင့်၊ သင့်အဆက်အသွယ်များနှင့် သင့်မက်ဆေ့ချ်များပါရှိသော အချက်အလက်အစုကို မဖွင့်နိုင်ပါ။\n\nအက်ပ်နောက်ဆုံးဗားရှင်းသို့ အဆင့်မြှင့်ပြီး ထပ်စမ်းကြည့်ပါ (သို့) စကားဝှက်တောင်းသည့်နေရာတွင် \'ကျွန်ုပ်၏စကားဝှက်ကို မေ့သွားပါသည်\' ကို ရွေးချယ်ပြီး အကောင့်အသစ်တစ်ခု ဖွင့်နိုင်ပါသည်။</string>
|
||||||
@@ -49,25 +49,30 @@
|
|||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="other">ဤအရာသည် Briar ၏ စမ်းသပ်ဆဲဗားရှင်းဖြစ်ပါသည်။ သင့်အကောင့်သည် %d ရက်ကြာလျှင် သက်တမ်းကုန်ဆုံးမည်ဖြစ်ပြီး သက်တမ်းတိုး၍မရနိုင်ပါ။</item>
|
<item quantity="other">ဤအရာသည် Briar ၏ စမ်းသပ်ဆဲဗားရှင်းဖြစ်ပါသည်။ သင့်အကောင့်သည် %d ရက်ကြာလျှင် သက်တမ်းကုန်ဆုံးမည်ဖြစ်ပြီး သက်တမ်းတိုး၍မရနိုင်ပါ။</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
<plurals name="old_android_expiry_warning">
|
||||||
|
<item quantity="other">အန်းဒရိုက် ၄ ကို မပံ့ပိုးတော့ပါ။ Briar သည် %s(ရက်%dတွင်) အလုပ် မလုပ်တော့ပါ။ ကျေးဇူးပြု၍ Briar ကို စက်ပစ္စည်းအသစ်တွင် ထည့်သွင်းပြီး အကောင့်အသစ်တစ်ခု ဖန်တီးပါ။</item>
|
||||||
|
</plurals>
|
||||||
<string name="expiry_date_reached">ဤဆော့ဖ်ဝဲသည် သက်တမ်းကုန်သွားပါပြီ။\nစမ်းသပ်အသုံးပြုခြင်းအတွက် ကျေးဇူးတင်ပါသည်။</string>
|
<string name="expiry_date_reached">ဤဆော့ဖ်ဝဲသည် သက်တမ်းကုန်သွားပါပြီ။\nစမ်းသပ်အသုံးပြုခြင်းအတွက် ကျေးဇူးတင်ပါသည်။</string>
|
||||||
<string name="download_briar">Briar ကို ဆက်လက်အသုံးပြုရန် နောက်ဆုံးထွက်ထားသည်ကို ဒေါင်းလုဒ်လုပ်ပါ။</string>
|
<string name="download_briar">Briar ကို ဆက်လက်အသုံးပြုရန် နောက်ဆုံးထွက်ထားသည်ကို ဒေါင်းလုဒ်လုပ်ပါ။</string>
|
||||||
<string name="create_new_account">အကောင့်အသစ်ဖွင့်ရန် လိုအပ်သော်လည်း သုံးလက်စနာမည်ပြောင်ကို ဆက်သုံးနိုင်ပါသည်။</string>
|
<string name="create_new_account">အကောင့်အသစ်ဖွင့်ရန် လိုအပ်သော်လည်း သုံးလက်စနာမည်ပြောင်ကို ဆက်သုံးနိုင်ပါသည်။</string>
|
||||||
<string name="download_briar_button">နောက်ဆုံးထွက်ထားသည်ကို ဒေါင်းလုဒ်လုပ်မည်</string>
|
<string name="download_briar_button">နောက်ဆုံးထွက်ထားသည့်ကို ဒေါင်းလုဒ်လုပ်ပါ</string>
|
||||||
|
<string name="old_android_expiry_date_reached">Briar သည် အန်းဒရိုက် ၄ တွင် အလုပ်လုပ်တော့မည် မဟုတ်ပါ။ \nကျေးဇူးပြု၍ Briar ကို ပိုသစ်သော စက်ပေါ်တွင် ထည့်သွင်းပါ။</string>
|
||||||
|
<string name="old_android_delete_account">သင့်အကောင့်ကို ဤစက်ပစ္စည်းမှ ဖျက်ရန် အောက်ပါ ခလုတ်ကို သင်နှိပ်နိုင်သည်။</string>
|
||||||
<string name="delete_account_button">အကောင့် ဖျက်သိမ်းမယ်</string>
|
<string name="delete_account_button">အကောင့် ဖျက်သိမ်းမယ်</string>
|
||||||
<string name="startup_open_database">အချက်အလက်အစုကို ပြန်ဖြည်နေသည်…</string>
|
<string name="startup_open_database">အချက်အလက်အစုကို ပြန်ဖြည်နေသည်…</string>
|
||||||
<string name="startup_migrate_database">အချက်အလက်အစုကို အဆင့်မြှင့်နေသည်…</string>
|
<string name="startup_migrate_database">အချက်အလက်အစုကို အဆင့်မြှင့်နေသည်…</string>
|
||||||
<string name="startup_compact_database">အချက်အလက်အစုကို သိပ်သည်းစေရန်လုပ်နေသည်…</string>
|
<string name="startup_compact_database">အချက်အလက်အစုကို သိပ်သည်းစေရန်လုပ်နေသည်…</string>
|
||||||
<!--Navigation Drawer-->
|
<!--Navigation Drawer-->
|
||||||
<string name="nav_drawer_open_description">လမ်းညွှန်အံ ဖွင့်မည်</string>
|
<string name="nav_drawer_open_description">လမ်းညွှန်အံ ဖွင့်ပါ</string>
|
||||||
<string name="nav_drawer_close_description">လမ်းညွှန်အံ ပိတ်မည်</string>
|
<string name="nav_drawer_close_description">လမ်းညွှန်အံ ပိတ်ပါ</string>
|
||||||
<string name="contact_list_button">အဆက်အသွယ်များ</string>
|
<string name="contact_list_button">အဆက်အသွယ်များ</string>
|
||||||
<string name="groups_button">ကိုယ်ရေးကိုယ်တာအဖွဲ့များ</string>
|
<string name="groups_button">ကိုယ်ရေးကိုယ်တာ အဖွဲ့များ</string>
|
||||||
<string name="forums_button">ဖိုရမ်များ</string>
|
<string name="forums_button">ဖိုရမ်များ</string>
|
||||||
<string name="blogs_button">ဘလော့ဂ်များ</string>
|
<string name="blogs_button">ဘလော့ဂ်များ</string>
|
||||||
<!--This is part of the main menu. The app will be locked when this is tapped.-->
|
<!--This is part of the main menu. The app will be locked when this is tapped.-->
|
||||||
<string name="lock_button">အပ္ပလီကေးရှင်းကို သော့ခတ်မည်</string>
|
<string name="lock_button">အပ္ပလီကေးရှင်းကို သော့ခတ်မယ်</string>
|
||||||
<string name="settings_button">ဆက်တင်များ</string>
|
<string name="settings_button">ဆက်တင်များ</string>
|
||||||
<string name="sign_out_button">အကောင့်ထွက်မည်</string>
|
<string name="sign_out_button">အကောင့်ထွက်ပါ</string>
|
||||||
<string name="transports_onboarding_text">Briar က သင့်အဆက်အသွယ်များနှင့် မည်သို့ချိတ်ဆက်သည်ကို ထိန်းချုပ်ရန် ဤနေရာကိုနှိပ်ပါ။</string>
|
<string name="transports_onboarding_text">Briar က သင့်အဆက်အသွယ်များနှင့် မည်သို့ချိတ်ဆက်သည်ကို ထိန်းချုပ်ရန် ဤနေရာကိုနှိပ်ပါ။</string>
|
||||||
<!--Transports: Tor-->
|
<!--Transports: Tor-->
|
||||||
<string name="transport_tor">အင်တာနက်</string>
|
<string name="transport_tor">အင်တာနက်</string>
|
||||||
@@ -83,8 +88,8 @@
|
|||||||
<string name="tor_plugin_status_disabled_country_blocked">ဤနိုင်ငံတွင် အင်တာနက်အသုံးမပြုရန် Briar ကို ချိန်ညှိထားသည်</string>
|
<string name="tor_plugin_status_disabled_country_blocked">ဤနိုင်ငံတွင် အင်တာနက်အသုံးမပြုရန် Briar ကို ချိန်ညှိထားသည်</string>
|
||||||
<!--Transports: Wi-Fi-->
|
<!--Transports: Wi-Fi-->
|
||||||
<string name="transport_lan">ဝိုင်ဖိုင်</string>
|
<string name="transport_lan">ဝိုင်ဖိုင်</string>
|
||||||
<string name="transport_lan_long">တူညီသောဝိုင်ဖိုင်ကွန်ရက်</string>
|
<string name="transport_lan_long">တူညီသော ဝိုင်ဖိုင်ကွန်ရက်</string>
|
||||||
<string name="lan_device_status_on">သင့်ဖုန်းသည် ဝိုင်ဖိုင်ချိတ်ဆက်ထားသည်</string>
|
<string name="lan_device_status_on">သင့်ဖုန်းသည် ဝိုင်ဖိုင် ချိတ်ဆက်ထားသည်</string>
|
||||||
<string name="lan_device_status_off">သင့်ဖုန်းသည် ဝိုင်ဖိုင်ချိတ်ဆက်မထားပါ</string>
|
<string name="lan_device_status_off">သင့်ဖုန်းသည် ဝိုင်ဖိုင်ချိတ်ဆက်မထားပါ</string>
|
||||||
<string name="lan_plugin_status_enabling">Briar သည် ဝိုင်ဖိုင်ကွန်ရက်ကို ချိတ်ဆက်နေပါသည်</string>
|
<string name="lan_plugin_status_enabling">Briar သည် ဝိုင်ဖိုင်ကွန်ရက်ကို ချိတ်ဆက်နေပါသည်</string>
|
||||||
<string name="lan_plugin_status_active">Briar သည် ဝိုင်ဖိုင်ကွန်ရက်ကို ချိတ်ဆက်ထားသည်</string>
|
<string name="lan_plugin_status_active">Briar သည် ဝိုင်ဖိုင်ကွန်ရက်ကို ချိတ်ဆက်ထားသည်</string>
|
||||||
@@ -95,9 +100,9 @@
|
|||||||
<string name="bt_device_status_on">သင့်ဖုန်းဘလူးတုသ် ဖွင့်ထားသည်</string>
|
<string name="bt_device_status_on">သင့်ဖုန်းဘလူးတုသ် ဖွင့်ထားသည်</string>
|
||||||
<string name="bt_device_status_off">သင့်ဖုန်းဘလူးတုသ် ပိတ်ထားသည်</string>
|
<string name="bt_device_status_off">သင့်ဖုန်းဘလူးတုသ် ပိတ်ထားသည်</string>
|
||||||
<string name="bt_plugin_status_enabling">Briar သည် ဘလူးတုသ်ချိတ်ဆက်နေသည်</string>
|
<string name="bt_plugin_status_enabling">Briar သည် ဘလူးတုသ်ချိတ်ဆက်နေသည်</string>
|
||||||
<string name="bt_plugin_status_active">Briar သည် ဘလူးတုသ်ချိတ်ဆက်ထားသည်</string>
|
<string name="bt_plugin_status_active">Briar သည် ဘလူးတုသ်သို့ ချိတ်ဆက်ထားသည်</string>
|
||||||
<string name="bt_plugin_status_inactive">Briar သည် ဘလူးတုသ်မချိတ်ဆက်နိုင်ပါ</string>
|
<string name="bt_plugin_status_inactive">Briar သည် ဘလူးတုသ်နှင့် မချိတ်ဆက်နိုင်ပါ</string>
|
||||||
<string name="bt_plugin_status_disabled">ဘလူးတုသ်အသုံးမပြုရန် Briar ကို ချိန်ညှိထားသည်</string>
|
<string name="bt_plugin_status_disabled">ဘလူးတုသ် အသုံးမပြုရန် Briar ကို ချိန်ညှိထားသည်</string>
|
||||||
<!--Notifications-->
|
<!--Notifications-->
|
||||||
<string name="reminder_notification_title">Briar မှ အကောင့်ထွက်ထားသည်</string>
|
<string name="reminder_notification_title">Briar မှ အကောင့်ထွက်ထားသည်</string>
|
||||||
<string name="reminder_notification_text">အကောင့်ပြန်ဝင်ရန် နှိပ်ပါ။</string>
|
<string name="reminder_notification_text">အကောင့်ပြန်ဝင်ရန် နှိပ်ပါ။</string>
|
||||||
@@ -106,7 +111,7 @@
|
|||||||
<string name="ongoing_notification_title">Briar သို့ အကောင့်ဝင်ထားသည်</string>
|
<string name="ongoing_notification_title">Briar သို့ အကောင့်ဝင်ထားသည်</string>
|
||||||
<string name="ongoing_notification_text">Briar ဖွင့်ရန် နှိပ်ပါ</string>
|
<string name="ongoing_notification_text">Briar ဖွင့်ရန် နှိပ်ပါ</string>
|
||||||
<plurals name="private_message_notification_text">
|
<plurals name="private_message_notification_text">
|
||||||
<item quantity="other">ကိုယ်ရေးမက်ဆေ့ချ်အသစ် %d ခု။</item>
|
<item quantity="other">သီးသန့်မက်ဆေ့ချ်အသစ် %d ခု။</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="group_message_notification_text">
|
<plurals name="group_message_notification_text">
|
||||||
<item quantity="other">အဖွဲ့မက်ဆေ့ချ်အသစ် %d ခု။</item>
|
<item quantity="other">အဖွဲ့မက်ဆေ့ချ်အသစ် %d ခု။</item>
|
||||||
@@ -134,6 +139,7 @@
|
|||||||
<string name="open">ဖွင့်မယ်</string>
|
<string name="open">ဖွင့်မယ်</string>
|
||||||
<string name="change">ပြောင်းလဲမယ်</string>
|
<string name="change">ပြောင်းလဲမယ်</string>
|
||||||
<string name="start">စတင်ရန်</string>
|
<string name="start">စတင်ရန်</string>
|
||||||
|
<string name="finish">ပြီးပြီ</string>
|
||||||
<string name="no_data">ဒေတာမရှိ</string>
|
<string name="no_data">ဒေတာမရှိ</string>
|
||||||
<string name="ellipsis">…</string>
|
<string name="ellipsis">…</string>
|
||||||
<string name="text_too_long">ရိုက်ထားသောစာများ ရှည်နေပါသည်</string>
|
<string name="text_too_long">ရိုက်ထားသောစာများ ရှည်နေပါသည်</string>
|
||||||
@@ -147,8 +153,8 @@
|
|||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">ပြသစရာအဆက်အသွယ် မရှိပါ</string>
|
<string name="no_contacts">ပြသစရာအဆက်အသွယ် မရှိပါ</string>
|
||||||
<string name="no_contacts_action">+ (အပေါင်းအိုင်ကွန်) အား နှိပ်၍ အဆက်အသွယ်ကို ထည့်သွင်းပါ</string>
|
<string name="no_contacts_action">+ (အပေါင်းအိုင်ကွန်) အား နှိပ်၍ အဆက်အသွယ်ကို ထည့်သွင်းပါ</string>
|
||||||
<string name="date_no_private_messages">မက်ဆေ့ချ်များမရှိပါ</string>
|
<string name="date_no_private_messages">မက်ဆေ့ချ်များ မရှိပါ။</string>
|
||||||
<string name="no_private_messages">ပြသစရာမက်ဆေ့ချ် မရှိပါ</string>
|
<string name="no_private_messages">ပြသစရာ မက်ဆေ့ချ် မရှိပါ</string>
|
||||||
<string name="message_hint">မက်ဆေ့ချ် အသစ်</string>
|
<string name="message_hint">မက်ဆေ့ချ် အသစ်</string>
|
||||||
<string name="message_hint_auto_delete">ပျောက်ကွယ်မည့် မက်ဆေ့ချ်အသစ်</string>
|
<string name="message_hint_auto_delete">ပျောက်ကွယ်မည့် မက်ဆေ့ချ်အသစ်</string>
|
||||||
<string name="message_error">မက်ဆေ့ချ်ပို့ရာတွင် ပျက်ကွက်မှုဖြစ်</string>
|
<string name="message_error">မက်ဆေ့ချ်ပို့ရာတွင် ပျက်ကွက်မှုဖြစ်</string>
|
||||||
@@ -184,7 +190,7 @@
|
|||||||
<string name="auto_delete_changed_warning_send">ဘာပဲဖြစ်ဖြစ် ပို့မယ်</string>
|
<string name="auto_delete_changed_warning_send">ဘာပဲဖြစ်ဖြစ် ပို့မယ်</string>
|
||||||
<string name="delete_all_messages">မက်ဆေ့ချ်များအားလုံး ဖျက်မယ်</string>
|
<string name="delete_all_messages">မက်ဆေ့ချ်များအားလုံး ဖျက်မယ်</string>
|
||||||
<string name="dialog_title_delete_all_messages">မက်ဆေ့ချ်ပယ်ဖျက်ခြင်းအား အတည်ပြုမယ်</string>
|
<string name="dialog_title_delete_all_messages">မက်ဆေ့ချ်ပယ်ဖျက်ခြင်းအား အတည်ပြုမယ်</string>
|
||||||
<string name="dialog_message_delete_all_messages">မက်ဆေ့ချ်များအားလုံးကို အပြီးပယ်ဖျက်ရန် သေချာပြီလား?</string>
|
<string name="dialog_message_delete_all_messages">မက်ဆေ့ချ်များအားလုံးကို အပြီးပယ်ဖျက်ရန် သေချာပြီလား။</string>
|
||||||
<string name="dialog_title_not_all_messages_deleted">မက်ဆေ့ချ်များအားလုံးကို အပြီးပယ်ဖျက်၍ မရနိုင်ပါ</string>
|
<string name="dialog_title_not_all_messages_deleted">မက်ဆေ့ချ်များအားလုံးကို အပြီးပယ်ဖျက်၍ မရနိုင်ပါ</string>
|
||||||
<string name="dialog_message_not_deleted_ongoing_both">ဆက်လက်ဖြစ်နေဆဲရှိသော ဖိတ်ကြားခြင်းများနှင့် မိတ်ဆက်ခြင်းများနှင့် ပတ်သက်သော မက်ဆေ့ချ်များ မပြီးဆုံးခြင်းထိ ပယ်ဖျက်၍မရပါ။</string>
|
<string name="dialog_message_not_deleted_ongoing_both">ဆက်လက်ဖြစ်နေဆဲရှိသော ဖိတ်ကြားခြင်းများနှင့် မိတ်ဆက်ခြင်းများနှင့် ပတ်သက်သော မက်ဆေ့ချ်များ မပြီးဆုံးခြင်းထိ ပယ်ဖျက်၍မရပါ။</string>
|
||||||
<string name="dialog_message_not_deleted_ongoing_introductions">ဆက်လက်ဖြစ်နေဆဲရှိသော မိတ်ဆက်ခြင်းများနှင့် ပတ်သက်သော မက်ဆေ့ချ်များ မပြီးဆုံးခြင်းထိ ပယ်ဖျက်၍မရပါ။</string>
|
<string name="dialog_message_not_deleted_ongoing_introductions">ဆက်လက်ဖြစ်နေဆဲရှိသော မိတ်ဆက်ခြင်းများနှင့် ပတ်သက်သော မက်ဆေ့ချ်များ မပြီးဆုံးခြင်းထိ ပယ်ဖျက်၍မရပါ။</string>
|
||||||
@@ -194,13 +200,13 @@
|
|||||||
<string name="dialog_message_not_deleted_not_all_selected_invitations">ဖိတ်ကြားခြင်းအား ပယ်ဖျက်ရန် တောင်းဆိုချက်နှင့် တုံ့ပြန်ချက်အား သင်ရွေးထားရပါသည်။</string>
|
<string name="dialog_message_not_deleted_not_all_selected_invitations">ဖိတ်ကြားခြင်းအား ပယ်ဖျက်ရန် တောင်းဆိုချက်နှင့် တုံ့ပြန်ချက်အား သင်ရွေးထားရပါသည်။</string>
|
||||||
<string name="delete_contact">အဆက်အသွယ်ကို ဖျက်မည်</string>
|
<string name="delete_contact">အဆက်အသွယ်ကို ဖျက်မည်</string>
|
||||||
<string name="dialog_title_delete_contact">အဆက်အသွယ်ကို အပြီးပယ်ဖျက်ခြင်းအား အတည်ပြုမည်</string>
|
<string name="dialog_title_delete_contact">အဆက်အသွယ်ကို အပြီးပယ်ဖျက်ခြင်းအား အတည်ပြုမည်</string>
|
||||||
<string name="dialog_message_delete_contact">ဤအဆက်အသွယ်အပြင် ၎င်းနှင့်ပြောထားသမျှမက်ဆေ့ချ်အားလုံးကို ဖယ်ရှားချင်တာ သေချာပါသလား?</string>
|
<string name="dialog_message_delete_contact">ဤအဆက်အသွယ်အပြင် ၎င်းနှင့်ပြောထားသမျှမက်ဆေ့ချ်အားလုံးကို ဖယ်ရှားချင်တာ သေချာပါသလား။</string>
|
||||||
<string name="contact_deleted_toast">အဆက်အသွယ်ကို ဖျက်ပြီးပါပြီ</string>
|
<string name="contact_deleted_toast">အဆက်အသွယ်ကို ဖျက်ပြီးပါပြီ</string>
|
||||||
<!--This is shown in the action bar when opening an image in fullscreen that the user sent-->
|
<!--This is shown in the action bar when opening an image in fullscreen that the user sent-->
|
||||||
<string name="you">သင်</string>
|
<string name="you">သင်</string>
|
||||||
<string name="save_image">ရုပ်ပုံသိမ်းဆည်းမယ်</string>
|
<string name="save_image">ရုပ်ပုံသိမ်းဆည်းမယ်</string>
|
||||||
<string name="dialog_title_save_image">ရုပ်ပုံသိမ်းဆည်းမည်လား?</string>
|
<string name="dialog_title_save_image">ရုပ်ပုံ သိမ်းဆည်းမည်လား။</string>
|
||||||
<string name="dialog_message_save_image">ဤရုပ်ပုံသိမ်းဆည်းခြင်းဖြင့် ၎င်းပုံကို အခြားအပ္ပလီကေးရှင်းများ အသုံးပြုနိုင်ပါသည်။ \n\n သင်သိမ်းဆည်းမည်ဆိုတာ သေချာပါလား?</string>
|
<string name="dialog_message_save_image">ဤရုပ်ပုံသိမ်းဆည်းခြင်းဖြင့် ၎င်းပုံကို အခြားအပ္ပလီကေးရှင်းများ အသုံးပြုနိုင်ပါသည်။ \n\n သင်သိမ်းဆည်းမည်ဆိုတာ သေချာပါလား။</string>
|
||||||
<string name="save_image_success">ရုပ်ပုံအား သိမ်းဆည်းပြီး</string>
|
<string name="save_image_success">ရုပ်ပုံအား သိမ်းဆည်းပြီး</string>
|
||||||
<string name="save_image_error">ရုပ်ပုံအား သိမ်းဆည်း၍ မရနိုင်ပါ</string>
|
<string name="save_image_error">ရုပ်ပုံအား သိမ်းဆည်း၍ မရနိုင်ပါ</string>
|
||||||
<string name="dialog_title_no_image_support">ရုပ်ပုံများ မရှိပါ</string>
|
<string name="dialog_title_no_image_support">ရုပ်ပုံများ မရှိပါ</string>
|
||||||
@@ -211,7 +217,7 @@
|
|||||||
<string name="menu_contact">ဆက်သွယ်ရန်</string>
|
<string name="menu_contact">ဆက်သွယ်ရန်</string>
|
||||||
<!--Adding Contacts-->
|
<!--Adding Contacts-->
|
||||||
<string name="add_contact_title">အနီးနားရှိ အဆက်အသွယ်အား ထည့်သွင်းမယ်</string>
|
<string name="add_contact_title">အနီးနားရှိ အဆက်အသွယ်အား ထည့်သွင်းမယ်</string>
|
||||||
<string name="face_to_face">သင်သည် ဤလူပုဂ္ဂိုလ်အား အပြင်မှာတွေ့ရှိမှသာလျှင် ၎င်း၏အဆက်အသွယ်ကို ပေါင်းထည့်လို့ရပါမည်။ \n\n ဒါမှသာလျှင် နောင်တွင် အခြားလူများ သင့်အား အယောင်ဆောင်ခြင်း သို့မဟုတ် သင့်မက်ဆေ့ချ်များဖတ်ရှုခြင်း တို့ကို တားဆီးနိုင်ပါမည်။</string>
|
<string name="face_to_face">သင်သည် ဤလူပုဂ္ဂိုလ်အား အပြင်မှာတွေ့ရှိမှသာလျှင် ၎င်း၏အဆက်အသွယ်ကို ပေါင်းထည့်လို့ရပါမည်။ \n\n ဒါမှသာလျှင် နောင်တွင် အခြားလူများ သင့်အား အယောင်ဆောင်ခြင်း သို့မဟုတ် သင့်မက်ဆေ့ချ်များ ဖတ်ရှုခြင်း တို့ကို တားဆီးနိုင်ပါမည်။</string>
|
||||||
<string name="continue_button">ဆက်လုပ်မယ်</string>
|
<string name="continue_button">ဆက်လုပ်မယ်</string>
|
||||||
<string name="try_again_button">ထပ်မံကြိုးစားမယ်</string>
|
<string name="try_again_button">ထပ်မံကြိုးစားမယ်</string>
|
||||||
<string name="waiting_for_contact_to_scan">အဆက်အသွယ်မှ စကန်ဖတ်၍ ချိတ်ဆက်ရန် စောင့်နေပါသည် \u2026</string>
|
<string name="waiting_for_contact_to_scan">အဆက်အသွယ်မှ စကန်ဖတ်၍ ချိတ်ဆက်ရန် စောင့်နေပါသည် \u2026</string>
|
||||||
@@ -271,6 +277,7 @@
|
|||||||
<string name="duplicate_link_dialog_text_1">သင့်မှာ ဒီလင့်ခ်နဲ့ ပတ်သက်ပြီး ဆိုင်းငံ့ထားသော အဆက်အသွယ်လိပ်စာ ရှိပြီးဖြစ်သည်: %s</string>
|
<string name="duplicate_link_dialog_text_1">သင့်မှာ ဒီလင့်ခ်နဲ့ ပတ်သက်ပြီး ဆိုင်းငံ့ထားသော အဆက်အသွယ်လိပ်စာ ရှိပြီးဖြစ်သည်: %s</string>
|
||||||
<string name="duplicate_link_dialog_text_1_contact">သင့်မှာ ဒီလင့်ခ်နဲ့ အဆက်အသွယ်လိပ်စာ ရှိပြီးဖြစ်သည်: %s</string>
|
<string name="duplicate_link_dialog_text_1_contact">သင့်မှာ ဒီလင့်ခ်နဲ့ အဆက်အသွယ်လိပ်စာ ရှိပြီးဖြစ်သည်: %s</string>
|
||||||
<!--This is a question asking whether two nicknames refer to the same person-->
|
<!--This is a question asking whether two nicknames refer to the same person-->
|
||||||
|
<string name="duplicate_link_dialog_text_2">%1$sနဲ့ %2$sအတူတူပဲလား။</string>
|
||||||
<!--This is a button for answering that two nicknames do indeed refer to the same person. This
|
<!--This is a button for answering that two nicknames do indeed refer to the same person. This
|
||||||
string will be used in a dialog button, so if the translation of this string is longer than 20
|
string will be used in a dialog button, so if the translation of this string is longer than 20
|
||||||
characters, please use "Yes" instead, and use "No" for the "Different Person" button-->
|
characters, please use "Yes" instead, and use "No" for the "Different Person" button-->
|
||||||
@@ -279,6 +286,7 @@
|
|||||||
will be used in a dialog button, so if the translation of this string longer than 20 characters,
|
will be used in a dialog button, so if the translation of this string longer than 20 characters,
|
||||||
please use "No" instead, and use "Yes" for the "Same Person" button-->
|
please use "No" instead, and use "Yes" for the "Same Person" button-->
|
||||||
<string name="different_person_button">နောက်တစ်ယောက် </string>
|
<string name="different_person_button">နောက်တစ်ယောက် </string>
|
||||||
|
<string name="duplicate_link_dialog_text_3">%1$sနှင့်%2$s တူညီသောလင့်ခ်ကို သင့်အား ပေးပို့ခဲ့သည်။ \n\n သူတို့ထဲမှ တစ်ဦးက သင့်အဆက်အသွယ်များသည် မည်သူဖြစ်သည်ကို ရှာဖွေရန် ကြိုးစားနေပေမည်။ \n\nသင်သည် အခြားသူတစ်ဦးထံမှ တူညီသောလင့်ခ်ကို ရရှိထားကြောင်း ၎င်းတို့အား မပြောပါနှင့်။</string>
|
||||||
<string name="pending_contact_updated_toast">ဆိုင်းငံ့ထားသော အဆက်အသွယ်ကို အပ်ဒိတ်လုပ်ပြီး</string>
|
<string name="pending_contact_updated_toast">ဆိုင်းငံ့ထားသော အဆက်အသွယ်ကို အပ်ဒိတ်လုပ်ပြီး</string>
|
||||||
<!--Introductions-->
|
<!--Introductions-->
|
||||||
<string name="introduction_onboarding_title">သင့်ရဲ့ အဆက်အသွယ်လိပ်စာများကို မိတ်ဆက်ပါ</string>
|
<string name="introduction_onboarding_title">သင့်ရဲ့ အဆက်အသွယ်လိပ်စာများကို မိတ်ဆက်ပါ</string>
|
||||||
@@ -292,7 +300,7 @@
|
|||||||
<string name="introduction_sent">သင့်ရဲ့ မိတ်ဆက်ခြင်းကို ပို့ပြီးပါပြီ။</string>
|
<string name="introduction_sent">သင့်ရဲ့ မိတ်ဆက်ခြင်းကို ပို့ပြီးပါပြီ။</string>
|
||||||
<string name="introduction_error">မိတ်ဆက်ခြင်းပြုလုပ်ရာတွင် ပြဿနာဖြစ်ခဲ့ပါသည်။</string>
|
<string name="introduction_error">မိတ်ဆက်ခြင်းပြုလုပ်ရာတွင် ပြဿနာဖြစ်ခဲ့ပါသည်။</string>
|
||||||
<string name="introduction_request_sent">သင်မှ %1$s ကို %2$s နှင့် မိတ်ဆက်ပေးဖို့ တောင်းဆိုလိုက်ပါသည်။</string>
|
<string name="introduction_request_sent">သင်မှ %1$s ကို %2$s နှင့် မိတ်ဆက်ပေးဖို့ တောင်းဆိုလိုက်ပါသည်။</string>
|
||||||
<string name="introduction_request_received">%1$s မှ သင့်ကို %2$s နှင့် မိတ်ဆက်ပေးဖို့ တောင်းဆိုပါသည်။ သင့် အဆက်အသွယ်စာရင်းထဲသို့ %2$s အားပေါင်းထည့်ချင်ပါသလား?</string>
|
<string name="introduction_request_received">%1$s မှ သင့်ကို %2$s နှင့် မိတ်ဆက်ပေးဖို့ တောင်းဆိုပါသည်။ သင့် အဆက်အသွယ်စာရင်းထဲသို့ %2$s အားပေါင်းထည့်ချင်ပါသလား။</string>
|
||||||
<string name="introduction_request_exists_received">%1$s မှ သင့်ကို %2$s နှင့် မိတ်ဆက်ပေးဖို့တောင်းဆိုပါသည်၊ သို့သော်လည်း %2$s သည် သင့် အဆက်အသွယ်စာရင်းထဲတွင် ရှိပြီးသားဖြစ်နေပါသည်။ %1$s မှ ဤအကြောင်းမသိရှိနိုင်သေး၍ သင် ပြန်တုံ့ပြန်ထားနိုင်ပါသည် -</string>
|
<string name="introduction_request_exists_received">%1$s မှ သင့်ကို %2$s နှင့် မိတ်ဆက်ပေးဖို့တောင်းဆိုပါသည်၊ သို့သော်လည်း %2$s သည် သင့် အဆက်အသွယ်စာရင်းထဲတွင် ရှိပြီးသားဖြစ်နေပါသည်။ %1$s မှ ဤအကြောင်းမသိရှိနိုင်သေး၍ သင် ပြန်တုံ့ပြန်ထားနိုင်ပါသည် -</string>
|
||||||
<string name="introduction_request_answered_received">%2$s ကို သင်မှ မိတ်ဆက်ပေးရန် %1$s ကတောင်းဆိုထားပါသည်။</string>
|
<string name="introduction_request_answered_received">%2$s ကို သင်မှ မိတ်ဆက်ပေးရန် %1$s ကတောင်းဆိုထားပါသည်။</string>
|
||||||
<string name="introduction_response_accepted_sent">%1$s နှင့် မိတ်ဆက်ခြင်းအား သင်လက်ခံခဲ့ပါသည်။</string>
|
<string name="introduction_response_accepted_sent">%1$s နှင့် မိတ်ဆက်ခြင်းအား သင်လက်ခံခဲ့ပါသည်။</string>
|
||||||
@@ -303,11 +311,15 @@
|
|||||||
<string name="introduction_response_declined_received">%2$s နှင့် မိတ်ဆက်ခြင်းကို %1$s က ငြင်းဆိုခဲ့ပါသည်။</string>
|
<string name="introduction_response_declined_received">%2$s နှင့် မိတ်ဆက်ခြင်းကို %1$s က ငြင်းဆိုခဲ့ပါသည်။</string>
|
||||||
<string name="introduction_response_declined_received_by_introducee">%2$s မှ မိတ်ဆက်ခြင်းအား ငြင်းဆိုခဲ့သည်ကို %1$s မှ ပြောပါသည်။</string>
|
<string name="introduction_response_declined_received_by_introducee">%2$s မှ မိတ်ဆက်ခြင်းအား ငြင်းဆိုခဲ့သည်ကို %1$s မှ ပြောပါသည်။</string>
|
||||||
<!--Connect via Bluetooth-->
|
<!--Connect via Bluetooth-->
|
||||||
<string name="menu_item_connect_via_bluetooth">ဘလူးတုသ် နှင့် ချိတ်မယ်</string>
|
<string name="menu_item_connect_via_bluetooth">ဘလူးတုသ်နှင့် ချိတ်မယ်</string>
|
||||||
<string name="connect_via_bluetooth_title">ဘလူးတုသ်မှတစ်ဆင့် ချိတ်မည်</string>
|
<string name="connect_via_bluetooth_title">ဘလူးတုသ်မှတစ်ဆင့် ချိတ်မည်</string>
|
||||||
|
<string name="connect_via_bluetooth_intro">ဘလူးတုသ်ချိတ်ဆက်မှုများ အလိုအလျောက် အလုပ်မလုပ်ပါက၊ သင်သည် ကိုယ်တိုင် ချိတ်ဆက်ရန် ဤစခရင်ကို အသုံးပြုနိုင်ပါသည်။ \n\n ၎င်းကို လုပ်ဆောင်ရန်အတွက် သင့်အဆက်အသွယ်သည် အနီးအနားတွင်ရှိရန် လိုအပ်ပါသည်။ \n\n သင်နှင့် သင့်အဆက်အသွယ်နှစ်ဦးစလုံးသည် \"Start\" ကို တစ်ပြိုင်နက်တည်း နှိပ်သင့်ပါသည်။</string>
|
||||||
|
<string name="connect_via_bluetooth_already_discovering">ဘလူးတုသ်မှတစ်ဆင့် ချိတ်ဆက်ရန် ကြိုးစားနေပြီဖြစ်သည်။ ခဏနေ ထပ်မံစမ်းကြည့်ပါ။ </string>
|
||||||
<string name="connect_via_bluetooth_no_location_permission">တည်နေရာ သုံးခွင့်မပါဘဲ ဆက်လက် မလုပ်ဆောင်နိုင်ပါ</string>
|
<string name="connect_via_bluetooth_no_location_permission">တည်နေရာ သုံးခွင့်မပါဘဲ ဆက်လက် မလုပ်ဆောင်နိုင်ပါ</string>
|
||||||
<string name="connect_via_bluetooth_start">ဘလူးတုသ် နှင့် ချိတ်ဆက်နေသည်...</string>
|
<string name="connect_via_bluetooth_start">ဘလူးတုသ်နှင့် ချိတ်ဆက်နေတယ်...</string>
|
||||||
<string name="connect_via_bluetooth_success">ဘလူးတုသ် နှင့် အောင်မြင်စွာ ချိတ်ဆက်ပြီး</string>
|
<string name="connect_via_bluetooth_success">ဘလူးတုသ်နှင့် အောင်မြင်စွာ ချိတ်ဆက်ပြီး</string>
|
||||||
|
<string name="connect_via_bluetooth_error">ဘလူးတုသ်မှ တစ်ဆင့် ချိတ်ဆက်၍ မရပါ။</string>
|
||||||
|
<string name="connect_via_bluetooth_error_not_supported">ဘလူးတုသ်ကို စက်က မပံ့ပိုးပါ။</string>
|
||||||
<!--Private Groups-->
|
<!--Private Groups-->
|
||||||
<string name="groups_list_empty">ပြသစရာအဖွဲ့များမရှိ</string>
|
<string name="groups_list_empty">ပြသစရာအဖွဲ့များမရှိ</string>
|
||||||
<string name="groups_list_empty_action">+ (အပေါင်းအိုင်ကွန်) အား နှိပ်၍ အဖွဲ့ဖန်တီးပါ သို့မဟုတ် သင့် အဆက်အသွယ်များကို သင့်စီသို့ အဖွဲ့များ ဝေမျှရန် တောင်းဆိုပါ</string>
|
<string name="groups_list_empty_action">+ (အပေါင်းအိုင်ကွန်) အား နှိပ်၍ အဖွဲ့ဖန်တီးပါ သို့မဟုတ် သင့် အဆက်အသွယ်များကို သင့်စီသို့ အဖွဲ့များ ဝေမျှရန် တောင်းဆိုပါ</string>
|
||||||
@@ -331,10 +343,10 @@
|
|||||||
<string name="groups_member_joined">%s သည် အဖွဲ့သို့ ဝင်ရောက်ခဲ့သည်</string>
|
<string name="groups_member_joined">%s သည် အဖွဲ့သို့ ဝင်ရောက်ခဲ့သည်</string>
|
||||||
<string name="groups_leave">အဖွဲ့မှ ထွက်မယ်</string>
|
<string name="groups_leave">အဖွဲ့မှ ထွက်မယ်</string>
|
||||||
<string name="groups_leave_dialog_title">အဖွဲ့မှ ထွက်ခြင်းအား အတည်ပြုသည်</string>
|
<string name="groups_leave_dialog_title">အဖွဲ့မှ ထွက်ခြင်းအား အတည်ပြုသည်</string>
|
||||||
<string name="groups_leave_dialog_message">အဖွဲ့မှ ထွက်ရန် သေချာပါသလား?</string>
|
<string name="groups_leave_dialog_message">အဖွဲ့မှ ထွက်ရန် သေချာပါသလား။</string>
|
||||||
<string name="groups_dissolve">အဖွဲ့အား ဖျက်သိမ်းမယ်</string>
|
<string name="groups_dissolve">အဖွဲ့အား ဖျက်သိမ်းမယ်</string>
|
||||||
<string name="groups_dissolve_dialog_title">အဖွဲ့ကို ဖျက်သိမ်းခြင်းအား အတည်ပြုသည်</string>
|
<string name="groups_dissolve_dialog_title">အဖွဲ့ကို ဖျက်သိမ်းခြင်းအား အတည်ပြုသည်</string>
|
||||||
<string name="groups_dissolve_dialog_message">ဤအဖွဲ့အား ဖျက်သိမ်းမည်ဆိုတာ သင်သေချာပါသလား? \n\n အခြားအဖွဲ့ဝင်များအားလုံးသည် ၎င်းတို့ စကားပြောဆိုမှုများနှင့် နောက်ဆုံးမက်ဆေ့ချ်များ ဆက်လက်ပေးပို့လက်ခံရန် မရနိုင်တော့ပါ။</string>
|
<string name="groups_dissolve_dialog_message">ဤအဖွဲ့အား ဖျက်သိမ်းမည်ဆိုတာ သင်သေချာပါသလား။ \n\n အခြားအဖွဲ့ဝင်များအားလုံးသည် ၎င်းတို့ စကားပြောဆိုမှုများနှင့် နောက်ဆုံးမက်ဆေ့ချ်များ ဆက်လက်ပေးပို့လက်ခံရန် မရနိုင်တော့ပါ။</string>
|
||||||
<string name="groups_dissolve_button">ဖျက်သိမ်းမယ်</string>
|
<string name="groups_dissolve_button">ဖျက်သိမ်းမယ်</string>
|
||||||
<string name="groups_dissolved_dialog_title">အဖွဲ့အား ဖျက်သိမ်းပြီးပြီဖြစ်ပါသည်</string>
|
<string name="groups_dissolved_dialog_title">အဖွဲ့အား ဖျက်သိမ်းပြီးပြီဖြစ်ပါသည်</string>
|
||||||
<string name="groups_dissolved_dialog_message">ဤအဖွဲ့ဖန်တီးသူသည် ဤအဖွဲ့အား ဖျက်သိမ်းခဲ့ပါသည်။ \n\n သင်သည် အဖွဲ့စီသို့ မက်ဆေ့ချ်များ ရေးသား၍မရနိုင်ပါ နှင့် ယခင်က ရေးပြီးသားပို့စ်များကိုလည်း မလက်ခံနိုင်လောက်ပါ။</string>
|
<string name="groups_dissolved_dialog_message">ဤအဖွဲ့ဖန်တီးသူသည် ဤအဖွဲ့အား ဖျက်သိမ်းခဲ့ပါသည်။ \n\n သင်သည် အဖွဲ့စီသို့ မက်ဆေ့ချ်များ ရေးသား၍မရနိုင်ပါ နှင့် ယခင်က ရေးပြီးသားပို့စ်များကိုလည်း မလက်ခံနိုင်လောက်ပါ။</string>
|
||||||
@@ -377,7 +389,7 @@
|
|||||||
<string name="btn_reply">ပြန်ကြားမယ်</string>
|
<string name="btn_reply">ပြန်ကြားမယ်</string>
|
||||||
<string name="forum_leave">ဆွေးနွေးမှုဖိုရမ်မှ ထွက်မယ်</string>
|
<string name="forum_leave">ဆွေးနွေးမှုဖိုရမ်မှ ထွက်မယ်</string>
|
||||||
<string name="dialog_title_leave_forum">ဆွေးနွေးမှုဖိုရမ်မှ ထွက်ခြင်း အတည်ပြုမယ်</string>
|
<string name="dialog_title_leave_forum">ဆွေးနွေးမှုဖိုရမ်မှ ထွက်ခြင်း အတည်ပြုမယ်</string>
|
||||||
<string name="dialog_message_leave_forum">ဤဖိုရမ်မှ ထွက်ချင်တာ သေချာပါသလား? \n\n သင် ဤဖိုရမ်ကိုမျှဝေထားသည့် သင့်အဆက်အသွယ်များအနေဖြင့် သတင်းအသစ်များရရှိမှု ရပ်တန့်သွားနိုင်ပါသည်။</string>
|
<string name="dialog_message_leave_forum">ဤဖိုရမ်မှ ထွက်ချင်တာ သေချာပါသလား။ \n\n သင် ဤဖိုရမ်ကိုမျှဝေထားသည့် သင့်အဆက်အသွယ်များအနေဖြင့် သတင်းအသစ်များရရှိမှု ရပ်တန့်သွားနိုင်ပါသည်။</string>
|
||||||
<string name="dialog_button_leave">ထွက်မယ်</string>
|
<string name="dialog_button_leave">ထွက်မယ်</string>
|
||||||
<string name="forum_left_toast">ဆွေးနွေးမှုဖိုရမ်မှ ထွက်သွားပါပြီ</string>
|
<string name="forum_left_toast">ဆွေးနွေးမှုဖိုရမ်မှ ထွက်သွားပါပြီ</string>
|
||||||
<!--Forum Sharing-->
|
<!--Forum Sharing-->
|
||||||
@@ -421,7 +433,7 @@
|
|||||||
<string name="blogs_feed_empty_state">ပြစရာ ပို့စ်များမရှိ</string>
|
<string name="blogs_feed_empty_state">ပြစရာ ပို့စ်များမရှိ</string>
|
||||||
<string name="blogs_feed_empty_state_action">သင့် အဆက်အသွယ်များနှင့် သင်စာရင်းသွင်းထားသော ဘလော့ဂ်များမှ ပို့စ်များသည် ဤနေရာတွင် ပေါ်ပါမည်။ \n\n ဘောပင်အိုင်ကွန်အားနှိပ်၍ ပို့စ်ရေးပါ</string>
|
<string name="blogs_feed_empty_state_action">သင့် အဆက်အသွယ်များနှင့် သင်စာရင်းသွင်းထားသော ဘလော့ဂ်များမှ ပို့စ်များသည် ဤနေရာတွင် ပေါ်ပါမည်။ \n\n ဘောပင်အိုင်ကွန်အားနှိပ်၍ ပို့စ်ရေးပါ</string>
|
||||||
<string name="blogs_remove_blog">ဘလော့ဂ်အား ဖယ်ရှားမယ်</string>
|
<string name="blogs_remove_blog">ဘလော့ဂ်အား ဖယ်ရှားမယ်</string>
|
||||||
<string name="blogs_remove_blog_dialog_message">ဤဘလော့ဂ်ကို ဖယ်ရှားချင်တာ သေချာပါသလား? \n\n ပို့စ်များကို သင့်ကိရိယာမှ ဖယ်ရှားလိုက်မည်ဖြစ်သော်လည်း အခြားသူများ၏ကိရိယာများမှမူ ဖယ်ရှားလိုက်မည်မဟုတ်ပါ။ \n\n သင် ဤဘလော့ဂ်ကိုမျှဝေထားသည့် သင့်အဆက်အသွယ်များအနေဖြင့် သတင်းအသစ်များရရှိမှု ရပ်တန့်သွားနိုင်ပါသည်။</string>
|
<string name="blogs_remove_blog_dialog_message">ဤဘလော့ဂ်ကို ဖယ်ရှားချင်တာ သေချာပါသလား။ \n\n ပို့စ်များကို သင့်ကိရိယာမှ ဖယ်ရှားလိုက်မည်ဖြစ်သော်လည်း အခြားသူများ၏ကိရိယာများမှမူ ဖယ်ရှားလိုက်မည်မဟုတ်ပါ။ \n\n သင် ဤဘလော့ဂ်ကိုမျှဝေထားသည့် သင့်အဆက်အသွယ်များအနေဖြင့် သတင်းအသစ်များရရှိမှု ရပ်တန့်သွားနိုင်ပါသည်။</string>
|
||||||
<string name="blogs_remove_blog_ok">ဖယ်ရှားမယ်</string>
|
<string name="blogs_remove_blog_ok">ဖယ်ရှားမယ်</string>
|
||||||
<string name="blogs_blog_removed">ဘလော့ဂ်အား ဖယ်ရှားပြီး</string>
|
<string name="blogs_blog_removed">ဘလော့ဂ်အား ဖယ်ရှားပြီး</string>
|
||||||
<string name="blogs_reblog_comment_hint">မှတ်ချက်ထည့်မယ် (မဖြစ်မနေမဟုတ်ပါ)</string>
|
<string name="blogs_reblog_comment_hint">မှတ်ချက်ထည့်မယ် (မဖြစ်မနေမဟုတ်ပါ)</string>
|
||||||
@@ -453,7 +465,7 @@
|
|||||||
<string name="blogs_rss_feeds_manage_author">စာရေးဆရာ -</string>
|
<string name="blogs_rss_feeds_manage_author">စာရေးဆရာ -</string>
|
||||||
<string name="blogs_rss_feeds_manage_updated">နောက်ဆုံးအပ်ဒိတ်လုပ်ခဲ့ခြင်း -</string>
|
<string name="blogs_rss_feeds_manage_updated">နောက်ဆုံးအပ်ဒိတ်လုပ်ခဲ့ခြင်း -</string>
|
||||||
<string name="blogs_rss_remove_feed">သတင်းပို့စ်အလွှာ ဖယ်ရှားမယ်</string>
|
<string name="blogs_rss_remove_feed">သတင်းပို့စ်အလွှာ ဖယ်ရှားမယ်</string>
|
||||||
<string name="blogs_rss_remove_feed_dialog_message">ဤသတင်းပို့စ်အလွှာကို ဖယ်ရှားချင်တာ သေချာပါသလား? \n\n ပို့စ်များကို သင့်ကိရိယာမှ ဖယ်ရှားလိုက်မည်ဖြစ်သော်လည်း အခြားသူများ၏ကိရိယာများမှမူ ဖယ်ရှားလိုက်မည်မဟုတ်ပါ။ \n\n သင်မှ ဤသတင်းပို့စ်အလွှာကို မျှဝေထားသည့် သင့်အဆက်အသွယ်များအနေဖြင့် သတင်းအသစ်များရရှိမှု ရပ်တန့်သွားနိုင်ပါသည်။</string>
|
<string name="blogs_rss_remove_feed_dialog_message">ဤသတင်းပို့စ်အလွှာကို ဖယ်ရှားချင်တာ သေချာပါသလား။ \n\n ပို့စ်များကို သင့်ကိရိယာမှ ဖယ်ရှားလိုက်မည်ဖြစ်သော်လည်း အခြားသူများ၏ကိရိယာများမှမူ ဖယ်ရှားလိုက်မည်မဟုတ်ပါ။ \n\n သင်မှ ဤသတင်းပို့စ်အလွှာကို မျှဝေထားသည့် သင့်အဆက်အသွယ်များအနေဖြင့် သတင်းအသစ်များရရှိမှု ရပ်တန့်သွားနိုင်ပါသည်။</string>
|
||||||
<string name="blogs_rss_remove_feed_ok">ဖယ်ရှားမယ်</string>
|
<string name="blogs_rss_remove_feed_ok">ဖယ်ရှားမယ်</string>
|
||||||
<string name="blogs_rss_feeds_manage_empty_state">RSS သတင်းပို့စ်အလွှာများပြရန် မရှိပါ \n\n + (အပေါင်းအိုင်ကွန်) အားနှိပ်၍ သတင်းအလွှာ တင်သွင်းပါ</string>
|
<string name="blogs_rss_feeds_manage_empty_state">RSS သတင်းပို့စ်အလွှာများပြရန် မရှိပါ \n\n + (အပေါင်းအိုင်ကွန်) အားနှိပ်၍ သတင်းအလွှာ တင်သွင်းပါ</string>
|
||||||
<string name="blogs_rss_feeds_manage_error">သင့် သတင်းပို့စ်အလွှာကို တင်သွင်းရာတွင် အခက်အခဲတွေ့ကြုံခဲ့ပါသည်။ နောင်မှ ပြန်စမ်းကြည့်ပေးပါ။</string>
|
<string name="blogs_rss_feeds_manage_error">သင့် သတင်းပို့စ်အလွှာကို တင်သွင်းရာတွင် အခက်အခဲတွေ့ကြုံခဲ့ပါသည်။ နောင်မှ ပြန်စမ်းကြည့်ပေးပါ။</string>
|
||||||
@@ -475,7 +487,7 @@
|
|||||||
<!--Settings Connections-->
|
<!--Settings Connections-->
|
||||||
<string name="network_settings_title">ချိတ်ဆက်မှုများ</string>
|
<string name="network_settings_title">ချိတ်ဆက်မှုများ</string>
|
||||||
<string name="bluetooth_setting">ဘလူးတုသ်မှတစ်ဆင့် အဆက်အသွယ်များနှင့် ချိတ်ဆက်မည်</string>
|
<string name="bluetooth_setting">ဘလူးတုသ်မှတစ်ဆင့် အဆက်အသွယ်များနှင့် ချိတ်ဆက်မည်</string>
|
||||||
<string name="wifi_setting">တူညီသောဝိုင်ဖိုင်လိုင်းပေါ်ရှိ အဆက်အသွယ်များနှင့် ချိတ်ဆက်မယ်</string>
|
<string name="wifi_setting">တူညီသော ဝိုင်ဖိုင်လိုင်းပေါ်ရှိ အဆက်အသွယ်များနှင့် ချိတ်ဆက်မယ်</string>
|
||||||
<string name="tor_enable_title">အင်တာနက်သုံး၍ အဆက်အသွယ်များနှင့် ချိတ်ဆက်မယ်</string>
|
<string name="tor_enable_title">အင်တာနက်သုံး၍ အဆက်အသွယ်များနှင့် ချိတ်ဆက်မယ်</string>
|
||||||
<string name="tor_enable_summary">လုံခြုံမှုအတွက် ချိတ်ဆက်မှုများသည် Tor ကွန်ယက်ပေါ် ဖြတ်သန်းပါသည်</string>
|
<string name="tor_enable_summary">လုံခြုံမှုအတွက် ချိတ်ဆက်မှုများသည် Tor ကွန်ယက်ပေါ် ဖြတ်သန်းပါသည်</string>
|
||||||
<string name="tor_network_setting">Tor ကွန်ယက်အတွက် ချိတ်ဆက်မှု နည်းလမ်း</string>
|
<string name="tor_network_setting">Tor ကွန်ယက်အတွက် ချိတ်ဆက်မှု နည်းလမ်း</string>
|
||||||
@@ -521,7 +533,7 @@
|
|||||||
<string name="panic_app_setting_summary">မည်သည့် အပ္ပလီကေးရှင်းမှ သတ်မှတ်ထားခြင်းမရှိပါ</string>
|
<string name="panic_app_setting_summary">မည်သည့် အပ္ပလီကေးရှင်းမှ သတ်မှတ်ထားခြင်းမရှိပါ</string>
|
||||||
<string name="panic_app_setting_none">ဘာမှမရှိ</string>
|
<string name="panic_app_setting_none">ဘာမှမရှိ</string>
|
||||||
<string name="dialog_title_connect_panic_app">ထိတ်လန့် အပ္ပလီကေးရှင်းအား အတည်ပြုမယ်</string>
|
<string name="dialog_title_connect_panic_app">ထိတ်လန့် အပ္ပလီကေးရှင်းအား အတည်ပြုမယ်</string>
|
||||||
<string name="dialog_message_connect_panic_app">ထိတ်လန့်ခလုတ်ဖြင့် ဖျက်သိမ်းရန် လုပ်ဆောင်ချက်များ လှုံ့ဆော်ခြင်းကို %1$s အား ခွင့်ပြုမည်ဆိုသည်ကို သင်သေချာပါသလား?</string>
|
<string name="dialog_message_connect_panic_app">ထိတ်လန့်ခလုတ်ဖြင့် ဖျက်သိမ်းရန် လုပ်ဆောင်ချက်များ လှုံ့ဆော်ခြင်းကို %1$s အား ခွင့်ပြုမည်ဆိုသည်ကို သင်သေချာပါသလား။</string>
|
||||||
<string name="panic_setting_destructive_action">ဖျက်သိမ်းမှု လုပ်ဆောင်ချက်များ</string>
|
<string name="panic_setting_destructive_action">ဖျက်သိမ်းမှု လုပ်ဆောင်ချက်များ</string>
|
||||||
<string name="panic_setting_signout_title">အကောင့်ထွက်မည်</string>
|
<string name="panic_setting_signout_title">အကောင့်ထွက်မည်</string>
|
||||||
<string name="panic_setting_signout_summary">ထိတ်လန့်ခလုတ် အားနှိပ်ခံရလျှင် Briar အကောင့်မှ ထွက်ခွာမည်</string>
|
<string name="panic_setting_signout_summary">ထိတ်လန့်ခလုတ် အားနှိပ်ခံရလျှင် Briar အကောင့်မှ ထွက်ခွာမည်</string>
|
||||||
@@ -549,6 +561,22 @@
|
|||||||
<string name="notify_sound_setting_disabled">ဘာမှမရှိ</string>
|
<string name="notify_sound_setting_disabled">ဘာမှမရှိ</string>
|
||||||
<string name="choose_ringtone_title">ဖုန်းမြည်သံရွေးမည်</string>
|
<string name="choose_ringtone_title">ဖုန်းမြည်သံရွေးမည်</string>
|
||||||
<string name="cannot_load_ringtone">ဖုန်းမြည်သံမဖွင့်နိုင်ပါ</string>
|
<string name="cannot_load_ringtone">ဖုန်းမြည်သံမဖွင့်နိုင်ပါ</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_settings_title">စာတိုက်ပုံး</string>
|
||||||
|
<string name="mailbox_setup_title">စာတိုက်ပုံး စနစ်ထည့်သွင်းခြင်း</string>
|
||||||
|
<string name="mailbox_setup_intro">သင်အော့ဖ်လိုင်းဖြစ်နေချိန်တွင် သင့်အဆက်အသွယ်များကို မက်ဆေ့ခ်ျများပေးပို့ရန် စာတိုက်ပုံးကို ဖွင့်ပေးသည်။ သင်အွန်လိုင်းပေါ်မလာမချင်း စာတိုက်ပုံး သည် သင့်မက်ဆေ့ဂျ်များကို လက်ခံရရှိပြီး ၎င်းတို့ကို သိမ်းဆည်းပါမည်။\n
|
||||||
|
\nသင်သည် Briar စာတိုက်ပုံး အက်ပ်ကို အားလပ်သည့်စက်ပစ္စည်းတစ်ခုတွင် ထည့်သွင်းနိုင်သည်။ ၎င်းကို ပါဝါနှင့် ဝိုင်ဖိုင်ချိတ်ဆက်ထားပါက ၎င်းကို အမြဲအွန်လိုင်းပေါ်နေစေပါသည်။</string>
|
||||||
|
<string name="mailbox_setup_download">ပထမဦးစွာ၊ Google Play တွင် \"Briar စာတိုက်ပုံး\" ကို ရှာဖွေခြင်းဖြင့် အခြားစက်ပစ္စည်းပေါ်တွင် စာတိုက်ပုံး အက်ပ်ကို ထည့်သွင်းပါ။\n
|
||||||
|
\nထို့နောက် စာတိုက်ပုံး အက်ပ်မှပြသထားသည့် QR ကုဒ်ကို စကင်န်ဖတ်ခြင်းဖြင့် သင်၏ စာတိုက်ပုံးကို Briar နှင့် ချိတ်ဆက်ပါ။</string>
|
||||||
|
<string name="mailbox_setup_download_link">ဒေါင်းလုဒ်လင့်ခ်ကို မျှဝေပါ</string>
|
||||||
|
<string name="mailbox_setup_button_scan">စာတိုက်ပုံး QR ကုဒ်ကို စကင်န်ဖတ်ပါ</string>
|
||||||
|
<string name="permission_camera_qr_denied_body">သင်သည် ကင်မရာအသုံးပြုခွင့်ကို ငြင်းပယ်ထားသော်လည်း QR ကုဒ်ကို စကင်န်ဖတ်ရန် ကင်မရာကို အသုံးပြုရန် လိုအပ်ပါသည်။ \n\nကျေးဇူးပြု၍ ဝင်ရောက်ခွင့်ပြုရန် စဉ်းစားပါ။</string>
|
||||||
|
<string name="mailbox_setup_connecting">ချိတ်ဆက်နေသည်…</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_title">QR ကုဒ် မှားနေသည်</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_description">စကင်ဖတ်ထားသော ကုဒ်သည် မမှန်ကန်ပါ။ ကျေးဇူးပြု၍ သင့်စာတိုက်ပုံး စက်ပစ္စည်းပေါ်ရှိ Briar စာတိုက်ပုံး အက်ပ်ကိုဖွင့်ပြီး ၎င်းတွင်ပါရှိသော QR ကုဒ်ကို စကင်န်ဖတ်ပါ။</string>
|
||||||
|
<string name="tor_offline_title">အော့ဖ်လိုင်း</string>
|
||||||
|
<string name="tor_offline_description">ဤစက်ပစ္စည်းသည် အွန်လိုင်းရှိပြီး အင်တာနက်ချိတ်ဆက်မှုများကို ခွင့်ပြုထားကြောင်း သေချာပါစေ။ \n\nထို့နောက်၊ ချိတ်ဆက်မှုဆက်တင်များရှိ ကမ္ဘာလုံးအိုင်ကွန်ကို စိမ်းသည်အထိ စောင့်ဆိုင်းပါ။</string>
|
||||||
|
<string name="tor_offline_button_check">ချိတ်ဆက်မှု ဆက်တင်များကို စစ်ဆေးပါ</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">ပျောက်ကွယ် မက်ဆေ့ချ်များ</string>
|
<string name="disappearing_messages_title">ပျောက်ကွယ် မက်ဆေ့ချ်များ</string>
|
||||||
<string name="disappearing_messages_explanation_long">၎င်းအပြင်အဆင်ကို ဖွင့်ထားလျှင်
|
<string name="disappearing_messages_explanation_long">၎င်းအပြင်အဆင်ကို ဖွင့်ထားလျှင်
|
||||||
@@ -572,6 +600,7 @@
|
|||||||
<string name="link_warning_open_link">လင့်ခ်ဖွင့်မယ်</string>
|
<string name="link_warning_open_link">လင့်ခ်ဖွင့်မယ်</string>
|
||||||
<!--Crash Reporter-->
|
<!--Crash Reporter-->
|
||||||
<string name="crash_report_title">Briar ပျက်ယွင်းမှုတိုင်ကြားခြင်း</string>
|
<string name="crash_report_title">Briar ပျက်ယွင်းမှုတိုင်ကြားခြင်း</string>
|
||||||
|
<string name="briar_crashed">ဝမ်းနည်းပါတယ်၊ Briar ပျက်သွားပါပြီ</string>
|
||||||
<string name="not_your_fault">သင့်အမှားမဟုတ်ပါ။</string>
|
<string name="not_your_fault">သင့်အမှားမဟုတ်ပါ။</string>
|
||||||
<string name="please_send_report">ပျက်ကွက်မှု တိုင်ကြားစာ ပေးပို့၍ ကျွန်ုပ်တို့်အား Briar အပ္ပလီကေးရှင်း တိုးတက်ရန် ကူညီပေးပါ။</string>
|
<string name="please_send_report">ပျက်ကွက်မှု တိုင်ကြားစာ ပေးပို့၍ ကျွန်ုပ်တို့်အား Briar အပ္ပလီကေးရှင်း တိုးတက်ရန် ကူညီပေးပါ။</string>
|
||||||
<string name="report_is_encrypted">သင်၏တိုင်ကြားမှုကို လျှို့ဝှက်ကုဒ်ပြောင်း၍ လုံခြုံစွာပို့ကြောင်း ကတိပြုပါသည်။</string>
|
<string name="report_is_encrypted">သင်၏တိုင်ကြားမှုကို လျှို့ဝှက်ကုဒ်ပြောင်း၍ လုံခြုံစွာပို့ကြောင်း ကတိပြုပါသည်။</string>
|
||||||
@@ -589,6 +618,7 @@
|
|||||||
<string name="dev_report_memory">မှတ်ညဏ်</string>
|
<string name="dev_report_memory">မှတ်ညဏ်</string>
|
||||||
<string name="dev_report_storage">သိမ်းဆည်းမှု</string>
|
<string name="dev_report_storage">သိမ်းဆည်းမှု</string>
|
||||||
<string name="dev_report_connectivity">ချိတ်ဆက်မှု</string>
|
<string name="dev_report_connectivity">ချိတ်ဆက်မှု</string>
|
||||||
|
<string name="dev_report_network_usage">ကွန်ရက် အသုံးပြုမှု</string>
|
||||||
<string name="dev_report_build_config">ပြင်ဆင်ချိန်ဆမှု တည်ဆောက်မယ်</string>
|
<string name="dev_report_build_config">ပြင်ဆင်ချိန်ဆမှု တည်ဆောက်မယ်</string>
|
||||||
<string name="dev_report_logcat">အပ္ပလီကေးရှင်း မှတ်တမ်း</string>
|
<string name="dev_report_logcat">အပ္ပလီကေးရှင်း မှတ်တမ်း</string>
|
||||||
<string name="dev_report_device_features">စက်ပစ္စည်း အင်္ဂါရပ်များ</string>
|
<string name="dev_report_device_features">စက်ပစ္စည်း အင်္ဂါရပ်များ</string>
|
||||||
@@ -631,18 +661,86 @@
|
|||||||
<string name="transports_help_text">Briar သည် သင့်အဆက်အသွယ်များကို အင်တာနက်၊ ဝိုင်ဖိုင်၊ သို့မဟုတ် ဘလူးတုသ် မှတစ်ဆင့် ချိတ်ဆက်နိုင်ပါသည်။ \n\n အင်တာနက်ချိတ်ဆက်မှုအားလုံးသည် လုံခြုံရေးအတွက် Tor ကွန်ယက်မှတစ်ဆင့် ဖြတ်သန်းပါသည်။ \n\n အဆက်အသွယ်တစ်ဦးကို နည်းမျိုးစုံနှင့် ဆက်သွယ်နိုင်ခဲ့လျှင် Briar သည် နည်းမျိုးစုံအား တစ်ပြိုင်နက်တည်း အသုံးပြုနေပါသည်။</string>
|
<string name="transports_help_text">Briar သည် သင့်အဆက်အသွယ်များကို အင်တာနက်၊ ဝိုင်ဖိုင်၊ သို့မဟုတ် ဘလူးတုသ် မှတစ်ဆင့် ချိတ်ဆက်နိုင်ပါသည်။ \n\n အင်တာနက်ချိတ်ဆက်မှုအားလုံးသည် လုံခြုံရေးအတွက် Tor ကွန်ယက်မှတစ်ဆင့် ဖြတ်သန်းပါသည်။ \n\n အဆက်အသွယ်တစ်ဦးကို နည်းမျိုးစုံနှင့် ဆက်သွယ်နိုင်ခဲ့လျှင် Briar သည် နည်းမျိုးစုံအား တစ်ပြိုင်နက်တည်း အသုံးပြုနေပါသည်။</string>
|
||||||
<!--Share app offline-->
|
<!--Share app offline-->
|
||||||
<string name="hotspot_title">ဤအက်ပ်ကို အော့ဖ်လိုင်းမျှဝေမည်</string>
|
<string name="hotspot_title">ဤအက်ပ်ကို အော့ဖ်လိုင်းမျှဝေမည်</string>
|
||||||
|
<string name="hotspot_intro">သင့်ဖုန်း၏ ဝိုင်ဖိုင်ကို အသုံးပြုခြင်းဖြင့် အင်တာနက်ချိတ်ဆက်မှုမရှိဘဲ အနီးနားရှိ လူတစ်ဦးနှင့် မျှဝေပါ။ \n\n သင့်ဖုန်းသည် ဝိုင်ဖိုင်ဟော့စပေါ့တစ်ခု စတင်ပါမည်။ အနီးနားရှိလူများသည် ဟော့စပေါ့သို့ ချိတ်ဆက်နိုင်ပြီး သင့်ဖုန်းမှ Briar အက်ပ်ကို ဒေါင်းလုဒ် လုပ်နိုင်ပါသည်။</string>
|
||||||
|
<string name="hotspot_button_start_sharing">hotspot ကို စတင်ပါ</string>
|
||||||
|
<string name="hotspot_button_stop_sharing">hotspot ကို ရပ်ပါ</string>
|
||||||
|
<string name="hotspot_progress_text_start">hotspot ကို တည်ဆောက်နေသည်...</string>
|
||||||
<string name="hotspot_notification_channel_title">ဝိုင်ဖိုင် ဟော့စပေါ့</string>
|
<string name="hotspot_notification_channel_title">ဝိုင်ဖိုင် ဟော့စပေါ့</string>
|
||||||
|
<string name="hotspot_notification_title">Briar အော့ဖ်လိုင်း မျှဝေခြင်း</string>
|
||||||
<string name="hotspot_button_connected">ရှေ့သို့</string>
|
<string name="hotspot_button_connected">ရှေ့သို့</string>
|
||||||
|
<string name="permission_hotspot_location_request_body">ဝိုင်ဖိုင်ဟော့စပေါ့ ဖန်တီးရန်၊ Briar သည် သင့်တည်နေရာကို ဝင်ရောက်အသုံးပြုရန် ခွင့်ပြုချက် လိုအပ်ပါသည်။ \n\n Briar သည် သင့်တည်နေရာကို သိမ်းဆည်းထားခြင်း သို့မဟုတ် ၎င်းကို မည်သူနှင့်မျှ မမျှဝေပါ။</string>
|
||||||
|
<string name="permission_hotspot_location_denied_body">သင့်တည်နေရာသို့ ဝင်ရောက်ခွင့်ကို သင်ငြင်းဆိုထားသော်လည်း Briar သည် ဝိုင်ဖိုင်ဟော့စပေါ့တစ်ခု ဖန်တီးရန် ဤခွင့်ပြုချက် လိုအပ်ပါသည်။ \n\n ကျေးဇူးပြု၍ အသုံးပြုခွင့်ပေးရန် စဉ်းစားပါ။</string>
|
||||||
|
<string name="wifi_settings_title">ဝိုင်ဖိုင်ဆက်တင်</string>
|
||||||
|
<string name="wifi_settings_request_enable_body">ဝိုင်ဖိုင်ဟော့စပေါ့ ဖန်တီးရန်၊ Briar သည် ဝိုင်ဖိုင်ကို အသုံးပြုရန် လိုအပ်သည်။ ၎င်းကိုဖွင့်ပါ။</string>
|
||||||
|
<string name="hotspot_tab_manual">လမ်းညွှန်စာအုပ်</string>
|
||||||
<!--The placeholder to be inserted into the string 'hotspot_manual_wifi': People can connect by %s-->
|
<!--The placeholder to be inserted into the string 'hotspot_manual_wifi': People can connect by %s-->
|
||||||
|
<string name="hotspot_scanning_a_qr_code">QR ကုဒ်ကို စကင်န်ဖတ်နေသည်</string>
|
||||||
<!--Wi-Fi setup-->
|
<!--Wi-Fi setup-->
|
||||||
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
|
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
|
||||||
|
<string name="hotspot_manual_wifi">သင့်ဖုန်းသည် ဝိုင်ဖိုင်ဟော့စပေါ့ကို ပံ့ပိုးပေးနေသည်။ Briar ကို ဒေါင်းလုဒ် လုပ်လိုသူများသည် အောက်ဖော်ပြပါ သေးစိတ်အချက်အလက်များကို အသုံးပြု၍ သို့မဟုတ် ၎င်းတို့၏ စက်ပစ္စည်း၏ ဝိုင်ဖိုင်ဆက်တင်များတွင် %sထည့်သွင်းခြင်းဖြင့် ဟော့စပေါ့သို့ ချိတ်ဆက်နိုင်ပါသည်။ ဟော့စပေါ့သို့ ချိတ်ဆက်ပြီးပါက \'Next\' ကိုနှိပ်ပါ။</string>
|
||||||
|
<string name="hotspot_manual_wifi_ssid">ကွန်ရက်အမည်</string>
|
||||||
|
<string name="hotspot_qr_wifi">သင့်ဖုန်းသည် ဝိုင်ဖိုင်ဟော့စပေါ့ကို ပံ့ပိုးပေးနေသည်။ Briar ကို ဒေါင်းလုဒ်လုပ်လိုသူများသည် ဤ QR ကုဒ်ကိုစကင်န်ဖတ်ခြင်းဖြင့် ဟော့စပေါ့သို့ ချိတ်ဆက်နိုင်သည်။ ဟော့စပေါ့သို့ ချိတ်ဆက်ပြီးပါက \'Next\' ကိုနှိပ်ပါ။</string>
|
||||||
|
<string name="hotspot_no_peers_connected">ချိတ်ဆက်ထားသော စက်များမရှိပါ</string>
|
||||||
|
<plurals name="hotspot_peers_connected">
|
||||||
|
<item quantity="other">%sစက်ပစ္စည်းများကို ချိတ်ဆက်ထားသည်</item>
|
||||||
|
</plurals>
|
||||||
<!--Download link-->
|
<!--Download link-->
|
||||||
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
|
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
|
||||||
|
<string name="hotspot_manual_site">သင့်ဖုန်းသည် ဝိုင်ဖိုင်ဟော့စပေါ့ကို ပံ့ပိုးပေးနေသည်။ ဝိုင်ဖိုင်ဟော့စပေါ့သို့ %sချိတ်ဆက်ထားသူများသည် ဝဘ်ဘရောက်ဆာတွင် အောက်ပါလင့်ခ်ကို ရိုက်ထည့်ခြင်းဖြင့် Briar ကို ဒေါင်းလုဒ် လုပ်နိုင်သည်။</string>
|
||||||
|
<string name="hotspot_manual_site_address">လိပ်စာ (URL)</string>
|
||||||
|
<string name="hotspot_qr_site">သင့်ဖုန်းသည် ဝိုင်ဖိုင်ဟော့စပေါ့ကို ပံ့ပိုးပေးနေသည်။ ဟော့စပေါ့သို့ ချိတ်ဆက်ထားသူများသည် ဤ QR ကုဒ်ကို စကင်န်ဖတ်ခြင်းဖြင့် Briar ကို ဒေါင်းလုဒ်လုပ်နိုင်ပါသည်။</string>
|
||||||
<!--e.g. Download Briar 1.2.20-->
|
<!--e.g. Download Briar 1.2.20-->
|
||||||
|
<string name="website_download_title">ဒေါင်းလုဒ်%s</string>
|
||||||
|
<string name="website_download_intro">အနီးတစ်ဝိုက်တွင် တစ်စုံတစ်ဦးမှ %sသင်နှင့် မျှဝေခဲ့သည်။</string>
|
||||||
|
<string name="website_download_outro">ဒေါင်းလုဒ်ပြီးပါက ဒေါင်းလုဒ်လုပ်ထားသော ဖိုင်ကိုဖွင့်ပြီး ထည့်သွင်းပါ။</string>
|
||||||
<string name="website_troubleshooting_title">ပြဿနာရှာဖွေပြင်ဆင်ခြင်း</string>
|
<string name="website_troubleshooting_title">ပြဿနာရှာဖွေပြင်ဆင်ခြင်း</string>
|
||||||
|
<string name="website_troubleshooting_1">အက်ပ်ကို သင်ဒေါင်းလုဒ် မလုပ်နိုင်ပါက အခြား ဝဘ်ဘရောက်ဆာ အက်ပ်ဖြင့် ၎င်းကို စမ်းကြည့်ပါ။</string>
|
||||||
|
<string name="website_troubleshooting_2_old">ဒေါင်းလုဒ်လုပ်ထားသောအက်ပ်ကို ထည့်သွင်းရန်၊ စနစ်ဆက်တင်များတွင် \"အမည်မသိရင်းမြစ်များ\" မှ အက်ပ်များကို တပ်ဆင်ခွင့်ပြုရန် လိုအပ်နိုင်သည်။ ထို့နောက်တွင် သင်သည် အက်ပ်ကို ထပ်မံဒေါင်းလုဒ်လုပ်ရန် လိုအပ်နိုင်သည်။ အက်ပ်ကိုထည့်သွင်းပြီးနောက် \"အမည်မသိရင်းမြစ်များ\" ဆက်တင်ကို ပိတ်ရန် အကြံပြုအပ်ပါသည်။</string>
|
||||||
|
<string name="website_troubleshooting_2_new">ဒေါင်းလုဒ်လုပ်ထားသောအက်ပ်ကို ထည့်သွင်းရန်၊ သင့်ဘရောက်ဆာသည် အမည်မသိအက်ပ်များကို ထည့်သွင်းခွင့်ပြုရန် လိုအပ်နိုင်သည်။ အက်ပ်ကို ထည့်သွင်းပြီးနောက်၊ အမည်မသိအက်ပ်များကို ထည့်သွင်းရန် ဘရောက်ဆာ၏ ခွင့်ပြုချက်ကို ဖယ်ရှားရန် အကြံပြုအပ်ပါသည်။</string>
|
||||||
|
<string name="hotspot_help_wifi_title">ဝိုင်ဖိုင်သို့ ချိတ်ဆက်ရာတွင် ပြဿနာများ -</string>
|
||||||
|
<string name="hotspot_help_wifi_1">ဖုန်းနှစ်မျိုးလုံးတွင် ဝိုင်ဖိုင်ကို ပိတ်ထားပြီး ပြန်ဖွင့်ကြည့်ပါ။ ထပ်လုပ်ကြည့်ပါ။</string>
|
||||||
|
<string name="hotspot_help_wifi_2">သင့်ဖုန်းတွင် ဝိုင်ဖိုင်တွင် အင်တာနက်မရှိဟု ပြလာပါက၊ မည်သို့ပင်ဖြစ်စေ ချိတ်ဆက်လိုကြောင်း အသိပေးပါ။</string>
|
||||||
|
<string name="hotspot_help_wifi_3">ဝိုင်ဖိုင်ဟော့စပေါ့ကို အသုံးပြုနေသည့် ဖုန်းကို ပြန်လည်စတင်ပါ၊ ထို့နောက် Briar ကို စတင်ပြီး ထပ်မံမျှဝေကြည့်ပါ။</string>
|
||||||
|
<string name="hotspot_help_site_title">စက်အတွင်းရှိ ဝဘ်ဆိုက်သို့ ဝင်ရောက်ကြည့်ရှုရာတွင် ပြဿနာများ -</string>
|
||||||
|
<string name="hotspot_help_site_1">သင်ပြထားသည့်အတိုင်း လိပ်စာအတိအကျကို ထည့်သွင်းထားကြောင်း နှစ်ခါ စစ်ဆေးပါ။ သေးငယ်တဲ့ ချို့ယွင်းချက်က ပျက်သွားနိုင်ပါတယ်။</string>
|
||||||
|
<string name="hotspot_help_site_2">ဆိုက်ကိုဝင်ရောက်ရန် ကြိုးစားသောအခါတွင် သင့်ဖုန်းသည် မှန်ကန်သော ဝိုင်ဖိုင်နှင့် ချိတ်ဆက်နေသေးကြောင်း သေချာပါစေ။</string>
|
||||||
|
<string name="hotspot_help_site_3">သင့်တွင် firewall အက်ပ်တစ်ခုရှိပါက၊ ၎င်းသည် ဝင်ရောက်ခွင့်ကို ပိတ်ဆို့ထားခြင်း မဟုတ်ကြောင်း စစ်ဆေးပါ။</string>
|
||||||
|
<string name="hotspot_help_site_4">အကယ်၍ သင်သည် ဝဘ်ဆိုက်သို့ ဝင်ရောက်ကြည့်ရှုနိုင်သော်လည်း Briar အက်ပ်ကို ဒေါင်းလုဒ်မလုပ်ပါက အခြား ဝဘ်ဘရောက်ဆာအက်ပ်ဖြင့် ၎င်းကို စမ်းကြည့်ပါ။</string>
|
||||||
|
<string name="hotspot_help_fallback_title">ဘာမှ အလုပ်မဖြစ်ဘူးလား။</string>
|
||||||
|
<string name="hotspot_help_fallback_intro">သင်သည် အက်ပ်အား .apk ဖိုင်အဖြစ် တစ်နည်းတစ်ဖုံ မျှဝေရန် ကြိုးစားနိုင်သည်။ ဖိုင်ကို အခြားစက်ပစ္စည်းသို့ လွှဲပြောင်းပြီးသည်နှင့် Briar ကို ထည့်သွင်းရန် အသုံးပြုနိုင်သည်။
|
||||||
|
\n\n အကြံပြုချက် - ဘလူးတုသ်မှ တစ်ဆင့် မျှဝေရန်အတွက်၊ သင်သည် .zip ဖြင့် ပထမအဆုံးသတ်ရန် ဖိုင်ကို အမည်ပြောင်းရန် လိုအပ်နိုင်သည်။</string>
|
||||||
|
<string name="hotspot_help_fallback_button">အက်ပ်ကို သိမ်းဆည်းပါ</string>
|
||||||
<!--error handling-->
|
<!--error handling-->
|
||||||
|
<string name="hotspot_error_intro">အက်ပ်အား ဝိုင်ဖိုင်မှ တစ်ဆင့် မျှဝေရန် ကြိုးစားစဉ် တစ်ခုခု မှားသွားသည် -</string>
|
||||||
|
<string name="hotspot_error_no_wifi_direct">စက်ပစ္စည်းသည် Wi-Fi Direct ကို မပံ့ပိုးပါ။</string>
|
||||||
|
<string name="hotspot_error_start_callback_failed">Hotspot စတင်မှု မအောင်မြင်ပါ - ပြဿနာ %s</string>
|
||||||
|
<string name="hotspot_error_start_callback_failed_unknown">Hotspot ကို အမည်မသိအမှားဖြင့် စတင်ရန် မအောင်မြင်ပါ၊ အကြောင်းပြချက် %d</string>
|
||||||
|
<string name="hotspot_error_start_callback_no_group_info">Hotspot စတင်ရန် မအောင်မြင်ပါ - အဖွဲ့ အချက်အလက် မရှိပါ</string>
|
||||||
|
<string name="hotspot_error_web_server_start">ဝဘ်ဆာဗာကို စတင်ရာတွင် အမှားအယွင်း ရှိနေသည်</string>
|
||||||
|
<string name="hotspot_error_web_server_serve">ဝဘ်ဆိုဒ်ကို တင်ပြရာတွင် အမှားအယွင်းရှိနေပါသည်။ \n\n ပြဿနာ ဆက်လက်ရှိနေပါက Briar အက်ပ်မှတစ်ဆင့် (အမည်မသိဒေတာဖြင့်) တုံ့ပြန်ချက်ပေးပို့ပါ။</string>
|
||||||
|
<string name="hotspot_flag_test">သတိပေးချက် - ဤအက်ပ်ကို Android Studio တွင် ထည့်သွင်းထားပြီး အခြားစက်ပစ္စည်းတွင် ထည့်သွင်း၍မရပါ။</string>
|
||||||
|
<string name="hotspot_error_framework_busy">ဟော့စပေါ့ကို စတင်၍မရပါ။ \n\n သင့်တွင် အခြားသော ဟော့စပေါ့တစ်ခု လုပ်ဆောင်နေပါက သို့မဟုတ် ဝိုင်ဖိုင်မှ တစ်ဆင့် သင့်အင်တာနက်ချိတ်ဆက်မှုကို မျှဝေနေပါက ၎င်းကို ရပ်လိုက်ပြီး နောက်မှ ထပ်စမ်းကြည့်ပါ။</string>
|
||||||
<!--Transfer Data via Removable Drives-->
|
<!--Transfer Data via Removable Drives-->
|
||||||
<string name="removable_drive_success_receive_text">ဤဖိုင်တွင်ပါဝင်သည့် လျှို့ဝှက်ကုဒ်ပြောင်းမက်ဆေ့ချ်အားလုံးကို လက်ခံရရှိပါပြီ။</string>
|
<string name="removable_drive_menu_title">ဖယ်ရှားနိုင်သော Drive မှတစ်ဆင့် ချိတ်ဆက်ပါ</string>
|
||||||
|
<string name="removable_drive_intro">အင်တာနက်၊ ဝိုင်ဖိုင်သို့မဟုတ် ဘလူးတုသ်မှ တဆင့် သင့်အဆက်အသွယ်ကို မချိတ်ဆက်နိုင်ပါက၊ Briar သည် USB stick သို့မဟုတ် SD ကတ်ကဲ့သို့ ဖြုတ်တပ်နိုင်သော drive ပေါ်တွင် မက်ဆေ့ချ်များကို လွှဲပြောင်းနိုင်သည်။</string>
|
||||||
|
<string name="removable_drive_explanation">အင်တာနက်၊ ဝိုင်ဖိုင်သို့မဟုတ် ဘလူးတုသ်မှတစ်ဆင့် သင့်အဆက်အသွယ်ထံသို့ ချိတ်ဆက်၍မရပါက၊ Briar သည် USB stick သို့မဟုတ် SD ကတ်ကဲ့သို့ ဖြုတ်တပ်နိုင်သော drive ပေါ်တွင် မက်ဆေ့ချ်များကို လွှဲပြောင်းနိုင်သည်။ \n\nသင် \"ဒေတာပေးပို့ရန်\" ခလုတ်ကို အသုံးပြုသည့်အခါ၊ အဆက်အသွယ်ထံ ပေးပို့ရန် စောင့်ဆိုင်းနေသည့် မည်သည့်ဒေတာကို ဖယ်ရှားနိုင်သော drive သို့ စာရေးပါမည်။ ၎င်းတွင် ကိုယ်ရေးကိုယ်တာမက်ဆေ့ချ်များ၊ ပူးတွဲပါဖိုင်များ၊ ဘလော့ဂ်များ၊ ဖိုရမ်များနှင့် သီးသန့်အုပ်စုများ ပါဝင်သည်။ \n\nဖယ်ရှားနိုင်သော drive သို့ မရေးထားမီ အရာအားလုံးကို ကုဒ်ဝှက်ထားပါမည်။ \n\nသင်၏အဆက်အသွယ်သည် ဖြုတ်တပ်နိုင်သော drive ကို လက်ခံရရှိသည့်အခါ ၎င်းတို့သည် \"ဒေတာလက်ခံရယူရန်\" ခလုတ်ကို အသုံးပြုနိုင်ပါသည်။ မက်ဆေ့ချ်များကို Briar သို့တင်သွင်းရန်။</string>
|
||||||
|
<string name="removable_drive_title_send">အချက်အလက် ပို့ပါ</string>
|
||||||
|
<string name="removable_drive_title_receive">အချက်အလက် ရယူပါ</string>
|
||||||
|
<string name="removable_drive_send_intro">ကုဒ်ဝှက်ထားသော မက်ဆေ့ချ်များပါရှိသော ဖိုင်အသစ်တစ်ခုကို ဖန်တီးရန် အောက်ပါခလုတ်ကို တို့ပါ။ ဖိုင်သိမ်းမည့်နေရာကို သင်ရွေးချယ်နိုင်ပါသည်။ \n\nဖယ်ရှားနိုင်သော drive တွင် ဖိုင်ကိုသိမ်းဆည်းလိုပါက၊ ယခု drive ကို ထည့်သွင်းပါ။</string>
|
||||||
|
<string name="removable_drive_send_no_data">လောလောဆယ်တွင် ဤအဆက်အသွယ်ထံ ပေးပို့ရန် စောင့်ဆိုင်းနေသည့် မက်ဆေ့ချ်များ မရှိပါ။</string>
|
||||||
|
<string name="removable_drive_send_not_supported">ဤအဆက်အသွယ်သည် Briar ဗားရှင်းဟောင်း သို့မဟုတ် ဤအင်္ဂါရပ်ကို မပံ့ပိုးသည့် စက်ဟောင်းကို အသုံးပြုနေသည်။</string>
|
||||||
|
<string name="removable_drive_send_button">ထုတ်ယူရန် ဖိုင်ကို ရွေးပါ</string>
|
||||||
|
<string name="removable_drive_ongoing">ကျေးဇူးပြု၍ လုပ်နေသောအလုပ် ပြီးအောင် စောင့်ပါ</string>
|
||||||
|
<string name="removable_drive_receive_intro">သင့်ထံ ဆက်သွယ်ပေးပို့သော ဖိုင်ကို ရွေးချယ်ရန် အောက်ဖော်ပြပါ ခလုတ်ကို တို့ထိပါ။ \n\nဖိုင်သည် ဖယ်ရှားနိုင်သော ဒရိုက်ဗ်ပေါ်တွင် ရှိနေပါက၊ ဒရိုက်ကို ယခု ထည့်သွင်းပါ။</string>
|
||||||
|
<string name="removable_drive_receive_button">တင်သွင်းရန်အတွက် ဖိုင်ကို ရွေးပါ</string>
|
||||||
|
<string name="removable_drive_success_send_title">တင်ပို့မှု အောင်မြင်သည်</string>
|
||||||
|
<string name="removable_drive_success_send_text">ဒေတာကို အောင်မြင်စွာ ထုတ်ယူပြီးပါပြီ။ ဖိုင်ကို သင့်အဆက်အသွယ်ထံ ပို့ဆောင်ရန် ယခု ၂၈ ရက်အချိန်ရှိသည်။\n\n ဖိုင်သည် ဖြုတ်တပ်နိုင်သော drive တွင်ရှိနေပါက၊ ပလပ်မဖြုတ်မီ drive ကို ထုတ်ပစ်ရန် status bar ရှိ သတိပေးချက်ကို အသုံးပြုပါ။</string>
|
||||||
|
<string name="removable_drive_success_receive_title">တင်သွင်းမှု အောင်မြင်သည်</string>
|
||||||
|
<string name="removable_drive_success_receive_text">ဤဖိုင်တွင်ပါဝင်သည့် လျှို့ဝှက်ကုဒ်ပြောင်း မက်ဆေ့ချ်အားလုံးကို လက်ခံရရှိပါပြီ။</string>
|
||||||
|
<string name="removable_drive_error_send_title">ဒေတာကို ထုတ်ယူရာတွင် အမှားအယွင်းရှိသည်</string>
|
||||||
|
<string name="removable_drive_error_send_text">ဖိုင်သို့ ဒေတာရေးရာတွင် အမှားအယွင်း တစ်ခုရှိခဲ့သည်။ \n\n ဖယ်ရှားနိုင်သော drive ကိုအသုံးပြုနေပါက ၎င်းကို မှန်ကန်စွာ ထည့်သွင်းထားကြောင်း သေချာစေရန်နှင့် ထပ်စမ်းကြည့်ပါ။ \n\n အမှား ဆက်လက်ရှိနေပါက Briar အဖွဲ့အား အသိပေးရန်အတွက် အကြံပြုချက်ပေးပို့ပါ။ </string>
|
||||||
|
<string name="removable_drive_error_receive_title">ဒေတာတင်သွင်းရာတွင် အမှားအယွင်း ရှိသည်</string>
|
||||||
|
<string name="removable_drive_error_receive_text">ရွေးချယ်ထားသောဖိုင်တွင် Briar မှတ်မိနိုင်သည့် မည်သည့်အရာမှ မပါဝင်ပါ။ \n\nမှန်ကန်သောဖိုင်ကို သင်ရွေးချယ်ထားကြောင်း စစ်ဆေးပါ။ \n\n သင်၏အဆက်အသွယ်သည် လွန်ခဲ့သည့် ၂၈ ရက်ကျော်က အဆိုပါဖိုင်ကို ဖန်တီးခဲ့ပါက၊ Briar သည် ၎င်းကို မှတ်မိနိုင်မည်မဟုတ်ပေ။</string>
|
||||||
<!--Screenshots-->
|
<!--Screenshots-->
|
||||||
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
|
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
|
||||||
<string name="screenshot_alice">Alice</string>
|
<string name="screenshot_alice">Alice</string>
|
||||||
|
|||||||
@@ -247,7 +247,7 @@
|
|||||||
<string name="face_to_face">Musisz spotkać się z osobą którą chcesz dodać jako kontakt.\n\nTo uniemożliwi komukolwiek udawanie Ciebie lub czytanie Twoich wiadomości w przyszłości.</string>
|
<string name="face_to_face">Musisz spotkać się z osobą którą chcesz dodać jako kontakt.\n\nTo uniemożliwi komukolwiek udawanie Ciebie lub czytanie Twoich wiadomości w przyszłości.</string>
|
||||||
<string name="continue_button">Kontynuuj</string>
|
<string name="continue_button">Kontynuuj</string>
|
||||||
<string name="try_again_button">Spróbuj ponownie</string>
|
<string name="try_again_button">Spróbuj ponownie</string>
|
||||||
<string name="waiting_for_contact_to_scan">Czekanie aż kontakt zeskanuje kod i połączy się\u2026</string>
|
<string name="waiting_for_contact_to_scan">Oczekiwanie aż kontakt zeskanuje kod i połączy się\u2026</string>
|
||||||
<string name="exchanging_contact_details">Wymienianie szczegółów dotyczących kontatku\u2026</string>
|
<string name="exchanging_contact_details">Wymienianie szczegółów dotyczących kontatku\u2026</string>
|
||||||
<string name="contact_added_toast">Kontakt dodany: %s</string>
|
<string name="contact_added_toast">Kontakt dodany: %s</string>
|
||||||
<string name="contact_already_exists">Kontakt %s już istnieje</string>
|
<string name="contact_already_exists">Kontakt %s już istnieje</string>
|
||||||
@@ -603,6 +603,22 @@
|
|||||||
<string name="notify_sound_setting_disabled">Brak</string>
|
<string name="notify_sound_setting_disabled">Brak</string>
|
||||||
<string name="choose_ringtone_title">Wybierz dzwonek</string>
|
<string name="choose_ringtone_title">Wybierz dzwonek</string>
|
||||||
<string name="cannot_load_ringtone">Nie mogę załadować dzwonka</string>
|
<string name="cannot_load_ringtone">Nie mogę załadować dzwonka</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_settings_title">Skrzynka pocztowa</string>
|
||||||
|
<string name="mailbox_setup_title">Konfiguracja skrzynki pocztowej</string>
|
||||||
|
<string name="mailbox_setup_intro">Skrzynka pocztowa umożliwia Twoim kontaktom wysyłanie Ci wiadomości, gdy jesteś offline. Skrzynka pocztowa odbierze Twoje wiadomości i przechowa je, dopóki nie będziesz online.\n
|
||||||
|
\nAplikację Briar Mailbox można zainstalować na zapasowym urządzeniu. Podłącz je do zasilania i Wi-Fi, aby zawsze było online.</string>
|
||||||
|
<string name="mailbox_setup_download">Najpierw zainstaluj aplikację Mailbox na innym urządzeniu, wyszukując „Briar Mailbox” w Google Play lub gdziekolwiek pobrałeś Briar.\n
|
||||||
|
\nNastępnie połącz swoją skrzynkę pocztową z Briar, skanując kod QR wyświetlony w aplikacji Mailbox.</string>
|
||||||
|
<string name="mailbox_setup_download_link">Udostępnij łącze pobierania</string>
|
||||||
|
<string name="mailbox_setup_button_scan">Zeskanuj kod QR aplikacji Mailbox</string>
|
||||||
|
<string name="permission_camera_qr_denied_body">Odmówiłeś dostępu do aparatu, ale zeskanowanie kodu QR wymaga użycia aparatu.\n\nRozważ przyznanie dostępu.</string>
|
||||||
|
<string name="mailbox_setup_connecting">Trwa łączenie...</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_title">Nieprawidłowy kod QR</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_description">Zeskanowany kod jest nieprawidłowy. Otwórz aplikację Briar Mailbox na urządzeniu ze skrzynką pocztową i zeskanuj wyświetlany kod QR. </string>
|
||||||
|
<string name="tor_offline_title">Offline</string>
|
||||||
|
<string name="tor_offline_description">Upewnij się, że to urządzenie jest w trybie online, a połączenia z internetem są dozwolone.\n\nNastępnie poczekaj, aż ikona kuli ziemskiej w ustawieniach połączenia zmieni kolor na zielony.</string>
|
||||||
|
<string name="tor_offline_button_check">Sprawdź ustawienia połączenia </string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Znikające wiadomości</string>
|
<string name="disappearing_messages_title">Znikające wiadomości</string>
|
||||||
<string name="disappearing_messages_explanation_long">Włączenie tego ustawienia spowoduje, że
|
<string name="disappearing_messages_explanation_long">Włączenie tego ustawienia spowoduje, że
|
||||||
|
|||||||
@@ -582,6 +582,9 @@
|
|||||||
<string name="notify_sound_setting_disabled">Nici unul</string>
|
<string name="notify_sound_setting_disabled">Nici unul</string>
|
||||||
<string name="choose_ringtone_title">Alegeți sunetul</string>
|
<string name="choose_ringtone_title">Alegeți sunetul</string>
|
||||||
<string name="cannot_load_ringtone">Nu se poate încărca sunetul</string>
|
<string name="cannot_load_ringtone">Nu se poate încărca sunetul</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_setup_connecting">Se conectează...</string>
|
||||||
|
<string name="tor_offline_title">Deconectat</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Mesaje ce dispar</string>
|
<string name="disappearing_messages_title">Mesaje ce dispar</string>
|
||||||
<string name="disappearing_messages_explanation_long">Activarea acestei setări va face ca noile
|
<string name="disappearing_messages_explanation_long">Activarea acestei setări va face ca noile
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<string name="setup_doze_title">Фоновые подключения</string>
|
<string name="setup_doze_title">Фоновые подключения</string>
|
||||||
<string name="setup_doze_intro">Для получения сообщений Briar должен работать в фоновом режиме.</string>
|
<string name="setup_doze_intro">Для получения сообщений Briar должен работать в фоновом режиме.</string>
|
||||||
<string name="setup_doze_explanation">Для получения сообщений Briar должен работать в фоновом режиме. Отключите оптимизацию электропитания для Briar.</string>
|
<string name="setup_doze_explanation">Для получения сообщений Briar должен работать в фоновом режиме. Отключите оптимизацию электропитания для Briar.</string>
|
||||||
<string name="setup_doze_button">Разрешить соединения</string>
|
<string name="setup_doze_button">Разрешить подключения</string>
|
||||||
<string name="choose_nickname">Придумайте псевдоним</string>
|
<string name="choose_nickname">Придумайте псевдоним</string>
|
||||||
<string name="choose_password">Придумайте пароль</string>
|
<string name="choose_password">Придумайте пароль</string>
|
||||||
<string name="confirm_password">Подтвердите пароль</string>
|
<string name="confirm_password">Подтвердите пароль</string>
|
||||||
@@ -267,7 +267,7 @@
|
|||||||
<string name="contact_link_hint">Ссылка контакта</string>
|
<string name="contact_link_hint">Ссылка контакта</string>
|
||||||
<string name="paste_button">Вставить</string>
|
<string name="paste_button">Вставить</string>
|
||||||
<string name="add_contact_button">Добавить контакт</string>
|
<string name="add_contact_button">Добавить контакт</string>
|
||||||
<string name="copy_button">Копировать</string>
|
<string name="copy_button">Скопировать</string>
|
||||||
<string name="share_button">Поделиться</string>
|
<string name="share_button">Поделиться</string>
|
||||||
<string name="send_link_title">Обмен ссылками</string>
|
<string name="send_link_title">Обмен ссылками</string>
|
||||||
<string name="add_contact_choose_nickname">Выберите псевдоним</string>
|
<string name="add_contact_choose_nickname">Выберите псевдоним</string>
|
||||||
@@ -520,7 +520,7 @@
|
|||||||
<string name="pref_language_title">Язык и регион</string>
|
<string name="pref_language_title">Язык и регион</string>
|
||||||
<string name="pref_language_changed">Этот параметр вступит в силу после перезапуска Briar. Пожалуйста, выйдите и перезапустите Briar.</string>
|
<string name="pref_language_changed">Этот параметр вступит в силу после перезапуска Briar. Пожалуйста, выйдите и перезапустите Briar.</string>
|
||||||
<string name="pref_language_default">По умолчанию</string>
|
<string name="pref_language_default">По умолчанию</string>
|
||||||
<string name="display_settings_title">Отображение</string>
|
<string name="display_settings_title">Вид</string>
|
||||||
<string name="pref_theme_title">Тема</string>
|
<string name="pref_theme_title">Тема</string>
|
||||||
<string name="pref_theme_light">Светлая</string>
|
<string name="pref_theme_light">Светлая</string>
|
||||||
<string name="pref_theme_dark">Темная</string>
|
<string name="pref_theme_dark">Темная</string>
|
||||||
@@ -603,6 +603,22 @@
|
|||||||
<string name="notify_sound_setting_disabled">Нет</string>
|
<string name="notify_sound_setting_disabled">Нет</string>
|
||||||
<string name="choose_ringtone_title">Выберите мелодию звонка</string>
|
<string name="choose_ringtone_title">Выберите мелодию звонка</string>
|
||||||
<string name="cannot_load_ringtone">Не удается загрузить мелодию звонка</string>
|
<string name="cannot_load_ringtone">Не удается загрузить мелодию звонка</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_settings_title">Mailbox</string>
|
||||||
|
<string name="mailbox_setup_title">Настройка Mailbox</string>
|
||||||
|
<string name="mailbox_setup_intro">Mailbox позволяет вашим контактам отправлять вам сообщения, пока вы находитесь в автономном режиме. Mailbox будет получать ваши сообщения и хранить их до тех пор, пока вы не подключитесь к сети.\n
|
||||||
|
\nВы можете установить приложение Briar Mailbox на запасное устройство. Чтобы устройство всегда находилось в сети, подключите его к питанию и Wi-Fi.</string>
|
||||||
|
<string name="mailbox_setup_download">Во-первых, установите приложение Mailbox на другое устройство, выполнив поиск \"Briar Mailbox\" в Google Play или там, откуда вы загрузили Briar.\n
|
||||||
|
\nЗатем свяжите ваш Mailbox с Briar, просканировав QR-код, показанный приложением Mailbox.</string>
|
||||||
|
<string name="mailbox_setup_download_link">Поделиться ссылкой на загрузку</string>
|
||||||
|
<string name="mailbox_setup_button_scan">Сканирование QR-кода Mailbox</string>
|
||||||
|
<string name="permission_camera_qr_denied_body">Вы запретили доступ к камере, однако сканирование QR-кода требует использования камеры.\n\nПожалуйста, рассмотрите возможность предоставления доступа.</string>
|
||||||
|
<string name="mailbox_setup_connecting">Соединение...</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_title">Неправильный QR-код</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_description">Отсканированный код недействителен. Пожалуйста, откройте приложение Briar Mailbox на вашем устройстве и просканируйте представленный QR-код.</string>
|
||||||
|
<string name="tor_offline_title">Отключен</string>
|
||||||
|
<string name="tor_offline_description">Убедитесь, что устройство находится в сети и подключение к интернету разрешено.\n\nПосле этого дождитесь, пока значок глобуса в настройках подключения станет зеленым.</string>
|
||||||
|
<string name="tor_offline_button_check">Проверьте настройки подключения</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Исчезающие сообщения</string>
|
<string name="disappearing_messages_title">Исчезающие сообщения</string>
|
||||||
<string name="disappearing_messages_explanation_long">Включение этого параметра приведет к созданию нового
|
<string name="disappearing_messages_explanation_long">Включение этого параметра приведет к созданию нового
|
||||||
|
|||||||
@@ -577,6 +577,22 @@ dhe s’mund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versi
|
|||||||
<string name="notify_sound_setting_disabled">Asnjë</string>
|
<string name="notify_sound_setting_disabled">Asnjë</string>
|
||||||
<string name="choose_ringtone_title">Zgjidhni zile</string>
|
<string name="choose_ringtone_title">Zgjidhni zile</string>
|
||||||
<string name="cannot_load_ringtone">S\’ngarkohet dot zile</string>
|
<string name="cannot_load_ringtone">S\’ngarkohet dot zile</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_settings_title">Kuti postare</string>
|
||||||
|
<string name="mailbox_setup_title">Ujdisje kutie postare</string>
|
||||||
|
<string name="mailbox_setup_intro">Një Kuti postare u lejon kontakteve tuaj t’ju dërgojnë mesazhe , kur s’jeni në linjë. Kutia postare do të marrë mesazhet tuaj dhe depozitojë deri sa të jeni në linjë.\n
|
||||||
|
\nAplikacionin Briar për Kuti postare mund ta instaloni në një pajisje tjetër. Mbajeni në prizë dhe nën Wi-Fi, që të jetë përherë në linjë.</string>
|
||||||
|
<string name="mailbox_setup_download">Së pari, instaloni aplikacionin Kuti postare te një pajisje tjetër, duke kërkuar për “Briar Mailbox” në Google Play, ose kudo ku shkarkuat Briar-in.\n
|
||||||
|
\nMandej lidheni Kutinë tuaj postare me Briar-in duke skanuar kodin QR të shfaqur te aplikacioni Kuti postare.</string>
|
||||||
|
<string name="mailbox_setup_download_link">Ndani Lidhje Shkarkimi</string>
|
||||||
|
<string name="mailbox_setup_button_scan">Skanoni kod QR Kutie postare</string>
|
||||||
|
<string name="permission_camera_qr_denied_body">Keni mohuar hyrjen te kamera, por skanimi i një kodi QR lyp përdorimin e kamerës.\n\nJu lutemi, shihni mundësinë e dhënies së hyrjes.</string>
|
||||||
|
<string name="mailbox_setup_connecting">Po lidhjet…</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_title">Kod QR i gabuar</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_description">Kodi i skanuar është i pavlefshëm. Ju lutemi, hapeni aplikacionin Kuti postare Briar te pajisja juaj për kuti postare dhe skanoni kodin QR që shfaq.</string>
|
||||||
|
<string name="tor_offline_title">Jo në linjë</string>
|
||||||
|
<string name="tor_offline_description">Garantoni që kjo pajisje të jetë në lidhje dhe me lidhje në internet të lejuara.\n\nMë pas, prisni që ikona glob, te rregullimet e lidhjes, të bëhet e gjelbër.</string>
|
||||||
|
<string name="tor_offline_button_check">Kontrolloni rregullime lidhjeje</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Mesazhe që treten</string>
|
<string name="disappearing_messages_title">Mesazhe që treten</string>
|
||||||
<string name="disappearing_messages_explanation_long">Aktivizimi i këtij rregullimi do të bëjë që
|
<string name="disappearing_messages_explanation_long">Aktivizimi i këtij rregullimi do të bëjë që
|
||||||
|
|||||||
@@ -50,10 +50,17 @@
|
|||||||
<item quantity="one">Det här är en test-version av Briar. Ditt konto kommer att upphöra om %d dagar och kan ej förnyas.</item>
|
<item quantity="one">Det här är en test-version av Briar. Ditt konto kommer att upphöra om %d dagar och kan ej förnyas.</item>
|
||||||
<item quantity="other">Det här är en test-version av Briar. Ditt konto kommer att upphöra om %d dag och kan ej förnyas.</item>
|
<item quantity="other">Det här är en test-version av Briar. Ditt konto kommer att upphöra om %d dag och kan ej förnyas.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
<plurals name="old_android_expiry_warning">
|
||||||
|
<item quantity="one">Android 4 stöds ej längre. Briar kommer att sluta fungera den %s (om %d dag). Vänligen installera Briar på en ny enhet och skapa ett nytt konto.</item>
|
||||||
|
<item quantity="other">Android 4 stöds ej längre. Briar kommer att sluta fungera den %s (om %d dagar). Vänligen installera Briar på en nyare enhet och skapa ett nytt konto.</item>
|
||||||
|
</plurals>
|
||||||
<string name="expiry_date_reached">Mjukvaran har gått ut.\nTack för att du bidragit till att testa!</string>
|
<string name="expiry_date_reached">Mjukvaran har gått ut.\nTack för att du bidragit till att testa!</string>
|
||||||
<string name="download_briar">För att fortsätta använda Briar, hämta den senaste utgåvan.</string>
|
<string name="download_briar">För att fortsätta använda Briar, hämta den senaste utgåvan.</string>
|
||||||
<string name="create_new_account">Du måste skapa ett nytt konto, men du kan använda samma smeknamn.</string>
|
<string name="create_new_account">Du måste skapa ett nytt konto, men du kan använda samma smeknamn.</string>
|
||||||
<string name="download_briar_button">Hämta senaste utgåvan</string>
|
<string name="download_briar_button">Hämta senaste utgåvan</string>
|
||||||
|
<string name="old_android_expiry_date_reached">Briar kan inte längre användas på Android 4.
|
||||||
|
Vänlige installera Briar på en nyare enhet.</string>
|
||||||
|
<string name="old_android_delete_account">Du kan trycka på knappen nedan för att ta bort ditt konto från denna enhet.</string>
|
||||||
<string name="delete_account_button">Radera kontot</string>
|
<string name="delete_account_button">Radera kontot</string>
|
||||||
<string name="startup_open_database">Dekrypterar databasen...</string>
|
<string name="startup_open_database">Dekrypterar databasen...</string>
|
||||||
<string name="startup_migrate_database">Uppgraderar databasen...</string>
|
<string name="startup_migrate_database">Uppgraderar databasen...</string>
|
||||||
@@ -569,6 +576,9 @@
|
|||||||
<string name="notify_sound_setting_disabled">Ingen</string>
|
<string name="notify_sound_setting_disabled">Ingen</string>
|
||||||
<string name="choose_ringtone_title">Välj ringsignal</string>
|
<string name="choose_ringtone_title">Välj ringsignal</string>
|
||||||
<string name="cannot_load_ringtone">Kan ej ladda ringsignal</string>
|
<string name="cannot_load_ringtone">Kan ej ladda ringsignal</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_setup_connecting">Ansluter...</string>
|
||||||
|
<string name="tor_offline_title">Nedkopplad</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Försvinnande meddelanden</string>
|
<string name="disappearing_messages_title">Försvinnande meddelanden</string>
|
||||||
<string name="disappearing_messages_explanation_long">Att slå på denna inställning kommer att få nya
|
<string name="disappearing_messages_explanation_long">Att slå på denna inställning kommer att få nya
|
||||||
|
|||||||
@@ -569,6 +569,9 @@
|
|||||||
<string name="notify_sound_setting_disabled">Yok</string>
|
<string name="notify_sound_setting_disabled">Yok</string>
|
||||||
<string name="choose_ringtone_title">Zil sesi seçin</string>
|
<string name="choose_ringtone_title">Zil sesi seçin</string>
|
||||||
<string name="cannot_load_ringtone">Zil sesi yüklenemiyor</string>
|
<string name="cannot_load_ringtone">Zil sesi yüklenemiyor</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_setup_connecting">Bağlantı kuruluyor…</string>
|
||||||
|
<string name="tor_offline_title">Çevrimdışı</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">Kaybolan iletiler</string>
|
<string name="disappearing_messages_title">Kaybolan iletiler</string>
|
||||||
<string name="disappearing_messages_explanation_long">Bu ayarı etkinleştirmeniz durumunda
|
<string name="disappearing_messages_explanation_long">Bu ayarı etkinleştirmeniz durumunda
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<resources>
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
<!--Setup-->
|
<!--Setup-->
|
||||||
<string name="setup_title">Вітаємо у Briar</string>
|
<string name="setup_title">Вітаємо у Briar</string>
|
||||||
<string name="setup_name_explanation">Ваше ім\'я користувача буде відображено біля будь-якого матеріалу, який ви опублікуєте. Ви не зможете змінити його після створення облікового запису.</string>
|
<string name="setup_name_explanation">Ваше ім\'я користувача буде відображено біля будь-якого матеріалу, який ви опублікуєте. Ви не зможете змінити його після створення облікового запису.</string>
|
||||||
@@ -22,29 +22,49 @@
|
|||||||
<string name="setup_huawei_text">Будь ласка, натисніть кнопку, що знаходиться нижче і впевніться у тому, що Briar захищено на екрані \"Захищені додатки\".</string>
|
<string name="setup_huawei_text">Будь ласка, натисніть кнопку, що знаходиться нижче і впевніться у тому, що Briar захищено на екрані \"Захищені додатки\".</string>
|
||||||
<string name="setup_huawei_button">Захистити Briar</string>
|
<string name="setup_huawei_button">Захистити Briar</string>
|
||||||
<string name="setup_huawei_help">Якщо Briar немає у списку захищених додатків, він не зможе працювати у фоновому режимі.</string>
|
<string name="setup_huawei_help">Якщо Briar немає у списку захищених додатків, він не зможе працювати у фоновому режимі.</string>
|
||||||
|
<string name="setup_huawei_app_launch_text">Будь ласка, торкніть кнопку внизу, відкрийте екран «Запуск програми» й переконайтесь, що Briar має налаштування «Керувати вручну».</string>
|
||||||
|
<string name="setup_huawei_app_launch_button">Відкрити налаштування батареї</string>
|
||||||
|
<string name="setup_huawei_app_launch_help">Якщо не вказати «Керувати вручну» для Briar на екрані «Запуск програми», він не зможе працювати в фоновому режимі.</string>
|
||||||
|
<string name="setup_xiaomi_text">Щоб Briar працював у фоновому режимі, закріпіть його в переліку недавніх застосунків.</string>
|
||||||
|
<string name="setup_xiaomi_button">Захистити Briar</string>
|
||||||
|
<string name="setup_xiaomi_help">Якщо не закріпити Briar у переліку недавніх застосунків, він не зможе працювати в фоновому режимі.</string>
|
||||||
|
<string name="setup_xiaomi_dialog_body_old">1. Відкрийте перелік недавніх застосунків (також називається перемикачем додатків)\n\n2. Проведіть униз по зображенню Briar, щоб з\'явився значок замка\n\n3. Якщо замок не замкнений, замкніть його дотиком</string>
|
||||||
|
<string name="setup_xiaomi_dialog_body_new">1. Відкрийте перелік недавніх застосунків (також називається перемикачем додатків)\n\n2. Затисніть зображення Briar до появи значка замка.\n\n3. Якщо замок не замкнений, замкніть його дотиком</string>
|
||||||
<string name="warning_dozed">%s не вдалося запустити у фоновому режимі</string>
|
<string name="warning_dozed">%s не вдалося запустити у фоновому режимі</string>
|
||||||
<!--Login-->
|
<!--Login-->
|
||||||
<string name="enter_password">Пароль</string>
|
<string name="enter_password">Пароль</string>
|
||||||
<string name="try_again">Неправильний пароль, спробуйте ще раз</string>
|
<string name="try_again">Неправильний пароль, спробуйте ще раз</string>
|
||||||
|
<string name="dialog_title_cannot_check_password">Не вдалося перевірити пароль</string>
|
||||||
|
<string name="dialog_message_cannot_check_password">Briar не зміг перевірити ваш пароль. Будь ласка, спробуйте перезавантажити пристрій, щоб розв\'язати цю проблему.</string>
|
||||||
<string name="sign_in_button">Увійти</string>
|
<string name="sign_in_button">Увійти</string>
|
||||||
<string name="forgotten_password">Я забув(-ла) свій пароль</string>
|
<string name="forgotten_password">Я забув(-ла) свій пароль</string>
|
||||||
<string name="dialog_title_lost_password">Пароль втрачено</string>
|
<string name="dialog_title_lost_password">Пароль втрачено</string>
|
||||||
<string name="dialog_message_lost_password">Ваш обліковий запис Briar знаходиться в зашифрованому вигляді на вашому пристрої, а не зберігається на хмарі, тому ми не можемо відновити ваш пароль. Бажаєте вилучити свій обліковий запис та створити новий?\n\nЗастереження: ваші особисті дані, контакти та повідомлення будуть втрачені назавжди.</string>
|
<string name="dialog_message_lost_password">Ваш обліковий запис Briar знаходиться в зашифрованому вигляді на вашому пристрої, а не зберігається на хмарі, тому ми не можемо відновити ваш пароль. Бажаєте вилучити свій обліковий запис та створити новий?\n\nЗастереження: ваші особисті дані, контакти та повідомлення будуть втрачені назавжди.</string>
|
||||||
<string name="startup_failed_notification_title">Briar не може запуститися</string>
|
|
||||||
<string name="startup_failed_notification_text">Натисніть для детальнішої інформації.</string>
|
|
||||||
<string name="startup_failed_activity_title">Помилка при запуску Briar</string>
|
<string name="startup_failed_activity_title">Помилка при запуску Briar</string>
|
||||||
<string name="startup_failed_db_error">З якоїсь причини база даних вашого Briar пошкоджена і не підлягає відновленню. Ваш обліковий запис, дані та усі контакти втрачені. На жаль, вам потрібно перевстановити Briar або створити новий обліковий запис, натиснувши \"Я забув(-ла) свій пароль\".</string>
|
<string name="startup_failed_clock_error">Briar не зміг запуститись, бо годинник вашого пристрою збився.\n\nБудь ласка, встановіть на своєму пристрої дійсний час і повторіть спробу.</string>
|
||||||
<string name="startup_failed_data_too_old_error">Ваш обліковий запис було створено за допомогою старішої версії цього застосунку і його неможливо відкрити за допомогою поточної версії. Вам необхідно знову встановити старішу версію або створити новий обліковий запис, обравши рядок \"Я забув(-ла) свій пароль\" у спливному вікні паролів.</string>
|
<string name="startup_failed_db_error">Briar не зміг відкрити базу даних, що містить ваш обліковий запис, контакти й повідомлення.\n\nБудь ласка, оновіть застосунок до останньої версії й повторіть спробу — або створіть новий обліковий запис, обравши «Не пам\'ятаю пароль» у запиті пароля.</string>
|
||||||
<string name="startup_failed_data_too_new_error">Ця версія програми застаріла. Будь ласка, оновіться до останньої версії та спробуйте знову.</string>
|
<string name="startup_failed_data_too_old_error">Ваш обліковий запис створено старою версією застосунка, й нова версія не може його відкрити.\n\nПеревстановіть стару версію або створіть новий обліковий запис, обравши «Не пам\'ятаю пароль» у запиті пароля.</string>
|
||||||
<string name="startup_failed_service_error">Briar не зміг запустити потрібну втулку. Перевстановлення Briar зазвичай вирішує цю проблему. Однак, будь ласка, зазначте, що у цьому випадку ви втратите свій обліковий запис та усю пов\'язану з ним інформацію, оскільки Briar не використовує центральні сервери для зберігання інформації.</string>
|
<string name="startup_failed_data_too_new_error">Ваш обліковий запис створено новішою версією застосунка, й поточна версія не може його відкрити.\n\nБудь ласка, оновіться до найновішої версії й повторіть спробу.</string>
|
||||||
|
<string name="startup_failed_service_error">Briar не зміг запустити необхідний компонент.\n\nБудь ласка, оновіть застосунок до найновішої версії й повторіть спробу.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Це тестова версія Briar. Термін дії вашого профілю спливає через %d день. Його не можна продовжити.</item>
|
<item quantity="one">Це тестова версія Briar. Термін дії вашого профілю спливає через %d день. Його не можна продовжити.</item>
|
||||||
<item quantity="few">Це тестова версія Briar. Термін дії вашого профілю спливає через %d дні. Його не можна продовжити.</item>
|
<item quantity="few">Це тестова версія Briar. Термін дії вашого профілю спливає через %d дні. Його не можна продовжити.</item>
|
||||||
<item quantity="many">Це тестова версія Briar. Термін дії вашого профілю спливає через %d днів. Його не можна продовжити.</item>
|
<item quantity="many">Це тестова версія Briar. Термін дії вашого профілю спливає через %d днів. Його не можна продовжити.</item>
|
||||||
<item quantity="other">Це тестова версія Briar. Термін дії вашого профілю спливає через %d дня. Його не можна продовжити.</item>
|
<item quantity="other">Це тестова версія Briar. Термін дії вашого профілю спливає через %d дня. Його не можна продовжити.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
<plurals name="old_android_expiry_warning">
|
||||||
|
<item quantity="one">Android 4 більше не підтримується. Briar припинить роботу %s (за %d день). Будь ласка, встановіть Briar на новіший пристрій і створіть новий обліковий запис.</item>
|
||||||
|
<item quantity="few">Android 4 більше не підтримується. Briar припинить роботу %s (за %d дні). Будь ласка, встановіть Briar на новіший пристрій і створіть новий обліковий запис.</item>
|
||||||
|
<item quantity="many">Android 4 більше не підтримується. Briar припинить роботу %s (за %d днів). Будь ласка, встановіть Briar на новіший пристрій і створіть новий обліковий запис.</item>
|
||||||
|
<item quantity="other">Android 4 більше не підтримується. Briar припинить роботу %s (за %d днів). Будь ласка, встановіть Briar на новіший пристрій і створіть новий обліковий запис.</item>
|
||||||
|
</plurals>
|
||||||
<string name="expiry_date_reached">У цієї програми закінчився термін дії\nДякуємо, що тестували її!</string>
|
<string name="expiry_date_reached">У цієї програми закінчився термін дії\nДякуємо, що тестували її!</string>
|
||||||
|
<string name="download_briar">Щоб далі користуватися Briar, будь ласка, завантажте найновіший випуск.</string>
|
||||||
<string name="create_new_account">Вам знадобиться створити новий обліковий запис, але ви можете використовувати те саме ім\'я користувача.</string>
|
<string name="create_new_account">Вам знадобиться створити новий обліковий запис, але ви можете використовувати те саме ім\'я користувача.</string>
|
||||||
|
<string name="download_briar_button">Завантажити найновіший випуск</string>
|
||||||
|
<string name="old_android_expiry_date_reached">Briar більше не працює на Android 4.\nБудь ласка, встановіть Briar на новіший пристрій.</string>
|
||||||
|
<string name="old_android_delete_account">Можете видалити обліковий запис із цього пристрою кнопкою внизу.</string>
|
||||||
|
<string name="delete_account_button">Видалити обліковий запис</string>
|
||||||
<string name="startup_open_database">Розшифрування бази даних...</string>
|
<string name="startup_open_database">Розшифрування бази даних...</string>
|
||||||
<string name="startup_migrate_database">Оновлення бази даних...</string>
|
<string name="startup_migrate_database">Оновлення бази даних...</string>
|
||||||
<string name="startup_compact_database">Стиснення бази даних...</string>
|
<string name="startup_compact_database">Стиснення бази даних...</string>
|
||||||
@@ -59,12 +79,36 @@
|
|||||||
<string name="lock_button">Заблокувати програму</string>
|
<string name="lock_button">Заблокувати програму</string>
|
||||||
<string name="settings_button">Налаштування</string>
|
<string name="settings_button">Налаштування</string>
|
||||||
<string name="sign_out_button">Вийти</string>
|
<string name="sign_out_button">Вийти</string>
|
||||||
|
<string name="transports_onboarding_text">Торкніть це, щоб налаштувати з\'єднання Briar із вашими контактами.</string>
|
||||||
<!--Transports: Tor-->
|
<!--Transports: Tor-->
|
||||||
<string name="transport_tor">Інтернет</string>
|
<string name="transport_tor">Інтернет</string>
|
||||||
|
<string name="tor_device_status_online_wifi">Ваш телефон має доступ до інтернету через Wi-Fi</string>
|
||||||
|
<string name="tor_device_status_online_mobile">Ваш телефон має доступ до інтернету через мобільні дані</string>
|
||||||
|
<string name="tor_device_status_offline">Ваш телефон не має доступу до інтернету</string>
|
||||||
|
<string name="tor_plugin_status_enabling">Briar з\'єднується з інтернетом</string>
|
||||||
|
<string name="tor_plugin_status_active">Briar з\'єднано з інтернетом</string>
|
||||||
|
<string name="tor_plugin_status_inactive">Briar не може з\'єднатися з інтернетом</string>
|
||||||
|
<string name="tor_plugin_status_disabled">Briar налаштовано не використовувати інтернет</string>
|
||||||
|
<string name="tor_plugin_status_disabled_mobile_data">Briar налаштовано не використовувати мобільні дані</string>
|
||||||
|
<string name="tor_plugin_status_disabled_battery">Briar налаштовано не використовувати інтернет при роботі від батареї</string>
|
||||||
|
<string name="tor_plugin_status_disabled_country_blocked">Briar налаштовано не використовувати інтернет у цій країні</string>
|
||||||
<!--Transports: Wi-Fi-->
|
<!--Transports: Wi-Fi-->
|
||||||
<string name="transport_lan">Wi-Fi</string>
|
<string name="transport_lan">Wi-Fi</string>
|
||||||
|
<string name="transport_lan_long">Спільна мережа Wi-Fi</string>
|
||||||
|
<string name="lan_device_status_on">Ваш телефон з\'єднано з Wi-Fi</string>
|
||||||
|
<string name="lan_device_status_off">Ваш телефон не з\'єднано з Wi-Fi</string>
|
||||||
|
<string name="lan_plugin_status_enabling">Briar з\'єднується з мережею Wi-Fi</string>
|
||||||
|
<string name="lan_plugin_status_active">Briar з\'єднано з мережею Wi-Fi</string>
|
||||||
|
<string name="lan_plugin_status_inactive">Briar не може з\'єднатися з мережею Wi-Fi</string>
|
||||||
|
<string name="lan_plugin_status_disabled">Briar налаштовано не використовувати мережу Wi-Fi</string>
|
||||||
<!--Transports: Bluetooth-->
|
<!--Transports: Bluetooth-->
|
||||||
<string name="transport_bt">Bluetooth</string>
|
<string name="transport_bt">Bluetooth</string>
|
||||||
|
<string name="bt_device_status_on">Bluetooth вашого телефона ввімкнено</string>
|
||||||
|
<string name="bt_device_status_off">Bluetooth вашого телефона вимкнено</string>
|
||||||
|
<string name="bt_plugin_status_enabling">Briar з\'єднується з Bluetooth</string>
|
||||||
|
<string name="bt_plugin_status_active">Briar з\'єднано з Bluetooth</string>
|
||||||
|
<string name="bt_plugin_status_inactive">Briar не може з\'єднатися з Bluetooth</string>
|
||||||
|
<string name="bt_plugin_status_disabled">Briar налаштовано не використовувати Bluetooth</string>
|
||||||
<!--Notifications-->
|
<!--Notifications-->
|
||||||
<string name="reminder_notification_title">Ви вийшли з Briar</string>
|
<string name="reminder_notification_title">Ви вийшли з Briar</string>
|
||||||
<string name="reminder_notification_text">Натисніть, щоб знову увійти.</string>
|
<string name="reminder_notification_text">Натисніть, щоб знову увійти.</string>
|
||||||
@@ -113,6 +157,7 @@
|
|||||||
<string name="open">Відкрити</string>
|
<string name="open">Відкрити</string>
|
||||||
<string name="change">Змінити</string>
|
<string name="change">Змінити</string>
|
||||||
<string name="start">Почати</string>
|
<string name="start">Почати</string>
|
||||||
|
<string name="finish">Закінчити</string>
|
||||||
<string name="no_data">Немає даних</string>
|
<string name="no_data">Немає даних</string>
|
||||||
<string name="ellipsis">…</string>
|
<string name="ellipsis">…</string>
|
||||||
<string name="text_too_long">Цей текст занадто довгий</string>
|
<string name="text_too_long">Цей текст занадто довгий</string>
|
||||||
@@ -120,13 +165,17 @@
|
|||||||
<string name="fix">Виправити</string>
|
<string name="fix">Виправити</string>
|
||||||
<string name="help">Довідка</string>
|
<string name="help">Довідка</string>
|
||||||
<string name="sorry">Вибачте</string>
|
<string name="sorry">Вибачте</string>
|
||||||
|
<string name="error_start_activity">Недоступно у вашій системі</string>
|
||||||
<string name="status_heading">Статус</string>
|
<string name="status_heading">Статус</string>
|
||||||
|
<string name="error">Помилка</string>
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">Немає контактів для відображення</string>
|
<string name="no_contacts">Немає контактів для відображення</string>
|
||||||
<string name="no_contacts_action">Натисніть на символ \"+\" для того, щоб додати контакт</string>
|
<string name="no_contacts_action">Натисніть на символ \"+\" для того, щоб додати контакт</string>
|
||||||
<string name="date_no_private_messages">Немає повідомлень.</string>
|
<string name="date_no_private_messages">Немає повідомлень.</string>
|
||||||
<string name="no_private_messages">Немає повідомлень для відображення</string>
|
<string name="no_private_messages">Немає повідомлень для відображення</string>
|
||||||
<string name="message_hint">Нове Повідомлення</string>
|
<string name="message_hint">Нове Повідомлення</string>
|
||||||
|
<string name="message_hint_auto_delete">Нове самознищуване повідомлення</string>
|
||||||
|
<string name="message_error">Помилка надсилання повідомлення</string>
|
||||||
<string name="image_caption_hint">Додати заголовок (за бажанням)</string>
|
<string name="image_caption_hint">Додати заголовок (за бажанням)</string>
|
||||||
<string name="image_attach">Прикріпити зображення</string>
|
<string name="image_attach">Прикріпити зображення</string>
|
||||||
<string name="image_attach_error">Неможливо приєднати зображення</string>
|
<string name="image_attach_error">Неможливо приєднати зображення</string>
|
||||||
@@ -134,13 +183,48 @@
|
|||||||
<string name="image_attach_error_invalid_mime_type">Формат зображення непідтримуваний: %s</string>
|
<string name="image_attach_error_invalid_mime_type">Формат зображення непідтримуваний: %s</string>
|
||||||
<string name="set_contact_alias">Змінити ім\'я контакту</string>
|
<string name="set_contact_alias">Змінити ім\'я контакту</string>
|
||||||
<string name="set_contact_alias_hint">Назва контакту</string>
|
<string name="set_contact_alias_hint">Назва контакту</string>
|
||||||
<string name="menu_item_connect_via_bluetooth">З\'єднатися через Bluetooth</string>
|
<string name="menu_item_disappearing_messages">Самознищувані повідомлення</string>
|
||||||
<string name="connect_via_bluetooth_title">З\'єднатися через Bluetooth</string>
|
|
||||||
<!--The first placeholder will show a duration like "7 days". The second placeholder at the end will add "Tap to learn more."-->
|
<!--The first placeholder will show a duration like "7 days". The second placeholder at the end will add "Tap to learn more."-->
|
||||||
|
<string name="auto_delete_msg_you_enabled">Ваші повідомлення самознищаться за %1$s. %2$s</string>
|
||||||
<!--The placeholder at the end will add "Tap to learn more."-->
|
<!--The placeholder at the end will add "Tap to learn more."-->
|
||||||
|
<string name="auto_delete_msg_you_disabled">Ваші повідомлення не самознищуватимуться. %1$s</string>
|
||||||
<!--The first placeholder will show a contact's name. The second placeholder will show a duration like "7 days". The third placeholder at the end will add "Tap to learn more."-->
|
<!--The first placeholder will show a contact's name. The second placeholder will show a duration like "7 days". The third placeholder at the end will add "Tap to learn more."-->
|
||||||
|
<string name="auto_delete_msg_contact_enabled">Повідомлення %1$s самознищаться за %2$s. %3$s</string>
|
||||||
|
<plurals name="duration_minutes">
|
||||||
|
<item quantity="one">%d хвилину</item>
|
||||||
|
<item quantity="few">%d хвилини</item>
|
||||||
|
<item quantity="many">%d хвилин</item>
|
||||||
|
<item quantity="other">%d хвилин</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="duration_hours">
|
||||||
|
<item quantity="one">%d годину</item>
|
||||||
|
<item quantity="few">%d години</item>
|
||||||
|
<item quantity="many">%d годин</item>
|
||||||
|
<item quantity="other">%d годин</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="duration_days">
|
||||||
|
<item quantity="one">%d день</item>
|
||||||
|
<item quantity="few">%d дні</item>
|
||||||
|
<item quantity="many">%d днів</item>
|
||||||
|
<item quantity="other">%d днів</item>
|
||||||
|
</plurals>
|
||||||
<!--The first placeholder will show a contact's name. The second placeholder at the end will add "Tap to learn more."-->
|
<!--The first placeholder will show a contact's name. The second placeholder at the end will add "Tap to learn more."-->
|
||||||
|
<string name="auto_delete_msg_contact_disabled">Повідомлення %1$s не самознищуватимуться. %2$s</string>
|
||||||
|
<string name="tap_to_learn_more">Торкніть, щоб дізнатися більше.</string>
|
||||||
|
<string name="auto_delete_changed_warning_title">Самознищення повідомлень змінено</string>
|
||||||
|
<string name="auto_delete_changed_warning_message_enabled">Поки ви писали, було увімкнено самознищення повідомлень.</string>
|
||||||
|
<string name="auto_delete_changed_warning_message_disabled">Поки ви писали, було вимкнено самознищення повідомлень.</string>
|
||||||
|
<string name="auto_delete_changed_warning_send">Надіслати все одно</string>
|
||||||
|
<string name="delete_all_messages">Видалити всі повідомлення</string>
|
||||||
|
<string name="dialog_title_delete_all_messages">Підтвердьте видалення повідомлень</string>
|
||||||
|
<string name="dialog_message_delete_all_messages">Ви впевнені, що бажаєте видалити всі повідомлення?</string>
|
||||||
<string name="dialog_title_not_all_messages_deleted">Не вдалося видалити всі повідомлення</string>
|
<string name="dialog_title_not_all_messages_deleted">Не вдалося видалити всі повідомлення</string>
|
||||||
|
<string name="dialog_message_not_deleted_ongoing_both">Повідомлення щодо незавершених запрошень чи вітань неможливо видалити.</string>
|
||||||
|
<string name="dialog_message_not_deleted_ongoing_introductions">Повідомлення щодо незавершених вітань неможливо видалити.</string>
|
||||||
|
<string name="dialog_message_not_deleted_ongoing_invitations">Повідомлення щодо незавершених запрошень неможливо видалити.</string>
|
||||||
|
<string name="dialog_message_not_deleted_not_all_selected_both">Щоб видалити запрошення чи вітання, оберіть запит і відповідь.</string>
|
||||||
|
<string name="dialog_message_not_deleted_not_all_selected_introductions">Щоб видалити вітання, оберіть запит і відповідь.</string>
|
||||||
|
<string name="dialog_message_not_deleted_not_all_selected_invitations">Щоб видалити запрошення, оберіть запит і відповідь.</string>
|
||||||
<string name="delete_contact">Вилучити контакт</string>
|
<string name="delete_contact">Вилучити контакт</string>
|
||||||
<string name="dialog_title_delete_contact">Підтвердити вилучення контакту</string>
|
<string name="dialog_title_delete_contact">Підтвердити вилучення контакту</string>
|
||||||
<string name="dialog_message_delete_contact">Ви впевнені, що хочете видалити цей контакт і всю історію листування з ним?</string>
|
<string name="dialog_message_delete_contact">Ви впевнені, що хочете видалити цей контакт і всю історію листування з ним?</string>
|
||||||
@@ -156,6 +240,8 @@
|
|||||||
<string name="dialog_message_no_image_support">Briar вашого контакту ще не підтримує прикріплення зображень. Щойно користувач(-ка) оновиться, ви бачитиме іншу піктограму.</string>
|
<string name="dialog_message_no_image_support">Briar вашого контакту ще не підтримує прикріплення зображень. Щойно користувач(-ка) оновиться, ви бачитиме іншу піктограму.</string>
|
||||||
<string name="dialog_title_image_support">Тепер ви можете надсилати зображення цьому контакту</string>
|
<string name="dialog_title_image_support">Тепер ви можете надсилати зображення цьому контакту</string>
|
||||||
<string name="dialog_message_image_support">Натисніть на цю піктограму, щоб прикріпити зображення.</string>
|
<string name="dialog_message_image_support">Натисніть на цю піктограму, щоб прикріпити зображення.</string>
|
||||||
|
<string name="messaging_too_many_attachments_toast">Лише перші %d зображень буде надіслано</string>
|
||||||
|
<string name="menu_contact">Контакти</string>
|
||||||
<!--Adding Contacts-->
|
<!--Adding Contacts-->
|
||||||
<string name="add_contact_title">Додати контакт поблизу</string>
|
<string name="add_contact_title">Додати контакт поблизу</string>
|
||||||
<string name="face_to_face">Ви маєте зустрітися з особою, яку ви бажаєте додати до списку контактів.\n\nЦе виключить можливість у майбутньому будь-кому видавати себе за вас або читати ваші повідомлення.</string>
|
<string name="face_to_face">Ви маєте зустрітися з особою, яку ви бажаєте додати до списку контактів.\n\nЦе виключить можливість у майбутньому будь-кому видавати себе за вас або читати ваші повідомлення.</string>
|
||||||
@@ -219,8 +305,9 @@
|
|||||||
<string name="offline_state">Відсутнє з\'єднання з інтернетом</string>
|
<string name="offline_state">Відсутнє з\'єднання з інтернетом</string>
|
||||||
<string name="duplicate_link_dialog_title">Дублювати посилання</string>
|
<string name="duplicate_link_dialog_title">Дублювати посилання</string>
|
||||||
<string name="duplicate_link_dialog_text_1">У вас наявний нерозглянутий запит на контакт з цим посиланням: %s</string>
|
<string name="duplicate_link_dialog_text_1">У вас наявний нерозглянутий запит на контакт з цим посиланням: %s</string>
|
||||||
|
<string name="duplicate_link_dialog_text_1_contact">Ви вже маєте контакт за цим посиланням: %s</string>
|
||||||
<!--This is a question asking whether two nicknames refer to the same person-->
|
<!--This is a question asking whether two nicknames refer to the same person-->
|
||||||
<string name="duplicate_link_dialog_text_2">%s та %s одна й та ж особа?</string>
|
<string name="duplicate_link_dialog_text_2">%1$s та %2$s — одна людина?</string>
|
||||||
<!--This is a button for answering that two nicknames do indeed refer to the same person. This
|
<!--This is a button for answering that two nicknames do indeed refer to the same person. This
|
||||||
string will be used in a dialog button, so if the translation of this string is longer than 20
|
string will be used in a dialog button, so if the translation of this string is longer than 20
|
||||||
characters, please use "Yes" instead, and use "No" for the "Different Person" button-->
|
characters, please use "Yes" instead, and use "No" for the "Different Person" button-->
|
||||||
@@ -229,7 +316,7 @@
|
|||||||
will be used in a dialog button, so if the translation of this string longer than 20 characters,
|
will be used in a dialog button, so if the translation of this string longer than 20 characters,
|
||||||
please use "No" instead, and use "Yes" for the "Same Person" button-->
|
please use "No" instead, and use "Yes" for the "Same Person" button-->
|
||||||
<string name="different_person_button">Різні особи</string>
|
<string name="different_person_button">Різні особи</string>
|
||||||
<string name="duplicate_link_dialog_text_3">%s та %s надіслали вам однакове посилання.\n\nОдин з них може намагатися виявити, які у вас є контакти.\n\nНе розповідайте їм, що ви отримали те саме посилання від ще когось.</string>
|
<string name="duplicate_link_dialog_text_3">%1$s та %2$s надіслали вам однакові посилання.\n\nХтось із них, можливо, намагається виявити ваші контакти.\n\nНе кажіть їм, що вже отримували це посилання від когось іще.</string>
|
||||||
<string name="pending_contact_updated_toast">Оновлено нерозглянутий контакт</string>
|
<string name="pending_contact_updated_toast">Оновлено нерозглянутий контакт</string>
|
||||||
<!--Introductions-->
|
<!--Introductions-->
|
||||||
<string name="introduction_onboarding_title">Поділитися своїми контактами</string>
|
<string name="introduction_onboarding_title">Поділитися своїми контактами</string>
|
||||||
@@ -242,16 +329,27 @@
|
|||||||
<string name="introduction_button">Познайомити з контактом</string>
|
<string name="introduction_button">Познайомити з контактом</string>
|
||||||
<string name="introduction_sent">Ваше представлення було надіслано.</string>
|
<string name="introduction_sent">Ваше представлення було надіслано.</string>
|
||||||
<string name="introduction_error">Виникла помилка під час представлення.</string>
|
<string name="introduction_error">Виникла помилка під час представлення.</string>
|
||||||
<string name="introduction_request_sent">Ви попросили представити %1$s%2$s.</string>
|
<string name="introduction_request_sent">Ви попросили представити %1$s %2$s.</string>
|
||||||
<string name="introduction_request_received">%1$sпопросили представити вас %2$s. Чи бажаєте ви додати %2$s до свого списку контактів?</string>
|
<string name="introduction_request_received">%1$s попросили представити вас %2$s. Чи бажаєте ви додати %2$s до свого списку контактів?</string>
|
||||||
<string name="introduction_request_exists_received">%1$sпопросив вас представити %2$s, однак %2$sвже є у вашому списку контактів. Оскільки %1$sпро це може бути невідомо, ви все ще можете відповісти:</string>
|
<string name="introduction_request_exists_received">%1$s попросив вас представити %2$s, однак %2$s вже є у вашому списку контактів. Оскільки %1$s про це може бути невідомо, ви все ще можете відповісти:</string>
|
||||||
<string name="introduction_request_answered_received">%1$sпопросив представити вас %2$s.</string>
|
<string name="introduction_request_answered_received">%1$s попросив представити вас %2$s.</string>
|
||||||
<string name="introduction_response_accepted_sent">Ви прийняли запит на знайомство від %1$s.</string>
|
<string name="introduction_response_accepted_sent">Ви прийняли запит на знайомство від %1$s.</string>
|
||||||
<string name="introduction_response_accepted_sent_info">Перед тим, як ви додасте %1$s до списку своїх контактів, він/вона також має підтвердити цей запит. Це може зайняти якийсь час.</string>
|
<string name="introduction_response_accepted_sent_info">Перед тим, як ви додасте %1$s до списку своїх контактів, він/вона також має підтвердити цей запит. Це може зайняти якийсь час.</string>
|
||||||
<string name="introduction_response_declined_sent">Ви відхилили запит на знайомство з %1$s.</string>
|
<string name="introduction_response_declined_sent">Ви відхилили запит на знайомство з %1$s.</string>
|
||||||
|
<string name="introduction_response_declined_auto">Вітання %1$s відхилено автоматично.</string>
|
||||||
<string name="introduction_response_accepted_received">%1$s прийняв(-ла) запит на знайомство із %2$s.</string>
|
<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">%1$s відхилив(-ла) запит на знайомство з %2$s.</string>
|
||||||
<string name="introduction_response_declined_received_by_introducee">%1$s повідомляє, що %2$s відхилив(-ла) запит на знайомство.</string>
|
<string name="introduction_response_declined_received_by_introducee">%1$s повідомляє, що %2$s відхилив(-ла) запит на знайомство.</string>
|
||||||
|
<!--Connect via Bluetooth-->
|
||||||
|
<string name="menu_item_connect_via_bluetooth">З\'єднатися через Bluetooth</string>
|
||||||
|
<string name="connect_via_bluetooth_title">З\'єднатися через Bluetooth</string>
|
||||||
|
<string name="connect_via_bluetooth_intro">Якщо Bluetooth-з\'єднання не спрацьовують автоматично, можете з\'єднатися вручну на цьому екрані.\n\nВаш контакт має бути поруч, щоб це спрацювало.\n\nВам обом слід одночасно натиснути «Почати».</string>
|
||||||
|
<string name="connect_via_bluetooth_already_discovering">Спроба Bluetooth-з\'єднання вже триває. Повторіть трохи пізніше.</string>
|
||||||
|
<string name="connect_via_bluetooth_no_location_permission">Не вдається продовжити без дозволу на отримання місцезнаходження</string>
|
||||||
|
<string name="connect_via_bluetooth_start">Триває Bluetooth-з\'єднання...</string>
|
||||||
|
<string name="connect_via_bluetooth_success">Bluetooth-з\'єднання успішне</string>
|
||||||
|
<string name="connect_via_bluetooth_error">Не вдалося з\'єднатися через Bluetooth.</string>
|
||||||
|
<string name="connect_via_bluetooth_error_not_supported">Пристрій не підтримує Bluetooth.</string>
|
||||||
<!--Private Groups-->
|
<!--Private Groups-->
|
||||||
<string name="groups_list_empty">Немає груп для відображення</string>
|
<string name="groups_list_empty">Немає груп для відображення</string>
|
||||||
<string name="groups_list_empty_action">Натисніть на символ \"+\", щоб створити групу або попросіть у своїх контактів поділитися з вами групами</string>
|
<string name="groups_list_empty_action">Натисніть на символ \"+\", щоб створити групу або попросіть у своїх контактів поділитися з вами групами</string>
|
||||||
@@ -299,6 +397,7 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="groups_invitations_response_accepted_sent">Ви прийняли запрошення до групи від %s.</string>
|
<string name="groups_invitations_response_accepted_sent">Ви прийняли запрошення до групи від %s.</string>
|
||||||
<string name="groups_invitations_response_declined_sent">Ви відхилили запрошення до групи від %s.</string>
|
<string name="groups_invitations_response_declined_sent">Ви відхилили запрошення до групи від %s.</string>
|
||||||
|
<string name="groups_invitations_response_declined_auto">Запрошення до групи від %s відхилено автоматично.</string>
|
||||||
<string name="groups_invitations_response_accepted_received">%s прийняв(-ла) запрошення до групи.</string>
|
<string name="groups_invitations_response_accepted_received">%s прийняв(-ла) запрошення до групи.</string>
|
||||||
<string name="groups_invitations_response_declined_received">%sвідхилив(-ла) запрошення до групи.</string>
|
<string name="groups_invitations_response_declined_received">%sвідхилив(-ла) запрошення до групи.</string>
|
||||||
<string name="sharing_status_groups">Лише засновник групи може запрошувати нових учасників до групи. Нижче зазначено усх актуальних учасників групи.</string>
|
<string name="sharing_status_groups">Лише засновник групи може запрошувати нових учасників до групи. Нижче зазначено усх актуальних учасників групи.</string>
|
||||||
@@ -351,6 +450,7 @@
|
|||||||
<string name="forum_invitation_already_sharing">Вже поширюється</string>
|
<string name="forum_invitation_already_sharing">Вже поширюється</string>
|
||||||
<string name="forum_invitation_response_accepted_sent">Ви прийняли запрошення до форуму від %s.</string>
|
<string name="forum_invitation_response_accepted_sent">Ви прийняли запрошення до форуму від %s.</string>
|
||||||
<string name="forum_invitation_response_declined_sent">Ви відхилили запрошення до форуму від %s.</string>
|
<string name="forum_invitation_response_declined_sent">Ви відхилили запрошення до форуму від %s.</string>
|
||||||
|
<string name="forum_invitation_response_declined_auto">Запрошення до форуму від %s відхилено автоматично.</string>
|
||||||
<string name="forum_invitation_response_accepted_received">%s прийняв запрошення до форуму.</string>
|
<string name="forum_invitation_response_accepted_received">%s прийняв запрошення до форуму.</string>
|
||||||
<string name="forum_invitation_response_declined_received">%s відхилив запрошення до форуму.</string>
|
<string name="forum_invitation_response_declined_received">%s відхилив запрошення до форуму.</string>
|
||||||
<string name="sharing_status">Поширення статусу</string>
|
<string name="sharing_status">Поширення статусу</string>
|
||||||
@@ -387,6 +487,7 @@
|
|||||||
<string name="blogs_sharing_snackbar">Блог було поширено поміж обраних контактів</string>
|
<string name="blogs_sharing_snackbar">Блог було поширено поміж обраних контактів</string>
|
||||||
<string name="blogs_sharing_response_accepted_sent">Ви прийняли запрошення до блогу від %s.</string>
|
<string name="blogs_sharing_response_accepted_sent">Ви прийняли запрошення до блогу від %s.</string>
|
||||||
<string name="blogs_sharing_response_declined_sent">Ви відхилили запрошення до блогу від %s.</string>
|
<string name="blogs_sharing_response_declined_sent">Ви відхилили запрошення до блогу від %s.</string>
|
||||||
|
<string name="blogs_sharing_response_declined_auto">Запрошення до блогу від %s відхилено автоматично.</string>
|
||||||
<string name="blogs_sharing_response_accepted_received">%s прийняв запрошення до блогу.</string>
|
<string name="blogs_sharing_response_accepted_received">%s прийняв запрошення до блогу.</string>
|
||||||
<string name="blogs_sharing_response_declined_received">%s відхилив запрошення до блогу.</string>
|
<string name="blogs_sharing_response_declined_received">%s відхилив запрошення до блогу.</string>
|
||||||
<string name="blogs_sharing_invitation_received">%1$s поділився з вами блогом \"%2$s\".</string>
|
<string name="blogs_sharing_invitation_received">%1$s поділився з вами блогом \"%2$s\".</string>
|
||||||
@@ -400,6 +501,8 @@
|
|||||||
<string name="blogs_rss_feeds_import_button">Імпортувати</string>
|
<string name="blogs_rss_feeds_import_button">Імпортувати</string>
|
||||||
<string name="blogs_rss_feeds_import_hint">Введіть URL-посилання RSS-стрічки</string>
|
<string name="blogs_rss_feeds_import_hint">Введіть URL-посилання RSS-стрічки</string>
|
||||||
<string name="blogs_rss_feeds_import_error">Нам шкода! Виникла помилка під час імпорту вашої стрічки.</string>
|
<string name="blogs_rss_feeds_import_error">Нам шкода! Виникла помилка під час імпорту вашої стрічки.</string>
|
||||||
|
<string name="blogs_rss_feeds_import_exists">Цю стрічку вже імпортовано.</string>
|
||||||
|
<string name="blogs_rss_feeds">RSS-стрічки</string>
|
||||||
<string name="blogs_rss_feeds_manage_imported">Імпортовано:</string>
|
<string name="blogs_rss_feeds_manage_imported">Імпортовано:</string>
|
||||||
<string name="blogs_rss_feeds_manage_author">Автор:</string>
|
<string name="blogs_rss_feeds_manage_author">Автор:</string>
|
||||||
<string name="blogs_rss_feeds_manage_updated">Востаннє оновлювалося:</string>
|
<string name="blogs_rss_feeds_manage_updated">Востаннє оновлювалося:</string>
|
||||||
@@ -409,6 +512,10 @@
|
|||||||
<string name="blogs_rss_feeds_manage_empty_state">Немає RSS-стрічок до відображення\n\nНатисніть на символ \"+\", щоб імпортувати стрічку</string>
|
<string name="blogs_rss_feeds_manage_empty_state">Немає RSS-стрічок до відображення\n\nНатисніть на символ \"+\", щоб імпортувати стрічку</string>
|
||||||
<string name="blogs_rss_feeds_manage_error">Під час завантаження ваших стрічок виникла проблема. Будь ласка, спробуйте пізніше.</string>
|
<string name="blogs_rss_feeds_manage_error">Під час завантаження ваших стрічок виникла проблема. Будь ласка, спробуйте пізніше.</string>
|
||||||
<!--Settings Profile Picture-->
|
<!--Settings Profile Picture-->
|
||||||
|
<string name="change_profile_picture">Торкніть, щоб змінити зображення профілю</string>
|
||||||
|
<string name="dialog_confirm_profile_picture_title">Змінити зображення профілю</string>
|
||||||
|
<string name="dialog_confirm_profile_picture_remark">Лише ваші контакти можуть бачити це зображення</string>
|
||||||
|
<string name="change_profile_picture_failed_message">Перепрошуємо, щось пішло не так при оновленні вашого зображення профілю</string>
|
||||||
<!--Settings Display-->
|
<!--Settings Display-->
|
||||||
<string name="pref_language_title">Мова & регіон</string>
|
<string name="pref_language_title">Мова & регіон</string>
|
||||||
<string name="pref_language_changed">Ці налаштування набувають чинності після того, як ви перезапустите Briar. Будь ласка, вийдіть з Briar та перезапустіть його.</string>
|
<string name="pref_language_changed">Ці налаштування набувають чинності після того, як ви перезапустите Briar. Будь ласка, вийдіть з Briar та перезапустіть його.</string>
|
||||||
@@ -418,12 +525,22 @@
|
|||||||
<string name="pref_theme_light">Світла</string>
|
<string name="pref_theme_light">Світла</string>
|
||||||
<string name="pref_theme_dark">Темна</string>
|
<string name="pref_theme_dark">Темна</string>
|
||||||
<string name="pref_theme_auto">Автоматично (Денна)</string>
|
<string name="pref_theme_auto">Автоматично (Денна)</string>
|
||||||
<string name="pref_theme_system">Усталені в системі</string>
|
<string name="pref_theme_system">Усталена в системі</string>
|
||||||
<!--Settings Connections-->
|
<!--Settings Connections-->
|
||||||
|
<string name="network_settings_title">З\'єднання</string>
|
||||||
|
<string name="bluetooth_setting">З\'єднуватися з контактами через Bluetooth</string>
|
||||||
|
<string name="wifi_setting">З\'єднуватися з контактами в спільній мережі Wi-Fi</string>
|
||||||
|
<string name="tor_enable_title">З\'єднуватися з контактами через інтернет</string>
|
||||||
|
<string name="tor_enable_summary">Всі з\'єднання спрямовано через мережу Tor для приватності</string>
|
||||||
|
<string name="tor_network_setting">Спосіб з\'єднання з мережею Tor</string>
|
||||||
<string name="tor_network_setting_automatic">Розпізнавати автоматично на основі місцезнаходження</string>
|
<string name="tor_network_setting_automatic">Розпізнавати автоматично на основі місцезнаходження</string>
|
||||||
|
<string name="tor_network_setting_without_bridges">Використовувати мережу Tor без мостів</string>
|
||||||
|
<string name="tor_network_setting_with_bridges">Використовувати мережу Tor із мостами</string>
|
||||||
|
<string name="tor_network_setting_never">Не з\'єднуватися з інтернетом</string>
|
||||||
<!--How and when Briar will connect to Tor: E.g. "Don't connect to the Internet (in China)" or "Use Tor network with bridges (in Belarus)"-->
|
<!--How and when Briar will connect to Tor: E.g. "Don't connect to the Internet (in China)" or "Use Tor network with bridges (in Belarus)"-->
|
||||||
<string name="tor_network_setting_summary">Автоматично: %1$s (через %2$s)</string>
|
<string name="tor_network_setting_summary">Автоматично: %1$s (через %2$s)</string>
|
||||||
<string name="tor_mobile_data_title">Використовувати мобільну мережу</string>
|
<string name="tor_mobile_data_title">Використовувати мобільну мережу</string>
|
||||||
|
<string name="tor_only_when_charging_title">З\'єднуватися з інтернетом лише під час заряджання</string>
|
||||||
<string name="tor_only_when_charging_summary">Вимикає з’єднання з інтернетом коли пристрій працює від батареї</string>
|
<string name="tor_only_when_charging_summary">Вимикає з’єднання з інтернетом коли пристрій працює від батареї</string>
|
||||||
<!--Settings Security and Panic-->
|
<!--Settings Security and Panic-->
|
||||||
<string name="security_settings_title">Безпека</string>
|
<string name="security_settings_title">Безпека</string>
|
||||||
@@ -486,9 +603,37 @@
|
|||||||
<string name="notify_sound_setting_disabled">Немає</string>
|
<string name="notify_sound_setting_disabled">Немає</string>
|
||||||
<string name="choose_ringtone_title">Обрати мелодію</string>
|
<string name="choose_ringtone_title">Обрати мелодію</string>
|
||||||
<string name="cannot_load_ringtone">Неможливо завантажити мелодію</string>
|
<string name="cannot_load_ringtone">Неможливо завантажити мелодію</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_settings_title">Mailbox</string>
|
||||||
|
<string name="mailbox_setup_title">Налаштуйте Mailbox</string>
|
||||||
|
<string name="mailbox_setup_intro">Скринька дає змогу контактам надсилати вам повідомлення, поки ви не в мережі. Скринька отримуватиме ваші повідомлення й зберігатиме їх до появи вас у мережі.\n
|
||||||
|
\nМожете встановити застосунок Briar Mailbox на окремий пристрій. Забезпечте йому безперервні електрику й Wi-Fi, щоб він завжди був онлайн.</string>
|
||||||
|
<string name="mailbox_setup_download">Спершу встановіть застосунок Mailbox на інший пристрій, знайшовши «Briar Mailbox» у Google Play чи іншому місці, звідки ви завантажили Briar.\n
|
||||||
|
\nТоді з\'єднайте свій Mailbox із Briar, просканувавши QR-код, показаний застосунком Mailbox.</string>
|
||||||
|
<string name="mailbox_setup_download_link">Поширити посилання на завантаження</string>
|
||||||
|
<string name="mailbox_setup_button_scan">Сканувати QR-код Mailbox</string>
|
||||||
|
<string name="permission_camera_qr_denied_body">Ви заборонили доступ до камери, але камера потрібна для сканування QR-коду.\n\nБудь ласка, надайте доступ.</string>
|
||||||
|
<string name="mailbox_setup_connecting">Під\'єднання...</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_title">Хибний QR-код</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_description">QR-код, який ви просканували, хибний. Будь ласка, відкрийте застосунок Briar Mailbox на вашому Mailbox-пристрої й проскануйте QR-код, який він покаже.</string>
|
||||||
|
<string name="tor_offline_title">Поза мережею</string>
|
||||||
|
<string name="tor_offline_description">Переконайтесь, що пристрій у мережі, а з\'єднання з інтернетом дозволено.\n\nТоді зачекайте, поки значок глобуса в налаштуваннях з\'єднання стане зеленим.</string>
|
||||||
|
<string name="tor_offline_button_check">Перевірити налаштування з\'єднання</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
|
<string name="disappearing_messages_title">Самознищувані повідомлення</string>
|
||||||
|
<string name="disappearing_messages_explanation_long">Коли цей параметр увімкнено, нові
|
||||||
|
повідомлення в цій розмові самознищуватимуться автоматично за 7\u00A0днів.
|
||||||
|
\n\nВаша копія починає відлік, щойно повідомлення доставлено.
|
||||||
|
Інша копія починає відлік, щойно повідомлення прочитано.
|
||||||
|
\n\nСамознищувані повідомлення позначаються значком бомби.
|
||||||
|
\n\nПам\'ятайте, всі, хто отримують надіслані вами повідомлення, все одно можуть їх копіювати.
|
||||||
|
\n\nЗміна цього параметру вплине на всі ваші нові повідомлення одразу, а на повідомлення
|
||||||
|
вашого контакту — щойно вони отримають ваше наступне повідомлення.
|
||||||
|
Контакт також може змінити цей параметр для вас обох.</string>
|
||||||
<string name="learn_more">Дізнатися більше</string>
|
<string name="learn_more">Дізнатися більше</string>
|
||||||
<!--Settings Feedback-->
|
<string name="disappearing_messages_summary">Знищувати майбутні повідомлення в цій розмові автоматично за 7\u00A0днів.</string>
|
||||||
|
<!--Settings Actions-->
|
||||||
|
<string name="pref_category_actions">Дії</string>
|
||||||
<string name="send_feedback">Надіслати відгук</string>
|
<string name="send_feedback">Надіслати відгук</string>
|
||||||
<!--Link Warning-->
|
<!--Link Warning-->
|
||||||
<string name="link_warning_title">Попередження про посилання</string>
|
<string name="link_warning_title">Попередження про посилання</string>
|
||||||
@@ -497,7 +642,7 @@
|
|||||||
<string name="link_warning_open_link">Відкрити посилання</string>
|
<string name="link_warning_open_link">Відкрити посилання</string>
|
||||||
<!--Crash Reporter-->
|
<!--Crash Reporter-->
|
||||||
<string name="crash_report_title">Аварійний звіт Briar</string>
|
<string name="crash_report_title">Аварійний звіт Briar</string>
|
||||||
<string name="briar_crashed">Вибачте, Briar перестав працювати.</string>
|
<string name="briar_crashed">Перепрошуємо, Briar зазнав збою</string>
|
||||||
<string name="not_your_fault">Це не ваша провина.</string>
|
<string name="not_your_fault">Це не ваша провина.</string>
|
||||||
<string name="please_send_report">Будь ласка, допоможіть нам покращити Briar надіславши нам аварійний звіт.</string>
|
<string name="please_send_report">Будь ласка, допоможіть нам покращити Briar надіславши нам аварійний звіт.</string>
|
||||||
<string name="report_is_encrypted">Ми обіцяємо, що цей звіт буде зашифровано та безпечно надіслано.</string>
|
<string name="report_is_encrypted">Ми обіцяємо, що цей звіт буде зашифровано та безпечно надіслано.</string>
|
||||||
@@ -507,15 +652,32 @@
|
|||||||
<string name="optional_contact_email">Ваша електронна адреса (необов\'язково)</string>
|
<string name="optional_contact_email">Ваша електронна адреса (необов\'язково)</string>
|
||||||
<string name="include_debug_report_crash">Додати анонімну інформацію про аварійний збій</string>
|
<string name="include_debug_report_crash">Додати анонімну інформацію про аварійний збій</string>
|
||||||
<string name="include_debug_report_feedback">Додати анонімну інформацію про цей пристрій</string>
|
<string name="include_debug_report_feedback">Додати анонімну інформацію про цей пристрій</string>
|
||||||
|
<string name="dev_report_user_info">Користувацькі дані</string>
|
||||||
|
<string name="dev_report_basic_info">Загальні дані</string>
|
||||||
|
<string name="dev_report_device_info">Дані про пристрій</string>
|
||||||
|
<string name="dev_report_stacktrace">Траса стеку</string>
|
||||||
|
<string name="dev_report_time_info">Часові дані</string>
|
||||||
|
<string name="dev_report_memory">Пам\'ять</string>
|
||||||
|
<string name="dev_report_storage">Сховище</string>
|
||||||
|
<string name="dev_report_connectivity">З\'єднання</string>
|
||||||
|
<string name="dev_report_network_usage">Використання мережі</string>
|
||||||
|
<string name="dev_report_build_config">Параметри збірки</string>
|
||||||
|
<string name="dev_report_logcat">Журнал застосунку</string>
|
||||||
|
<string name="dev_report_device_features">Можливості пристрою</string>
|
||||||
<string name="send_report">Надіслати звіт</string>
|
<string name="send_report">Надіслати звіт</string>
|
||||||
<string name="close">Закрити</string>
|
<string name="close">Закрити</string>
|
||||||
|
<string name="dev_report_sending">Надсилання відгуку...</string>
|
||||||
|
<string name="dev_report_sent">Відгук надіслано</string>
|
||||||
<string name="dev_report_saved">Звіт збережено. Його буде надіслано наступного разу, як ви увійдете до Briar.</string>
|
<string name="dev_report_saved">Звіт збережено. Його буде надіслано наступного разу, як ви увійдете до Briar.</string>
|
||||||
|
<string name="dev_report_error">Помилка: не вдалося надіслати звіт</string>
|
||||||
<!--Sign Out-->
|
<!--Sign Out-->
|
||||||
<string name="progress_title_logout">Відбувається вихід з Briar…</string>
|
<string name="progress_title_logout">Відбувається вихід з Briar…</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Виявлено накладення іншої програми</string>
|
<string name="screen_filter_title">Виявлено накладення іншої програми</string>
|
||||||
<string name="screen_filter_body">Інша програма накладається на Briar. Для вашої безпеки, Briar не реагуватиме на дотики, коли інша програма накладатиметься зверху.\n\nЗверху можуть накладатися наступні програми:\n\n%1$s</string>
|
<string name="screen_filter_body">Інша програма накладається на Briar. Для вашої безпеки, Briar не реагуватиме на дотики, коли інша програма накладатиметься зверху.\n\nЗверху можуть накладатися наступні програми:\n\n%1$s</string>
|
||||||
|
<string name="screen_filter_body_api_30">Над Briar знаходиться інший застосунок. Щоб захистити вашу безпеку, Briar не реагуватиме на дотики, поки той застосунок над ним.\n\nЗнайдіть цей застосунок у переліку внизу.</string>
|
||||||
<string name="screen_filter_allow">Дозволити цим програмам накладатися зверху</string>
|
<string name="screen_filter_allow">Дозволити цим програмам накладатися зверху</string>
|
||||||
|
<string name="screen_filter_review_apps">Перелічити застосунки</string>
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Дозвіл камери</string>
|
<string name="permission_camera_title">Дозвіл камери</string>
|
||||||
<string name="permission_camera_request_body">Щоб відсканувати цей QR-код, Briar потрібен доступ до камери.</string>
|
<string name="permission_camera_request_body">Щоб відсканувати цей QR-код, Briar потрібен доступ до камери.</string>
|
||||||
@@ -524,6 +686,10 @@
|
|||||||
<string name="permission_camera_location_title">Камера та місцезнаходження</string>
|
<string name="permission_camera_location_title">Камера та місцезнаходження</string>
|
||||||
<string name="permission_camera_location_request_body">Щоб відсканувати QR-код, Briar потребує доступу до камери.\n\nЩоб знайти Bluetooth-пристрої, Briar потребує доступу до інформації про ваше місцезнаходження.\n\nBriar не зберігає дані про ваше місцезнаходження та не ділиться ні з ким цією інформацією.</string>
|
<string name="permission_camera_location_request_body">Щоб відсканувати QR-код, Briar потребує доступу до камери.\n\nЩоб знайти Bluetooth-пристрої, Briar потребує доступу до інформації про ваше місцезнаходження.\n\nBriar не зберігає дані про ваше місцезнаходження та не ділиться ні з ким цією інформацією.</string>
|
||||||
<string name="permission_camera_denied_body">Ви відмовилися надати доступ до камери, але додавання контактів потребує використання камери.\n\nБудь ласка, подумайте про можливість надання доступу.</string>
|
<string name="permission_camera_denied_body">Ви відмовилися надати доступ до камери, але додавання контактів потребує використання камери.\n\nБудь ласка, подумайте про можливість надання доступу.</string>
|
||||||
|
<string name="permission_location_denied_body">Ви заборонили доступ до місцеперебування, але Briar потребує цього доступу, щоб знаходити Bluetooth-пристрої.\n\nБудь ласка, надайте доступ.</string>
|
||||||
|
<string name="permission_location_setting_title">Визначення місцеперебування</string>
|
||||||
|
<string name="permission_location_setting_body">Ваш пристрій не дозволяє визначати місцеперебування, а це потрібно для знаходження інших пристроїв через Bluetooth. Будь ласка, увімкніть визначення місцеперебування, щоб продовжити. Згодом ви зможете знову його вимкнути.</string>
|
||||||
|
<string name="permission_location_setting_button">Увімкнути визначення місцеперебування</string>
|
||||||
<string name="qr_code">QR-код</string>
|
<string name="qr_code">QR-код</string>
|
||||||
<string name="show_qr_code_fullscreen">Вивести QR-код на весь екран</string>
|
<string name="show_qr_code_fullscreen">Вивести QR-код на весь екран</string>
|
||||||
<!--App Locking-->
|
<!--App Locking-->
|
||||||
@@ -534,6 +700,93 @@
|
|||||||
<string name="lock_is_locked">Briar заблоковано</string>
|
<string name="lock_is_locked">Briar заблоковано</string>
|
||||||
<string name="lock_tap_to_unlock">Натисніть, щоб розблокувати</string>
|
<string name="lock_tap_to_unlock">Натисніть, щоб розблокувати</string>
|
||||||
<!--Connections Screen-->
|
<!--Connections Screen-->
|
||||||
|
<string name="transports_help_text">Briar може з\'єднуватися з вашими контактами через інтернет, Wi-Fi чи Bluetooth.\n\nУсі інтернет-з\'єднання спрямовано через мережу Tor для приватності.\n\nЯкщо до контакту є кілька шляхів, Briar використовує їх паралельно.</string>
|
||||||
|
<!--Share app offline-->
|
||||||
|
<string name="hotspot_title">Поширити застосунок офлайн</string>
|
||||||
|
<string name="hotspot_intro">Поширте цей застосунок із кимось поруч без інтернет-з\'єднання, використовуючи лише Wi-Fi свого телефону.
|
||||||
|
\n\nВаш телефон стане точкою доступу Wi-Fi. Люди поруч зможуть з\'єднатися з точкою й завантажити застосунок Briar із вашого телефону.</string>
|
||||||
|
<string name="hotspot_button_start_sharing">Увімкнути точку доступу</string>
|
||||||
|
<string name="hotspot_button_stop_sharing">Вимкнути точку доступу</string>
|
||||||
|
<string name="hotspot_progress_text_start">Запуск точки доступу...</string>
|
||||||
|
<string name="hotspot_notification_channel_title">Точка доступу Wi-Fi</string>
|
||||||
|
<string name="hotspot_notification_title">Поширення Briar поза мережею</string>
|
||||||
|
<string name="hotspot_button_connected">Вперед</string>
|
||||||
|
<string name="permission_hotspot_location_request_body">Для створення точки доступу Wi-Fi треба дозвіл на отримання місцеперебування.\n\nBriar не зберігає місцеперебування й нікому його не передає.</string>
|
||||||
|
<string name="permission_hotspot_location_denied_body">Ви заборонили доступ до місцеперебування, але Briar потребує цього доступу, щоб створити точку доступу Wi-Fi.\n\nБудь ласка, надайте доступ.</string>
|
||||||
|
<string name="wifi_settings_title">Налаштування Wi-Fi</string>
|
||||||
|
<string name="wifi_settings_request_enable_body">Будь ласка, ввімкніть Wi-Fi, щоб Briar міг створити точку доступу.</string>
|
||||||
|
<string name="hotspot_tab_manual">Вручну</string>
|
||||||
|
<!--The placeholder to be inserted into the string 'hotspot_manual_wifi': People can connect by %s-->
|
||||||
|
<string name="hotspot_scanning_a_qr_code">просканувавши QR-код</string>
|
||||||
|
<!--Wi-Fi setup-->
|
||||||
|
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
|
||||||
|
<string name="hotspot_manual_wifi">Ваш телефон надає точку доступу Wi-Fi. Щоб інші змогли завантажити Briar, їм слід додати з\'єднання з цією точкою доступу в налаштуваннях Wi-Fi свого пристрою, ввівши дані внизу чи %s. Коли вони з\'єднаються з точкою доступу, натисніть «Далі».</string>
|
||||||
|
<string name="hotspot_manual_wifi_ssid">Назва мережі</string>
|
||||||
|
<string name="hotspot_qr_wifi">Ваш телефон надає точку доступу Wi-Fi. Щоб інші змогли завантажити Briar, їм слід з\'єднатися з точкою доступу, просканувавши цей QR-код. Коли вони з\'єднаються з точкою доступу, натисніть «Далі».</string>
|
||||||
|
<string name="hotspot_no_peers_connected">Жодного пристрою не з\'єднано</string>
|
||||||
|
<plurals name="hotspot_peers_connected">
|
||||||
|
<item quantity="one">%s пристрій з\'єднано</item>
|
||||||
|
<item quantity="few">%s пристрої з\'єднано</item>
|
||||||
|
<item quantity="many">%s пристроїв з\'єднано</item>
|
||||||
|
<item quantity="other">%s пристроїв з\'єднано</item>
|
||||||
|
</plurals>
|
||||||
|
<!--Download link-->
|
||||||
|
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
|
||||||
|
<string name="hotspot_manual_site">Ваш телефон надає точку доступу Wi-Fi. З\'єднані з нею можуть завантажити Briar, ввівши наступне посилання у вебпереглядач або %s.</string>
|
||||||
|
<string name="hotspot_manual_site_address">Адреса (URL)</string>
|
||||||
|
<string name="hotspot_qr_site">Ваш телефон надає точку доступу Wi-Fi. З\'єднані з нею можуть завантажити Briar, просканувавши цей QR-код.</string>
|
||||||
|
<!--e.g. Download Briar 1.2.20-->
|
||||||
|
<string name="website_download_title">Завантажте %s</string>
|
||||||
|
<string name="website_download_intro">Хтось поруч поширює вам %s.</string>
|
||||||
|
<string name="website_download_outro">Після завантаження, відкрийте завантажений файл і встановіть його.</string>
|
||||||
|
<string name="website_troubleshooting_title">Виправлення неполадок</string>
|
||||||
|
<string name="website_troubleshooting_1">Якщо не вдається завантажити застосунок, повторіть спробу іншим вебпереглядачем.</string>
|
||||||
|
<string name="website_troubleshooting_2_old">Щоб встановити завантажений застосунок, може бути потрібно дозволити встановлення застосунків із «невідомих джерел» у налаштуваннях системи. Після цього, можливо, доведеться завантажити застосунок іще раз. Радимо вимкнути параметр «невідомих джерел» після встановлення застосунку.</string>
|
||||||
|
<string name="website_troubleshooting_2_new">Щоб встановити завантажений застосунок, може бути потрібно дозволити вебпереглядачу встановлювати невідомі застосунки. Після встановлення застосунку радимо вилучити у вебпереглядача цей дозвіл.</string>
|
||||||
|
<string name="hotspot_help_wifi_title">Проблеми з\'єднання з Wi-Fi:</string>
|
||||||
|
<string name="hotspot_help_wifi_1">Вимкніть і знов увімкніть Wi-Fi на обох телефонах і повторіть спробу.</string>
|
||||||
|
<string name="hotspot_help_wifi_2">Якщо телефон скаржиться на відсутність інтернету в мережі Wi-Fi, підтвердьте йому, що все одно бажаєте продовжити з\'єднання.</string>
|
||||||
|
<string name="hotspot_help_wifi_3">Перезавантажте телефон, на якому працює точка доступу Wi-Fi, запустіть Briar і повторіть спробу поширення.</string>
|
||||||
|
<string name="hotspot_help_site_title">Проблеми відкриття локального вебсайту:</string>
|
||||||
|
<string name="hotspot_help_site_1">Ще раз перевірте, що ввели адресу точно так, як показано. Будь-який одрук може спричинити невдачу.</string>
|
||||||
|
<string name="hotspot_help_site_2">Переконайтесь, що телефон досі з\'єднано з правильною мережею Wi-Fi (див. вище) під час відкриття сайту.</string>
|
||||||
|
<string name="hotspot_help_site_3">Якщо маєте застосунок-файрвол, переконайтесь, що він не блокує доступ.</string>
|
||||||
|
<string name="hotspot_help_site_4">Якщо вдається відкрити сайт, але не завантажити застосунок Briar, спробуйте завантажити іншим вебпереглядачем.</string>
|
||||||
|
<string name="hotspot_help_fallback_title">Нічого не працює?</string>
|
||||||
|
<string name="hotspot_help_fallback_intro">Можете зберегти застосунок як apk-файл і поширити його якось іще. Щойно файл передано на інший пристрій, за його допомогою можна встановити Briar.
|
||||||
|
\n\nПорада: може бути потрібно спершу змінити суфікс файлу на .zip для Bluetooth-передання.</string>
|
||||||
|
<string name="hotspot_help_fallback_button">Зберегти застосунок</string>
|
||||||
|
<!--error handling-->
|
||||||
|
<string name="hotspot_error_intro">Щось пішло не так при спробі поширити застосунок через Wi-Fi:</string>
|
||||||
|
<string name="hotspot_error_no_wifi_direct">Пристрій не підтримує Wi-Fi Direct</string>
|
||||||
|
<string name="hotspot_error_start_callback_failed">Не вдалося створити точку доступу: помилка %s</string>
|
||||||
|
<string name="hotspot_error_start_callback_failed_unknown">Не вдалося створити точку доступу через невідому помилку: %d</string>
|
||||||
|
<string name="hotspot_error_start_callback_no_group_info">Не вдалося створити точку доступу: бракує даних групи</string>
|
||||||
|
<string name="hotspot_error_web_server_start">Помилка запуску вебсервера</string>
|
||||||
|
<string name="hotspot_error_web_server_serve">Помилка показу вебсайту.\n\nБудь ласка, надішліть відгук (з анонімними даними) застосунком Briar, якщо проблема повторюватиметься.</string>
|
||||||
|
<string name="hotspot_flag_test">Попередження: застосунок встановлено Android Studio й НЕ може бути встановлено на інший пристрій.</string>
|
||||||
|
<string name="hotspot_error_framework_busy">Не вдалося створити точку доступу.\n\nЯкщо вже працює інша точка доступу чи ви роздаєте інтернет-з\'єднання через Wi-Fi, зупиніть це й повторіть спробу.</string>
|
||||||
|
<!--Transfer Data via Removable Drives-->
|
||||||
|
<string name="removable_drive_menu_title">З\'єднатися через флешку</string>
|
||||||
|
<string name="removable_drive_intro">Якщо не вдається з\'єднатися з контактом через інтернет, Wi-Fi та Bluetooth, Briar ще може передавати повідомлення за допомогою флешки чи SD-картки.</string>
|
||||||
|
<string name="removable_drive_explanation">Якщо не вдається з\'єднатися з контактом через інтернет, Wi-Fi та Bluetooth, Briar ще може передавати повідомлення за допомогою флешки чи SD-картки.\n\nКоли ви натиснете кнопку «Надіслати дані», будь-які дані в очікуванні надсилання контактові буде записано на флешку. Зокрема дані особистих повідомлень, прикріплень, блогів, форумів і приватних груп.\n\nПеред записом на флешку все буде зашифровано.\n\nОтримавши флешку, ваш контакт зможе імпортувати повідомлення в свій Briar кнопкою «Отримати дані».</string>
|
||||||
|
<string name="removable_drive_title_send">Надіслати дані</string>
|
||||||
|
<string name="removable_drive_title_receive">Отримати дані</string>
|
||||||
|
<string name="removable_drive_send_intro">Торкніть кнопку внизу, щоб створити файл зашифрованих повідомлень. Ви зможете обрати, куди зберегти файл.\n\nЯкщо бажаєте зберегти файл на флешку, під\'єднайте її зараз.</string>
|
||||||
|
<string name="removable_drive_send_no_data">Жодне повідомлення не очікує на надсилання цьому контактові.</string>
|
||||||
|
<string name="removable_drive_send_not_supported">Контакт використовує стару версію Briar чи старий пристрій, що не підтримує цієї можливості.</string>
|
||||||
|
<string name="removable_drive_send_button">Оберіть файл експорту</string>
|
||||||
|
<string name="removable_drive_ongoing">Дочекайтесь завершення поточного завдання</string>
|
||||||
|
<string name="removable_drive_receive_intro">Торкніть кнопку внизу, щоб обрати файл, надісланий вам контактом.\n\nЯкщо файл на флешці, під\'єднайте її зараз.</string>
|
||||||
|
<string name="removable_drive_receive_button">Оберіть файл імпорту</string>
|
||||||
|
<string name="removable_drive_success_send_title">Експорт успішний</string>
|
||||||
|
<string name="removable_drive_success_send_text">Дані успішно експортовано. Маєте 28 днів, щоб передати файл контактові.\n\nЯкщо файл на флешці, перед від\'єднанням вимкніть її за допомогою сповіщення в рядку стану.</string>
|
||||||
|
<string name="removable_drive_success_receive_title">Імпорт успішний</string>
|
||||||
|
<string name="removable_drive_success_receive_text">Усі зашифровані повідомлення з цього файлу отримано.</string>
|
||||||
|
<string name="removable_drive_error_send_title">Помилка експортування даних</string>
|
||||||
|
<string name="removable_drive_error_send_text">Запис даних до файлу зазнав збою.\nЯкщо використовуєте флешку, переконайтесь, що її правильно під\'єднано, й повторіть спробу.\n\nЯкщо збій повторюється, будь ласка, надішліть відгук, щоб команда Briar дізналася про проблему.</string>
|
||||||
|
<string name="removable_drive_error_receive_title">Помилка імпортування даних</string>
|
||||||
|
<string name="removable_drive_error_receive_text">Обраний файл не містив нічого зрозумілого Briar.\n\nБудь ласка, перевірте, що обрали правильний файл.\n\nЯкщо файл було створено контактом понад 28 днів тому, Briar не зможе його розпізнати.</string>
|
||||||
<!--Screenshots-->
|
<!--Screenshots-->
|
||||||
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
|
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
|
||||||
<string name="screenshot_alice">Аліса</string>
|
<string name="screenshot_alice">Аліса</string>
|
||||||
|
|||||||
@@ -561,6 +561,22 @@
|
|||||||
<string name="notify_sound_setting_disabled">无</string>
|
<string name="notify_sound_setting_disabled">无</string>
|
||||||
<string name="choose_ringtone_title">选择铃声</string>
|
<string name="choose_ringtone_title">选择铃声</string>
|
||||||
<string name="cannot_load_ringtone">无法加载铃声</string>
|
<string name="cannot_load_ringtone">无法加载铃声</string>
|
||||||
|
<!--Mailbox-->
|
||||||
|
<string name="mailbox_settings_title">邮箱</string>
|
||||||
|
<string name="mailbox_setup_title">邮箱设置</string>
|
||||||
|
<string name="mailbox_setup_intro">邮箱使你的联系人能够在你离线时向你发送消息。邮箱将接收你的邮件,并将其存储到你上线为止。\n
|
||||||
|
\n 你可以在备用设备上安装 Briar Mailbox 应用,并确保此设备始终有电且和Wi-Fi连接,这样它就永远在线了。</string>
|
||||||
|
<string name="mailbox_setup_download">首先,通过 Google Play 或任何你下载了 Briar 的地方搜索“Briar Mailbox”,在另一台设备上安装 Mailbox 应用。\n
|
||||||
|
\n然后通过扫描邮箱应用显示的二维码将你的 Mailbox 与Briar 链接起来。</string>
|
||||||
|
<string name="mailbox_setup_download_link">分享下载链接</string>
|
||||||
|
<string name="mailbox_setup_button_scan">扫描 Mailbox 二维码</string>
|
||||||
|
<string name="permission_camera_qr_denied_body">你拒绝了使用相机,但扫描二维码需要使用相机。\n\n请考虑授予访问权限。</string>
|
||||||
|
<string name="mailbox_setup_connecting">连接中……</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_title">错误的二维码</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_description">扫描的代码无效。请在安装有 Mailbox 应用的设备上打开 Briar 邮箱应用,并扫描它显示的二维码。</string>
|
||||||
|
<string name="tor_offline_title">离线</string>
|
||||||
|
<string name="tor_offline_description">请确保设备处于在线状态,且允许连接到互联网。\n\n然后,等待连接设置中的全局图标变为绿色。</string>
|
||||||
|
<string name="tor_offline_button_check">检查连接设置</string>
|
||||||
<!--Conversation Settings-->
|
<!--Conversation Settings-->
|
||||||
<string name="disappearing_messages_title">让消息自动消失</string>
|
<string name="disappearing_messages_title">让消息自动消失</string>
|
||||||
<string name="disappearing_messages_explanation_long">打开此设置将使
|
<string name="disappearing_messages_explanation_long">打开此设置将使
|
||||||
|
|||||||
@@ -612,6 +612,23 @@
|
|||||||
<string name="choose_ringtone_title">Choose ringtone</string>
|
<string name="choose_ringtone_title">Choose ringtone</string>
|
||||||
<string name="cannot_load_ringtone">Cannot load ringtone</string>
|
<string name="cannot_load_ringtone">Cannot load ringtone</string>
|
||||||
|
|
||||||
|
<!-- Mailbox -->
|
||||||
|
<string name="mailbox_settings_title">Mailbox</string>
|
||||||
|
<string name="mailbox_setup_title">Mailbox Setup</string>
|
||||||
|
<string name="mailbox_setup_intro">A Mailbox enables your contacts to send you messages while you are offline. The Mailbox will receive your messages and store them until you come online.\n
|
||||||
|
\nYou can install the Briar Mailbox app on a spare device. Keep it connected to power and Wi-Fi so it\'s always online.</string>
|
||||||
|
<string name="mailbox_setup_download">First, install the Mailbox app on another device by searching for \"Briar Mailbox\" on Google Play or wherever you downloaded Briar.\n
|
||||||
|
\nThen link your Mailbox with Briar by scanning the QR code shown by the Mailbox app.</string>
|
||||||
|
<string name="mailbox_setup_download_link">Share Download Link</string>
|
||||||
|
<string name="mailbox_setup_button_scan">Scan Mailbox QR code</string>
|
||||||
|
<string name="permission_camera_qr_denied_body">You have denied access to the camera, but scanning a QR code requires using the camera.\n\nPlease consider granting access.</string>
|
||||||
|
<string name="mailbox_setup_connecting">Connecting…</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_title">Wrong QR code</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_description">The scanned code is invalid. Please open the Briar Mailbox app on your mailbox device and scan the QR code it presents.</string>
|
||||||
|
<string name="tor_offline_title">Offline</string>
|
||||||
|
<string name="tor_offline_description">Ensure that this device is online and connections to the internet are allowed.\n\nAfterwards, wait for the globe icon in connection settings to turn green.</string>
|
||||||
|
<string name="tor_offline_button_check">Check connection settings</string>
|
||||||
|
|
||||||
<!-- Conversation Settings -->
|
<!-- Conversation Settings -->
|
||||||
<string name="disappearing_messages_title">Disappearing messages</string>
|
<string name="disappearing_messages_title">Disappearing messages</string>
|
||||||
<string name="disappearing_messages_explanation_long">Turning on this setting will make new
|
<string name="disappearing_messages_explanation_long">Turning on this setting will make new
|
||||||
|
|||||||
@@ -24,6 +24,11 @@
|
|||||||
app:fragment="org.briarproject.briar.android.settings.NotificationsFragment"
|
app:fragment="org.briarproject.briar.android.settings.NotificationsFragment"
|
||||||
app:icon="@drawable/ic_notifications" />
|
app:icon="@drawable/ic_notifications" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="pref_key_mailbox"
|
||||||
|
android:title="@string/mailbox_settings_title"
|
||||||
|
app:icon="@drawable/ic_mailbox" />
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="pref_key_actions"
|
android:key="pref_key_actions"
|
||||||
android:layout="@layout/preferences_category"
|
android:layout="@layout/preferences_category"
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ internal class HeadlessModule(private val appDir: File) {
|
|||||||
override fun shouldEnableImageAttachments() = false
|
override fun shouldEnableImageAttachments() = false
|
||||||
override fun shouldEnableProfilePictures() = false
|
override fun shouldEnableProfilePictures() = false
|
||||||
override fun shouldEnableDisappearingMessages() = false
|
override fun shouldEnableDisappearingMessages() = false
|
||||||
|
override fun shouldEnableMailbox() = false
|
||||||
override fun shouldEnablePrivateGroupsInCore() = false
|
override fun shouldEnablePrivateGroupsInCore() = false
|
||||||
override fun shouldEnableForumsInCore() = true
|
override fun shouldEnableForumsInCore() = true
|
||||||
override fun shouldEnableBlogsInCore() = true
|
override fun shouldEnableBlogsInCore() = true
|
||||||
|
|||||||
Reference in New Issue
Block a user