diff --git a/README.md b/README.md index c3dc4acea411e2d221a3693b5634cedc3a177baa..3f76a84498e57d510c66a7210ed0e72ab8ffc72a 100644 --- a/README.md +++ b/README.md @@ -1 +1,83 @@ -Briar is a messaging app designed for activists, journalists, and anyone else who needs a safe, easy and robust way to communicate. Unlike traditional messaging tools such as email, Twitter or Telegram, Briar doesn't rely on a central server - messages are synchronized directly between the users' devices. If the Internet's down, Briar can sync via Bluetooth or Wi-Fi, keeping the information flowing in a crisis. If the Internet's up, Briar can sync via the Tor network, protecting users and their relationships from surveillance. +# Briar Mailbox + +This project aims to develop an easy way for Briar users to increase their +reachability and lower the battery drain of their phone. + +In Briar messages are exchanged directly between contacts (peer-to-peer). +This kind of synchronous message exchange requires contacts to be online and +connected to each other. +While this is great for privacy (no central server which +can log things or be censored) it's bad for reachability, especially in +mobile networks where connectivity can be limited. + +```mermaid +graph LR + A[Alice] + B[Bob] + A1[Alice] + B1[Bob] + style B fill:#8db600 + style A1 fill:#8db600 + subgraph Alice offline + B-. can't send message .-> A + end + subgraph Bob offline + B1-. can't send message .-> A1 + end +``` + +Message delivery could be delayed for an arbitrary time (or even indefinitely) +until both Bob and Alice are online at the same time. +The repeater solves this problem by providing +mailbox-like message buffer where contacts can leave messages for the owner +of the repeater and which is connected to a stable internet connection +(e.g. the wifi at home, cable internet) and a power source. + + +```mermaid +graph LR + A[Alice] + A1[Alice] + B[Bob] + B1[Bob] + RA["Mailbox (always online)"] + style B fill:#8db600 + style RA fill:#8db600 + style A1 fill:#8db600 + subgraph Alice offline + B-. can't send message .-> A + end + subgraph Alices' Mailbox + B-- send message --> RA + end + subgraph Alice online + B1-. can't send message .-> A1 + A1-- get message --> RA + end +``` + +## Hardware + +We want the repeater to be as easy to deploy as possible. The first version +will come as Android application since it will be easy to setup and besides a +spare phone no special hardware is required. Once this is done support for +any hardware supporting Java (e.g. unix server, raspberry pi) will be added. + +## Features + +### Core features + +* Allow contacts to store messages for the owner of the repeater +* Allow the owner to store messages for her contacts. Contacts can pick them up + when syncing with the repeater. +* Owner and contacts connect to the repeater via Tor. + +### Extended features/components + +* The repeater can sync group messages (from groups the owner is part of) with + other group members (increases message circulation) +* Contacts and the owner can connect to the repeater via other transports (Bluetooth, Wifi-Direct, Lan) +* Push-like message notification for the owner to decrease battery drain + + + diff --git a/mailbox-android/.gitignore b/mailbox-android/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ab81bc92bd452bf46096efa34df3ac9d934a4163 --- /dev/null +++ b/mailbox-android/.gitignore @@ -0,0 +1,13 @@ +bin +gen +build +local.properties +.settings +src/main/assets/*.zip +src/main/res/values-iw + +# Fastlane Screenshots +/fastlane/metadata/android/screenshots.html +/fastlane/metadata/android/*/images +/fastlane/report.xml +/fastlane/README.md \ No newline at end of file diff --git a/mailbox-android/.tx/config b/mailbox-android/.tx/config new file mode 100644 index 0000000000000000000000000000000000000000..67e77d7d4977c12cf0cbfad979874c527b8091e4 --- /dev/null +++ b/mailbox-android/.tx/config @@ -0,0 +1,11 @@ +[main] +host = https://www.transifex.com +lang_map = pt_BR: pt-rBR, nb_NO: nb, zh-Hans: zh-rCN + +[briar.stringsxml-5] +file_filter = src/main/res/values-<lang>/strings.xml +source_file = src/main/res/values/strings.xml +source_lang = en +type = ANDROID +minimum_perc = 25 + diff --git a/mailbox-android/artwork/bluetooth.svg b/mailbox-android/artwork/bluetooth.svg new file mode 100644 index 0000000000000000000000000000000000000000..ed248d1daa4b58ecdfe2738cdff02cdb0be05188 --- /dev/null +++ b/mailbox-android/artwork/bluetooth.svg @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + width="499.24374" + height="175.49413" + viewBox="0 0 499.24373 175.49413" + id="svg2" + version="1.1"> + <defs + id="defs4" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <path + id="path4201" + d="m 459.80937,171.15983 -4.32657,-4.3343 -7.06956,-2.42737 c -3.88825,-1.33505 -8.72285,-2.99587 -10.74354,-3.6907 l -3.674,-1.26333 3.524,-0.1726 c 8.24183,-0.40367 12.98778,-4.00671 14.33634,-10.88389 0.79628,-4.06078 1.12887,-17.29805 0.83016,-33.04122 -0.15338,-8.08375 -0.16617,-15.41641 -0.0284,-16.29481 0.13775,-0.8784 0.53527,-2.42011 0.88339,-3.42602 1.22247,-3.53243 0.33996,-11.90828 -1.8577,-17.63146 -0.34848,-0.9075 -1.93434,-4.215 -3.52415,-7.35 -4.15849,-8.2003 -4.50458,-8.94188 -4.89292,-10.4841 -0.45865,-1.82145 -0.21161,-5.43531 0.4625,-6.7659 0.66625,-1.31505 2.15695,-2.91616 3.24622,-3.48662 1.29885,-0.68024 2.61568,0.12202 4.6864,2.85512 3.42153,4.51599 14.00135,19.44095 15.73191,22.19301 3.74551,5.95636 5.95558,11.16496 7.9722,18.78849 0.6547,2.475 1.88525,6.9975 2.73456,10.05 0.84931,3.0525 2.71404,10.15792 4.14385,15.78983 l 2.59964,10.23983 4.65,5.19319 c 2.5575,2.85626 5.7975,6.46371 7.2,8.01657 1.4025,1.55286 2.55,2.97543 2.55,3.16127 0,0.33546 -34.49955,29.29931 -34.89913,29.29931 -0.11475,0 -2.15559,-1.95044 -4.5352,-4.3343 z M 365.9443,154.77206 c -1.25762,-0.62844 -2.20557,-1.3788 -2.91402,-2.30663 -2.08931,-2.73629 -1.95034,2.36868 -1.86433,-68.48249 l 0.0777,-64.03881 0.66066,-1.23494 c 1.0152,-1.89767 1.99201,-2.91087 3.73952,-3.87887 l 1.59982,-0.88619 37.78387,-0.0796 c 42.45592,-0.0894 39.40239,-0.2483 42.11646,2.19188 0.87544,0.78709 1.75715,1.95946 2.18393,2.90385 0.71264,1.57698 0.71613,1.63839 0.80561,14.20405 l 0.0899,12.62022 -1.79817,-0.13007 c -1.42577,-0.10313 -2.08143,0.007 -3.16601,0.5321 -2.01294,0.97445 -3.93993,2.89871 -5.11476,5.10753 l -1.03717,1.95 -0.007,-12.825 -0.007,-12.825 -33.6,0 -33.6,0 0,51.3 0,51.3 33.59873,0 33.59874,0 0.0763,-34.425 c 0.073,-32.96021 0.0982,-34.36117 0.59098,-32.925 0.28309,0.825 1.80562,3.9975 3.3834,7.05 5.49252,10.62624 5.40494,9.86009 5.39597,47.20335 -0.007,27.62122 -0.12358,29.95084 -1.66204,33.10906 -1.07144,2.19949 -2.71143,3.71042 -5.05823,4.66019 l -1.67381,0.6774 -36.1677,0.0797 -36.16769,0.0797 -1.864,-0.93145 z m 42.39939,-5.03813 c 2.87119,-1.30885 4.45771,-3.6784 4.43003,-6.61652 -0.0388,-4.11587 -3.1088,-7.22328 -7.1364,-7.22328 -2.11956,0 -3.56727,0.60889 -5.16364,2.17177 -2.24518,2.19807 -2.75398,5.43897 -1.30101,8.28704 0.71312,1.39782 2.52137,3.00905 3.96214,3.53045 1.49707,0.54176 3.84003,0.47454 5.20888,-0.14946 z" + style="fill:#000000" /> + <path + id="path4201-1" + d="m 39.434334,171.15983 4.32657,-4.3343 7.06956,-2.42737 c 3.88825,-1.33505 8.72285,-2.99587 10.74354,-3.6907 l 3.674,-1.26333 -3.524,-0.1726 c -8.24183,-0.40367 -12.98778,-4.00671 -14.33634,-10.88389 -0.79628,-4.06078 -1.12887,-17.29805 -0.83016,-33.04122 0.15338,-8.08375 0.16617,-15.41641 0.0284,-16.29481 -0.13775,-0.8784 -0.53527,-2.42011 -0.88339,-3.42602 -1.22247,-3.53243 -0.33996,-11.90828 1.8577,-17.63146 0.34848,-0.9075 1.93434,-4.215 3.52415,-7.35 4.15849,-8.2003 4.50458,-8.94188 4.89292,-10.4841 0.45865,-1.82145 0.21161,-5.43531 -0.4625,-6.7659 -0.66625,-1.31505 -2.15695,-2.91616 -3.24622,-3.48662 -1.29885,-0.68024 -2.61568,0.12202 -4.6864,2.85512 -3.42153,4.51599 -14.00135,19.44095 -15.73191,22.19301 -3.74551,5.95636 -5.955584,11.16496 -7.972204,18.78849 -0.6547,2.475 -1.88525,6.9975 -2.73456,10.05 -0.84931,3.0525 -2.71404,10.15792 -4.14385,15.78983 L 14.4,129.82379 9.75,135.01698 c -2.5575,2.85626 -5.7975,6.46371 -7.2,8.01657 -1.4025,1.55286 -2.55,2.97543 -2.55,3.16127 0,0.33546 34.499554,29.29931 34.899134,29.29931 0.11475,0 2.15559,-1.95044 4.53519,-4.3343 z m 93.865056,-16.38777 c 1.25762,-0.62844 2.20557,-1.3788 2.91402,-2.30663 2.08931,-2.73629 1.95034,2.36868 1.86433,-68.48249 l -0.0777,-64.03881 -0.66066,-1.23494 c -1.0152,-1.89767 -1.99201,-2.91087 -3.73952,-3.87887 l -1.59982,-0.88619 -37.783856,-0.0796 c -42.45592,-0.0894 -39.40239,-0.2483 -42.11646,2.19188 -0.87544,0.78709 -1.75715,1.95946 -2.18393,2.90385 -0.71264,1.57698 -0.71613,1.63839 -0.80561,14.20405 l -0.0899,12.62022 1.79817,-0.13007 c 1.42577,-0.10313 2.08143,0.007 3.16601,0.5321 2.01294,0.97445 3.93993,2.89871 5.11476,5.10753 l 1.03717,1.95 0.007,-12.825 0.007,-12.825 33.6,0 33.599986,0 0,51.3 0,51.3 -33.598716,0 -33.59874,0 -0.0763,-34.425 c -0.073,-32.96021 -0.0982,-34.36117 -0.59098,-32.925 -0.28309,0.825 -1.80562,3.9975 -3.3834,7.05 -5.49252,10.62624 -5.40494,9.86009 -5.39597,47.20335 0.007,27.62122 0.12358,29.95084 1.66204,33.10906 1.07144,2.19949 2.71143,3.71042 5.05823,4.66019 l 1.67381,0.6774 36.1677,0.0797 36.167676,0.0797 1.864,-0.93145 z m -42.399376,-5.03813 c -2.87119,-1.30885 -4.45771,-3.6784 -4.43003,-6.61652 0.0388,-4.11587 3.1088,-7.22328 7.1364,-7.22328 2.11956,0 3.56727,0.60889 5.16364,2.17177 2.245176,2.19807 2.753976,5.43897 1.301006,8.28704 -0.713116,1.39782 -2.521366,3.00905 -3.962136,3.53045 -1.49707,0.54176 -3.84003,0.47454 -5.20888,-0.14946 z" + style="fill:#000000" /> + <path + id="rect4270" + d="m 247.25369,75.97921 4.73637,0 c 13.16497,0 23.76348,10.598514 23.76348,23.763485 l 0,32.174615 c 0,13.16497 -10.59851,23.76348 -23.76348,23.76348 l -4.73637,0 c -13.16497,0 -23.76349,-10.59851 -23.76349,-23.76348 l 0,-32.174615 c 0,-13.164971 10.59852,-23.763485 23.76349,-23.763485 z" + style="fill:#0a3d91" /> + <path + id="path4272" + d="m 236.31105,102.92749 24.90674,25.07007 -12.00423,14.53574 0,-51.936691 12.00423,13.882451 -24.90674,24.41678" + style="fill:none;stroke:#ffffff;stroke-width:4.32805729" /> + <path + id="path4844" + d="m 143.67921,27.5571 c -1.59043,2.623831 0.18153,5.574737 2.78461,6.642714 2.69504,1.572445 6.1706,4.987176 9.14793,2.232151 2.23313,-2.039515 0.60129,-5.727894 -2.04109,-6.67035 -3.06433,-1.676733 -6.55172,-5.514807 -9.89145,-2.204515 z M 351.7046,27.12937 c -2.76779,1.960623 -7.06819,2.694997 -8.37782,6.042717 -0.64195,2.73095 1.93572,4.99255 4.58419,4.426453 3.2021,-1.637914 7.05658,-2.8424 9.17849,-5.94769 0.56931,-2.60435 -1.49324,-5.35066 -4.26769,-4.745697 -0.41558,-0.107679 -0.76003,0.03505 -1.11717,0.224217 z m -26.76172,13.17187 c -2.93431,1.708015 -7.32039,1.922759 -8.93076,5.153004 -0.90775,2.654328 1.43202,5.159236 4.12365,4.861044 3.35587,-1.304271 7.31954,-2.112696 9.73662,-5.002268 0.81368,-2.537666 -0.97658,-5.469583 -3.79644,-5.128908 -0.4035,-0.14574 -0.75969,-0.03824 -1.13307,0.117128 z m -155.23633,2.46289 c -1.21948,2.711869 0.75683,5.460507 3.4437,6.14538 2.85847,1.080772 6.66937,4.11785 9.31224,1.23392 2.3151,-2.03652 0.33929,-5.835383 -2.40983,-6.41823 -3.32833,-1.175814 -7.38479,-4.713633 -10.34611,-0.96107 z m 127.27344,7.61719 c -3.12289,1.309174 -7.49226,0.970678 -9.49244,3.970097 -1.23184,2.518748 0.7727,5.298264 3.48037,5.339749 3.48706,-0.907308 7.56742,-1.1128 10.30314,-3.739116 1.11397,-2.422222 -0.31199,-5.546068 -3.1516,-5.551016 -0.3827,-0.195662 -0.75023,-0.126964 -1.13947,-0.01971 z m -97.49023,1.54492 c -2.22858,1.461838 -2.68005,4.865948 -0.27553,6.376909 2.5869,1.470583 5.91459,1.954941 8.83971,2.495346 2.78485,0.332188 4.74603,-2.479173 3.89118,-5.048668 -2.04264,-3.279676 -6.47206,-2.73364 -9.71704,-4.089227 -0.91277,0.08855 -1.82555,0.177093 -2.73832,0.26564 z m 68.51367,4.50782 c -3.27623,0.788856 -7.46081,-0.187875 -9.93635,2.381992 -1.64972,2.268076 -0.15709,5.353662 2.50432,5.86185 3.61172,-0.292365 7.71764,0.09072 10.84009,-2.093962 1.46245,-2.227649 0.52336,-5.531725 -2.28478,-5.959415 -0.34949,-0.249225 -0.72211,-0.239347 -1.12328,-0.190465 z m -39.44922,1.41796 c -1.93309,1.83595 -1.76537,5.266611 0.87081,6.321491 2.80857,0.988807 6.17065,0.846733 9.1444,0.861366 2.79909,-0.172766 4.22635,-3.289835 2.92376,-5.664738 -2.60365,-2.851635 -6.84699,-1.541752 -10.29251,-2.269899 -0.88215,0.250593 -1.76431,0.501187 -2.64646,0.75178 z" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0a3d91;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:7.55000019;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:7.55, 22.65;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> +</svg> diff --git a/mailbox-android/artwork/empty_state_blog.svg b/mailbox-android/artwork/empty_state_blog.svg new file mode 100644 index 0000000000000000000000000000000000000000..eb1cd25c747ec817e8444810054ece25d0a638b3 --- /dev/null +++ b/mailbox-android/artwork/empty_state_blog.svg @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="162" + height="156" + viewBox="0 0 162 156" + fill="none" + version="1.1" + id="svg16" + sodipodi:docname="No-Posts.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata22"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs20" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="754" + inkscape:window-height="480" + id="namedview18" + showgrid="false" + inkscape:zoom="1.5128205" + inkscape:cx="81" + inkscape:cy="78" + inkscape:window-x="0" + inkscape:window-y="20" + inkscape:window-maximized="0" + inkscape:current-layer="svg16" /> + <rect + width="80.9997" + height="78" + fill="black" + fill-opacity="0" + transform="scale(2)" + id="rect2" /> + <rect + width="80.9997" + height="78" + fill="black" + fill-opacity="0" + transform="scale(2)" + id="rect4" /> + <path + d="M140.87 53.647H91.5654V64.2352H140.87V53.647Z" + fill="white" + fill-opacity="0.6" + id="path6" /> + <path + d="M140.869 99.5292V88.9409H115.512L126.077 99.5292H140.869Z" + fill="white" + fill-opacity="0.6" + id="path8" /> + <path + d="M140.869 71.2939H97.9038L108.469 81.8822H140.869V71.2939Z" + fill="white" + fill-opacity="0.6" + id="path10" /> + <path + d="M147.912 14.8232H41.5557L84.5209 57.8821V28.9409H147.912V120.706H147.208L157.773 131.294C160.59 128.47 161.999 124.941 161.999 120.706V28.9409C161.999 21.1762 155.66 14.8232 147.912 14.8232Z" + fill="white" + fill-opacity="0.6" + id="path12" /> + <path + d="M129.6 120.706L84.5217 75.5294L23.9478 14.8235L9.15652 0L0 9.17647L10.5652 19.7647C8.45217 21.8824 7.04348 25.4118 7.04348 28.9412V120.706C7.04348 128.471 13.3826 134.824 21.1304 134.824H125.374L146.504 156L155.661 146.824L143.687 134.824L129.6 120.706ZM84.5217 120.706V93.8824L111.287 120.706H84.5217Z" + fill="white" + fill-opacity="0.6" + id="path14" /> +</svg> diff --git a/mailbox-android/artwork/empty_state_contact_list.svg b/mailbox-android/artwork/empty_state_contact_list.svg new file mode 100644 index 0000000000000000000000000000000000000000..efc3f10baf1c46444b8cac0b4cd2769346fcfad5 --- /dev/null +++ b/mailbox-android/artwork/empty_state_contact_list.svg @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="164" + height="164" + viewBox="0 0 164 164" + fill="none" + version="1.1" + id="svg12" + sodipodi:docname="empty_state_contact_list.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata18"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs16" /> + <sodipodi:namedview + pagecolor="#000000" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1020" + id="namedview14" + showgrid="false" + inkscape:zoom="1.4390244" + inkscape:cx="81.305085" + inkscape:cy="109.79661" + inkscape:window-x="1440" + inkscape:window-y="24" + inkscape:window-maximized="0" + inkscape:current-layer="svg12" /> + <path + style="clip-rule:evenodd;display:inline;fill:#ffffff;fill-rule:evenodd" + d="M 27.333984 0 L 27.333984 13.666016 L 136.66797 13.666016 L 136.66797 0 L 27.333984 0 z M 27.333984 27.333984 C 19.817284 27.333984 13.666016 33.4834 13.666016 41 L 13.666016 123 C 13.666016 130.517 19.817284 136.66797 27.333984 136.66797 L 136.66797 136.66797 C 144.18397 136.66797 150.33203 130.517 150.33203 123 L 150.33203 41 C 150.33203 33.4834 144.18397 27.333984 136.66797 27.333984 L 27.333984 27.333984 z M 82.150391 44.757812 C 89.592295 44.757812 95.348492 46.476807 99.419922 49.914062 C 103.52467 53.351338 105.57617 58.23949 105.57617 64.580078 C 105.57617 67.349967 105.0272 69.869409 103.92578 72.138672 C 102.82458 74.407935 101.05521 76.728225 98.619141 79.097656 L 92.863281 84.453125 C 91.227921 86.021639 90.093094 87.640125 89.458984 89.308594 C 88.824874 90.943745 88.475053 93.030171 88.408203 95.566406 L 74.091797 95.566406 C 74.091797 90.694273 74.640917 86.855942 75.742188 84.052734 C 76.843435 81.216209 78.63001 78.762286 81.099609 76.693359 C 83.568995 74.624218 85.436853 72.739109 86.705078 71.037109 C 88.006403 69.30179 88.658203 67.400958 88.658203 65.332031 C 88.658203 60.292857 86.488795 57.771484 82.150391 57.771484 C 80.1481 57.771484 78.529614 58.506262 77.294922 59.974609 C 76.060186 61.442955 75.40854 63.42881 75.341797 65.931641 L 58.423828 65.931641 C 58.490468 59.25736 60.592402 54.067509 64.730469 50.363281 C 68.868538 46.625672 74.675257 44.757813 82.150391 44.757812 z M 81.398438 102.32422 C 84.068159 102.32422 86.287795 103.12473 88.056641 104.72656 C 89.858601 106.29508 90.759766 108.31381 90.759766 110.7832 C 90.759766 113.2528 89.858601 115.28879 88.056641 116.89062 C 86.287795 118.45914 84.068159 119.24219 81.398438 119.24219 C 78.728717 119.24219 76.493467 118.45914 74.691406 116.89062 C 72.922705 115.28879 72.039062 113.2528 72.039062 110.7832 C 72.039062 108.31381 72.922705 106.29508 74.691406 104.72656 C 76.493467 103.12473 78.728716 102.32422 81.398438 102.32422 z M 27.333984 150.33203 L 27.333984 164 L 136.66797 164 L 136.66797 150.33203 L 27.333984 150.33203 z " + id="path8" /> +</svg> diff --git a/mailbox-android/artwork/empty_state_forum_list.svg b/mailbox-android/artwork/empty_state_forum_list.svg new file mode 100644 index 0000000000000000000000000000000000000000..101eca192d5d85bb09530fc12456248d1b8de966 --- /dev/null +++ b/mailbox-android/artwork/empty_state_forum_list.svg @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="148" + height="148" + viewBox="0 0 148 148" + fill="none" + version="1.1" + id="svg12" + sodipodi:docname="No-Forums.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata18"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs16" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1366" + inkscape:window-height="720" + id="namedview14" + showgrid="false" + inkscape:zoom="1.5945946" + inkscape:cx="74" + inkscape:cy="74" + inkscape:window-x="0" + inkscape:window-y="20" + inkscape:window-maximized="1" + inkscape:current-layer="svg12" /> + <rect + width="74" + height="74" + fill="black" + fill-opacity="0" + transform="scale(2)" + id="rect2" /> + <rect + width="74" + height="74" + fill="black" + fill-opacity="0" + transform="scale(2)" + id="rect4" /> + <path + d="M107.266 74.6791C111.34 74.6791 114.055 71.9635 114.055 67.8901V6.78901C114.055 2.7156 111.34 0 107.266 0H24.4404L99.1194 74.6791H107.266Z" + fill="white" + fill-opacity="0.6" + id="path6" /> + <path + d="M141.211 27.156H127.633V88.2571H112.697L148 123.56V33.945C148 29.8716 144.606 27.156 141.211 27.156Z" + fill="white" + fill-opacity="0.6" + id="path8" /> + <path + d="M8.8257 1.35742L0 10.1831L12.2202 22.4033V101.835L39.3762 74.6787H64.4955L78.0735 88.2567H39.3762V101.835C39.3762 105.908 42.0918 108.624 46.1652 108.624H98.4405L137.817 148L146.642 139.174L8.8257 1.35742Z" + fill="white" + fill-opacity="0.6" + id="path10" /> +</svg> diff --git a/mailbox-android/artwork/empty_state_group_list.svg b/mailbox-android/artwork/empty_state_group_list.svg new file mode 100644 index 0000000000000000000000000000000000000000..58e0218d74556f218eab8a1d1d0279eab7ab0050 --- /dev/null +++ b/mailbox-android/artwork/empty_state_group_list.svg @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="172" + height="140" + viewBox="0 0 172 140" + fill="none" + version="1.1" + id="svg14" + sodipodi:docname="No-Groups.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata20"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs18" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="754" + inkscape:window-height="480" + id="namedview16" + showgrid="false" + inkscape:zoom="1.6857143" + inkscape:cx="86" + inkscape:cy="70" + inkscape:window-x="0" + inkscape:window-y="20" + inkscape:window-maximized="0" + inkscape:current-layer="svg14" /> + <rect + width="85.9999" + height="70" + fill="black" + fill-opacity="0" + transform="scale(2)" + id="rect2" /> + <rect + width="85.9999" + height="70" + fill="black" + fill-opacity="0" + transform="scale(2)" + id="rect4" /> + <path + d="M125.091 103.444L71.9274 50.5556L38.3092 17.1111L21.1091 0L10.9455 10.1111L31.2728 30.3333C31.2728 31.8889 31.2728 32.6667 31.2728 34.2222C31.2728 47.4444 41.4365 57.5556 54.7274 57.5556C56.291 57.5556 57.0729 57.5556 58.6365 56.7778L78.182 76.2222C69.582 74.6667 60.982 73.1111 54.7274 73.1111C36.7455 73.1111 0 82.4444 0 100.333V119.778H109.455V107.333L142.291 140L152.455 129.889L142.291 119.778L125.091 103.444Z" + fill="white" + fill-opacity="0.6" + id="path6" /> + <path + d="M117.273 57.5549C130.227 57.5549 140.728 47.1082 140.728 34.2215C140.728 21.3349 130.227 10.8882 117.273 10.8882C104.319 10.8882 93.8184 21.3349 93.8184 34.2215C93.8184 47.1082 104.319 57.5549 117.273 57.5549Z" + fill="white" + fill-opacity="0.6" + id="path8" /> + <path + d="M78.1819 34.2215C78.1819 20.9993 68.0182 10.8882 54.7273 10.8882C53.9455 10.8882 53.1637 10.8882 52.3818 10.8882L78.1819 36.5548C78.1819 35.7771 78.1819 34.9993 78.1819 34.2215Z" + fill="white" + fill-opacity="0.6" + id="path10" /> + <path + d="M117.272 73.1104C116.49 73.1104 115.709 73.1104 114.927 73.1104L161.836 119.777H172V100.333C172 82.4437 135.254 73.1104 117.272 73.1104Z" + fill="white" + fill-opacity="0.6" + id="path12" /> +</svg> diff --git a/mailbox-android/artwork/ic_emoji_emoticons.svg b/mailbox-android/artwork/ic_emoji_emoticons.svg new file mode 100644 index 0000000000000000000000000000000000000000..7ef60e16b09175f557649d9639d94107f41b7d78 --- /dev/null +++ b/mailbox-android/artwork/ic_emoji_emoticons.svg @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + width="24" + height="24" + viewBox="0 0 24 24" + sodipodi:docname="ic_emoji_emoticons.svg"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1021" + id="namedview4" + showgrid="false" + inkscape:zoom="4.6354778" + inkscape:cx="47.926788" + inkscape:cy="24.127496" + inkscape:window-x="1440" + inkscape:window-y="23" + inkscape:window-maximized="0" + inkscape:current-layer="svg2" /> + <path + style="fill:#000000;fill-opacity:1" + d="m 15.483903,3.8556996 c -0.661546,0.040406 -0.536253,1.2125273 -0.08054,1.6240791 1.361771,1.4519837 1.747379,3.5080793 1.895646,5.4253553 0.109142,2.216286 -0.0846,4.555699 -1.171466,6.533591 -0.361828,0.731167 -1.339597,1.273078 -1.15283,2.195835 0.287109,1.037426 1.187031,0.242862 1.620751,-0.183708 1.991711,-1.742024 2.867744,-4.428018 2.93133,-7.013492 0.02009,-1.918049 -0.231841,-3.9213035 -1.212735,-5.6044037 -0.664187,-1.0906817 -1.39072,-2.2339438 -2.497355,-2.9193489 -0.127976,-0.045915 -0.238296,-0.06368 -0.332802,-0.057908 z M 5.9118212,7.6583077 A 1.3631614,1.3631614 0 0 0 4.54866,9.0214691 1.3631614,1.3631614 0 0 0 5.9118212,10.38463 1.3631614,1.3631614 0 0 0 7.2749824,9.0214691 1.3631614,1.3631614 0 0 0 5.9118212,7.6583077 Z m 3.0731032,3.0012183 0,2.044742 4.7710646,0 0,-2.044742 -4.7710646,0 z m -3.1496485,3.471136 a 1.3631614,1.3631614 0 0 0 -1.3631612,1.363161 1.3631614,1.3631614 0 0 0 1.3631612,1.363161 1.3631614,1.3631614 0 0 0 1.3631612,-1.363161 1.3631614,1.3631614 0 0 0 -1.3631612,-1.363161 z" + id="path4142" + inkscape:connector-curvature="0" /> +</svg> diff --git a/mailbox-android/artwork/logo_circle.svg b/mailbox-android/artwork/logo_circle.svg new file mode 100644 index 0000000000000000000000000000000000000000..3acaa5ea9506680685a7d2073053d2b63f4245e7 --- /dev/null +++ b/mailbox-android/artwork/logo_circle.svg @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Ebene_1" + x="0px" + y="0px" + viewBox="0 0 330.00001 330.00001" + xml:space="preserve" + inkscape:version="0.91 r13725" + sodipodi:docname="logo_circle.svg" + width="330" + height="330"><metadata + id="metadata61"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs59" /><sodipodi:namedview + pagecolor="#000000" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1021" + id="namedview57" + showgrid="false" + inkscape:zoom="1.4333435" + inkscape:cx="137.64067" + inkscape:cy="223.06028" + inkscape:window-x="1440" + inkscape:window-y="23" + inkscape:window-maximized="0" + inkscape:current-layer="Ebene_1" /><style + type="text/css" + id="style3"> + .st0{fill:#FFFFFF;} + .st1{display:none;fill:#87C214;} + .st2{fill:#87C214;} + .st3{display:none;fill:#FFFFFF;} + .st4{fill:#95D220;} + .st5{display:none;fill:#95D220;} +</style><circle + style="fill:#ffffff" + id="circle7" + cy="165" + cx="165" + class="st0" + r="165" /><g + id="g4214" + transform="translate(0.2999939,1.2000061)"><g + id="g9"><g + id="g11"><rect + x="94" + y="93.800003" + class="st1" + width="43.700001" + height="43.700001" + id="rect13" + style="display:none;fill:#87c214" /><path + class="st2" + d="M 94,144.5 94,264 c 0,9.7 7.9,17.7 17.7,17.7 l 8.3,0 c 9.7,0 17.7,-8 17.7,-17.7 l 0,-119.5 -43.7,0 z" + id="path15" + inkscape:connector-curvature="0" + style="fill:#87c214" /><path + class="st2" + d="m 137.7,86.8 0,-22.5 c 0,-9.7 -8,-17.7 -17.7,-17.7 l -8.3,0 C 102,46.6 94,54.6 94,64.3 l 0,22.5 43.7,0 z" + id="path17" + inkscape:connector-curvature="0" + style="fill:#87c214" /></g><path + class="st3" + d="m 120,46.7 c 9.7,0 17.7,8 17.7,17.7 l 0,199.6 c 0,9.7 -8,17.7 -17.7,17.7 l -8.3,0 C 102,281.7 94,273.7 94,264 L 94,64.3 c 0,-9.7 7.9,-17.7 17.7,-17.7 l 8.3,0 m 0,-6.9 -8.3,0 C 98.1,39.7 87,50.7 87,64.3 L 87,264 c 0,13.6 11.1,24.7 24.7,24.7 l 8.3,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-199.7 C 144.7,50.7 133.6,39.7 120,39.7 l 0,0 z" + id="path19" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /></g><g + id="g21"><g + id="g23"><path + class="st2" + d="m 234.7,183.8 0,-119.5 c 0,-9.7 -7.9,-17.7 -17.7,-17.7 l -8.3,0 c -9.7,0 -17.7,8 -17.7,17.7 l 0,119.5 43.7,0 z" + id="path25" + inkscape:connector-curvature="0" + style="fill:#87c214" /><rect + x="191" + y="190.8" + class="st1" + width="43.700001" + height="43.700001" + id="rect27" + style="display:none;fill:#87c214" /><path + class="st2" + d="m 191,241.5 0,22.5 c 0,9.7 8,17.7 17.7,17.7 l 8.3,0 c 9.7,0 17.7,-8 17.7,-17.7 l 0,-22.5 -43.7,0 z" + id="path29" + inkscape:connector-curvature="0" + style="fill:#87c214" /></g><path + class="st3" + d="m 217,46.7 c 9.7,0 17.7,8 17.7,17.7 l 0,199.6 c 0,9.7 -7.9,17.7 -17.7,17.7 l -8.3,0 c -9.7,0 -17.7,-8 -17.7,-17.7 l 0,-199.7 c 0,-9.7 8,-17.7 17.7,-17.7 l 8.3,0 m 0,-6.9 -8.3,0 C 195.1,39.7 184,50.8 184,64.4 l 0,199.6 c 0,13.6 11.1,24.7 24.7,24.7 l 8.3,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-199.7 C 241.7,50.7 230.6,39.7 217,39.7 l 0,0 z" + id="path31" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /></g><g + id="g33"><g + id="g35"><path + class="st4" + d="m 87,190.8 -22.5,0 c -9.7,0 -17.7,7.9 -17.7,17.7 l 0,8.3 c 0,9.7 7.9,17.7 17.7,17.7 l 22.5,0 0,-43.7 z" + id="path37" + inkscape:connector-curvature="0" + style="fill:#95d220" /><rect + x="94" + y="190.8" + class="st5" + width="43.700001" + height="43.700001" + id="rect39" + style="display:none;fill:#95d220" /><path + class="st4" + d="m 264.2,190.8 -119.5,0 0,43.7 119.5,0 c 9.7,0 17.7,-8 17.7,-17.7 l 0,-8.3 c -0.1,-9.7 -8,-17.7 -17.7,-17.7 z" + id="path41" + inkscape:connector-curvature="0" + style="fill:#95d220" /></g><path + class="st3" + d="m 264.2,190.8 c 9.7,0 17.7,7.9 17.7,17.7 l 0,8.3 c 0,9.7 -8,17.7 -17.7,17.7 l -199.7,0 c -9.7,0 -17.7,-8 -17.7,-17.7 l 0,-8.3 c 0,-9.7 7.9,-17.7 17.7,-17.7 l 199.7,0 m 0,-7 -199.7,0 c -13.6,0 -24.7,11.1 -24.7,24.7 l 0,8.3 c 0,13.6 11.1,24.7 24.7,24.7 l 199.7,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-8.3 c -0.1,-13.6 -11.1,-24.7 -24.7,-24.7 l 0,0 z" + id="path43" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /></g><g + id="g45"><g + id="g47"><rect + x="191" + y="93.800003" + class="st5" + width="43.700001" + height="43.700001" + id="rect49" + style="display:none;fill:#95d220" /><path + class="st4" + d="m 184,93.8 -119.5,0 c -9.7,0 -17.7,7.9 -17.7,17.7 l 0,8.3 c 0,9.7 7.9,17.7 17.7,17.7 l 119.5,0 0,-43.7 z" + id="path51" + inkscape:connector-curvature="0" + style="fill:#95d220" /><path + class="st4" + d="m 264.2,93.8 -22.5,0 0,43.7 22.5,0 c 9.7,0 17.7,-7.9 17.7,-17.7 l 0,-8.3 c -0.1,-9.7 -8,-17.7 -17.7,-17.7 z" + id="path53" + inkscape:connector-curvature="0" + style="fill:#95d220" /></g><path + class="st3" + d="m 264.2,93.8 c 9.7,0 17.7,7.9 17.7,17.7 l 0,8.3 c 0,9.7 -8,17.7 -17.7,17.7 l -199.7,0 c -9.7,0 -17.7,-7.9 -17.7,-17.7 l 0,-8.3 c 0,-9.7 7.9,-17.7 17.7,-17.7 l 199.7,0 m 0,-7 -199.7,0 c -13.6,0 -24.7,11.1 -24.7,24.7 l 0,8.3 c 0,13.6 11.1,24.7 24.7,24.7 l 199.7,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-8.3 C 288.8,97.9 277.8,86.8 264.2,86.8 l 0,0 z" + id="path55" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /></g></g></svg> \ No newline at end of file diff --git a/mailbox-android/artwork/logo_horizontal_white.svg b/mailbox-android/artwork/logo_horizontal_white.svg new file mode 100644 index 0000000000000000000000000000000000000000..d3835aae678c827d88b1e9bab35f1444affc8d43 --- /dev/null +++ b/mailbox-android/artwork/logo_horizontal_white.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Ebene_1" + x="0px" + y="0px" + xml:space="preserve" + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="logo_horizontal_white.svg" + width="138" + height="50"><metadata + id="metadata71"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs + id="defs69" /><sodipodi:namedview + pagecolor="#000000" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1020" + id="namedview67" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:zoom="5.640316" + inkscape:cx="47.227033" + inkscape:cy="7.5801079" + inkscape:window-x="1440" + inkscape:window-y="24" + inkscape:window-maximized="0" + inkscape:current-layer="Ebene_1" /><style + type="text/css" + id="style3"> + .st0{display:none;fill:#87C214;} + .st1{fill:#87C214;} + .st2{display:none;fill:#FFFFFF;} + .st3{fill:#95D220;} + .st4{display:none;fill:#95D220;} + .st5{fill:#FFFFFF;} +</style><path + style="fill:#ffffff" + d="m 57.097656,30.69922 0,19.30078 9.06836,0 c 4.22557,0 6.474893,-2.12355 6.496093,-5.47852 0,-2.14464 -1.017672,-3.78004 -3.013671,-4.67187 l 0,-0.041 c 1.507609,-0.9343 2.166015,-2.10331 2.166015,-3.9082 0,-2.73919 -1.848098,-5.20117 -5.861328,-5.20117 l -8.855469,0 z m 18.75,0 0,19.30078 2.271485,0 0,-7.72852 -0.232422,-0.23437 4.585937,0 c 2.54808,0 4.012966,0.91391 4.947266,2.88867 L 89.820312,50 92.367188,50 89.4375,43.96875 c -0.63702,-1.35898 -1.614284,-2.20763 -2.527344,-2.58984 l 0,-0.043 c 2.1234,-0.55208 3.865235,-2.42042 3.865235,-4.94727 0,-3.80089 -2.951713,-5.68945 -6.476563,-5.68945 l -8.451172,0 z m 18.876953,0 0,19.30078 2.273438,0 0,-19.30078 -2.273438,0 z m 13.419921,0 L 99.650391,50 l 2.484379,0 2.03906,-4.65039 -0.12695,-0.23438 10.57421,0 -0.12695,0.23438 2.03906,4.65039 2.48438,0 -8.47266,-19.30078 -2.40039,0 z m 13.33594,0 0,19.30078 2.27148,0 0,-7.72852 -0.23437,-0.23437 4.58789,0 c 2.54808,0 4.01296,0.91391 4.94726,2.88867 L 135.45117,50 138,50 135.07031,43.96875 c -0.63702,-1.35898 -1.61427,-2.20763 -2.52734,-2.58984 l 0,-0.043 c 2.12341,-0.55208 3.86523,-2.42042 3.86523,-4.94727 0,-3.80089 -2.95171,-5.68945 -6.47656,-5.68945 l -8.45117,0 z m -62.322267,2.14453 6.560547,0 c 2.46315,0 3.759766,0.9967 3.759766,3.03516 0,1.71996 -0.999336,3.10156 -3.759766,3.10156 l -6.560547,0 0.234375,-0.23438 0,-5.66992 -0.234375,-0.23242 z m 18.728516,0 6.433593,0 c 2.378211,0 4.14091,0.97535 4.16211,3.52344 0,2.03846 -1.634356,3.5039 -4.416016,3.5039 l -6.179687,0 0.232422,-0.23242 0,-6.5625 -0.232422,-0.23242 z m 45.652341,0 6.4336,0 c 2.35698,0 4.14062,0.97535 4.14062,3.52344 0,2.03846 -1.61288,3.5039 -4.39453,3.5039 l -6.17969,0 0.23438,-0.23242 0,-6.5625 -0.23438,-0.23242 z m -14.20508,0.21094 0.043,0 0.57227,1.93359 3.39844,7.75 0.23242,0.23242 -8.4707,0 0.23242,-0.23242 3.39843,-7.75 0.59375,-1.93359 z m -50.197261,8.07031 7.007812,0 c 2.84536,0 4.16211,1.3153 4.16211,3.375 0,2.14464 -1.189095,3.33398 -4.140625,3.33398 l -7.029297,0 0.234375,-0.23437 0,-6.24219 -0.234375,-0.23242 z" + id="path57" + inkscape:connector-curvature="0" /><g + id="g4770" + transform="matrix(0.21276595,0,0,0.21276595,32.24269,18.624329)"><path + id="path13-3" + d="m -86.640255,-87.534339 c -9.7,0 -17.701175,7.999219 -17.701175,17.699219 l 0,22.5 43.601565,0 0,-22.5 c 0,-9.7 -7.901562,-17.699219 -17.601562,-17.699219 l -8.298828,0 z m 96.999999,0 c -9.69999995,0 -17.7011699,7.999219 -17.7011699,17.699219 l 0,119.500001 43.6015599,0 0,-119.500001 c 0,-9.7 -7.90156,-17.699219 -17.60156,-17.699219 l -8.29883,0 z m -114.701174,97.800781 0,119.499998 c 0,9.7 7.901175,17.69922 17.701175,17.69922 l 8.298828,0 c 9.7,0 17.701172,-7.99922 17.701172,-17.69922 l 0,-119.499998 -43.701175,0 z m 97.0000041,96.999998 0,22.5 c 0,9.7 8.00116995,17.69922 17.7011699,17.69922 l 8.29883,0 c 9.7,0 17.70117,-7.99922 17.70117,-17.69922 l 0,-22.5 -43.7011699,0 z" + style="fill:#87c214" + inkscape:connector-curvature="0" /><path + id="path35" + d="m -133.84143,-40.33512 c -9.7,0 -17.69922,7.901172 -17.69922,17.701172 l 0,8.298828 c 0,9.7000005 7.89922,17.7011725 17.69922,17.7011725 l 119.500004,0 0,-43.7011725 -119.500004,0 z m 177.101564,0 0,43.7011725 22.5,0 c 9.7,0 17.69922,-7.901172 17.69922,-17.7011725 l 0,-8.298828 c 0,-9.8 -7.99922,-17.701172 -17.69922,-17.701172 l -22.5,0 z M -133.84143,56.664881 c -9.7,0 -17.69922,7.90117 -17.69922,17.70117 l 0,8.29883 c 0,9.7 7.89922,17.701169 17.69922,17.701169 l 22.5,0 0,-43.701169 -22.5,0 z m 80.101565,0 0,43.701169 119.499999,0 c 9.7,0 17.69922,-8.001169 17.69922,-17.701169 l 0,-8.29883 c 0,-9.8 -7.99922,-17.70117 -17.69922,-17.70117 l -119.499999,0 z" + style="fill:#95d220" + inkscape:connector-curvature="0" /></g></svg> \ No newline at end of file diff --git a/mailbox-android/artwork/logo_no_text.svg b/mailbox-android/artwork/logo_no_text.svg new file mode 100644 index 0000000000000000000000000000000000000000..d093809b07a9921362a339678b959acc89e3e66c --- /dev/null +++ b/mailbox-android/artwork/logo_no_text.svg @@ -0,0 +1,154 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Ebene_1" + x="0px" + y="0px" + viewBox="0 0 235 234.99999" + xml:space="preserve" + inkscape:version="0.91 r13725" + sodipodi:docname="logo_no_text.svg" + width="235" + height="235"><metadata + id="metadata71"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs69" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1021" + id="namedview67" + showgrid="false" + inkscape:zoom="2" + inkscape:cx="42.80241" + inkscape:cy="93.181868" + inkscape:window-x="1443" + inkscape:window-y="23" + inkscape:window-maximized="0" + inkscape:current-layer="Ebene_1" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" /><style + type="text/css" + id="style3"> + .st0{display:none;fill:#87C214;} + .st1{fill:#87C214;} + .st2{display:none;fill:#FFFFFF;} + .st3{fill:#95D220;} + .st4{display:none;fill:#95D220;} +</style><g + id="g5" + transform="translate(-0.5,0)"><g + id="g7"><g + id="g9"><rect + x="47.700001" + y="47.200001" + class="st0" + width="43.700001" + height="43.700001" + id="rect11" + style="display:none;fill:#87c214" /><path + class="st1" + d="m 47.7,97.8 0,119.5 c 0,9.7 7.9,17.7 17.7,17.7 l 8.3,0 c 9.7,0 17.7,-8 17.7,-17.7 l 0,-119.5 -43.7,0 z" + id="path13" + inkscape:connector-curvature="0" + style="fill:#87c214" /><path + class="st1" + d="m 91.3,40.2 0,-22.5 C 91.3,8 83.4,0 73.7,0 L 65.4,0 C 55.7,0 47.7,8 47.7,17.7 l 0,22.5 43.6,0 z" + id="path15" + inkscape:connector-curvature="0" + style="fill:#87c214" /></g><path + class="st2" + d="m 73.7,0 c 9.7,0 17.7,8 17.7,17.7 l 0,199.7 c 0,9.7 -8,17.7 -17.7,17.7 l -8.3,0 c -9.7,0 -17.7,-8 -17.7,-17.7 l 0,-199.7 C 47.7,8 55.6,0 65.3,0 l 8.4,0 m 0,-7 -8.3,0 C 51.7,-7 40.7,4.1 40.7,17.7 l 0,199.7 c 0,13.6 11.1,24.7 24.7,24.7 l 8.3,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-199.7 C 98.3,4.1 87.3,-7 73.7,-7 l 0,0 z" + id="path17" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /></g><g + id="g19"><g + id="g21"><path + class="st1" + d="m 188.3,137.2 0,-119.5 C 188.3,8 180.4,0 170.7,0 l -8.3,0 c -9.7,0 -17.7,8 -17.7,17.7 l 0,119.5 43.6,0 z" + id="path23" + inkscape:connector-curvature="0" + style="fill:#87c214" /><rect + x="144.7" + y="144.2" + class="st0" + width="43.700001" + height="43.700001" + id="rect25" + style="display:none;fill:#87c214" /><path + class="st1" + d="m 144.7,194.8 0,22.5 c 0,9.7 8,17.7 17.7,17.7 l 8.3,0 c 9.7,0 17.7,-8 17.7,-17.7 l 0,-22.5 -43.7,0 z" + id="path27" + inkscape:connector-curvature="0" + style="fill:#87c214" /></g><path + class="st2" + d="m 170.7,0 c 9.7,0 17.7,8 17.7,17.7 l 0,199.7 c 0,9.7 -7.9,17.7 -17.7,17.7 l -8.3,0 c -9.7,0 -17.7,-8 -17.7,-17.7 l 0,-199.7 C 144.7,8 152.7,0 162.4,0 l 8.3,0 m 0,-7 -8.3,0 c -13.6,0 -24.7,11.1 -24.7,24.7 l 0,199.7 c 0,13.6 11.1,24.7 24.7,24.7 l 8.3,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-199.7 C 195.3,4.1 184.3,-7 170.7,-7 l 0,0 z" + id="path29" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /></g><g + id="g31"><g + id="g33"><path + class="st3" + d="m 40.7,144.2 -22.5,0 c -9.7,0 -17.7,7.9 -17.7,17.7 l 0,8.3 c 0,9.7 7.9,17.7 17.7,17.7 l 22.5,0 0,-43.7 z" + id="path35" + inkscape:connector-curvature="0" + style="fill:#95d220" /><rect + x="47.700001" + y="144.2" + class="st4" + width="43.700001" + height="43.700001" + id="rect37" + style="display:none;fill:#95d220" /><path + class="st3" + d="m 217.8,144.2 -119.5,0 0,43.7 119.5,0 c 9.7,0 17.7,-8 17.7,-17.7 l 0,-8.3 c 0,-9.8 -8,-17.7 -17.7,-17.7 z" + id="path39" + inkscape:connector-curvature="0" + style="fill:#95d220" /></g><path + class="st2" + d="m 217.8,144.2 c 9.7,0 17.7,7.9 17.7,17.7 l 0,8.3 c 0,9.7 -8,17.7 -17.7,17.7 l -199.6,0 c -9.7,0 -17.7,-8 -17.7,-17.7 l 0,-8.3 c 0,-9.7 7.9,-17.7 17.7,-17.7 l 199.6,0 m 0,-7 -199.6,0 c -13.6,0 -24.7,11.1 -24.7,24.7 l 0,8.3 c 0,13.6 11.1,24.7 24.7,24.7 l 199.7,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-8.3 c -0.1,-13.7 -11.2,-24.7 -24.8,-24.7 l 0,0 z" + id="path41" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /></g><g + id="g43"><g + id="g45"><rect + x="144.7" + y="47.200001" + class="st4" + width="43.700001" + height="43.700001" + id="rect47" + style="display:none;fill:#95d220" /><path + class="st3" + d="m 137.7,47.2 -119.5,0 C 8.5,47.2 0.5,55.1 0.5,64.9 l 0,8.3 c 0,9.7 7.9,17.7 17.7,17.7 l 119.5,0 0,-43.7 z" + id="path49" + inkscape:connector-curvature="0" + style="fill:#95d220" /><path + class="st3" + d="m 217.8,47.2 -22.5,0 0,43.7 22.5,0 c 9.7,0 17.7,-7.9 17.7,-17.7 l 0,-8.3 c 0,-9.8 -8,-17.7 -17.7,-17.7 z" + id="path51" + inkscape:connector-curvature="0" + style="fill:#95d220" /></g><path + class="st2" + d="m 217.8,47.2 c 9.7,0 17.7,7.9 17.7,17.7 l 0,8.3 c 0,9.7 -8,17.7 -17.7,17.7 l -199.6,0 C 8.5,90.9 0.5,83 0.5,73.2 l 0,-8.3 c 0,-9.7 7.9,-17.7 17.7,-17.7 l 199.6,0 m 0,-7 -199.6,0 c -13.6,0 -24.7,11 -24.7,24.6 l 0,8.3 c 0,13.6 11.1,24.7 24.7,24.7 l 199.7,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-8.3 C 242.5,51.2 231.4,40.2 217.8,40.2 l 0,0 z" + id="path53" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /></g></g></svg> \ No newline at end of file diff --git a/mailbox-android/artwork/logo_vertical_black.svg b/mailbox-android/artwork/logo_vertical_black.svg new file mode 100644 index 0000000000000000000000000000000000000000..89f9b907d9677b32b1709e1af30860c498624385 --- /dev/null +++ b/mailbox-android/artwork/logo_vertical_black.svg @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Ebene_1" + x="0px" + y="0px" + viewBox="0 0 235 309.99999" + xml:space="preserve" + inkscape:version="0.91 r13725" + sodipodi:docname="logo_vertical_black.svg" + width="235" + height="310"><metadata + id="metadata71"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs69" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1021" + id="namedview67" + showgrid="false" + inkscape:zoom="2" + inkscape:cx="44.30241" + inkscape:cy="167.18188" + inkscape:window-x="1440" + inkscape:window-y="23" + inkscape:window-maximized="0" + inkscape:current-layer="Ebene_1" /><style + type="text/css" + id="style3"> + .st0{display:none;fill:#87C214;} + .st1{fill:#87C214;} + .st2{display:none;fill:#FFFFFF;} + .st3{fill:#95D220;} + .st4{display:none;fill:#95D220;} +</style><rect + style="display:none;fill:#87c214" + id="rect11" + height="43.700001" + width="43.700001" + class="st0" + y="47.199989" + x="47.200001" /><path + style="fill:#87c214" + d="M 64.900391 0 C 55.200391 0 47.199219 7.9992183 47.199219 17.699219 L 47.199219 40.199219 L 90.800781 40.199219 L 90.800781 17.699219 C 90.800781 7.9992183 82.899219 -4.7369516e-15 73.199219 0 L 64.900391 0 z M 161.90039 0 C 152.20039 0 144.19922 7.9992183 144.19922 17.699219 L 144.19922 137.19922 L 187.80078 137.19922 L 187.80078 17.699219 C 187.80078 7.9992183 179.89922 -4.7369516e-15 170.19922 0 L 161.90039 0 z M 47.199219 97.800781 L 47.199219 217.30078 C 47.199219 227.00078 55.100391 235 64.900391 235 L 73.199219 235 C 82.899219 235 90.900391 227.00078 90.900391 217.30078 L 90.900391 97.800781 L 47.199219 97.800781 z M 144.19922 194.80078 L 144.19922 217.30078 C 144.19922 227.00078 152.20039 235 161.90039 235 L 170.19922 235 C 179.89922 235 187.90039 227.00078 187.90039 217.30078 L 187.90039 194.80078 L 144.19922 194.80078 z " + id="path13" /><path + class="st2" + d="m 73.2,-1.221e-5 c 9.7,0 17.7,8.00000001 17.7,17.70000021 l 0,199.700002 c 0,9.7 -8,17.7 -17.7,17.7 l -8.3,0 c -9.7,0 -17.7,-8 -17.7,-17.7 l 0,-199.700002 C 47.2,7.9999878 55.1,-1.221e-5 64.8,-1.221e-5 l 8.4,0 m 0,-6.99999999 -8.3,0 c -13.7,0 -24.7,11.1 -24.7,24.7000002 l 0,199.700002 c 0,13.6 11.1,24.7 24.7,24.7 l 8.3,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-199.700002 C 97.8,4.0999878 86.8,-7.0000122 73.2,-7.0000122 l 0,0 z" + id="path17" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /><rect + style="display:none;fill:#87c214" + id="rect25" + height="43.700001" + width="43.700001" + class="st0" + y="144.19998" + x="144.2" /><path + class="st2" + d="m 170.2,-1.221e-5 c 9.7,0 17.7,8.00000001 17.7,17.70000021 l 0,199.700002 c 0,9.7 -7.9,17.7 -17.7,17.7 l -8.3,0 c -9.7,0 -17.7,-8 -17.7,-17.7 l 0,-199.700002 c 0,-9.7000002 8,-17.70000021 17.7,-17.70000021 l 8.3,0 m 0,-6.99999999 -8.3,0 c -13.6,0 -24.7,11.1 -24.7,24.7000002 l 0,199.700002 c 0,13.6 11.1,24.7 24.7,24.7 l 8.3,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-199.700002 C 194.8,4.0999878 183.8,-7.0000122 170.2,-7.0000122 l 0,0 z" + id="path29" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /><path + style="fill:#95d220" + d="M 17.699219 47.199219 C 7.9992186 47.199219 2.3684758e-15 55.100391 0 64.900391 L 0 73.199219 C 0 82.899219 7.8992186 90.900391 17.699219 90.900391 L 137.19922 90.900391 L 137.19922 47.199219 L 17.699219 47.199219 z M 194.80078 47.199219 L 194.80078 90.900391 L 217.30078 90.900391 C 227.00078 90.900391 235 82.999219 235 73.199219 L 235 64.900391 C 235 55.100391 227.00078 47.199219 217.30078 47.199219 L 194.80078 47.199219 z M 17.699219 144.19922 C 7.9992186 144.19922 2.3684758e-15 152.10039 0 161.90039 L 0 170.19922 C 0 179.89922 7.8992186 187.90039 17.699219 187.90039 L 40.199219 187.90039 L 40.199219 144.19922 L 17.699219 144.19922 z M 97.800781 144.19922 L 97.800781 187.90039 L 217.30078 187.90039 C 227.00078 187.90039 235 179.89922 235 170.19922 L 235 161.90039 C 235 152.10039 227.00078 144.19922 217.30078 144.19922 L 97.800781 144.19922 z " + id="path35" /><rect + style="display:none;fill:#95d220" + id="rect37" + height="43.700001" + width="43.700001" + class="st4" + y="144.19998" + x="47.200001" /><path + class="st2" + d="m 217.3,144.19999 c 9.7,0 17.7,7.9 17.7,17.7 l 0,8.3 c 0,9.7 -8,17.7 -17.7,17.7 l -199.6,0 c -9.7,0 -17.7,-8 -17.7,-17.7 l 0,-8.3 c 0,-9.7 7.9,-17.7 17.7,-17.7 l 199.6,0 m 0,-7 -199.6,0 c -13.6,0 -24.7,11.1 -24.7,24.7 l 0,8.3 c 0,13.6 11.1,24.7 24.7,24.7 l 199.7,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-8.3 c -0.1,-13.7 -11.2,-24.7 -24.8,-24.7 l 0,0 z" + id="path41" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /><rect + style="display:none;fill:#95d220" + id="rect47" + height="43.700001" + width="43.700001" + class="st4" + y="47.199989" + x="144.2" /><path + class="st2" + d="m 217.3,47.199988 c 9.7,0 17.7,7.9 17.7,17.7 l 0,8.3 c 0,9.7 -8,17.7 -17.7,17.7 l -199.6,0 c -9.7,0 -17.7,-7.9 -17.7,-17.7 l 0,-8.3 c 0,-9.7 7.9,-17.7 17.7,-17.7 l 199.6,0 m 0,-7 -199.6,0 c -13.6,0 -24.7,11 -24.7,24.6 l 0,8.3 c 0,13.6 11.1,24.7 24.7,24.7 l 199.7,0 c 13.6,0 24.7,-11.1 24.7,-24.7 l 0,-8.3 c -0.1,-13.6 -11.2,-24.6 -24.8,-24.6 l 0,0 z" + id="path53" + inkscape:connector-curvature="0" + style="display:none;fill:#ffffff" /><path + d="M 0 253.90039 L 0 310 L 26.265625 310 C 38.649816 310 45.142578 303.79961 45.142578 294.09961 C 45.142578 287.79961 42.24573 283.1 36.453125 280.5 L 36.453125 280.40039 C 40.847515 277.70039 42.746094 274.3 42.746094 269 C 42.746094 261 37.25318 253.90039 25.667969 253.90039 L 0 253.90039 z M 54.53125 253.90039 L 54.53125 310 L 61.121094 310 L 61.121094 287.5 L 60.423828 286.80078 L 73.705078 286.80078 C 81.095643 286.80078 85.291724 289.39922 87.988281 295.19922 L 94.978516 310 L 102.36914 310 L 94.080078 292.5 C 92.282373 288.6 89.385747 286.1 86.789062 285 L 86.789062 284.90039 C 92.881286 283.30039 97.974609 277.8 97.974609 270.5 C 97.974609 259.4 89.386477 253.90039 79.099609 253.90039 L 54.53125 253.90039 z M 109.25977 253.90039 L 109.25977 310 L 115.85156 310 L 115.85156 253.90039 L 109.25977 253.90039 z M 148.01172 253.90039 L 123.3418 310 L 130.5332 310 L 136.52539 296.5 L 136.22656 295.80078 L 166.88672 295.80078 L 166.58789 296.5 L 172.58008 310 L 179.77148 310 L 155.00195 253.90039 L 148.01172 253.90039 z M 187.16016 253.90039 L 187.16016 310 L 193.75195 310 L 193.75195 287.5 L 193.05273 286.80078 L 206.33594 286.80078 C 213.72651 286.80078 217.92258 289.39922 220.61914 295.19922 L 227.60938 310 L 235 310 L 226.71094 292.5 C 224.91324 288.6 222.0166 286.1 219.41992 285 L 219.41992 284.90039 C 225.51214 283.30039 230.60547 277.8 230.60547 270.5 C 230.60547 259.4 222.01733 253.90039 211.73047 253.90039 L 187.16016 253.90039 z M 5.8925781 260.09961 L 24.96875 260.09961 C 32.15957 260.09961 35.953125 263 35.953125 269 C 35.953125 274 32.95855 278 24.96875 278 L 5.8925781 278 L 6.5917969 277.30078 L 6.5917969 260.80078 L 5.8925781 260.09961 z M 60.423828 260.09961 L 79.099609 260.09961 C 85.89094 260.09961 91.083724 262.90039 91.183594 270.40039 C 91.183594 276.40039 86.490064 280.59961 78.400391 280.59961 L 60.423828 280.59961 L 61.121094 279.90039 L 61.121094 260.80078 L 60.423828 260.09961 z M 192.95312 260.09961 L 211.62891 260.09961 C 218.52012 260.09961 223.71484 262.90039 223.71484 270.40039 C 223.71484 276.40039 219.02131 280.59961 210.93164 280.59961 L 192.95312 280.59961 L 193.65234 279.90039 L 193.65234 260.80078 L 192.95312 260.09961 z M 151.60547 260.80078 L 151.70703 260.80078 L 153.4043 266.40039 L 163.29102 288.90039 L 163.99023 289.59961 L 139.32227 289.59961 L 140.02148 288.90039 L 149.9082 266.40039 L 151.60547 260.80078 z M 5.8925781 284.19922 L 26.265625 284.19922 C 34.555043 284.19922 38.351562 287.99961 38.351562 294.09961 C 38.351562 300.29961 34.854661 303.80078 26.265625 303.80078 L 5.8925781 303.80078 L 6.5917969 303.09961 L 6.5917969 284.90039 L 5.8925781 284.19922 z " + id="path57" /></svg> \ No newline at end of file diff --git a/mailbox-android/artwork/navigation_drawer_header.svg b/mailbox-android/artwork/navigation_drawer_header.svg new file mode 100644 index 0000000000000000000000000000000000000000..c0e0270ab5b9cd8889e16862a390766e79a6fdb2 --- /dev/null +++ b/mailbox-android/artwork/navigation_drawer_header.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Ebene_1" + x="0px" + y="0px" + xml:space="preserve" + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="navigation_drawer_header.svg" + width="146" + height="50"><metadata + id="metadata71"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs69" /><sodipodi:namedview + pagecolor="#000000" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1020" + id="namedview67" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:zoom="3.9883057" + inkscape:cx="55.084459" + inkscape:cy="13.664636" + inkscape:window-x="1442" + inkscape:window-y="24" + inkscape:window-maximized="0" + inkscape:current-layer="Ebene_1" + showguides="true" + inkscape:guide-bbox="true" /><style + type="text/css" + id="style3"> + .st0{display:none;fill:#87C214;} + .st1{fill:#87C214;} + .st2{display:none;fill:#FFFFFF;} + .st3{fill:#95D220;} + .st4{display:none;fill:#95D220;} + .st5{fill:#FFFFFF;} +</style><path + style="fill:#ffffff;fill-opacity:1" + d="m 65.097656,30.699216 v 19.30078 h 9.06836 c 4.22557,0 6.474893,-2.12355 6.496093,-5.47852 0,-2.14464 -1.017672,-3.78004 -3.013671,-4.67187 v -0.041 c 1.507609,-0.9343 2.166015,-2.10331 2.166015,-3.9082 0,-2.73919 -1.848098,-5.20117 -5.861328,-5.20117 h -8.855469 z m 18.75,0 v 19.30078 h 2.271485 v -7.72852 l -0.232422,-0.23437 h 4.585937 c 2.54808,0 4.012966,0.91391 4.947266,2.88867 l 2.40039,5.07422 h 2.546878 l -2.92969,-6.03125 c -0.63702,-1.35898 -1.614284,-2.20763 -2.527344,-2.58984 v -0.043 c 2.1234,-0.55208 3.865235,-2.42042 3.865235,-4.94727 0,-3.80089 -2.951713,-5.68945 -6.476563,-5.68945 h -8.451172 z m 18.876954,0 v 19.30078 h 2.27344 v -19.30078 z m 13.41992,0 -8.49414,19.30078 h 2.48438 l 2.03906,-4.65039 -0.12695,-0.23438 h 10.57421 l -0.12695,0.23438 2.03906,4.65039 h 2.48438 l -8.47266,-19.30078 z m 13.33594,0 v 19.30078 h 2.27148 v -7.72852 l -0.23437,-0.23437 h 4.58789 c 2.54808,0 4.01296,0.91391 4.94726,2.88867 l 2.39844,5.07422 H 146 l -2.92969,-6.03125 c -0.63702,-1.35898 -1.61427,-2.20763 -2.52734,-2.58984 v -0.043 c 2.12341,-0.55208 3.86523,-2.42042 3.86523,-4.94727 0,-3.80089 -2.95171,-5.68945 -6.47656,-5.68945 h -8.45117 z m -62.322267,2.14453 h 6.560547 c 2.46315,0 3.759766,0.9967 3.759766,3.03516 0,1.71996 -0.999336,3.10156 -3.759766,3.10156 h -6.560547 l 0.234375,-0.23438 v -5.66992 z m 18.728516,0 h 6.433593 c 2.378211,0 4.14091,0.97535 4.16211,3.52344 0,2.03846 -1.634356,3.5039 -4.416016,3.5039 h -6.179687 l 0.232422,-0.23242 v -6.5625 z m 45.652341,0 h 6.4336 c 2.35698,0 4.14062,0.97535 4.14062,3.52344 0,2.03846 -1.61288,3.5039 -4.39453,3.5039 h -6.17969 l 0.23438,-0.23242 v -6.5625 z m -14.20508,0.21094 h 0.043 l 0.57227,1.93359 3.39844,7.75 0.23242,0.23242 h -8.4707 l 0.23242,-0.23242 3.39843,-7.75 0.59375,-1.93359 z m -50.197261,8.07031 h 7.007812 c 2.84536,0 4.16211,1.3153 4.16211,3.375 0,2.14464 -1.189095,3.33398 -4.140625,3.33398 h -7.029297 l 0.234375,-0.23437 v -6.24219 z" + id="path57" + inkscape:connector-curvature="0" /><path + inkscape:connector-curvature="0" + style="fill:#87c214;stroke-width:0.21276595" + d="m 13.808594,0 c -2.06383,0 -3.766207,1.7019614 -3.766207,3.7657911 V 8.553025 h 9.276928 V 3.7657911 C 19.319315,1.7019614 17.638132,0 15.574302,0 Z m 20.638297,0 c -2.06383,0 -3.766206,1.7019614 -3.766206,3.7657911 V 29.191323 h 9.276927 V 3.7657911 C 39.957612,1.7019614 38.276429,0 36.212599,0 Z M 10.042387,20.808676 v 25.425531 c 0,2.06383 1.681101,3.765791 3.766207,3.765791 h 1.765708 c 2.06383,0 3.766207,-1.701961 3.766207,-3.765791 V 20.808676 Z m 20.638298,20.638297 v 4.787234 c 0,2.06383 1.702376,3.765791 3.766206,3.765791 h 1.765708 c 2.06383,0 3.766206,-1.701961 3.766206,-3.765791 v -4.787234 z" + id="path13-3" /><path + inkscape:connector-curvature="0" + style="fill:#95d220;stroke-width:0.21276595" + d="M 3.7657914,10.042387 C 1.7019617,10.042387 0,11.723487 0,13.808594 v 1.765708 c 0,2.063829 1.6806851,3.766206 3.7657914,3.766206 H 29.191323 v -9.298121 z m 37.6811826,0 v 9.298121 h 4.787233 c 2.06383,0 3.765792,-1.6811 3.765792,-3.766206 v -1.765708 c 0,-2.085107 -1.701962,-3.766207 -3.765792,-3.766207 z M 3.7657914,30.680684 C 1.7019617,30.680684 0,32.361784 0,34.44689 v 1.765709 c 0,2.06383 1.6806851,3.766206 3.7657914,3.766206 h 4.7872339 v -9.298121 z m 17.0428856,0 v 9.298121 h 25.42553 c 2.06383,0 3.765792,-1.702376 3.765792,-3.766206 V 34.44689 c 0,-2.085106 -1.701962,-3.766206 -3.765792,-3.766206 z" + id="path35" /></svg> \ No newline at end of file diff --git a/mailbox-android/artwork/navigation_drawer_header_night.svg b/mailbox-android/artwork/navigation_drawer_header_night.svg new file mode 100644 index 0000000000000000000000000000000000000000..6627e299edcc7c7b5436e7760dd82f9bf8196130 --- /dev/null +++ b/mailbox-android/artwork/navigation_drawer_header_night.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Ebene_1" + x="0px" + y="0px" + xml:space="preserve" + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="navigation_drawer_header_night.svg" + width="146" + height="50"><metadata + id="metadata71"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs69" /><sodipodi:namedview + pagecolor="#000000" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1020" + id="namedview67" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:zoom="3.9883057" + inkscape:cx="110.49646" + inkscape:cy="13.664636" + inkscape:window-x="1442" + inkscape:window-y="24" + inkscape:window-maximized="0" + inkscape:current-layer="Ebene_1" + showguides="true" + inkscape:guide-bbox="true" /><style + type="text/css" + id="style3"> + .st0{display:none;fill:#87C214;} + .st1{fill:#87C214;} + .st2{display:none;fill:#FFFFFF;} + .st3{fill:#95D220;} + .st4{display:none;fill:#95D220;} + .st5{fill:#FFFFFF;} +</style><path + style="fill:#95d220;fill-opacity:1" + d="m 65.097656,15.349623 v 19.30078 h 9.06836 c 4.22557,0 6.474893,-2.12355 6.496093,-5.47852 0,-2.14464 -1.017672,-3.78004 -3.013671,-4.67187 v -0.041 c 1.507609,-0.9343 2.166015,-2.10331 2.166015,-3.9082 0,-2.73919 -1.848098,-5.20117 -5.861328,-5.20117 h -8.855469 z m 18.75,0 v 19.30078 h 2.271485 v -7.72852 l -0.232422,-0.23437 h 4.585937 c 2.54808,0 4.012966,0.91391 4.947266,2.88867 l 2.40039,5.07422 h 2.546878 l -2.92969,-6.03125 c -0.63702,-1.35898 -1.614284,-2.20763 -2.527344,-2.58984 v -0.043 c 2.1234,-0.55208 3.865235,-2.42042 3.865235,-4.94727 0,-3.80089 -2.951713,-5.68945 -6.476563,-5.68945 h -8.451172 z m 18.876954,0 v 19.30078 h 2.27344 v -19.30078 z m 13.41992,0 -8.49414,19.30078 h 2.48438 l 2.03906,-4.65039 -0.12695,-0.23438 h 10.57421 l -0.12695,0.23438 2.03906,4.65039 h 2.48438 l -8.47266,-19.30078 z m 13.33594,0 v 19.30078 h 2.27148 v -7.72852 l -0.23437,-0.23437 h 4.58789 c 2.54808,0 4.01296,0.91391 4.94726,2.88867 l 2.39844,5.07422 H 146 l -2.92969,-6.03125 c -0.63702,-1.35898 -1.61427,-2.20763 -2.52734,-2.58984 v -0.043 c 2.12341,-0.55208 3.86523,-2.42042 3.86523,-4.94727 0,-3.80089 -2.95171,-5.68945 -6.47656,-5.68945 h -8.45117 z m -62.322267,2.14453 h 6.560547 c 2.46315,0 3.759766,0.9967 3.759766,3.03516 0,1.71996 -0.999336,3.10156 -3.759766,3.10156 h -6.560547 l 0.234375,-0.23438 v -5.66992 z m 18.728516,0 h 6.433593 c 2.378211,0 4.14091,0.97535 4.16211,3.52344 0,2.03846 -1.634356,3.5039 -4.416016,3.5039 h -6.179687 l 0.232422,-0.23242 v -6.5625 z m 45.652341,0 h 6.4336 c 2.35698,0 4.14062,0.97535 4.14062,3.52344 0,2.03846 -1.61288,3.5039 -4.39453,3.5039 h -6.17969 l 0.23438,-0.23242 v -6.5625 z m -14.20508,0.21094 h 0.043 l 0.57227,1.93359 3.39844,7.75 0.23242,0.23242 h -8.4707 l 0.23242,-0.23242 3.39843,-7.75 0.59375,-1.93359 z m -50.197261,8.07031 h 7.007812 c 2.84536,0 4.16211,1.3153 4.16211,3.375 0,2.14464 -1.189095,3.33398 -4.140625,3.33398 h -7.029297 l 0.234375,-0.23437 v -6.24219 z" + id="path57" + inkscape:connector-curvature="0" /><path + inkscape:connector-curvature="0" + style="fill:#87c214;stroke-width:0.21276595" + d="m 13.808594,0 c -2.06383,0 -3.766207,1.7019614 -3.766207,3.7657911 V 8.553025 h 9.276928 V 3.7657911 C 19.319315,1.7019614 17.638132,0 15.574302,0 Z m 20.638297,0 c -2.06383,0 -3.766206,1.7019614 -3.766206,3.7657911 V 29.191323 h 9.276927 V 3.7657911 C 39.957612,1.7019614 38.276429,0 36.212599,0 Z M 10.042387,20.808676 v 25.425531 c 0,2.06383 1.681101,3.765791 3.766207,3.765791 h 1.765708 c 2.06383,0 3.766207,-1.701961 3.766207,-3.765791 V 20.808676 Z m 20.638298,20.638297 v 4.787234 c 0,2.06383 1.702376,3.765791 3.766206,3.765791 h 1.765708 c 2.06383,0 3.766206,-1.701961 3.766206,-3.765791 v -4.787234 z" + id="path13-3" /><path + inkscape:connector-curvature="0" + style="fill:#95d220;stroke-width:0.21276595" + d="M 3.7657914,10.042387 C 1.7019617,10.042387 0,11.723487 0,13.808594 v 1.765708 c 0,2.063829 1.6806851,3.766206 3.7657914,3.766206 H 29.191323 v -9.298121 z m 37.6811826,0 v 9.298121 h 4.787233 c 2.06383,0 3.765792,-1.6811 3.765792,-3.766206 v -1.765708 c 0,-2.085107 -1.701962,-3.766207 -3.765792,-3.766207 z M 3.7657914,30.680684 C 1.7019617,30.680684 0,32.361784 0,34.44689 v 1.765709 c 0,2.06383 1.6806851,3.766206 3.7657914,3.766206 h 4.7872339 v -9.298121 z m 17.0428856,0 v 9.298121 h 25.42553 c 2.06383,0 3.765792,-1.702376 3.765792,-3.766206 V 34.44689 c 0,-2.085106 -1.701962,-3.766206 -3.765792,-3.766206 z" + id="path35" /></svg> \ No newline at end of file diff --git a/mailbox-android/artwork/notification_ongoing.svg b/mailbox-android/artwork/notification_ongoing.svg new file mode 100644 index 0000000000000000000000000000000000000000..b85939f22e36b43a19e8d316ef10001d3ca9286c --- /dev/null +++ b/mailbox-android/artwork/notification_ongoing.svg @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Ebene_1" + x="0px" + y="0px" + viewBox="0 0 24 24" + xml:space="preserve" + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="notification_ongoing.svg" + width="24" + height="24"><metadata + id="metadata61"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs + id="defs59" /><sodipodi:namedview + pagecolor="#000000" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1020" + id="namedview57" + showgrid="false" + inkscape:zoom="11.466748" + inkscape:cx="-4.790356" + inkscape:cy="17.536496" + inkscape:window-x="1442" + inkscape:window-y="24" + inkscape:window-maximized="0" + inkscape:current-layer="Ebene_1" + units="px" /><style + type="text/css" + id="style3"> + .st0{fill:#FFFFFF;} + .st1{display:none;fill:#87C214;} + .st2{fill:#87C214;} + .st3{display:none;fill:#FFFFFF;} + .st4{fill:#95D220;} + .st5{display:none;fill:#95D220;} +</style><path + style="fill:#ffffff;stroke-width:0.07272727" + d="M 12,0 A 12,12 0 0 0 0,12 12,12 0 0 0 12,24 12,12 0 0 0 24,12 12,12 0 0 0 12,0 Z M 8.1454545,3.4764204 h 0.6036931 c 0.7054546,0 1.2872164,0.5817614 1.2872164,1.287216 V 6.4 H 6.8582386 V 4.7636364 c 0,-0.7054546 0.5817614,-1.287216 1.2872159,-1.287216 z m 7.0545455,0 h 0.603693 c 0.712727,0 1.287216,0.5817614 1.287216,1.287216 V 13.454545 H 13.912784 V 4.7636364 c 0,-0.7054546 0.581761,-1.287216 1.287216,-1.287216 z M 4.7127841,6.9090909 H 13.403693 V 10.087216 H 4.7127841 c -0.7127273,0 -1.287358,-0.5817618 -1.287358,-1.2872156 V 8.1963069 c 0,-0.7127273 0.5819034,-1.287216 1.287358,-1.287216 z m 12.8872159,0 h 1.636364 c 0.705454,0 1.279943,0.5817615 1.287216,1.287216 v 0.6036935 c 0,0.7127269 -0.581762,1.2872156 -1.287216,1.2872156 H 17.6 Z M 6.8582386,10.596307 h 3.1781254 v 8.690909 c 0,0.705454 -0.5817618,1.287358 -1.2872164,1.287358 H 8.1454545 c -0.7127272,0 -1.2872159,-0.581904 -1.2872159,-1.287358 z m -2.1454545,3.367329 h 1.6363636 v 3.178125 H 4.7127841 c -0.7127273,0 -1.287358,-0.581761 -1.287358,-1.287216 v -0.603693 c 0,-0.712727 0.5819034,-1.287216 1.287358,-1.287216 z m 5.8326709,0 h 8.690909 c 0.705454,0 1.279943,0.581761 1.287216,1.287216 v 0.603693 c 0,0.705455 -0.581762,1.287216 -1.287216,1.287216 h -8.690909 z m 3.367329,3.687216 h 3.178125 v 1.636364 c 0,0.705454 -0.581761,1.287358 -1.287216,1.287358 H 15.2 c -0.705455,0 -1.287216,-0.581904 -1.287216,-1.287358 z" + id="circle7" + inkscape:connector-curvature="0" /></svg> diff --git a/mailbox-android/artwork/qr_code.svg b/mailbox-android/artwork/qr_code.svg new file mode 100644 index 0000000000000000000000000000000000000000..07930f849b6ac18afb8bad78edd76d3d2a531fc3 --- /dev/null +++ b/mailbox-android/artwork/qr_code.svg @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="svg2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="-47 347.2 409.2 161.7" style="enable-background:new -47 347.2 409.2 161.7;" xml:space="preserve"> +<style type="text/css"> + .st0{display:none;fill:none;stroke:#FFFFFF;stroke-width:4.3281;} + .st1{fill-rule:evenodd;clip-rule:evenodd;fill:#020202;} +</style> +<path id="path4201" d="M322.8,504.6l-4.3-4.3l-7.1-2.4c-3.9-1.3-8.7-3-10.7-3.7l-3.7-1.3l3.5-0.2c8.2-0.4,13-4,14.3-10.9 + c0.8-4.1,1.1-17.3,0.8-33c-0.2-8.1-0.2-15.4,0-16.3c0.1-0.9,0.5-2.4,0.9-3.4c1.2-3.5,0.3-11.9-1.9-17.6c-0.3-0.9-1.9-4.2-3.5-7.4 + c-4.2-8.2-4.5-8.9-4.9-10.5c-0.5-1.8-0.2-5.4,0.5-6.8c0.7-1.3,2.2-2.9,3.2-3.5c1.3-0.7,2.6,0.1,4.7,2.9c3.4,4.5,14,19.4,15.7,22.2 + c3.7,6,6,11.2,8,18.8c0.7,2.5,1.9,7,2.7,10.1c0.8,3.1,2.7,10.2,4.1,15.8l2.6,10.2l4.6,5.2c2.6,2.9,5.8,6.5,7.2,8 + c1.4,1.6,2.5,3,2.5,3.2c0,0.3-34.5,29.3-34.9,29.3C327.2,508.9,325.2,506.9,322.8,504.6z M228.9,488.2c-1.3-0.6-2.2-1.4-2.9-2.3 + c-2.1-2.7-2,2.4-1.9-68.5l0.1-64l0.7-1.2c1-1.9,2-2.9,3.7-3.9l1.6-0.9l37.8-0.1c42.5-0.1,39.4-0.2,42.1,2.2c0.9,0.8,1.8,2,2.2,2.9 + c0.7,1.6,0.7,1.6,0.8,14.2l0.1,12.6l-1.8-0.1c-1.4-0.1-2.1,0-3.2,0.5c-2,1-3.9,2.9-5.1,5.1l-1,2l0-12.8l0-12.8h-33.6h-33.6v51.3 + v51.3h33.6h33.6l0.1-34.4c0.1-33,0.1-34.4,0.6-32.9c0.3,0.8,1.8,4,3.4,7c5.5,10.6,5.4,9.9,5.4,47.2c0,27.6-0.1,30-1.7,33.1 + c-1.1,2.2-2.7,3.7-5.1,4.7l-1.7,0.7L267,489l-36.2,0.1L228.9,488.2L228.9,488.2z M271.3,483.1c2.9-1.3,4.5-3.7,4.4-6.6 + c0-4.1-3.1-7.2-7.1-7.2c-2.1,0-3.6,0.6-5.2,2.2c-2.2,2.2-2.8,5.4-1.3,8.3c0.7,1.4,2.5,3,4,3.5C267.6,483.8,270,483.8,271.3,483.1z" + /> +<path id="path4201-1" d="M-7.6,504.6l4.3-4.3l7.1-2.4c3.9-1.3,8.7-3,10.7-3.7l3.7-1.3l-3.5-0.2c-8.2-0.4-13-4-14.3-10.9 + c-0.8-4.1-1.1-17.3-0.8-33c0.2-8.1,0.2-15.4,0-16.3c-0.1-0.9-0.5-2.4-0.9-3.4c-1.2-3.5-0.3-11.9,1.9-17.6c0.3-0.9,1.9-4.2,3.5-7.4 + c4.2-8.2,4.5-8.9,4.9-10.5c0.5-1.8,0.2-5.4-0.5-6.8c-0.7-1.3-2.2-2.9-3.2-3.5c-1.3-0.7-2.6,0.1-4.7,2.9c-3.4,4.5-14,19.4-15.7,22.2 + c-3.7,6-6,11.2-8,18.8c-0.7,2.5-1.9,7-2.7,10.1c-0.8,3.1-2.7,10.2-4.1,15.8l-2.6,10.2l-4.6,5.2c-2.6,2.9-5.8,6.5-7.2,8 + s-2.5,3-2.5,3.2c0,0.3,34.5,29.3,34.9,29.3C-12,508.9-9.9,506.9-7.6,504.6z M86.3,488.2c1.3-0.6,2.2-1.4,2.9-2.3 + c2.1-2.7,2,2.4,1.9-68.5l-0.1-64l-0.7-1.2c-1-1.9-2-2.9-3.7-3.9l-1.6-0.9l-37.8-0.1c-42.5-0.1-39.4-0.2-42.1,2.2 + c-0.9,0.8-1.8,2-2.2,2.9c-0.7,1.6-0.7,1.6-0.8,14.2L2,379.2l1.8-0.1c1.4-0.1,2.1,0,3.2,0.5c2,1,3.9,2.9,5.1,5.1l1,2l0-12.8l0-12.8 + h33.6h33.6v51.3v51.3H46.8H13.2l-0.1-34.4c-0.1-33-0.1-34.4-0.6-32.9c-0.3,0.8-1.8,4-3.4,7c-5.5,10.6-5.4,9.9-5.4,47.2 + c0,27.6,0.1,30,1.7,33.1c1.1,2.2,2.7,3.7,5.1,4.7l1.7,0.7l36.2,0.1l36.2,0.1L86.3,488.2L86.3,488.2z M43.9,483.1 + c-2.9-1.3-4.5-3.7-4.4-6.6c0-4.1,3.1-7.2,7.1-7.2c2.1,0,3.6,0.6,5.2,2.2c2.2,2.2,2.8,5.4,1.3,8.3c-0.7,1.4-2.5,3-4,3.5 + C47.6,483.8,45.3,483.8,43.9,483.1z"/> +<g> + <path d="M33.5,410.2h2.3v2.3h2.3v2.3H26.6v-2.3h2.3v-4.6h4.6L33.5,410.2L33.5,410.2z M63.5,431h2.3v-2.3h-2.3V431z M35.8,410.2h2.3 + v-2.3h-2.3V410.2z M68.1,431h2.3v-2.3h-2.3V431z M40.4,433.3H45V431h-4.6V433.3z M61.2,433.3V431h-2.3v2.3H61.2z M52,433.3h2.3 + v-4.6H52V433.3z M33.5,403.3v2.3h6.9v-2.3H33.5z M31.2,405.6v-2.3h-4.6v4.6h2.3v-2.3H31.2z M38.1,401H22v-16.1h16.1V401z + M35.8,387.2H24.3v11.5h11.5V387.2z M26.6,428.7h6.9v-6.9h-6.9V428.7z M49.6,426.3v2.3H52v-2.3H49.6z M33.5,389.5h-6.9v6.9h6.9 + V389.5z M70.4,384.9V401H54.3v-16.1H70.4z M68.1,387.2H56.6v11.5h11.5V387.2z M22,417.1h16.1v16.1H22V417.1z M24.3,431h11.5v-11.5 + H24.3V431z M24.3,403.3H22v11.5h2.3V403.3z M54.3,414.8v2.3h2.3v-2.3H54.3z M47.3,424.1v-2.3H45v2.3h-4.6v4.6H45v2.3h2.3v-4.6h2.3 + v-2.3H47.3z M40.4,394.1H45v-2.3h-4.6V394.1z M58.9,412.5h4.6v2.3h2.3v-6.9h-2.3v-4.6h-2.3v6.9h-6.9v2.3h2.3v2.3h2.3V412.5z + M61.2,419.4h-2.3v-2.3h-2.3v4.6h-6.9v2.3h4.6v4.6h2.3v2.3h2.3v-4.6h9.2v-2.3h-6.9V419.4z M61.2,419.4h2.3v-4.6h-2.3V419.4z + M42.7,419.4v-2.3H45v-2.3h2.3v-2.3h2.3v-4.6h6.9v-4.6h-2.3v2.3H52v-9.2h-2.3v-4.6H52v-6.9h-2.3v4.6h-2.3v-4.6h-6.9v4.6h2.3v-2.3 + H45v4.6h2.3v6.9h2.3v2.3h-2.3v4.6H45V401h-2.3v-2.3h-2.3v4.6h2.3v2.3h-2.3v6.9h2.3v-4.6H45v4.6h-2.3v2.3h-2.3v6.9H45v-2.3H42.7z + M68.1,421.7v-2.3h-4.6v2.3H68.1z M65.8,389.5h-6.9v6.9h6.9V389.5z M47.3,419.4H52v-2.3h-2.3v-2.3h-2.3V419.4z M52,414.8v-2.3h-2.3 + v2.3H52z M65.8,405.6h4.6v-2.3h-4.6V405.6z M68.1,424.1h2.3v-2.3h-2.3V424.1z M68.1,410.2h2.3v-2.3h-2.3V410.2z M47.3,398.7H45v2.3 + h2.3V398.7z M47.3,398.7"/> +</g> +<g> + <path d="M256.5,410.2h2.3v2.3h2.3v2.3h-11.5v-2.3h2.3v-4.6h4.6L256.5,410.2L256.5,410.2z M286.5,431h2.3v-2.3h-2.3V431z + M258.8,410.2h2.3v-2.3h-2.3V410.2z M291.1,431h2.3v-2.3h-2.3V431z M263.4,433.3h4.6V431h-4.6V433.3z M284.2,433.3V431h-2.3v2.3 + H284.2z M275,433.3h2.3v-4.6H275V433.3z M256.5,403.3v2.3h6.9v-2.3H256.5z M254.2,405.6v-2.3h-4.6v4.6h2.3v-2.3H254.2z M261.1,401 + H245v-16.1h16.1V401z M258.8,387.2h-11.5v11.5h11.5V387.2z M249.6,428.7h6.9v-6.9h-6.9V428.7z M272.6,426.3v2.3h2.3v-2.3H272.6z + M256.5,389.5h-6.9v6.9h6.9V389.5z M293.4,384.9V401h-16.1v-16.1H293.4z M291.1,387.2h-11.5v11.5h11.5V387.2z M245,417.1h16.1v16.1 + H245V417.1z M247.3,431h11.5v-11.5h-11.5V431z M247.3,403.3H245v11.5h2.3V403.3z M277.3,414.8v2.3h2.3v-2.3H277.3z M270.3,424.1 + v-2.3H268v2.3h-4.6v4.6h4.6v2.3h2.3v-4.6h2.3v-2.3H270.3z M263.4,394.1h4.6v-2.3h-4.6V394.1z M281.9,412.5h4.6v2.3h2.3v-6.9h-2.3 + v-4.6h-2.3v6.9h-6.9v2.3h2.3v2.3h2.3V412.5z M284.2,419.4h-2.3v-2.3h-2.3v4.6h-6.9v2.3h4.6v4.6h2.3v2.3h2.3v-4.6h9.2v-2.3h-6.9 + V419.4z M284.2,419.4h2.3v-4.6h-2.3V419.4z M265.7,419.4v-2.3h2.3v-2.3h2.3v-2.3h2.3v-4.6h6.9v-4.6h-2.3v2.3H275v-9.2h-2.3v-4.6 + h2.3v-6.9h-2.3v4.6h-2.3v-4.6h-6.9v4.6h2.3v-2.3h2.3v4.6h2.3v6.9h2.3v2.3h-2.3v4.6H268V401h-2.3v-2.3h-2.3v4.6h2.3v2.3h-2.3v6.9 + h2.3v-4.6h2.3v4.6h-2.3v2.3h-2.3v6.9h4.6v-2.3H265.7z M291.1,421.7v-2.3h-4.6v2.3H291.1z M288.8,389.5h-6.9v6.9h6.9V389.5z + M270.3,419.4h4.6v-2.3h-2.3v-2.3h-2.3V419.4z M275,414.8v-2.3h-2.3v2.3H275z M288.8,405.6h4.6v-2.3h-4.6V405.6z M291.1,424.1h2.3 + v-2.3h-2.3V424.1z M291.1,410.2h2.3v-2.3h-2.3V410.2z M270.3,398.7H268v2.3h2.3V398.7z M270.3,398.7"/> +</g> +<polygon class="st0" points="152,392 152,411.8 110,411.8 126,383.1 126,392 "/> +<polygon class="st0" points="152,392 152,411.8 110,411.8 126,383.1 126,392 "/> +<g> + <path class="st1" d="M132.6,396.1l-20.6,18l20.6,16.7v-5.2H152v-24.3h-19.3V396.1z"/> + <path class="st1" d="M182.4,430.9l20.6-18l-20.6-16.7v5.2H163v24.3h19.3V430.9z"/> +</g> +</svg> diff --git a/mailbox-android/artwork/qr_code_error.svg b/mailbox-android/artwork/qr_code_error.svg new file mode 100644 index 0000000000000000000000000000000000000000..cfd12461e56e60b0579d4a0bdfa7724e610fbb5b --- /dev/null +++ b/mailbox-android/artwork/qr_code_error.svg @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + height="161.7" + width="409.20001" + version="1.1" + id="svg2" + x="0px" + y="0px" + viewBox="0 0 409.2 161.7" + xml:space="preserve"><metadata + id="metadata853"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs851" /> +<style + type="text/css" + id="style826"> + .st0{display:none;fill:none;stroke:#FFFFFF;stroke-width:4.3281;} + .st1{fill-rule:evenodd;clip-rule:evenodd;fill:#020202;} +</style> +<path + id="path4201" + d="m 369.6,157.3 -4.3,-4.3 -7.1,-2.4 c -3.9,-1.3 -8.7,-3 -10.7,-3.7 l -3.7,-1.3 3.5,-0.2 c 8.2,-0.4 13,-4 14.3,-10.9 0.8,-4.1 1.1,-17.3 0.8,-33 -0.2,-8.100003 -0.2,-15.400003 0,-16.300003 0.1,-0.9 0.5,-2.4 0.9,-3.4 1.2,-3.5 0.3,-11.9 -1.9,-17.6 -0.3,-0.9 -1.9,-4.2 -3.5,-7.4 -4.2,-8.2 -4.5,-8.9 -4.9,-10.5 -0.5,-1.8 -0.2,-5.4 0.5,-6.8 0.7,-1.3 2.2,-2.9 3.2,-3.5 1.3,-0.7 2.6,0.1 4.7,2.9 3.4,4.5 14,19.4 15.7,22.2 3.7,6 6,11.2 8,18.8 0.7,2.5 1.9,7 2.7,10.1 0.8,3.1 2.7,10.200003 4.1,15.800003 l 2.6,10.2 4.6,5.2 c 2.6,2.9 5.8,6.5 7.2,8 1.4,1.6 2.5,3 2.5,3.2 0,0.3 -34.5,29.3 -34.9,29.3 0.1,-0.1 -1.9,-2.1 -4.3,-4.4 z m -93.9,-16.4 c -1.3,-0.6 -2.2,-1.4 -2.9,-2.3 -2.1,-2.7 -2,2.4 -1.9,-68.500003 l 0.1,-64.0000001 0.7,-1.2 c 1,-1.9 2,-2.9 3.7,-3.89999995 l 1.6,-0.9 L 314.8,-3.0517578e-6 C 357.3,-0.10000305 354.2,-0.20000305 356.9,2.1999969 c 0.9,0.8 1.8,2 2.2,2.9 0.7,1.6 0.7,1.6 0.8,14.2000001 l 0.1,12.6 -1.8,-0.1 c -1.4,-0.1 -2.1,0 -3.2,0.5 -2,1 -3.9,2.9 -5.1,5.1 l -1,2 v -12.8 -12.8 h -33.6 -33.6 v 51.3 V 116.4 h 33.6 33.6 L 349,81.999997 c 0.1,-33 0.1,-34.4 0.6,-32.9 0.3,0.8 1.8,4 3.4,7 5.5,10.6 5.4,9.9 5.4,47.200003 0,27.6 -0.1,30 -1.7,33.1 -1.1,2.2 -2.7,3.7 -5.1,4.7 l -1.7,0.7 -36.1,-0.1 -36.2,0.1 z m 42.4,-5.1 c 2.9,-1.3 4.5,-3.7 4.4,-6.6 0,-4.1 -3.1,-7.2 -7.1,-7.2 -2.1,0 -3.6,0.6 -5.2,2.2 -2.2,2.2 -2.8,5.4 -1.3,8.3 0.7,1.4 2.5,3 4,3.5 1.5,0.5 3.9,0.5 5.2,-0.2 z" /> +<path + id="path4201-1" + d="m 39.2,157.3 4.3,-4.3 7.1,-2.4 c 3.9,-1.3 8.7,-3 10.7,-3.7 l 3.7,-1.3 -3.5,-0.2 c -8.2,-0.4 -13,-4 -14.3,-10.9 -0.8,-4.1 -1.1,-17.3 -0.8,-33 0.2,-8.100003 0.2,-15.400003 0,-16.300003 -0.1,-0.9 -0.5,-2.4 -0.9,-3.4 -1.2,-3.5 -0.3,-11.9 1.9,-17.6 0.3,-0.9 1.9,-4.2 3.5,-7.4 4.2,-8.2 4.5,-8.9 4.9,-10.5 0.5,-1.8 0.2,-5.4 -0.5,-6.8 -0.7,-1.3 -2.2,-2.9 -3.2,-3.5 -1.3,-0.7 -2.6,0.1 -4.7,2.9 -3.4,4.5 -14,19.4 -15.7,22.2 -3.7,6 -6,11.2 -8,18.8 -0.7,2.5 -1.9,7 -2.7,10.1 -0.8,3.1 -2.7,10.200003 -4.1,15.800003 l -2.6,10.2 -4.6,5.2 c -2.6,2.9 -5.8,6.5 -7.2,8 -1.4,1.5 -2.5,3 -2.5,3.2 0,0.3 34.5,29.3 34.9,29.3 -0.1,-0.1 2,-2.1 4.3,-4.4 z m 93.9,-16.4 c 1.3,-0.6 2.2,-1.4 2.9,-2.3 2.1,-2.7 2,2.4 1.9,-68.500003 l -0.1,-64.0000001 -0.7,-1.2 c -1,-1.9 -2,-2.9 -3.7,-3.89999995 l -1.6,-0.9 L 94,-3.0517578e-6 C 51.5,-0.10000305 54.6,-0.20000305 51.9,2.1999969 c -0.9,0.8 -1.8,2 -2.2,2.9 -0.7,1.6 -0.7,1.6 -0.8,14.2000001 l -0.1,12.6 1.8,-0.1 c 1.4,-0.1 2.1,0 3.2,0.5 2,1 3.9,2.9 5.1,5.1 l 1,2 v -12.8 -12.8 h 33.6 33.6 v 51.3 V 116.4 H 93.6 60 L 59.9,81.999997 c -0.1,-33 -0.1,-34.4 -0.6,-32.9 -0.3,0.8 -1.8,4 -3.4,7 -5.5,10.6 -5.4,9.9 -5.4,47.200003 0,27.6 0.1,30 1.7,33.1 1.1,2.2 2.7,3.7 5.1,4.7 l 1.7,0.7 36.2,0.1 36.2,0.1 z m -42.4,-5.1 c -2.9,-1.3 -4.5,-3.7 -4.4,-6.6 0,-4.1 3.1,-7.2 7.1,-7.2 2.1,0 3.6,0.6 5.2,2.2 2.2,2.2 2.8,5.4 1.3,8.3 -0.7,1.4 -2.5,3 -4,3.5 -1.5,0.5 -3.8,0.5 -5.2,-0.2 z" /> +<g + transform="translate(46.8,-347.3)" + id="g832"> + <path + d="m 33.5,410.2 h 2.3 v 2.3 h 2.3 v 2.3 H 26.6 v -2.3 h 2.3 v -4.6 h 4.6 z m 30,20.8 h 2.3 v -2.3 H 63.5 Z M 35.8,410.2 h 2.3 v -2.3 H 35.8 Z M 68.1,431 h 2.3 v -2.3 h -2.3 z m -27.7,2.3 H 45 V 431 h -4.6 z m 20.8,0 V 431 h -2.3 v 2.3 z m -9.2,0 h 2.3 v -4.6 H 52 Z m -18.5,-30 v 2.3 h 6.9 v -2.3 z m -2.3,2.3 v -2.3 h -4.6 v 4.6 h 2.3 v -2.3 z M 38.1,401 H 22 V 384.9 H 38.1 Z M 35.8,387.2 H 24.3 v 11.5 h 11.5 z m -9.2,41.5 h 6.9 v -6.9 h -6.9 z m 23,-2.4 v 2.3 H 52 v -2.3 z M 33.5,389.5 h -6.9 v 6.9 h 6.9 z m 36.9,-4.6 V 401 H 54.3 v -16.1 z m -2.3,2.3 H 56.6 v 11.5 H 68.1 Z M 22,417.1 h 16.1 v 16.1 H 22 Z M 24.3,431 H 35.8 V 419.5 H 24.3 Z m 0,-27.7 H 22 v 11.5 h 2.3 z m 30,11.5 v 2.3 h 2.3 v -2.3 z m -7,9.3 v -2.3 H 45 v 2.3 h -4.6 v 4.6 H 45 v 2.3 h 2.3 v -4.6 h 2.3 v -2.3 z m -6.9,-30 H 45 v -2.3 h -4.6 z m 18.5,18.4 h 4.6 v 2.3 h 2.3 v -6.9 h -2.3 v -4.6 h -2.3 v 6.9 h -6.9 v 2.3 h 2.3 v 2.3 h 2.3 z m 2.3,6.9 h -2.3 v -2.3 h -2.3 v 4.6 h -6.9 v 2.3 h 4.6 v 4.6 h 2.3 v 2.3 h 2.3 v -4.6 h 9.2 V 424 h -6.9 z m 0,0 h 2.3 v -4.6 h -2.3 z m -18.5,0 v -2.3 H 45 v -2.3 h 2.3 v -2.3 h 2.3 v -4.6 h 6.9 v -4.6 h -2.3 v 2.3 H 52 v -9.2 h -2.3 v -4.6 H 52 v -6.9 h -2.3 v 4.6 h -2.3 v -4.6 h -6.9 v 4.6 h 2.3 v -2.3 H 45 v 4.6 h 2.3 v 6.9 h 2.3 v 2.3 h -2.3 v 4.6 H 45 V 401 h -2.3 v -2.3 h -2.3 v 4.6 h 2.3 v 2.3 h -2.3 v 6.9 h 2.3 v -4.6 H 45 v 4.6 h -2.3 v 2.3 h -2.3 v 6.9 H 45 v -2.3 z m 25.4,2.3 v -2.3 h -4.6 v 2.3 z m -2.3,-32.2 h -6.9 v 6.9 h 6.9 z M 47.3,419.4 H 52 v -2.3 h -2.3 v -2.3 h -2.3 v 4.6 z m 4.7,-4.6 v -2.3 h -2.3 v 2.3 z m 13.8,-9.2 h 4.6 v -2.3 h -4.6 z m 2.3,18.5 h 2.3 v -2.3 h -2.3 z m 0,-13.9 h 2.3 v -2.3 H 68.1 Z M 47.3,398.7 H 45 v 2.3 h 2.3 z m 0,0" + id="path830" /> +</g> +<g + transform="translate(46.8,-347.3)" + id="g836"> + <path + d="m 256.5,410.2 h 2.3 v 2.3 h 2.3 v 2.3 h -11.5 v -2.3 h 2.3 v -4.6 h 4.6 z m 30,20.8 h 2.3 v -2.3 h -2.3 z m -27.7,-20.8 h 2.3 v -2.3 h -2.3 z m 32.3,20.8 h 2.3 v -2.3 h -2.3 z m -27.7,2.3 H 268 V 431 h -4.6 z m 20.8,0 V 431 h -2.3 v 2.3 z m -9.2,0 h 2.3 v -4.6 H 275 Z m -18.5,-30 v 2.3 h 6.9 v -2.3 z m -2.3,2.3 v -2.3 h -4.6 v 4.6 h 2.3 v -2.3 z m 6.9,-4.6 H 245 v -16.1 h 16.1 z m -2.3,-13.8 h -11.5 v 11.5 h 11.5 z m -9.2,41.5 h 6.9 v -6.9 h -6.9 z m 23,-2.4 v 2.3 h 2.3 v -2.3 z m -16.1,-36.8 h -6.9 v 6.9 h 6.9 z m 36.9,-4.6 V 401 h -16.1 v -16.1 z m -2.3,2.3 h -11.5 v 11.5 h 11.5 z M 245,417.1 h 16.1 v 16.1 H 245 Z m 2.3,13.9 h 11.5 v -11.5 h -11.5 z m 0,-27.7 H 245 v 11.5 h 2.3 z m 30,11.5 v 2.3 h 2.3 v -2.3 z m -7,9.3 v -2.3 H 268 v 2.3 h -4.6 v 4.6 h 4.6 v 2.3 h 2.3 v -4.6 h 2.3 v -2.3 z m -6.9,-30 h 4.6 v -2.3 h -4.6 z m 18.5,18.4 h 4.6 v 2.3 h 2.3 v -6.9 h -2.3 v -4.6 h -2.3 v 6.9 h -6.9 v 2.3 h 2.3 v 2.3 h 2.3 z m 2.3,6.9 h -2.3 v -2.3 h -2.3 v 4.6 h -6.9 v 2.3 h 4.6 v 4.6 h 2.3 v 2.3 h 2.3 v -4.6 h 9.2 V 424 h -6.9 z m 0,0 h 2.3 v -4.6 h -2.3 z m -18.5,0 v -2.3 h 2.3 v -2.3 h 2.3 v -2.3 h 2.3 v -4.6 h 6.9 v -4.6 h -2.3 v 2.3 H 275 v -9.2 h -2.3 v -4.6 h 2.3 v -6.9 h -2.3 v 4.6 h -2.3 v -4.6 h -6.9 v 4.6 h 2.3 v -2.3 h 2.3 v 4.6 h 2.3 v 6.9 h 2.3 v 2.3 h -2.3 v 4.6 H 268 V 401 h -2.3 v -2.3 h -2.3 v 4.6 h 2.3 v 2.3 h -2.3 v 6.9 h 2.3 v -4.6 h 2.3 v 4.6 h -2.3 v 2.3 h -2.3 v 6.9 h 4.6 v -2.3 z m 25.4,2.3 v -2.3 h -4.6 v 2.3 z m -2.3,-32.2 h -6.9 v 6.9 h 6.9 z m -18.5,29.9 h 4.6 v -2.3 h -2.3 v -2.3 h -2.3 z m 4.7,-4.6 v -2.3 h -2.3 v 2.3 z m 13.8,-9.2 h 4.6 v -2.3 h -4.6 z m 2.3,18.5 h 2.3 v -2.3 h -2.3 z m 0,-13.9 h 2.3 v -2.3 h -2.3 z M 270.3,398.7 H 268 v 2.3 h 2.3 z m 0,0" + id="path834" /> +</g> + + + +<path + style="opacity:1;fill:#000000;stroke-width:3.21294165" + d="m 207.61295,88.782357 h -6.42588 v -12.85177 h 6.42588 m 0,25.703533 h -6.42588 v -6.425883 h 6.42588 m -38.5553,16.064713 h 70.68472 L 204.40001,50.227047 Z" + id="path2" /></svg> \ No newline at end of file diff --git a/mailbox-android/artwork/trust-indicator.svg b/mailbox-android/artwork/trust-indicator.svg new file mode 100644 index 0000000000000000000000000000000000000000..c8f94b6f65347cd2c7f195ebf7148db85ce80be4 --- /dev/null +++ b/mailbox-android/artwork/trust-indicator.svg @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="49" + height="20" + viewBox="0 0 49.000004 20" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="trust-indicator.svg"> + <defs + id="defs4" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="15.839192" + inkscape:cx="19.828141" + inkscape:cy="4.1791031" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + units="px" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="1920" + inkscape:window-height="993" + inkscape:window-x="1440" + inkscape:window-y="0" + inkscape:window-maximized="1" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-216.17711,-507.04154)"> + <g + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25px;line-height:125%;font-family:FreeSans;-inkscape-font-specification:FreeSans;letter-spacing:0px;word-spacing:0px;fill:#b7b7b7;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + id="text4136" + transform="matrix(1,0,0,0.90497738,-18.96574,55.694085)"> + <path + d="m 250.64285,514.07648 0,-2.275 -2.55,0 0,-3.8 2.55,0 0,-2.275 -2.55,0 0,-4.225 -2.375,0 0,4.225 -3.15,0 0,-4.225 -2.375,0 0,4.225 -2.55,0 0,2.275 2.55,0 0,3.8 -2.55,0 0,2.275 2.55,0 0,4 2.375,0 0,-4 3.15,0 0,4 2.375,0 0,-4 2.55,0 z m -4.925,-2.275 -3.15,0 0,-3.8 3.15,0 0,3.8 z" + style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:Titillium;-inkscape-font-specification:'Titillium Semi-Bold';fill:#b7b7b7;fill-opacity:1" + id="path4745" + inkscape:connector-curvature="0" /> + </g> + <g + transform="matrix(1,0,0,0.90497738,-3.4657389,55.694085)" + id="g4755" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25px;line-height:125%;font-family:FreeSans;-inkscape-font-specification:FreeSans;letter-spacing:0px;word-spacing:0px;fill:#b7b7b7;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"> + <path + inkscape:connector-curvature="0" + id="path4757" + style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:Titillium;-inkscape-font-specification:'Titillium Semi-Bold';fill:#b7b7b7;fill-opacity:1" + d="m 250.64285,514.07648 0,-2.275 -2.55,0 0,-3.8 2.55,0 0,-2.275 -2.55,0 0,-4.225 -2.375,0 0,4.225 -3.15,0 0,-4.225 -2.375,0 0,4.225 -2.55,0 0,2.275 2.55,0 0,3.8 -2.55,0 0,2.275 2.55,0 0,4 2.375,0 0,-4 3.15,0 0,4 2.375,0 0,-4 2.55,0 z m -4.925,-2.275 -3.15,0 0,-3.8 3.15,0 0,3.8 z" /> + </g> + <g + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25px;line-height:125%;font-family:FreeSans;-inkscape-font-specification:FreeSans;letter-spacing:0px;word-spacing:0px;fill:#b7b7b7;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + id="g4139" + transform="matrix(1,0,0,0.90497738,12.034262,55.694085)"> + <path + d="m 250.64285,514.07648 0,-2.275 -2.55,0 0,-3.8 2.55,0 0,-2.275 -2.55,0 0,-4.225 -2.375,0 0,4.225 -3.15,0 0,-4.225 -2.375,0 0,4.225 -2.55,0 0,2.275 2.55,0 0,3.8 -2.55,0 0,2.275 2.55,0 0,4 2.375,0 0,-4 3.15,0 0,4 2.375,0 0,-4 2.55,0 z m -4.925,-2.275 -3.15,0 0,-3.8 3.15,0 0,3.8 z" + style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:Titillium;-inkscape-font-specification:'Titillium Semi-Bold';fill:#b7b7b7;fill-opacity:1" + id="path4141" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/mailbox-android/build.gradle b/mailbox-android/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..f2ba02c0b3ed66172e8a56e9d41e05d233864e55 --- /dev/null +++ b/mailbox-android/build.gradle @@ -0,0 +1,197 @@ +apply plugin: 'com.android.application' +apply plugin: 'witness' +apply from: 'witness.gradle' + +dependencies { + implementation project(path: ':bramble-core', configuration: 'default') + implementation project(':bramble-android') + + def lifecycle_version = "1.1.1" + // ViewModel and LiveData + implementation "android.arch.lifecycle:extensions:$lifecycle_version" + // alternately - if using Java8, use the following instead of compiler + implementation "android.arch.lifecycle:common-java8:$lifecycle_version" + + def supportVersion = '27.1.1' + implementation "com.android.support:support-v4:$supportVersion" + implementation("com.android.support:appcompat-v7:$supportVersion") { + exclude module: 'support-v4' + } + implementation("com.android.support:preference-v14:$supportVersion") { + exclude module: 'support-v4' + } + implementation("com.android.support:design:$supportVersion") { + exclude module: 'support-v4' + exclude module: 'recyclerview-v7' + } + implementation "com.android.support:cardview-v7:$supportVersion" + implementation "com.android.support:support-annotations:$supportVersion" + implementation 'com.android.support.constraint:constraint-layout:1.1.0' + + implementation('ch.acra:acra:4.9.1') { + exclude module: 'support-v4' + exclude module: 'support-annotations' + } + implementation 'info.guardianproject.panic:panic:0.5' + implementation 'info.guardianproject.trustedintents:trustedintents:0.2' + implementation 'de.hdodenhof:circleimageview:2.2.0' + implementation 'com.google.zxing:core:3.3.0' + implementation 'com.jpardogo.materialtabstrip:library:1.1.0' + implementation 'com.github.bumptech.glide:glide:3.8.0' + implementation 'uk.co.samuelwall:material-tap-target-prompt:2.8.0' + + annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2' + + compileOnly 'javax.annotation:jsr250-api:1.0' + + testImplementation project(path: ':bramble-api', configuration: 'testOutput') + testImplementation project(path: ':bramble-core', configuration: 'testOutput') + testImplementation 'org.robolectric:robolectric:3.8' + testImplementation 'org.robolectric:shadows-support-v4:3.3.2' + testImplementation 'org.mockito:mockito-core:2.13.0' + testImplementation 'junit:junit:4.12' + testImplementation "org.jmock:jmock:2.8.2" + testImplementation "org.jmock:jmock-junit4:2.8.2" + testImplementation "org.jmock:jmock-legacy:2.8.2" + testImplementation "org.hamcrest:hamcrest-library:1.3" + testImplementation "org.hamcrest:hamcrest-core:1.3" + + def espressoVersion = '3.0.2' + androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion" + androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espressoVersion" + androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espressoVersion" + androidTestImplementation "tools.fastlane:screengrab:1.1.0" + androidTestImplementation "com.android.support.test.uiautomator:uiautomator-v18:2.1.3" + androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.0.2" + androidTestCompileOnly 'javax.annotation:jsr250-api:1.0' + androidTestImplementation 'junit:junit:4.12' +} + +def getStdout = { command, defaultValue -> + def stdout = new ByteArrayOutputStream() + try { + exec { + commandLine = command + standardOutput = stdout + } + return stdout.toString().trim() + } catch (Exception ignored) { + return defaultValue + } +} + +android { + compileSdkVersion 27 + buildToolsVersion '27.0.3' + + defaultConfig { + minSdkVersion 14 + targetSdkVersion 26 + versionCode 10001 + versionName "0.0.01" + applicationId "org.briarproject.mailbox.android" + buildConfigField "String", "GitHash", + "\"${getStdout(['git', 'rev-parse', '--short=7', 'HEAD'], 'No commit hash')}\"" + def now = (long) (System.currentTimeMillis() / 1000) + buildConfigField "Long", "BuildTimestamp", + "${getStdout(['git', 'log', '-n', '1', '--format=%ct'], now)}000L" + testInstrumentationRunner 'org.briarproject.mailbox.android.test.MailboxTestRunner' + } + + buildTypes { + debug { + applicationIdSuffix ".debug" + shrinkResources false + minifyEnabled true + crunchPngs false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-test.txt' + } + release { + shrinkResources false + minifyEnabled true + crunchPngs false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } + + flavorDimensions "version" + productFlavors { + screenshot { + dimension "version" + minSdkVersion 18 + applicationIdSuffix ".screenshot" // = org.briarproject.briar.android.screenshot.debug + } + official { + dimension "version" + } + } + variantFilter { variant -> + if (variant.flavors*.name.contains("screenshot") && variant.buildType.name == "release") { + setIgnore(true) + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + testOptions { + unitTests { + includeAndroidResources = true + } + } + + lintOptions { + warning 'MissingTranslation' + warning 'ImpliedQuantity' + warning 'ExtraTranslation' + } +} + +task verifyTranslations { + doLast { + def file = project.file("src/main/res/values/arrays.xml") + def arrays = new XmlParser().parse(file) + def lc = arrays.children().find { it.@name == "pref_language_values" } + def translations = [] + lc.children().each { value -> translations.add(value.text()) } + + def folders = ["default", "en-US"] + project.file("src/main/res").eachDir { dir -> + if (dir.name.startsWith("values-") && !dir.name.endsWith("night") && !dir.name.endsWith("v21")) { + folders.add(dir.name.substring(7).replace("-r", "-")) + } + } + folders.each { n -> + if (!translations.remove(n) && n != 'iw') { + throw new GradleException("Translation " + n + " is missing in $file") + } + } + if (translations.size() != 0) + throw new GradleException("Translations\n" + translations.join("\n") + + "\nhave no matching value folder") + + // Some devices use iw instead of he for hebrew + def hebrew_legacy = project.file("src/main/res/values-iw") + def hebrew = project.file("src/main/res/values-he") + // Copy values-he to values-iw + if (hebrew.exists()) { + hebrew_legacy.mkdir() + copy { + from hebrew.getAbsolutePath() + into hebrew_legacy.getAbsolutePath() + } + } + } +} + +project.afterEvaluate { + preBuild.dependsOn.add(verifyTranslations) +} + +tasks.withType(Test) { + // Use entropy-gathering device specified on command line, if any + systemProperty 'java.security.egd', System.getProperty('java.security.egd') +} diff --git a/mailbox-android/fastlane/Appfile b/mailbox-android/fastlane/Appfile new file mode 100644 index 0000000000000000000000000000000000000000..05204c92cfa9c7201e9c4121e9f07e4de9800ce6 --- /dev/null +++ b/mailbox-android/fastlane/Appfile @@ -0,0 +1,2 @@ +json_key_file("") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one +package_name("org.briarproject.briar.android") diff --git a/mailbox-android/fastlane/Fastfile b/mailbox-android/fastlane/Fastfile new file mode 100644 index 0000000000000000000000000000000000000000..01035f6ece05abdbf1228c4f326f2abec41a62db --- /dev/null +++ b/mailbox-android/fastlane/Fastfile @@ -0,0 +1,30 @@ +# This file contains the fastlane.tools configuration +# You can find the documentation at https://docs.fastlane.tools +# +# For a list of all available actions, check out +# +# https://docs.fastlane.tools/actions +# +# For a list of all available plugins, check out +# +# https://docs.fastlane.tools/plugins/available-plugins +# + +# Uncomment the line if you want fastlane to automatically update itself +# update_fastlane + +default_platform(:android) + +platform :android do + desc "Takes screenshots for manual and Google Play" + lane :screenshots do + gradle(project_dir: "..", task: "assembleScreenshot assembleAndroidTest") + system './demo-mode-activate.sh' + capture_android_screenshots + system './demo-mode-deactivate.sh' + system './rename_screenshots.py' + end +end + + +# vi:syntax=ruby diff --git a/mailbox-android/fastlane/Screengrabfile b/mailbox-android/fastlane/Screengrabfile new file mode 100644 index 0000000000000000000000000000000000000000..bacf6905bc5b584d7dbfd52d01c864f439d184ea --- /dev/null +++ b/mailbox-android/fastlane/Screengrabfile @@ -0,0 +1,9 @@ +app_package_name "org.briarproject.briar.android.screenshot.debug" +locales ['en-US'] +use_tests_in_classes([ + 'org.briarproject.briar.android.login.SetupActivityScreenshotTest', + 'org.briarproject.briar.android.settings.SettingsActivityScreenshotTest', +]) +app_apk_path "build/outputs/apk/screenshot/debug/briar-android-screenshot-debug.apk" +tests_apk_path "build/outputs/apk/androidTest/screenshot/debug/briar-android-screenshot-debug-androidTest.apk" +test_instrumentation_runner "org.briarproject.briar.android.test.BriarTestRunner" \ No newline at end of file diff --git a/mailbox-android/fastlane/demo-mode-activate.sh b/mailbox-android/fastlane/demo-mode-activate.sh new file mode 100755 index 0000000000000000000000000000000000000000..23001fb56c0ad6baae18a51938a0a1a6752dbbf7 --- /dev/null +++ b/mailbox-android/fastlane/demo-mode-activate.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +adb shell settings put global sysui_demo_allowed 1 +adb shell am broadcast -a com.android.systemui.demo -e command enter +adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false +adb shell am broadcast -a com.android.systemui.demo -e command battery -e level 100 +adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi show +adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1337 \ No newline at end of file diff --git a/mailbox-android/fastlane/demo-mode-deactivate.sh b/mailbox-android/fastlane/demo-mode-deactivate.sh new file mode 100755 index 0000000000000000000000000000000000000000..c70cd53264b22c91524f176e64558af7757d3094 --- /dev/null +++ b/mailbox-android/fastlane/demo-mode-deactivate.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +adb shell am broadcast -a com.android.systemui.demo -e command exit \ No newline at end of file diff --git a/mailbox-android/fastlane/rename_screenshots.py b/mailbox-android/fastlane/rename_screenshots.py new file mode 100755 index 0000000000000000000000000000000000000000..f1f0485fa7723c570378b44552653ab0278af686 --- /dev/null +++ b/mailbox-android/fastlane/rename_screenshots.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +# Author: Torsten Grote +# License: GPLv3 or later + +import os +import re +import glob + +METADATA_PATH = 'metadata/android' +GLOB = '/*/images/phoneScreenshots/*.png' + +REGEX = re.compile(r'(^\w+)_\d{13}\.png$') +REGEX_IN_FILE = re.compile(r'(\w+)_\d{13}\.png', re.MULTILINE) +PATH = os.path.dirname(os.path.realpath(__file__)) + + +def main(): + for path in glob.glob("%s%s" % (os.path.join(PATH, METADATA_PATH), GLOB)): + filename = os.path.basename(path) + match = REGEX.match(filename) + if match: + directory = os.path.dirname(path) + new_filename = "%s.png" % match.group(1) + new_path = os.path.join(directory, new_filename) + os.rename(path, new_path) + print("Renaming\n %s\nto\n %s\n" % (path, new_path)) + else: + print("Warning: Path did not match %s" % path) + + # rename fields also in screenshot overview file + overview = os.path.join(PATH, METADATA_PATH, 'screenshots.html') + with open(overview, 'r') as f: + file_data = f.read() + + file_data = REGEX_IN_FILE.sub(r'\1.png', file_data) + + with open(overview, 'w') as f: + f.write(file_data) + + +if __name__ == "__main__": + main() diff --git a/mailbox-android/proguard-rules.txt b/mailbox-android/proguard-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..88fb5b29b5ec5d8fad53c2ee53f14b5091419b94 --- /dev/null +++ b/mailbox-android/proguard-rules.txt @@ -0,0 +1,35 @@ +# Android defaults and rules from ../bramble-android/proguard-rules.txt are also applied + +-dontobfuscate +-keepattributes SourceFile, LineNumberTable, *Annotation*, Signature, InnerClasses, EnclosingMethod + +# QR codes +-keep class com.google.zxing.Result + +# RSS libraries +-keep,includedescriptorclasses class com.rometools.rome.feed.synd.impl.** { *; } +-keep,includedescriptorclasses class com.rometools.rome.io.impl.** { *; } +-dontwarn javax.xml.stream.** +-dontwarn org.jaxen.** +-dontwarn java.nio.** +-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement +-dontwarn org.slf4j.impl.** + +# OkHttp does some shenanigans with Android's SSL classes +-dontnote com.android.org.conscrypt.SSLParametersImpl +-dontnote org.apache.harmony.xnet.provider.jsse.SSLParametersImpl +-dontnote sun.security.ssl.SSLContextImpl + +# HTML sanitiser +-keep class org.jsoup.safety.Whitelist + +# KeyboardAwareLinearLayout uses reflection on android.View +-dontnote org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout + +# Emoji +-keep class org.thoughtcrime.securesms.** +-keep class com.astuetz.PagerSlidingTabStrip$OnTabReselectedListener +-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { + **[] $VALUES; + public *; +} diff --git a/mailbox-android/proguard-test.txt b/mailbox-android/proguard-test.txt new file mode 100644 index 0000000000000000000000000000000000000000..df4eb272e3ca506cc376f147f2bb0ebf25ede814 --- /dev/null +++ b/mailbox-android/proguard-test.txt @@ -0,0 +1,15 @@ +-dontwarn android.test.** +-dontwarn android.support.test.** +-dontnote android.support.test.** +-dontwarn com.googlecode.eyesfree.compat.CompatUtils + +-keep class org.xmlpull.v1.** { *; } +-dontwarn org.xmlpull.v1.** + +-keep class org.junit.** { *; } +-dontwarn org.junit.** + +-keep class junit.** { *; } +-dontwarn junit.** + +-dontwarn org.briarproject.briar.android.BriarTestComponentApplication \ No newline at end of file diff --git a/mailbox-android/project.properties b/mailbox-android/project.properties new file mode 100644 index 0000000000000000000000000000000000000000..629dfb0da17d1cce0b5a8a1df0611abdd6711e37 --- /dev/null +++ b/mailbox-android/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-rules.txt + +# Project target. +target=android-22 diff --git a/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/BriarUiTestComponent.java b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/BriarUiTestComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..2ee2115d700ca35d1280775b5bab93e6e8689504 --- /dev/null +++ b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/BriarUiTestComponent.java @@ -0,0 +1,29 @@ +package org.briarproject.mailbox.android; + +import org.briarproject.bramble.BrambleAndroidModule; +import org.briarproject.bramble.BrambleCoreModule; +import org.briarproject.bramble.account.BriarAccountModule; +import org.briarproject.mailbox.BriarCoreModule; +import org.briarproject.mailbox.android.login.SetupActivityScreenshotTest; +import org.briarproject.mailbox.android.navdrawer.NavDrawerActivityTest; +import org.briarproject.mailbox.android.settings.SettingsActivityScreenshotTest; + +import javax.inject.Singleton; + +import dagger.Component; + +@Singleton +@Component(modules = { + AppModule.class, + BriarCoreModule.class, + BrambleAndroidModule.class, + BriarAccountModule.class, + BrambleCoreModule.class +}) +public interface BriarUiTestComponent extends AndroidComponent { + + void inject(SetupActivityScreenshotTest test); + void inject(NavDrawerActivityTest test); + void inject(SettingsActivityScreenshotTest test); + +} diff --git a/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/MailboxTestComponentApplication.java b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/MailboxTestComponentApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..5acd930d65a498bd63a555da576954645935cf96 --- /dev/null +++ b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/MailboxTestComponentApplication.java @@ -0,0 +1,20 @@ +package org.briarproject.mailbox.android; + +import org.briarproject.bramble.BrambleCoreModule; +import org.briarproject.mailbox.BriarCoreModule; + +public class MailboxTestComponentApplication extends MailboxApplicationImpl { + + @Override + protected AndroidComponent createApplicationComponent() { + AndroidComponent component = DaggerBriarUiTestComponent.builder() + .appModule(new AppModule(this)).build(); + // We need to load the eager singletons directly after making the + // dependency graphs + BrambleCoreModule.initEagerSingletons(component); + BriarCoreModule.initEagerSingletons(component); + AndroidEagerSingletons.initEagerSingletons(component); + return component; + } + +} diff --git a/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/login/SetupActivityScreenshotTest.java b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/login/SetupActivityScreenshotTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1ba965dc95cf0a6073ffff47cccc195db2c91f4c --- /dev/null +++ b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/login/SetupActivityScreenshotTest.java @@ -0,0 +1,106 @@ +package org.briarproject.mailbox.android.login; + +import android.support.test.espresso.intent.rule.IntentsTestRule; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject; +import android.support.test.uiautomator.UiSelector; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.BriarUiTestComponent; +import org.briarproject.mailbox.android.test.ScreenshotTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static android.support.test.InstrumentationRegistry.getInstrumentation; +import static android.support.test.InstrumentationRegistry.getTargetContext; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.action.ViewActions.typeText; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.intent.Intents.intended; +import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.isRoot; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static android.support.test.runner.lifecycle.Stage.PAUSED; +import static junit.framework.Assert.assertTrue; +import static org.briarproject.mailbox.android.test.ViewActions.waitForActivity; +import static org.briarproject.mailbox.android.test.ViewActions.waitUntilMatches; +import static org.briarproject.mailbox.android.util.UiUtils.needsDozeWhitelisting; + + +@RunWith(AndroidJUnit4.class) +public class SetupActivityScreenshotTest extends ScreenshotTest { + + @Rule + public IntentsTestRule<SetupActivity> testRule = + new IntentsTestRule<SetupActivity>(SetupActivity.class) { + @Override + protected void beforeActivityLaunched() { + super.beforeActivityLaunched(); + accountManager.deleteAccount(); + } + }; + + @Override + protected void inject(BriarUiTestComponent component) { + component.inject(this); + } + + @Test + public void createAccount() throws Exception { + // Enter username + onView(withText(R.string.setup_title)) + .check(matches(isDisplayed())); + onView(withId(R.id.nickname_entry)) + .check(matches(isDisplayed())) + .perform(typeText(USERNAME)); + onView(withId(R.id.nickname_entry)) + .perform(waitUntilMatches(withText(USERNAME))); + + screenshot("manual_create_account"); + + onView(withId(R.id.next)) + .check(matches(isDisplayed())) + .perform(click()); + + // Enter password + onView(withId(R.id.password_entry)) + .check(matches(isDisplayed())) + .perform(typeText(PASSWORD)); + onView(withId(R.id.password_confirm)) + .check(matches(isDisplayed())) + .perform(typeText(PASSWORD)); + onView(withId(R.id.next)) + .check(matches(isDisplayed())) + .perform(click()); + + // White-list Doze if needed + if (needsDozeWhitelisting(getTargetContext())) { + onView(withText(R.string.setup_doze_button)) + .check(matches(isDisplayed())) + .perform(click()); + UiDevice device = UiDevice.getInstance(getInstrumentation()); + UiObject allowButton = device.findObject( + new UiSelector().className("android.widget.Button") + .index(1)); + allowButton.click(); + onView(withId(R.id.next)) + .check(matches(isDisplayed())) + .perform(click()); + } + + // wait for OpenDatabaseActivity to show up + onView(withId(R.id.progress)) + .check(matches(isDisplayed())); + onView(isRoot()) + .perform(waitForActivity(testRule.getActivity(), PAUSED)); + intended(hasComponent(OpenDatabaseActivity.class.getName())); + + assertTrue(accountManager.hasDatabaseKey()); + } + +} diff --git a/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/navdrawer/NavDrawerActivityTest.java b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/navdrawer/NavDrawerActivityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..06e351f60e66eb129ad57bebebf079056f2bfe78 --- /dev/null +++ b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/navdrawer/NavDrawerActivityTest.java @@ -0,0 +1,48 @@ +package org.briarproject.mailbox.android.navdrawer; + +import android.support.test.espresso.contrib.DrawerActions; +import android.support.test.runner.AndroidJUnit4; +import android.view.Gravity; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.BriarUiTestComponent; +import org.briarproject.mailbox.android.settings.SettingsActivity; +import org.briarproject.mailbox.android.test.ScreenshotTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.contrib.DrawerMatchers.isClosed; +import static android.support.test.espresso.intent.Intents.intended; +import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +@RunWith(AndroidJUnit4.class) +public class NavDrawerActivityTest extends ScreenshotTest { + + @Rule + public CleanAccountTestRule<NavDrawerActivity> testRule = + new CleanAccountTestRule<>(NavDrawerActivity.class); + + @Override + protected void inject(BriarUiTestComponent component) { + component.inject(this); + } + + @Test + public void openSettings() { + onView(withId(R.id.drawer_layout)) + .check(matches(isClosed(Gravity.START))) + .perform(DrawerActions.open()); + onView(withText(R.string.settings_button)) + .check(matches(isDisplayed())) + .perform(click()); + intended(hasComponent(SettingsActivity.class.getName())); + } + +} diff --git a/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/settings/SettingsActivityScreenshotTest.java b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/settings/SettingsActivityScreenshotTest.java new file mode 100644 index 0000000000000000000000000000000000000000..69c4fdb0ad5d32d7bbc15110fd745b6ba73467bb --- /dev/null +++ b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/settings/SettingsActivityScreenshotTest.java @@ -0,0 +1,70 @@ +package org.briarproject.mailbox.android.settings; + +import android.content.Intent; +import android.support.test.espresso.contrib.DrawerActions; +import android.support.test.runner.AndroidJUnit4; +import android.view.Gravity; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.BriarUiTestComponent; +import org.briarproject.mailbox.android.navdrawer.NavDrawerActivity; +import org.briarproject.mailbox.android.test.ScreenshotTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.contrib.DrawerMatchers.isClosed; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +@RunWith(AndroidJUnit4.class) +public class SettingsActivityScreenshotTest extends ScreenshotTest { + + @Rule + public CleanAccountTestRule<SettingsActivity> testRule = + new CleanAccountTestRule<>(SettingsActivity.class); + + @Override + protected void inject(BriarUiTestComponent component) { + component.inject(this); + } + + @Test + public void changeTheme() { + onView(withText(R.string.settings_button)) + .check(matches(isDisplayed())); + + screenshot("manual_dark_theme_settings"); + + // switch to dark theme + onView(withText(R.string.pref_theme_title)) + .check(matches(isDisplayed())) + .perform(click()); + onView(withText(R.string.pref_theme_dark)) + .check(matches(isDisplayed())) + .perform(click()); + + // start main activity + Intent i = + new Intent(testRule.getActivity(), NavDrawerActivity.class); + testRule.getActivity().startActivity(i); + + // close expiry warning + onView(withId(R.id.expiryWarningClose)) + .check(matches(isDisplayed())); + onView(withId(R.id.expiryWarningClose)) + .perform(click()); + + // open navigation drawer + onView(withId(R.id.drawer_layout)) + .check(matches(isClosed(Gravity.START))) + .perform(DrawerActions.open()); + + screenshot("manual_dark_theme_nav_drawer"); + } + +} diff --git a/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/test/BriarTestRunner.java b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/test/BriarTestRunner.java new file mode 100644 index 0000000000000000000000000000000000000000..9b46338ca276df431a7ada40e5ceb7f9d65d001e --- /dev/null +++ b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/test/BriarTestRunner.java @@ -0,0 +1,20 @@ +package org.briarproject.mailbox.android.test; + +import android.app.Application; +import android.content.Context; +import android.support.test.runner.AndroidJUnitRunner; + +import org.briarproject.mailbox.android.MailboxTestComponentApplication; + +public class BriarTestRunner extends AndroidJUnitRunner { + + @Override + public Application newApplication(ClassLoader cl, String className, + Context context) + throws InstantiationException, IllegalAccessException, + ClassNotFoundException { + return super.newApplication(cl, MailboxTestComponentApplication.class.getName(), + context); + } + +} diff --git a/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/test/ScreenshotTest.java b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/test/ScreenshotTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a704c6db1450110a020b6497a2253b6df0e7444b --- /dev/null +++ b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/test/ScreenshotTest.java @@ -0,0 +1,73 @@ +package org.briarproject.mailbox.android.test; + +import android.app.Activity; +import android.support.test.espresso.intent.rule.IntentsTestRule; +import android.util.Log; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.mailbox.android.MailboxTestComponentApplication; +import org.briarproject.mailbox.android.BriarUiTestComponent; +import org.junit.ClassRule; + +import javax.inject.Inject; + +import tools.fastlane.screengrab.Screengrab; +import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy; +import tools.fastlane.screengrab.locale.LocaleTestRule; + +import static android.support.test.InstrumentationRegistry.getTargetContext; +import static tools.fastlane.screengrab.Screengrab.setDefaultScreenshotStrategy; + +public abstract class ScreenshotTest { + + @ClassRule + public static final LocaleTestRule localeTestRule = new LocaleTestRule(); + + protected static final String USERNAME = "Alice"; + protected static final String PASSWORD = "123456"; + + @Inject + protected AccountManager accountManager; + @Inject + protected LifecycleManager lifecycleManager; + + public ScreenshotTest() { + super(); + setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy()); + MailboxTestComponentApplication app = + (MailboxTestComponentApplication) getTargetContext() + .getApplicationContext(); + inject((BriarUiTestComponent) app.getApplicationComponent()); + } + + protected abstract void inject(BriarUiTestComponent component); + + protected void screenshot(String name) { + try { + Screengrab.screenshot(name); + } catch (RuntimeException e) { + if (!e.getMessage().equals("Unable to capture screenshot.")) + throw e; + // The tests should still pass when run from AndroidStudio + // without manually granting permissions like fastlane does. + Log.w("Screengrab", "Permission to write screenshot is missing."); + } + } + + protected class CleanAccountTestRule<A extends Activity> + extends IntentsTestRule<A> { + + public CleanAccountTestRule(Class<A> activityClass) { + super(activityClass); + } + + @Override + protected void beforeActivityLaunched() { + super.beforeActivityLaunched(); + accountManager.deleteAccount(); + accountManager.createAccount(USERNAME, PASSWORD); + } + } + +} diff --git a/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/test/ViewActions.java b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/test/ViewActions.java new file mode 100644 index 0000000000000000000000000000000000000000..0fd929813f6ff09efd7a638a835436f5585b349a --- /dev/null +++ b/mailbox-android/src/androidTest/java/org/briarproject/mailbox/android/test/ViewActions.java @@ -0,0 +1,93 @@ +package org.briarproject.mailbox.android.test; + +import android.app.Activity; +import android.support.test.espresso.PerformException; +import android.support.test.espresso.UiController; +import android.support.test.espresso.ViewAction; +import android.support.test.runner.lifecycle.ActivityLifecycleMonitor; +import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; +import android.support.test.runner.lifecycle.Stage; +import android.view.View; + +import org.hamcrest.Matcher; + +import java.util.concurrent.TimeoutException; + +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.util.HumanReadables.describe; +import static android.support.test.espresso.util.TreeIterables.breadthFirstViewTraversal; +import static java.lang.System.currentTimeMillis; +import static java.util.concurrent.TimeUnit.SECONDS; + +public class ViewActions { + + private final static long TIMEOUT_MS = SECONDS.toMillis(10); + private final static long WAIT_MS = 50; + + public static ViewAction waitUntilMatches(Matcher<View> viewMatcher) { + return waitUntilMatches(viewMatcher, TIMEOUT_MS); + } + + private static ViewAction waitUntilMatches(Matcher<View> viewMatcher, + long timeout) { + return new CustomViewAction() { + @Override + protected boolean exitConditionTrue(View view) { + for (View child : breadthFirstViewTraversal(view)) { + if (viewMatcher.matches(child)) return true; + } + return false; + } + + @Override + public String getDescription() { + return "Wait for view matcher " + viewMatcher + + " to match within " + timeout + " milliseconds."; + } + }; + } + + public static ViewAction waitForActivity(Activity activity, Stage stage) { + return new CustomViewAction() { + @Override + protected boolean exitConditionTrue(View view) { + ActivityLifecycleMonitor lifecycleMonitor = + ActivityLifecycleMonitorRegistry.getInstance(); + return lifecycleMonitor.getLifecycleStageOf(activity) == stage; + } + + @Override + public String getDescription() { + return "Wait for activity " + activity.getClass().getName() + + " to resume within " + TIMEOUT_MS + " milliseconds."; + } + }; + } + + private static abstract class CustomViewAction implements ViewAction { + @Override + public Matcher<View> getConstraints() { + return isDisplayed(); + } + + @Override + public void perform(UiController uiController, View view) { + uiController.loopMainThreadUntilIdle(); + long endTime = currentTimeMillis() + TIMEOUT_MS; + do { + if (exitConditionTrue(view)) return; + uiController.loopMainThreadForAtLeast(WAIT_MS); + } + while (currentTimeMillis() < endTime); + + throw new PerformException.Builder() + .withActionDescription(getDescription()) + .withViewDescription(describe(view)) + .withCause(new TimeoutException()) + .build(); + } + + protected abstract boolean exitConditionTrue(View view); + } + +} diff --git a/mailbox-android/src/debug/res/values/strings.xml b/mailbox-android/src/debug/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..032ead0453f91525f2860d2afdaa19a9f2abc841 --- /dev/null +++ b/mailbox-android/src/debug/res/values/strings.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name" translatable="false">Briar Mailbox Debug</string> + <string name="app_package" translatable="false">org.briarproject.mailbox.android.debug</string> +</resources> diff --git a/mailbox-android/src/main/AndroidManifest.xml b/mailbox-android/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..79a3a86ccce98a5a69b26677c4edc9d086869123 --- /dev/null +++ b/mailbox-android/src/main/AndroidManifest.xml @@ -0,0 +1,180 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest + package="org.briarproject.mailbox" + xmlns:android="http://schemas.android.com/apk/res/android"> + + <uses-feature + android:name="android.hardware.bluetooth" + android:required="false"/> + <uses-feature + android:name="android.hardware.camera" + android:required="false"/> + <uses-feature + android:name="android.hardware.touchscreen" + android:required="false"/> + + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> + <uses-permission android:name="android.permission.BLUETOOTH"/> + <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> + <uses-permission android:name="android.permission.CAMERA"/> + <uses-permission android:name="android.permission.INTERNET"/> + <uses-permission android:name="android.permission.VIBRATE"/> + <uses-permission android:name="android.permission.WAKE_LOCK"/> + <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> + + <uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/> + + <application + android:name="org.briarproject.mailbox.android.MailboxApplicationImpl" + android:allowBackup="false" + android:icon="@mipmap/ic_launcher_round" + android:label="@string/app_name" + android:logo="@mipmap/ic_launcher_round" + android:theme="@style/BriarTheme"> + + <receiver + android:name=".android.login.SignInReminderReceiver" + android:exported="false"> + <intent-filter> + <action android:name="android.intent.action.BOOT_COMPLETED"/> + <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/> + </intent-filter> + </receiver> + + <service + android:name=".android.BriarService" + android:exported="false"> + <intent-filter> + <action android:name="org.briarproject.briar.android.BriarService"/> + </intent-filter> + </service> + + <activity + android:name=".android.reporting.DevReportActivity" + android:excludeFromRecents="true" + android:exported="false" + android:finishOnTaskLaunch="true" + android:label="@string/crash_report_title" + android:launchMode="singleInstance" + android:theme="@style/BriarTheme.NoActionBar" + android:windowSoftInputMode="stateHidden"> + </activity> + + <activity + android:name=".android.splash.ExpiredActivity" + android:label="@string/app_name"> + </activity> + + <activity + android:name=".android.login.PasswordActivity" + android:label="@string/app_name" + android:windowSoftInputMode="stateVisible"> + </activity> + + <activity + android:name=".android.login.SetupActivity" + android:label="@string/setup_title" + android:windowSoftInputMode="adjustResize"> + </activity> + + <activity + android:name=".android.splash.SplashScreenActivity" + android:label="@string/app_name" + android:theme="@style/BriarTheme.NoActionBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + + <activity + android:name=".android.login.OpenDatabaseActivity" + android:label="@string/app_name" + android:launchMode="singleTop"/> + + <activity + android:name=".android.navdrawer.NavDrawerActivity" + android:launchMode="singleTop" + android:theme="@style/BriarTheme.NoActionBar"> + </activity> + + <activity + android:name=".android.keyagreement.MailboxExchangeActivity" + android:label="@string/add_contact_title" + android:parentActivityName=".android.navdrawer.NavDrawerActivity" + android:theme="@style/BriarTheme.NoActionBar"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".android.navdrawer.NavDrawerActivity"/> + </activity> + + <activity + android:name=".android.StartupFailureActivity" + android:label="@string/startup_failed_activity_title"> + </activity> + + <activity + android:name=".android.settings.SettingsActivity" + android:label="@string/settings_button" + android:parentActivityName=".android.navdrawer.NavDrawerActivity" + android:permission="android.permission.READ_NETWORK_USAGE_HISTORY"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".android.navdrawer.NavDrawerActivity" + /> + <intent-filter> + <action android:name="android.intent.action.MANAGE_NETWORK_USAGE"/> + <category android:name="android.intent.category.DEFAULT"/> + </intent-filter> + </activity> + + <activity + android:name=".android.login.ChangePasswordActivity" + android:label="@string/change_password" + android:parentActivityName=".android.settings.SettingsActivity"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".android.settings.SettingsActivity" + /> + </activity> + + <activity + android:name=".android.panic.PanicPreferencesActivity" + android:label="@string/panic_setting" + android:parentActivityName=".android.settings.SettingsActivity"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".android.settings.SettingsActivity" + /> + </activity> + + <activity + android:name=".android.panic.PanicResponderActivity" + android:noHistory="true" + android:theme="@android:style/Theme.NoDisplay"> + <!-- this can never have launchMode singleTask or singleInstance! --> + <intent-filter> + <action android:name="info.guardianproject.panic.action.TRIGGER"/> + <category android:name="android.intent.category.DEFAULT"/> + </intent-filter> + </activity> + + <activity + android:name=".android.logout.ExitActivity" + android:theme="@android:style/Theme.NoDisplay"> + </activity> + + <activity + android:name=".android.logout.HideUiActivity" + android:theme="@android:style/Theme.NoDisplay"> + </activity> + + <activity + android:name=".android.login.UnlockActivity" + android:label="@string/lock_unlock" + android:launchMode="singleTask" + android:theme="@style/BriarTheme.NoActionBar"/> + + </application> +</manifest> diff --git a/mailbox-android/src/main/assets/emoji_activity.png b/mailbox-android/src/main/assets/emoji_activity.png new file mode 100644 index 0000000000000000000000000000000000000000..908370dd15ec125d7b57b96ae932ee5fbe58a9d9 Binary files /dev/null and b/mailbox-android/src/main/assets/emoji_activity.png differ diff --git a/mailbox-android/src/main/assets/emoji_animals_nature.png b/mailbox-android/src/main/assets/emoji_animals_nature.png new file mode 100644 index 0000000000000000000000000000000000000000..7a0661fe1ff7b9c82e2a36381ce303ceb1246693 Binary files /dev/null and b/mailbox-android/src/main/assets/emoji_animals_nature.png differ diff --git a/mailbox-android/src/main/assets/emoji_flags.png b/mailbox-android/src/main/assets/emoji_flags.png new file mode 100644 index 0000000000000000000000000000000000000000..80f6bbd0db5f9e5e4a9938a344f064372e894606 Binary files /dev/null and b/mailbox-android/src/main/assets/emoji_flags.png differ diff --git a/mailbox-android/src/main/assets/emoji_food_drink.png b/mailbox-android/src/main/assets/emoji_food_drink.png new file mode 100644 index 0000000000000000000000000000000000000000..33d7cd0a6849759c4ccb852a8938afd5354ec25b Binary files /dev/null and b/mailbox-android/src/main/assets/emoji_food_drink.png differ diff --git a/mailbox-android/src/main/assets/emoji_objects.png b/mailbox-android/src/main/assets/emoji_objects.png new file mode 100644 index 0000000000000000000000000000000000000000..f2b6dfbf9d7b20287d6e95a9739373f37f5eaaaa Binary files /dev/null and b/mailbox-android/src/main/assets/emoji_objects.png differ diff --git a/mailbox-android/src/main/assets/emoji_smiley_people.png b/mailbox-android/src/main/assets/emoji_smiley_people.png new file mode 100644 index 0000000000000000000000000000000000000000..9325d703a8010ac1ca938f3a8b20836cc1efc4c0 Binary files /dev/null and b/mailbox-android/src/main/assets/emoji_smiley_people.png differ diff --git a/mailbox-android/src/main/assets/emoji_symbols.png b/mailbox-android/src/main/assets/emoji_symbols.png new file mode 100644 index 0000000000000000000000000000000000000000..e88275b2fc82bc0a03759a642186a8184c8746f9 Binary files /dev/null and b/mailbox-android/src/main/assets/emoji_symbols.png differ diff --git a/mailbox-android/src/main/assets/emoji_travel_places.png b/mailbox-android/src/main/assets/emoji_travel_places.png new file mode 100644 index 0000000000000000000000000000000000000000..16e2be37d680dd410b6856de655770f3c7cbbac8 Binary files /dev/null and b/mailbox-android/src/main/assets/emoji_travel_places.png differ diff --git a/mailbox-android/src/main/ic_launcher_round-web.png b/mailbox-android/src/main/ic_launcher_round-web.png new file mode 100644 index 0000000000000000000000000000000000000000..235caf294dec5b487de1db3d2bc1c5234eb01ff7 Binary files /dev/null and b/mailbox-android/src/main/ic_launcher_round-web.png differ diff --git a/mailbox-android/src/main/java/im/delight/android/identicons/Identicon.java b/mailbox-android/src/main/java/im/delight/android/identicons/Identicon.java new file mode 100644 index 0000000000000000000000000000000000000000..42f5c959151de89a199811b4235ff1018f3fcfd1 --- /dev/null +++ b/mailbox-android/src/main/java/im/delight/android/identicons/Identicon.java @@ -0,0 +1,101 @@ +package im.delight.android.identicons; + +/** + * Copyright 2014 www.delight.im <info@delight.im> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.support.annotation.NonNull; +import android.support.annotation.UiThread; + +import static android.graphics.Paint.Style.FILL; + +@UiThread +class Identicon { + + private static final int ROWS = 9, COLUMNS = 9; + private static final int CENTER_COLUMN_INDEX = COLUMNS / 2 + COLUMNS % 2; + + private final byte[] input; + private final Paint paint; + private final int[][] colors; + + private int cellWidth, cellHeight; + + Identicon(@NonNull byte[] input) { + if (input.length == 0) throw new IllegalArgumentException(); + this.input = input; + + paint = new Paint(); + paint.setStyle(FILL); + paint.setAntiAlias(true); + paint.setDither(true); + + colors = new int[ROWS][COLUMNS]; + int colorVisible = getForegroundColor(); + int colorInvisible = getBackgroundColor(); + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLUMNS; c++) { + if (isCellVisible(r, c)) colors[r][c] = colorVisible; + else colors[r][c] = colorInvisible; + } + } + } + + private byte getByte(int index) { + return input[index % input.length]; + } + + private boolean isCellVisible(int row, int column) { + return getByte(3 + row * CENTER_COLUMN_INDEX + + getSymmetricColumnIndex(column)) >= 0; + } + + private int getSymmetricColumnIndex(int index) { + if (index < CENTER_COLUMN_INDEX) return index; + else return COLUMNS - index - 1; + } + + private int getForegroundColor() { + int r = getByte(0) * 3 / 4 + 96; + int g = getByte(1) * 3 / 4 + 96; + int b = getByte(2) * 3 / 4 + 96; + return Color.rgb(r, g, b); + } + + private int getBackgroundColor() { + // http://www.google.com/design/spec/style/color.html#color-themes + return Color.rgb(0xFA, 0xFA, 0xFA); + } + + void updateSize(int w, int h) { + cellWidth = w / COLUMNS; + cellHeight = h / ROWS; + } + + void draw(Canvas canvas) { + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLUMNS; c++) { + int x = cellWidth * c; + int y = cellHeight * r; + paint.setColor(colors[r][c]); + canvas.drawRect(x, y + cellHeight, x + cellWidth, y, paint); + } + } + } +} diff --git a/mailbox-android/src/main/java/im/delight/android/identicons/IdenticonDrawable.java b/mailbox-android/src/main/java/im/delight/android/identicons/IdenticonDrawable.java new file mode 100644 index 0000000000000000000000000000000000000000..75663bd297eaa918f0abab90cd448b43e8601409 --- /dev/null +++ b/mailbox-android/src/main/java/im/delight/android/identicons/IdenticonDrawable.java @@ -0,0 +1,82 @@ +package im.delight.android.identicons; + +/** + * Copyright 2014 www.delight.im <info@delight.im> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.UiThread; + +import static android.graphics.PixelFormat.OPAQUE; + +@UiThread +public class IdenticonDrawable extends Drawable { + + private static final int HEIGHT = 200, WIDTH = 200; + + private final Identicon identicon; + + public IdenticonDrawable(@NonNull byte[] input) { + super(); + identicon = new Identicon(input); + } + + @Override + public int getIntrinsicHeight() { + return HEIGHT; + } + + @Override + public int getIntrinsicWidth() { + return WIDTH; + } + + @Override + public void setBounds(@NonNull Rect bounds) { + super.setBounds(bounds); + identicon.updateSize(bounds.right - bounds.left, + bounds.bottom - bounds.top); + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + super.setBounds(left, top, right, bottom); + identicon.updateSize(right - left, bottom - top); + } + + @Override + public void draw(@NonNull Canvas canvas) { + identicon.draw(canvas); + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter cf) { + + } + + @Override + public int getOpacity() { + return OPAQUE; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java b/mailbox-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java new file mode 100644 index 0000000000000000000000000000000000000000..2ffad3a7dec31c0ba82176afc18d35e6d3bf1284 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java @@ -0,0 +1,33 @@ +package org.briarproject.bramble.account; + +import android.app.Application; +import android.content.SharedPreferences; + +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.Localizer; +import org.briarproject.mailbox.android.util.UiUtils; + +import javax.inject.Inject; + +class BriarAccountManager extends AndroidAccountManager { + + @Inject + BriarAccountManager(DatabaseConfig databaseConfig, CryptoComponent crypto, + IdentityManager identityManager, SharedPreferences prefs, + Application app) { + super(databaseConfig, crypto, identityManager, prefs, app); + } + + @Override + public void deleteAccount() { + synchronized (stateChangeLock) { + super.deleteAccount(); + Localizer.reinitialize(); + UiUtils.setTheme(appContext, + appContext.getString(R.string.pref_theme_light_value)); + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/bramble/account/BriarAccountModule.java b/mailbox-android/src/main/java/org/briarproject/bramble/account/BriarAccountModule.java new file mode 100644 index 0000000000000000000000000000000000000000..3ed782d77ac791db1b68f0fcf1504e195de57ddd --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/bramble/account/BriarAccountModule.java @@ -0,0 +1,18 @@ +package org.briarproject.bramble.account; + +import org.briarproject.bramble.api.account.AccountManager; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class BriarAccountModule { + + @Provides + @Singleton + AccountManager provideAccountManager(BriarAccountManager accountManager) { + return accountManager; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidComponent.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..4d20692cff18d15a2bc21a2b4adab19589f5a56d --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidComponent.java @@ -0,0 +1,113 @@ +package org.briarproject.mailbox.android; + +import org.briarproject.bramble.BrambleAndroidModule; +import org.briarproject.bramble.BrambleCoreEagerSingletons; +import org.briarproject.bramble.BrambleCoreModule; +import org.briarproject.bramble.account.BriarAccountModule; +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.contact.ContactExchangeTask; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.crypto.CryptoExecutor; +import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; +import org.briarproject.bramble.api.db.DatabaseExecutor; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.keyagreement.KeyAgreementTask; +import org.briarproject.bramble.api.keyagreement.PayloadEncoder; +import org.briarproject.bramble.api.keyagreement.PayloadParser; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.plugin.ConnectionRegistry; +import org.briarproject.bramble.api.plugin.PluginManager; +import org.briarproject.bramble.api.settings.SettingsManager; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.plugin.tor.CircumventionProvider; +import org.briarproject.mailbox.android.login.SignInReminderReceiver; +import org.briarproject.mailbox.android.reporting.BriarReportSender; +import org.briarproject.mailbox.api.android.AndroidNotificationManager; +import org.briarproject.mailbox.api.android.DozeWatchdog; +import org.briarproject.mailbox.api.android.LockManager; +import org.briarproject.mailbox.api.android.ScreenFilterMonitor; +import org.thoughtcrime.securesms.components.emoji.EmojiProvider; +import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel; + +import java.util.concurrent.Executor; + +import javax.inject.Singleton; + +import dagger.Component; + +@Singleton +@Component(modules = { + BrambleCoreModule.class, + BrambleAndroidModule.class, + BriarAccountModule.class, + AppModule.class +}) +public interface AndroidComponent + extends BrambleCoreEagerSingletons { + + // Exposed objects + @CryptoExecutor + Executor cryptoExecutor(); + + PasswordStrengthEstimator passwordStrengthIndicator(); + + @DatabaseExecutor + Executor databaseExecutor(); + + LifecycleManager lifecycleManager(); + + IdentityManager identityManager(); + + PluginManager pluginManager(); + + EventBus eventBus(); + + AndroidNotificationManager androidNotificationManager(); + + ScreenFilterMonitor screenFilterMonitor(); + + ConnectionRegistry connectionRegistry(); + + ContactManager contactManager(); + + SettingsManager settingsManager(); + + ContactExchangeTask contactExchangeTask(); + + KeyAgreementTask keyAgreementTask(); + + PayloadEncoder payloadEncoder(); + + PayloadParser payloadParser(); + + AndroidExecutor androidExecutor(); + + DozeWatchdog dozeWatchdog(); + + @IoExecutor + Executor ioExecutor(); + + AccountManager accountManager(); + + LockManager lockManager(); + + LocationUtils locationUtils(); + + CircumventionProvider circumventionProvider(); + + void inject(SignInReminderReceiver briarService); + + void inject(BriarService briarService); + + void inject(BriarReportSender briarReportSender); + + void inject(EmojiProvider emojiProvider); + + void inject(RecentEmojiPageModel recentEmojiPageModel); + + // Eager singleton load + void inject(AppModule.EagerSingletons init); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidDatabaseConfig.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidDatabaseConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..ecd9aaba66c4adb4db30d503846996d9dbdaef2a --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidDatabaseConfig.java @@ -0,0 +1,32 @@ +package org.briarproject.mailbox.android; + +import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.io.File; + +@NotNullByDefault +class AndroidDatabaseConfig implements DatabaseConfig { + + private final File dbDir, keyDir; + + AndroidDatabaseConfig(File dbDir, File keyDir) { + this.dbDir = dbDir; + this.keyDir = keyDir; + } + + @Override + public File getDatabaseDirectory() { + return dbDir; + } + + @Override + public File getDatabaseKeyDirectory() { + return keyDir; + } + + @Override + public long getMaxSize() { + return Long.MAX_VALUE; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidEagerSingletons.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidEagerSingletons.java new file mode 100644 index 0000000000000000000000000000000000000000..2efe9687680595c0f7c4ea7fa8fb74a7d28e5fff --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidEagerSingletons.java @@ -0,0 +1,8 @@ +package org.briarproject.mailbox.android; + +class AndroidEagerSingletons { + + static void initEagerSingletons(AndroidComponent c) { + c.inject(new AppModule.EagerSingletons()); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidNotificationManagerImpl.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidNotificationManagerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..d5a8ea9cdf5c1372727f82a9138643dc15078512 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AndroidNotificationManagerImpl.java @@ -0,0 +1,163 @@ +package org.briarproject.mailbox.android; + +import android.app.Application; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.support.annotation.UiThread; +import android.support.v4.app.NotificationCompat; + +import org.briarproject.bramble.api.lifecycle.Service; +import org.briarproject.bramble.api.lifecycle.ServiceException; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.login.SignInReminderReceiver; +import org.briarproject.mailbox.android.navdrawer.NavDrawerActivity; +import org.briarproject.mailbox.android.splash.SplashScreenActivity; +import org.briarproject.mailbox.api.android.AndroidNotificationManager; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.annotation.concurrent.ThreadSafe; +import javax.inject.Inject; + +import static android.app.NotificationManager.IMPORTANCE_LOW; +import static android.content.Context.NOTIFICATION_SERVICE; +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.os.Build.VERSION.SDK_INT; +import static android.support.v4.app.NotificationCompat.CATEGORY_SERVICE; +import static android.support.v4.app.NotificationCompat.PRIORITY_LOW; +import static android.support.v4.app.NotificationCompat.PRIORITY_MIN; +import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET; +import static android.support.v4.content.ContextCompat.getColor; + +@ThreadSafe +@MethodsNotNullByDefault +@ParametersNotNullByDefault +class AndroidNotificationManagerImpl implements AndroidNotificationManager, + Service { + + private final Context appContext; + private final NotificationManager notificationManager; + private final AtomicBoolean used = new AtomicBoolean(false); + + // The following must only be accessed on the main UI thread + private boolean blockSignInReminder = false; + + @Inject + AndroidNotificationManagerImpl(Application app) { + appContext = app.getApplicationContext(); + notificationManager = (NotificationManager) + appContext.getSystemService(NOTIFICATION_SERVICE); + } + + @Override + public void startService() throws ServiceException { + if (used.getAndSet(true)) throw new IllegalStateException(); + } + + @Override + public void stopService() throws ServiceException { + } + + @UiThread + @Override + public Notification getForegroundNotification() { + return getForegroundNotification(false); + } + + @UiThread + private Notification getForegroundNotification(boolean locked) { + int title = locked ? R.string.lock_is_locked : + R.string.ongoing_notification_title; + int text = locked ? R.string.lock_tap_to_unlock : + R.string.ongoing_notification_text; + int icon = locked ? R.drawable.startup_lock : + R.drawable.notification_ongoing; + // Ongoing foreground notification that shows BriarService is running + NotificationCompat.Builder b = + new NotificationCompat.Builder(appContext, + ONGOING_CHANNEL_ID); + b.setSmallIcon(icon); + b.setColor(getColor(appContext, R.color.briar_primary)); + b.setContentTitle(appContext.getText(title)); + b.setContentText(appContext.getText(text)); + b.setWhen(0); // Don't show the time + b.setOngoing(true); + Intent i = new Intent(appContext, NavDrawerActivity.class); + i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP); + b.setContentIntent(PendingIntent.getActivity(appContext, 0, i, 0)); + if (SDK_INT >= 21) { + b.setCategory(CATEGORY_SERVICE); + b.setVisibility(VISIBILITY_SECRET); + } + b.setPriority(PRIORITY_MIN); + return b.build(); + } + + @UiThread + @Override + public void updateForegroundNotification(boolean locked) { + Notification n = getForegroundNotification(locked); + notificationManager.notify(ONGOING_NOTIFICATION_ID, n); + } + + @Override + public void showSignInNotification() { + if (blockSignInReminder) return; + if (SDK_INT >= 26) { + NotificationChannel channel = + new NotificationChannel(REMINDER_CHANNEL_ID, appContext + .getString( + R.string.reminder_notification_channel_title), + IMPORTANCE_LOW); + channel.setLockscreenVisibility( + NotificationCompat.VISIBILITY_SECRET); + notificationManager.createNotificationChannel(channel); + } + + NotificationCompat.Builder b = + new NotificationCompat.Builder(appContext, + REMINDER_CHANNEL_ID); + b.setSmallIcon(R.drawable.ic_signout); + b.setColor(getColor(appContext, R.color.briar_primary)); + b.setContentTitle( + appContext.getText(R.string.reminder_notification_title)); + b.setContentText( + appContext.getText(R.string.reminder_notification_text)); + b.setAutoCancel(true); + b.setWhen(0); // Don't show the time + b.setPriority(PRIORITY_LOW); + + // Add a 'Dismiss' action + String actionTitle = + appContext + .getString(R.string.reminder_notification_dismiss); + Intent i1 = new Intent(appContext, SignInReminderReceiver.class); + i1.setAction(ACTION_DISMISS_REMINDER); + PendingIntent actionIntent = + PendingIntent.getBroadcast(appContext, 0, i1, 0); + b.addAction(0, actionTitle, actionIntent); + + Intent i = new Intent(appContext, SplashScreenActivity.class); + i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP); + b.setContentIntent(PendingIntent.getActivity(appContext, 0, i, 0)); + + notificationManager.notify(REMINDER_NOTIFICATION_ID, b.build()); + } + + @Override + public void clearSignInNotification() { + notificationManager.cancel(REMINDER_NOTIFICATION_ID); + } + + @Override + public void blockSignInNotification() { + blockSignInReminder = true; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/AppModule.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AppModule.java new file mode 100644 index 0000000000000000000000000000000000000000..9ec9a923176d99db69483312abf4439efed04a7e --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AppModule.java @@ -0,0 +1,213 @@ +package org.briarproject.mailbox.android; + +import android.app.Application; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.StrictMode; + +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.crypto.PublicKey; +import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.network.NetworkManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.BackoffFactory; +import org.briarproject.bramble.api.plugin.PluginConfig; +import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; +import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; +import org.briarproject.bramble.api.reporting.DevConfig; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; +import org.briarproject.bramble.api.system.Scheduler; +import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory; +import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory; +import org.briarproject.bramble.plugin.tor.AndroidTorPluginFactory; +import org.briarproject.bramble.plugin.tor.CircumventionProvider; +import org.briarproject.bramble.util.AndroidUtils; +import org.briarproject.bramble.util.StringUtils; +import org.briarproject.mailbox.android.account.LockManagerImpl; +import org.briarproject.mailbox.api.android.AndroidNotificationManager; +import org.briarproject.mailbox.api.android.DozeWatchdog; +import org.briarproject.mailbox.api.android.LockManager; +import org.briarproject.mailbox.api.android.ScreenFilterMonitor; + +import java.io.File; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Collection; +import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.net.SocketFactory; + +import dagger.Module; +import dagger.Provides; + +import static android.content.Context.MODE_PRIVATE; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS; +import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX; + +@Module +public class AppModule { + + static class EagerSingletons { + @Inject + AndroidNotificationManager androidNotificationManager; + @Inject + NetworkUsageLogger networkUsageLogger; + @Inject + DozeWatchdog dozeWatchdog; + } + + private final Application application; + + public AppModule(Application application) { + this.application = application; + } + + @Provides + @Singleton + Application providesApplication() { + return application; + } + + @Provides + @Singleton + DatabaseConfig provideDatabaseConfig(Application app) { + //FIXME: StrictMode + StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskReads(); + StrictMode.allowThreadDiskWrites(); + File dbDir = app.getApplicationContext().getDir("db", MODE_PRIVATE); + File keyDir = app.getApplicationContext().getDir("key", MODE_PRIVATE); + StrictMode.setThreadPolicy(tp); + return new AndroidDatabaseConfig(dbDir, keyDir); + } + + @Provides + PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor, + @Scheduler ScheduledExecutorService scheduler, + AndroidExecutor androidExecutor, SecureRandom random, + SocketFactory torSocketFactory, BackoffFactory backoffFactory, + Application app, NetworkManager networkManager, + LocationUtils locationUtils, EventBus eventBus, + ResourceProvider resourceProvider, + CircumventionProvider circumventionProvider, Clock clock) { + Context appContext = app.getApplicationContext(); + DuplexPluginFactory bluetooth = + new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor, + appContext, random, eventBus, backoffFactory); + DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor, + scheduler, appContext, networkManager, locationUtils, eventBus, + torSocketFactory, backoffFactory, resourceProvider, + circumventionProvider, clock); + DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor, + eventBus, backoffFactory, appContext); + Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan); + @NotNullByDefault + PluginConfig pluginConfig = new PluginConfig() { + + @Override + public Collection<DuplexPluginFactory> getDuplexFactories() { + return duplex; + } + + @Override + public Collection<SimplexPluginFactory> getSimplexFactories() { + return emptyList(); + } + + @Override + public boolean shouldPoll() { + return true; + } + }; + return pluginConfig; + } + + @Provides + @Singleton + DevConfig provideDevConfig(Application app, CryptoComponent crypto) { + @NotNullByDefault + DevConfig devConfig = new DevConfig() { + + @Override + public PublicKey getDevPublicKey() { + try { + return crypto.getMessageKeyParser().parsePublicKey( + StringUtils.fromHexString(DEV_PUBLIC_KEY_HEX)); + } catch (GeneralSecurityException e) { + throw new RuntimeException(e); + } + } + + @Override + public String getDevOnionAddress() { + return DEV_ONION_ADDRESS; + } + + @Override + public File getReportDir() { + return AndroidUtils.getReportDir(app.getApplicationContext()); + } + }; + return devConfig; + } + + @Provides + SharedPreferences provideSharedPreferences(Application app) { + // FIXME unify this with getDefaultSharedPreferences() + return app.getSharedPreferences("db", MODE_PRIVATE); + } + + @Provides + @Singleton + AndroidNotificationManager provideAndroidNotificationManager( + LifecycleManager lifecycleManager, EventBus eventBus, + AndroidNotificationManagerImpl notificationManager) { + lifecycleManager.registerService(notificationManager); + return notificationManager; + } + + @Provides + @Singleton + ScreenFilterMonitor provideScreenFilterMonitor( + LifecycleManager lifecycleManager, + ScreenFilterMonitorImpl screenFilterMonitor) { + lifecycleManager.registerService(screenFilterMonitor); + return screenFilterMonitor; + } + + @Provides + NetworkUsageLogger provideNetworkUsageLogger( + LifecycleManager lifecycleManager) { + NetworkUsageLogger networkUsageLogger = new NetworkUsageLogger(); + lifecycleManager.registerService(networkUsageLogger); + return networkUsageLogger; + } + + @Provides + @Singleton + DozeWatchdog provideDozeWatchdog(LifecycleManager lifecycleManager) { + DozeWatchdogImpl dozeWatchdog = new DozeWatchdogImpl(application); + lifecycleManager.registerService(dozeWatchdog); + return dozeWatchdog; + } + + @Provides + @Singleton + LockManager provideLockManager(LifecycleManager lifecycleManager, + EventBus eventBus, LockManagerImpl lockManager) { + lifecycleManager.registerService(lockManager); + eventBus.addListener(lockManager); + return lockManager; + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/BriarService.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/BriarService.java new file mode 100644 index 0000000000000000000000000000000000000000..1b237a022ccd0ce2b04073092a4bd511e83ecf7b --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/BriarService.java @@ -0,0 +1,338 @@ +package org.briarproject.mailbox.android; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.IBinder; +import android.support.v4.app.NotificationCompat; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.logout.HideUiActivity; +import org.briarproject.mailbox.android.navdrawer.NavDrawerActivity; +import org.briarproject.mailbox.api.android.AndroidNotificationManager; +import org.briarproject.mailbox.api.android.LockManager; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; +import static android.app.NotificationManager.IMPORTANCE_DEFAULT; +import static android.app.NotificationManager.IMPORTANCE_NONE; +import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; +import static android.content.Intent.ACTION_SHUTDOWN; +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; +import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; +import static android.os.Build.VERSION.SDK_INT; +import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING; +import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS; +import static org.briarproject.mailbox.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID; +import static org.briarproject.mailbox.api.android.AndroidNotificationManager.FAILURE_NOTIFICATION_ID; +import static org.briarproject.mailbox.api.android.AndroidNotificationManager.ONGOING_CHANNEL_ID; +import static org.briarproject.mailbox.api.android.AndroidNotificationManager.ONGOING_NOTIFICATION_ID; +import static org.briarproject.mailbox.api.android.LockManager.ACTION_LOCK; + +public class BriarService extends Service { + + public static String EXTRA_START_RESULT = + "org.briarproject.briar.START_RESULT"; + public static String EXTRA_NOTIFICATION_ID = + "org.briarproject.briar.FAILURE_NOTIFICATION_ID"; + public static String EXTRA_STARTUP_FAILED = + "org.briarproject.briar.STARTUP_FAILED"; + + private static final Logger LOG = + Logger.getLogger(BriarService.class.getName()); + + private final AtomicBoolean created = new AtomicBoolean(false); + private final Binder binder = new BriarBinder(); + + @Nullable + private BroadcastReceiver receiver = null; + + @Inject + AndroidNotificationManager notificationManager; + @Inject + AccountManager accountManager; + @Inject + LockManager lockManager; + + // Fields that are accessed from background threads must be volatile + @Inject + volatile LifecycleManager lifecycleManager; + @Inject + volatile AndroidExecutor androidExecutor; + private volatile boolean started = false; + + @Override + public void onCreate() { + super.onCreate(); + + MailboxApplication application = (MailboxApplication) getApplication(); + application.getApplicationComponent().inject(this); + + LOG.info("Created"); + if (created.getAndSet(true)) { + LOG.info("Already created"); + stopSelf(); + return; + } + SecretKey dbKey = accountManager.getDatabaseKey(); + if (dbKey == null) { + LOG.info("No database key"); + stopSelf(); + return; + } + + // Create notification channels + if (SDK_INT >= 26) { + NotificationManager nm = (NotificationManager) + getSystemService(NOTIFICATION_SERVICE); + NotificationChannel ongoingChannel = new NotificationChannel( + ONGOING_CHANNEL_ID, + getString(R.string.ongoing_notification_title), + IMPORTANCE_NONE); + ongoingChannel.setLockscreenVisibility(VISIBILITY_SECRET); + nm.createNotificationChannel(ongoingChannel); + NotificationChannel failureChannel = new NotificationChannel( + FAILURE_CHANNEL_ID, + getString(R.string.startup_failed_notification_title), + IMPORTANCE_DEFAULT); + failureChannel.setLockscreenVisibility(VISIBILITY_SECRET); + nm.createNotificationChannel(failureChannel); + } + Notification foregroundNotification = + notificationManager.getForegroundNotification(); + startForeground(ONGOING_NOTIFICATION_ID, foregroundNotification); + // Start the services in a background thread + new Thread(() -> { + StartResult result = lifecycleManager.startServices(dbKey); + if (result == SUCCESS) { + started = true; + } else if (result == ALREADY_RUNNING) { + LOG.info("Already running"); + stopSelf(); + } else { + if (LOG.isLoggable(WARNING)) + LOG.warning("Startup failed: " + result); + showStartupFailureNotification(result); + stopSelf(); + } + }).start(); + // Register for device shutdown broadcasts + receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + LOG.info("Device is shutting down"); + shutdownFromBackground(); + } + }; + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_SHUTDOWN); + filter.addAction("android.intent.action.QUICKBOOT_POWEROFF"); + filter.addAction("com.htc.intent.action.QUICKBOOT_POWEROFF"); + registerReceiver(receiver, filter); + } + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(Localizer.getInstance().setLocale(base)); + } + + private void showStartupFailureNotification(StartResult result) { + androidExecutor.runOnUiThread(() -> { + NotificationCompat.Builder b = new NotificationCompat.Builder( + BriarService.this, FAILURE_CHANNEL_ID); + b.setSmallIcon(android.R.drawable.stat_notify_error); + b.setContentTitle(getText( + R.string.startup_failed_notification_title)); + b.setContentText(getText( + R.string.startup_failed_notification_text)); + Intent i = new Intent(BriarService.this, + StartupFailureActivity.class); + i.setFlags(FLAG_ACTIVITY_NEW_TASK); + i.putExtra(EXTRA_START_RESULT, result); + i.putExtra(EXTRA_NOTIFICATION_ID, FAILURE_NOTIFICATION_ID); + b.setContentIntent(PendingIntent.getActivity(BriarService.this, + 0, i, FLAG_UPDATE_CURRENT)); + Object o = getSystemService(NOTIFICATION_SERVICE); + NotificationManager nm = (NotificationManager) o; + nm.notify(FAILURE_NOTIFICATION_ID, b.build()); + // Bring the dashboard to the front to clear the back stack + i = new Intent(BriarService.this, NavDrawerActivity.class); + i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP); + i.putExtra(EXTRA_STARTUP_FAILED, true); + startActivity(i); + }); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (ACTION_LOCK.equals(intent.getAction())) { + lockManager.setLocked(true); + } + return START_NOT_STICKY; // Don't restart automatically if killed + } + + @Override + public IBinder onBind(Intent intent) { + return binder; + } + + @Override + public void onDestroy() { + super.onDestroy(); + LOG.info("Destroyed"); + stopForeground(true); + if (receiver != null) unregisterReceiver(receiver); + // Stop the services in a background thread + new Thread(() -> { + if (started) lifecycleManager.stopServices(); + }).start(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + LOG.warning("Memory is low"); + // Clear the UI - this is done in onTrimMemory() if SDK_INT >= 16 + if (SDK_INT < 16) hideUi(); + } + + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + if (level == TRIM_MEMORY_UI_HIDDEN) { + LOG.info("Trim memory: UI hidden"); + } else if (level == TRIM_MEMORY_BACKGROUND) { + LOG.info("Trim memory: added to LRU list"); + } else if (level == TRIM_MEMORY_MODERATE) { + LOG.info("Trim memory: near middle of LRU list"); + } else if (level == TRIM_MEMORY_COMPLETE) { + LOG.info("Trim memory: near end of LRU list"); + } else if (SDK_INT >= 16) { + if (level == TRIM_MEMORY_RUNNING_MODERATE) { + LOG.info("Trim memory: running moderately low"); + } else if (level == TRIM_MEMORY_RUNNING_LOW) { + LOG.info("Trim memory: running low"); + } else if (level == TRIM_MEMORY_RUNNING_CRITICAL) { + LOG.info("Trim memory: running critically low"); + // If we're not in the foreground, clear the UI to save memory + RunningAppProcessInfo info = new RunningAppProcessInfo(); + ActivityManager.getMyMemoryState(info); + if (info.importance != IMPORTANCE_FOREGROUND) hideUi(); + } else if (LOG.isLoggable(INFO)) { + LOG.info("Trim memory: unknown level " + level); + } + } else if (LOG.isLoggable(INFO)) { + LOG.info("Trim memory: unknown level " + level); + } + } + + private void hideUi() { + Intent i = new Intent(this, HideUiActivity.class); + i.addFlags(FLAG_ACTIVITY_NEW_TASK + | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | FLAG_ACTIVITY_NO_ANIMATION + | FLAG_ACTIVITY_CLEAR_TASK); + startActivity(i); + } + + private void shutdownFromBackground() { + // Stop the service + stopSelf(); + // Hide the UI + hideUi(); + // Wait for shutdown to complete, then exit + new Thread(() -> { + try { + if (started) lifecycleManager.waitForShutdown(); + } catch (InterruptedException e) { + LOG.info("Interrupted while waiting for shutdown"); + } + LOG.info("Exiting"); + System.exit(0); + }).start(); + } + + /** + * Waits for all services to start before returning. + */ + public void waitForStartup() throws InterruptedException { + lifecycleManager.waitForStartup(); + } + + /** + * Waits for all services to stop before returning. + */ + public void waitForShutdown() throws InterruptedException { + lifecycleManager.waitForShutdown(); + } + + /** + * Starts the shutdown process. + */ + public void shutdown() { + stopSelf(); // This will call onDestroy() + } + + public class BriarBinder extends Binder { + + /** + * Returns the bound service. + */ + public BriarService getService() { + return BriarService.this; + } + } + + public static class BriarServiceConnection implements ServiceConnection { + + private final CountDownLatch binderLatch = new CountDownLatch(1); + + private volatile IBinder binder = null; + + @Override + public void onServiceConnected(ComponentName name, IBinder binder) { + this.binder = binder; + binderLatch.countDown(); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + } + + /** + * Waits for the service to connect and returns its binder. + */ + public IBinder waitForBinder() throws InterruptedException { + binderLatch.await(); + return binder; + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/DestroyableContext.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/DestroyableContext.java new file mode 100644 index 0000000000000000000000000000000000000000..6a80372cc2fb1e6ac50f5801bd9835b9e41d318e --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/DestroyableContext.java @@ -0,0 +1,6 @@ +package org.briarproject.mailbox.android; + +public interface DestroyableContext { + + void runOnUiThreadUnlessDestroyed(Runnable runnable); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/DozeWatchdogImpl.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/DozeWatchdogImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..faff99659fc79a0984c77703865963138c8c0f91 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/DozeWatchdogImpl.java @@ -0,0 +1,57 @@ +package org.briarproject.mailbox.android; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.PowerManager; + +import org.briarproject.bramble.api.lifecycle.Service; +import org.briarproject.bramble.api.lifecycle.ServiceException; +import org.briarproject.mailbox.api.android.DozeWatchdog; + +import java.util.concurrent.atomic.AtomicBoolean; + +import static android.content.Context.POWER_SERVICE; +import static android.os.Build.VERSION.SDK_INT; +import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED; + +class DozeWatchdogImpl implements DozeWatchdog, Service { + + private final Context appContext; + private final AtomicBoolean dozed = new AtomicBoolean(false); + private final BroadcastReceiver receiver = new DozeBroadcastReceiver(); + + DozeWatchdogImpl(Context appContext) { + this.appContext = appContext; + } + + @Override + public boolean getAndResetDozeFlag() { + return dozed.getAndSet(false); + } + + @Override + public void startService() throws ServiceException { + if (SDK_INT < 23) return; + IntentFilter filter = new IntentFilter(ACTION_DEVICE_IDLE_MODE_CHANGED); + appContext.registerReceiver(receiver, filter); + } + + @Override + public void stopService() throws ServiceException { + if (SDK_INT < 23) return; + appContext.unregisterReceiver(receiver); + } + + private class DozeBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + if (SDK_INT < 23) return; + PowerManager pm = + (PowerManager) appContext.getSystemService(POWER_SERVICE); + if (pm.isDeviceIdleMode()) dozed.set(true); + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/Localizer.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/Localizer.java new file mode 100644 index 0000000000000000000000000000000000000000..f4c6e52786a282185388aa81c843a8b6a986ae7b --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/Localizer.java @@ -0,0 +1,92 @@ +package org.briarproject.mailbox.android; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.content.res.Resources; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.util.Locale; + +import javax.annotation.Nullable; + +import static android.os.Build.VERSION.SDK_INT; +import static org.briarproject.mailbox.android.settings.SettingsFragment.LANGUAGE; + +@NotNullByDefault +public class Localizer { + + // Locking: class + @Nullable + private static Localizer INSTANCE; + private final Locale systemLocale; + private final Locale locale; + + private Localizer(SharedPreferences sharedPreferences) { + this(Locale.getDefault(), getLocaleFromTag( + sharedPreferences.getString(LANGUAGE, "default"))); + } + + private Localizer(Locale systemLocale, @Nullable Locale userLocale) { + this.systemLocale = systemLocale; + if (userLocale == null) locale = systemLocale; + else locale = userLocale; + } + + // Instantiate the Localizer. + public static synchronized void initialize(SharedPreferences prefs) { + if (INSTANCE == null) + INSTANCE = new Localizer(prefs); + } + + // Reinstantiate the Localizer with the system locale + public static synchronized void reinitialize() { + if (INSTANCE != null) + INSTANCE = new Localizer(INSTANCE.systemLocale, null); + } + + // Get the current instance. + public static synchronized Localizer getInstance() { + if (INSTANCE == null) + throw new IllegalStateException("Localizer not initialized"); + return INSTANCE; + } + + // Get Locale from BCP-47 tag + @Nullable + public static Locale getLocaleFromTag(String tag) { + if (tag.equals("default")) + return null; + if (SDK_INT >= 21) { + return Locale.forLanguageTag(tag); + } + if (tag.contains("-")) { + String[] langArray = tag.split("-"); + return new Locale(langArray[0], langArray[1]); + } else + return new Locale(tag); + } + + // Returns the localized version of context + public Context setLocale(Context context) { + Resources res = context.getResources(); + Configuration conf = res.getConfiguration(); + Locale currentLocale; + if (SDK_INT >= 24) { + currentLocale = conf.getLocales().get(0); + } else + currentLocale = conf.locale; + if (locale.equals(currentLocale)) + return context; + Locale.setDefault(locale); + if (SDK_INT >= 17) { + conf.setLocale(locale); + context.createConfigurationContext(conf); + } else + conf.locale = locale; + //noinspection deprecation + res.updateConfiguration(conf, res.getDisplayMetrics()); + return context; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/MailboxApplication.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/MailboxApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..09b9735ec634fd7616c380cc0ff4cbc2c8dea4c6 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/MailboxApplication.java @@ -0,0 +1,19 @@ +package org.briarproject.mailbox.android; + +import android.content.SharedPreferences; + +import java.util.Collection; +import java.util.logging.LogRecord; + +/** + * This exists so that the Application object will not necessarily be cast + * directly to the Briar application object. + */ +public interface MailboxApplication { + + Collection<LogRecord> getRecentLogRecords(); + + AndroidComponent getApplicationComponent(); + + SharedPreferences getDefaultSharedPreferences(); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/MailboxApplicationImpl.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/MailboxApplicationImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..b931c1db9eaf0e91eafa74a408965299a80a7518 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/MailboxApplicationImpl.java @@ -0,0 +1,168 @@ +package org.briarproject.mailbox.android; + +import android.app.Application; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.os.StrictMode; +import android.os.StrictMode.ThreadPolicy; +import android.os.StrictMode.VmPolicy; +import android.preference.PreferenceManager; + +import org.acra.ACRA; +import org.acra.ReportingInteractionMode; +import org.acra.annotation.ReportsCrashes; +import org.briarproject.bramble.BrambleCoreModule; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.logging.CachingLogHandler; +import org.briarproject.mailbox.android.reporting.BriarReportPrimer; +import org.briarproject.mailbox.android.reporting.BriarReportSenderFactory; +import org.briarproject.mailbox.android.reporting.DevReportActivity; +import org.briarproject.mailbox.android.util.UiUtils; + +import java.util.Collection; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.INFO; +import static org.acra.ReportField.ANDROID_VERSION; +import static org.acra.ReportField.APP_VERSION_CODE; +import static org.acra.ReportField.APP_VERSION_NAME; +import static org.acra.ReportField.BRAND; +import static org.acra.ReportField.BUILD_CONFIG; +import static org.acra.ReportField.CRASH_CONFIGURATION; +import static org.acra.ReportField.CUSTOM_DATA; +import static org.acra.ReportField.DEVICE_FEATURES; +import static org.acra.ReportField.DISPLAY; +import static org.acra.ReportField.INITIAL_CONFIGURATION; +import static org.acra.ReportField.PACKAGE_NAME; +import static org.acra.ReportField.PHONE_MODEL; +import static org.acra.ReportField.PRODUCT; +import static org.acra.ReportField.REPORT_ID; +import static org.acra.ReportField.STACK_TRACE; +import static org.acra.ReportField.USER_APP_START_DATE; +import static org.acra.ReportField.USER_CRASH_DATE; +import static org.briarproject.mailbox.android.TestingConstants.IS_BETA_BUILD; +import static org.briarproject.mailbox.android.TestingConstants.IS_DEBUG_BUILD; + +@ReportsCrashes( + reportPrimerClass = BriarReportPrimer.class, + logcatArguments = {"-d", "-v", "time", "*:I"}, + reportSenderFactoryClasses = {BriarReportSenderFactory.class}, + mode = ReportingInteractionMode.DIALOG, + reportDialogClass = DevReportActivity.class, + resDialogOkToast = R.string.dev_report_saved, + deleteOldUnsentReportsOnApplicationStart = false, + customReportContent = { + REPORT_ID, + APP_VERSION_CODE, APP_VERSION_NAME, PACKAGE_NAME, + PHONE_MODEL, ANDROID_VERSION, BRAND, PRODUCT, + BUILD_CONFIG, + CUSTOM_DATA, + STACK_TRACE, + INITIAL_CONFIGURATION, CRASH_CONFIGURATION, + DISPLAY, DEVICE_FEATURES, + USER_APP_START_DATE, USER_CRASH_DATE + } +) +public class MailboxApplicationImpl extends Application + implements MailboxApplication { + + private static final Logger LOG = + Logger.getLogger(MailboxApplicationImpl.class.getName()); + + private final CachingLogHandler logHandler = new CachingLogHandler(); + + private AndroidComponent applicationComponent; + private volatile SharedPreferences prefs; + + @Override + protected void attachBaseContext(Context base) { + if (prefs == null) + prefs = PreferenceManager.getDefaultSharedPreferences(base); + // Loading the language needs to be done here. + Localizer.initialize(prefs); + super.attachBaseContext( + Localizer.getInstance().setLocale(base)); + setTheme(base, prefs); + ACRA.init(this); + } + + @Override + public void onCreate() { + super.onCreate(); + + if (IS_DEBUG_BUILD) enableStrictMode(); + + Logger rootLogger = Logger.getLogger(""); + if (!IS_DEBUG_BUILD && !IS_BETA_BUILD) { + // Remove default log handlers so system log is not used + for (Handler handler : rootLogger.getHandlers()) { + rootLogger.removeHandler(handler); + } + } + rootLogger.addHandler(logHandler); + rootLogger.setLevel(IS_DEBUG_BUILD || IS_BETA_BUILD ? FINE : INFO); + + LOG.info("Created"); + + applicationComponent = createApplicationComponent(); + } + + protected AndroidComponent createApplicationComponent() { + AndroidComponent androidComponent = DaggerAndroidComponent.builder() + .appModule(new AppModule(this)) + .build(); + + // We need to load the eager singletons directly after making the + // dependency graphs + BrambleCoreModule.initEagerSingletons(androidComponent); + AndroidEagerSingletons.initEagerSingletons(androidComponent); + return androidComponent; + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Localizer.getInstance().setLocale(this); + } + + private void setTheme(Context ctx, SharedPreferences prefs) { + String theme = prefs.getString("pref_key_theme", null); + if (theme == null) { + // set default value + theme = getString(R.string.pref_theme_light_value); + prefs.edit().putString("pref_key_theme", theme).apply(); + } + // set theme + UiUtils.setTheme(ctx, theme); + } + + private void enableStrictMode() { + ThreadPolicy.Builder threadPolicy = new ThreadPolicy.Builder(); + threadPolicy.detectAll(); + threadPolicy.penaltyLog(); + StrictMode.setThreadPolicy(threadPolicy.build()); + VmPolicy.Builder vmPolicy = new VmPolicy.Builder(); + vmPolicy.detectAll(); + vmPolicy.penaltyLog(); + StrictMode.setVmPolicy(vmPolicy.build()); + } + + @Override + public Collection<LogRecord> getRecentLogRecords() { + return logHandler.getRecentLogRecords(); + } + + @Override + public AndroidComponent getApplicationComponent() { + return applicationComponent; + } + + @Override + public SharedPreferences getDefaultSharedPreferences() { + return prefs; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/NetworkUsageLogger.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/NetworkUsageLogger.java new file mode 100644 index 0000000000000000000000000000000000000000..b3bfb58d2a2bdc5b2d88574deeee23268fe0befc --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/NetworkUsageLogger.java @@ -0,0 +1,40 @@ +package org.briarproject.mailbox.android; + +import android.net.TrafficStats; +import android.os.Process; + +import org.briarproject.bramble.api.lifecycle.Service; + +import java.util.logging.Logger; + +import static java.util.logging.Level.INFO; +import static org.briarproject.bramble.util.LogUtils.now; + +class NetworkUsageLogger implements Service { + + private static final Logger LOG = + Logger.getLogger(NetworkUsageLogger.class.getName()); + + private volatile long startTime, rxBytes, txBytes; + + @Override + public void startService() { + startTime = now(); + int uid = Process.myUid(); + rxBytes = TrafficStats.getUidRxBytes(uid); + txBytes = TrafficStats.getUidTxBytes(uid); + } + + @Override + public void stopService() { + if (LOG.isLoggable(INFO)) { + long sessionDuration = now() - startTime; + int uid = Process.myUid(); + long rx = TrafficStats.getUidRxBytes(uid) - rxBytes; + long tx = TrafficStats.getUidTxBytes(uid) - txBytes; + LOG.info("Duration " + (sessionDuration / 1000) + " seconds"); + LOG.info("Received " + rx + " bytes"); + LOG.info("Sent " + tx + " bytes"); + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/ScreenFilterMonitorImpl.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/ScreenFilterMonitorImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..f74f8c911cf9136525ac314a4d26dd502c5a0e40 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/ScreenFilterMonitorImpl.java @@ -0,0 +1,229 @@ +package org.briarproject.mailbox.android; + +import android.annotation.SuppressLint; +import android.app.Application; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.Signature; +import android.support.annotation.UiThread; + +import org.briarproject.bramble.api.lifecycle.Service; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.bramble.util.StringUtils; +import org.briarproject.mailbox.api.android.ScreenFilterMonitor; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; +import static android.content.Intent.ACTION_PACKAGE_ADDED; +import static android.content.Intent.ACTION_PACKAGE_CHANGED; +import static android.content.Intent.ACTION_PACKAGE_REMOVED; +import static android.content.Intent.ACTION_PACKAGE_REPLACED; +import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; +import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; +import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; +import static android.content.pm.PackageManager.GET_PERMISSIONS; +import static android.content.pm.PackageManager.GET_SIGNATURES; +import static android.os.Build.VERSION.SDK_INT; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; + +@NotNullByDefault +class ScreenFilterMonitorImpl implements ScreenFilterMonitor, Service { + + private static final Logger LOG = + Logger.getLogger(ScreenFilterMonitorImpl.class.getName()); + + /* + * Ignore Play Services if it uses this package name and public key - it's + * effectively a system app, but not flagged as such on older systems + */ + private static final String PLAY_SERVICES_PACKAGE = + "com.google.android.gms"; + private static final String PLAY_SERVICES_PUBLIC_KEY = + "30820120300D06092A864886F70D01010105000382010D0030820108" + + "0282010100AB562E00D83BA208AE0A966F124E29DA11F2AB56D08F58" + + "E2CCA91303E9B754D372F640A71B1DCB130967624E4656A7776A9219" + + "3DB2E5BFB724A91E77188B0E6A47A43B33D9609B77183145CCDF7B2E" + + "586674C9E1565B1F4C6A5955BFF251A63DABF9C55C27222252E875E4" + + "F8154A645F897168C0B1BFC612EABF785769BB34AA7984DC7E2EA276" + + "4CAE8307D8C17154D7EE5F64A51A44A602C249054157DC02CD5F5C0E" + + "55FBEF8519FBE327F0B1511692C5A06F19D18385F5C4DBC2D6B93F68" + + "CC2979C70E18AB93866B3BD5DB8999552A0E3B4C99DF58FB918BEDC1" + + "82BA35E003C1B4B10DD244A8EE24FFFD333872AB5221985EDAB0FC0D" + + "0B145B6AA192858E79020103"; + + private static final String PREF_KEY_ALLOWED = "allowedOverlayApps"; + + private final PackageManager pm; + private final Application app; + private final AndroidExecutor androidExecutor; + private final SharedPreferences prefs; + private final AtomicBoolean used = new AtomicBoolean(false); + + // UiThread + @Nullable + private BroadcastReceiver receiver = null; + + // UiThread + @Nullable + private Collection<AppDetails> cachedApps = null; + + @Inject + ScreenFilterMonitorImpl(Application app, AndroidExecutor androidExecutor, + SharedPreferences prefs) { + pm = app.getPackageManager(); + this.app = app; + this.androidExecutor = androidExecutor; + this.prefs = prefs; + } + + @Override + @UiThread + public Collection<AppDetails> getApps() { + if (cachedApps != null) return cachedApps; + Set<String> allowed = prefs.getStringSet(PREF_KEY_ALLOWED, + Collections.emptySet()); + List<AppDetails> apps = new ArrayList<>(); + List<PackageInfo> packageInfos = + pm.getInstalledPackages(GET_PERMISSIONS); + for (PackageInfo packageInfo : packageInfos) { + if (!allowed.contains(packageInfo.packageName) + && isOverlayApp(packageInfo)) { + String name = getAppName(packageInfo); + apps.add(new AppDetails(name, packageInfo.packageName)); + } + } + Collections.sort(apps, (a, b) -> a.name.compareTo(b.name)); + apps = Collections.unmodifiableList(apps); + cachedApps = apps; + return apps; + } + + @Override + @UiThread + public void allowApps(Collection<String> packageNames) { + cachedApps = null; + Set<String> allowed = prefs.getStringSet(PREF_KEY_ALLOWED, + Collections.emptySet()); + Set<String> merged = new HashSet<>(allowed); + merged.addAll(packageNames); + prefs.edit().putStringSet(PREF_KEY_ALLOWED, merged).apply(); + } + + // Returns the application name for a given package, or the package name + // if no application name is available + private String getAppName(PackageInfo pkgInfo) { + CharSequence seq = pm.getApplicationLabel(pkgInfo.applicationInfo); + return seq == null ? pkgInfo.packageName : seq.toString(); + } + + // Checks if an installed package is a user app using the permission. + private boolean isOverlayApp(PackageInfo packageInfo) { + int mask = FLAG_SYSTEM | FLAG_UPDATED_SYSTEM_APP; + // Ignore system apps + if ((packageInfo.applicationInfo.flags & mask) != 0) return false; + // Ignore Play Services, it's effectively a system app + if (isPlayServices(packageInfo.packageName)) return false; + // Get permissions + String[] requestedPermissions = packageInfo.requestedPermissions; + if (requestedPermissions == null) return false; + if (SDK_INT >= 16 && SDK_INT < 23) { + // Check whether the permission has been requested and granted + int[] flags = packageInfo.requestedPermissionsFlags; + for (int i = 0; i < requestedPermissions.length; i++) { + if (requestedPermissions[i].equals(SYSTEM_ALERT_WINDOW)) { + // 'flags' may be null on Robolectric + return flags == null || + (flags[i] & REQUESTED_PERMISSION_GRANTED) != 0; + } + } + } else { + // Check whether the permission has been requested + for (String requestedPermission : requestedPermissions) { + if (requestedPermission.equals(SYSTEM_ALERT_WINDOW)) { + return true; + } + } + } + return false; + } + + @SuppressLint("PackageManagerGetSignatures") + private boolean isPlayServices(String pkg) { + if (!PLAY_SERVICES_PACKAGE.equals(pkg)) return false; + try { + PackageInfo sigs = pm.getPackageInfo(pkg, GET_SIGNATURES); + // The genuine Play Services app should have a single signature + Signature[] signatures = sigs.signatures; + if (signatures == null || signatures.length != 1) return false; + // Extract the public key from the signature + CertificateFactory certFactory = + CertificateFactory.getInstance("X509"); + byte[] signatureBytes = signatures[0].toByteArray(); + InputStream in = new ByteArrayInputStream(signatureBytes); + X509Certificate cert = + (X509Certificate) certFactory.generateCertificate(in); + byte[] publicKeyBytes = cert.getPublicKey().getEncoded(); + String publicKey = StringUtils.toHexString(publicKeyBytes); + return PLAY_SERVICES_PUBLIC_KEY.equals(publicKey); + } catch (NameNotFoundException | CertificateException e) { + logException(LOG, WARNING, e); + return false; + } + } + + @Override + public void startService() { + if (used.getAndSet(true)) throw new IllegalStateException(); + androidExecutor.runOnUiThread(() -> { + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_PACKAGE_ADDED); + filter.addAction(ACTION_PACKAGE_CHANGED); + filter.addAction(ACTION_PACKAGE_REMOVED); + filter.addAction(ACTION_PACKAGE_REPLACED); + filter.addDataScheme("package"); + receiver = new PackageBroadcastReceiver(); + app.registerReceiver(receiver, filter); + cachedApps = null; + }); + } + + @Override + public void stopService() { + androidExecutor.runOnUiThread(() -> { + if (receiver != null) app.unregisterReceiver(receiver); + }); + } + + private class PackageBroadcastReceiver extends BroadcastReceiver { + + @Override + @UiThread + public void onReceive(Context context, Intent intent) { + cachedApps = null; + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/StartupFailureActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/StartupFailureActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..d4d13bd7e4677f3bfbebd732ff37e01181f0adda --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/StartupFailureActivity.java @@ -0,0 +1,73 @@ +package org.briarproject.mailbox.android; + +import android.app.NotificationManager; +import android.content.Intent; +import android.os.Bundle; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BaseActivity; +import org.briarproject.mailbox.android.fragment.BaseFragment.BaseFragmentListener; +import org.briarproject.mailbox.android.fragment.ErrorFragment; + +import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult; +import static org.briarproject.mailbox.android.BriarService.EXTRA_NOTIFICATION_ID; +import static org.briarproject.mailbox.android.BriarService.EXTRA_START_RESULT; + +public class StartupFailureActivity extends BaseActivity implements + BaseFragmentListener { + + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + + setContentView(R.layout.activity_fragment_container); + handleIntent(getIntent()); + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + private void handleIntent(Intent i) { + StartResult result = + (StartResult) i.getSerializableExtra(EXTRA_START_RESULT); + int notificationId = i.getIntExtra(EXTRA_NOTIFICATION_ID, -1); + + // cancel notification + if (notificationId > -1) { + Object o = getSystemService(NOTIFICATION_SERVICE); + NotificationManager nm = (NotificationManager) o; + nm.cancel(notificationId); + } + + // show proper error message + String errorMsg; + switch (result) { + case DATA_TOO_OLD_ERROR: + errorMsg = getString(R.string.startup_failed_db_error); + break; + case DATA_TOO_NEW_ERROR: + errorMsg = + getString(R.string.startup_failed_data_too_new_error); + break; + case DB_ERROR: + errorMsg = + getString(R.string.startup_failed_data_too_old_error); + break; + case SERVICE_ERROR: + errorMsg = getString(R.string.startup_failed_service_error); + break; + default: + throw new IllegalArgumentException(); + } + showInitialFragment(ErrorFragment.newInstance(errorMsg)); + } + + @Override + public void runOnDbThread(Runnable runnable) { + throw new AssertionError("Deprecated and should not be used"); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/TestingConstants.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/TestingConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..b8ee94cf06b950c838af32061d3ba3a52eda2484 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/TestingConstants.java @@ -0,0 +1,48 @@ +package org.briarproject.mailbox.android; + +import org.briarproject.mailbox.BuildConfig; + +public interface TestingConstants { + + /** + * Whether this is a debug build. + */ + boolean IS_DEBUG_BUILD = BuildConfig.DEBUG; + + /** + * Whether this is a beta build. This should be set to false for final + * release builds. + */ + boolean IS_BETA_BUILD = false; + + /** + * Whether to prevent screenshots from being taken. Setting this to true + * prevents Recent Apps from storing screenshots of private information. + * Unfortunately this also prevents the user from taking screenshots + * intentionally. + */ + boolean PREVENT_SCREENSHOTS = !IS_DEBUG_BUILD; + + /** + * Debug and beta builds expire after 90 days. Final release builds expire + * after 292 million years. + */ + long EXPIRY_DATE = IS_DEBUG_BUILD || IS_BETA_BUILD ? + BuildConfig.BuildTimestamp + 90 * 24 * 60 * 60 * 1000L : + Long.MAX_VALUE; + + /** + * Feature flag for enabling the dark UI theme in release builds. + */ + boolean FEATURE_FLAG_DARK_THEME = false; + + /** + * Feature flag for enabling the sign-in reminder in release builds. + */ + boolean FEATURE_FLAG_SIGN_IN_REMINDER = IS_DEBUG_BUILD; + + /** + * Feature flag for enabling the PIN lock in release builds. + */ + boolean FEATURE_FLAG_PIN_LOCK = IS_DEBUG_BUILD; +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/account/LockManagerImpl.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/account/LockManagerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..f0060649b986a4f9c2fd72d7167a75ee4ae41ad7 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/account/LockManagerImpl.java @@ -0,0 +1,209 @@ +package org.briarproject.mailbox.android.account; + +import android.app.AlarmManager; +import android.app.Application; +import android.app.PendingIntent; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MutableLiveData; +import android.content.Context; +import android.content.Intent; +import android.support.annotation.UiThread; + +import org.briarproject.bramble.api.db.DatabaseExecutor; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.event.EventListener; +import org.briarproject.bramble.api.lifecycle.Service; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.settings.Settings; +import org.briarproject.bramble.api.settings.SettingsManager; +import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.BriarService; +import org.briarproject.mailbox.api.android.AndroidNotificationManager; +import org.briarproject.mailbox.api.android.LockManager; + +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.annotation.concurrent.ThreadSafe; +import javax.inject.Inject; + +import static android.app.AlarmManager.ELAPSED_REALTIME; +import static android.app.PendingIntent.getService; +import static android.content.Context.ALARM_SERVICE; +import static android.os.SystemClock.elapsedRealtime; +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.mailbox.android.settings.SettingsFragment.PREF_SCREEN_LOCK; +import static org.briarproject.mailbox.android.settings.SettingsFragment.PREF_SCREEN_LOCK_TIMEOUT; +import static org.briarproject.mailbox.android.settings.SettingsFragment.SETTINGS_NAMESPACE; +import static org.briarproject.mailbox.android.util.UiUtils.hasScreenLock; + +@ThreadSafe +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class LockManagerImpl implements LockManager, Service, EventListener { + + private static final Logger LOG = + Logger.getLogger(LockManagerImpl.class.getName()); + + private final Context appContext; + private final SettingsManager settingsManager; + private final AndroidNotificationManager notificationManager; + @DatabaseExecutor + private final Executor dbExecutor; + private final AlarmManager alarmManager; + private final PendingIntent lockIntent; + private final int timeoutNever, timeoutDefault; + + private volatile boolean locked = false; + private volatile boolean lockableSetting = false; + private volatile int timeoutMinutes; + private int activitiesRunning = 0; + private boolean alarmSet = false; + // This is to ensure that we don't start unlocked after a timeout and thus + // is set to the elapsed real time when no more activities are running. + // Its value is only relevant as long as no activity is running. + private long idleTime; + private final MutableLiveData<Boolean> lockable = new MutableLiveData<>(); + + @Inject + LockManagerImpl(Application app, SettingsManager settingsManager, + AndroidNotificationManager notificationManager, + @DatabaseExecutor Executor dbExecutor) { + this.appContext = app.getApplicationContext(); + this.settingsManager = settingsManager; + this.notificationManager = notificationManager; + this.dbExecutor = dbExecutor; + this.alarmManager = + (AlarmManager) appContext.getSystemService(ALARM_SERVICE); + Intent i = + new Intent(ACTION_LOCK, null, appContext, BriarService.class); + this.lockIntent = getService(appContext, 0, i, 0); + this.timeoutNever = Integer.valueOf( + appContext.getString(R.string.pref_lock_timeout_value_never)); + this.timeoutDefault = Integer.valueOf( + appContext.getString(R.string.pref_lock_timeout_value_default)); + this.timeoutMinutes = timeoutNever; + + // setting this in the constructor makes #getValue() @NonNull + this.lockable.setValue(false); + } + + @Override + public void startService() { + // only load the setting here, because database isn't open before + loadLockableSetting(); + } + + @Override + public void stopService() { + } + + @UiThread + @Override + public void onActivityStart() { + if (!locked && activitiesRunning == 0 && timeoutEnabled() && + timedOut()) { + // lock the app in case the alarm wasn't run during sleep + setLocked(true); + } + activitiesRunning++; + if (alarmSet) { + alarmManager.cancel(lockIntent); + alarmSet = false; + } + } + + @UiThread + @Override + public void onActivityStop() { + activitiesRunning--; + if (activitiesRunning == 0) { + idleTime = elapsedRealtime(); + if (!locked && timeoutEnabled()) { + if (alarmSet) alarmManager.cancel(lockIntent); + long triggerAt = + elapsedRealtime() + MINUTES.toMillis(timeoutMinutes); + alarmManager.set(ELAPSED_REALTIME, triggerAt, lockIntent); + alarmSet = true; + } + } + } + + @Override + public LiveData<Boolean> isLockable() { + return lockable; + } + + @UiThread + @Override + public void checkIfLockable() { + boolean oldValue = lockable.getValue(); + boolean newValue = hasScreenLock(appContext) && lockableSetting; + if (oldValue != newValue) { + this.lockable.setValue(newValue); + } + } + + @Override + public boolean isLocked() { + if (locked && !hasScreenLock(appContext)) { + lockable.postValue(false); + locked = false; + } else if (!locked && activitiesRunning == 0 && timeoutEnabled() && + timedOut()) { + setLocked(true); + } + return locked; + } + + @Override + public void setLocked(boolean locked) { + this.locked = locked; + notificationManager.updateForegroundNotification(locked); + } + + @Override + public void eventOccurred(Event event) { + if (event instanceof SettingsUpdatedEvent) { + SettingsUpdatedEvent e = (SettingsUpdatedEvent) event; + String namespace = e.getNamespace(); + if (namespace.equals(SETTINGS_NAMESPACE)) { + loadLockableSetting(); + } + } + } + + private void loadLockableSetting() { + dbExecutor.execute(() -> { + try { + Settings settings = + settingsManager.getSettings(SETTINGS_NAMESPACE); + // is the app lockable? + lockableSetting = settings.getBoolean(PREF_SCREEN_LOCK, false); + boolean newValue = hasScreenLock(appContext) && lockableSetting; + lockable.postValue(newValue); + // what is the timeout in minutes? + timeoutMinutes = settings.getInt(PREF_SCREEN_LOCK_TIMEOUT, + timeoutDefault); + } catch (DbException e) { + logException(LOG, WARNING, e); + lockableSetting = false; + lockable.postValue(false); + } + }); + } + + private boolean timeoutEnabled() { + return timeoutMinutes != timeoutNever && lockable.getValue(); + } + + private boolean timedOut() { + return elapsedRealtime() - idleTime > MINUTES.toMillis(timeoutMinutes); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/ActivityComponent.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/ActivityComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..164dc4f0ddc3dc40beffeefb14f420046d0d0190 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/ActivityComponent.java @@ -0,0 +1,83 @@ +package org.briarproject.mailbox.android.activity; + +import android.app.Activity; + +import org.briarproject.mailbox.android.AndroidComponent; +import org.briarproject.mailbox.android.StartupFailureActivity; +import org.briarproject.mailbox.android.fragment.ScreenFilterDialogFragment; +import org.briarproject.mailbox.android.keyagreement.ContactExchangeErrorFragment; +import org.briarproject.mailbox.android.keyagreement.IntroFragment; +import org.briarproject.mailbox.android.keyagreement.KeyAgreementActivity; +import org.briarproject.mailbox.android.keyagreement.KeyAgreementFragment; +import org.briarproject.mailbox.android.keyagreement.MailboxExchangeActivity; +import org.briarproject.mailbox.android.login.AuthorNameFragment; +import org.briarproject.mailbox.android.login.ChangePasswordActivity; +import org.briarproject.mailbox.android.login.DozeFragment; +import org.briarproject.mailbox.android.login.OpenDatabaseActivity; +import org.briarproject.mailbox.android.login.PasswordActivity; +import org.briarproject.mailbox.android.login.PasswordFragment; +import org.briarproject.mailbox.android.login.SetupActivity; +import org.briarproject.mailbox.android.login.UnlockActivity; +import org.briarproject.mailbox.android.navdrawer.NavDrawerActivity; +import org.briarproject.mailbox.android.overview.OverviewFragment; +import org.briarproject.mailbox.android.panic.PanicPreferencesActivity; +import org.briarproject.mailbox.android.panic.PanicResponderActivity; +import org.briarproject.mailbox.android.settings.SettingsActivity; +import org.briarproject.mailbox.android.settings.SettingsFragment; +import org.briarproject.mailbox.android.splash.SplashScreenActivity; + +import dagger.Component; + +@ActivityScope +@Component( + modules = {ActivityModule.class}, + dependencies = AndroidComponent.class) +public interface ActivityComponent { + + Activity activity(); + + void inject(SplashScreenActivity activity); + + void inject(SetupActivity activity); + + void inject(OpenDatabaseActivity activity); + + void inject(NavDrawerActivity activity); + + void inject(PasswordActivity activity); + + void inject(PanicResponderActivity activity); + + void inject(PanicPreferencesActivity activity); + + void inject(KeyAgreementActivity activity); + + void inject(MailboxExchangeActivity activity); + + void inject(SettingsActivity activity); + + void inject(ChangePasswordActivity activity); + + void inject(StartupFailureActivity activity); + + void inject(UnlockActivity activity); + + // Fragments + void inject(AuthorNameFragment fragment); + + void inject(PasswordFragment fragment); + + void inject(DozeFragment fragment); + + void inject(IntroFragment fragment); + + void inject(KeyAgreementFragment fragment); + + void inject(SettingsFragment fragment); + + void inject(ScreenFilterDialogFragment fragment); + + void inject(ContactExchangeErrorFragment fragment); + + void inject(OverviewFragment overviewFragment); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/ActivityModule.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/ActivityModule.java new file mode 100644 index 0000000000000000000000000000000000000000..8dde48a5ce724dcae81fb139a94b67c3c7dfa9d7 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/ActivityModule.java @@ -0,0 +1,84 @@ +package org.briarproject.mailbox.android.activity; + +import android.app.Activity; + +import org.briarproject.mailbox.android.controller.BriarController; +import org.briarproject.mailbox.android.controller.BriarControllerImpl; +import org.briarproject.mailbox.android.controller.DbController; +import org.briarproject.mailbox.android.controller.DbControllerImpl; +import org.briarproject.mailbox.android.login.PasswordController; +import org.briarproject.mailbox.android.login.PasswordControllerImpl; +import org.briarproject.mailbox.android.login.SetupController; +import org.briarproject.mailbox.android.login.SetupControllerImpl; +import org.briarproject.mailbox.android.navdrawer.NavDrawerController; +import org.briarproject.mailbox.android.navdrawer.NavDrawerControllerImpl; + +import dagger.Module; +import dagger.Provides; + +import static org.briarproject.mailbox.android.BriarService.BriarServiceConnection; + +@Module +public class ActivityModule { + + private final BaseActivity activity; + + public ActivityModule(BaseActivity activity) { + this.activity = activity; + } + + @ActivityScope + @Provides + BaseActivity provideBaseActivity() { + return activity; + } + + @ActivityScope + @Provides + Activity provideActivity() { + return activity; + } + + @ActivityScope + @Provides + SetupController provideSetupController( + SetupControllerImpl setupController) { + return setupController; + } + + @ActivityScope + @Provides + PasswordController providePasswordController( + PasswordControllerImpl passwordController) { + return passwordController; + } + + @ActivityScope + @Provides + protected BriarController provideBriarController( + BriarControllerImpl briarController) { + activity.addLifecycleController(briarController); + return briarController; + } + + @ActivityScope + @Provides + DbController provideDBController(DbControllerImpl dbController) { + return dbController; + } + + @ActivityScope + @Provides + NavDrawerController provideNavDrawerController( + NavDrawerControllerImpl navDrawerController) { + activity.addLifecycleController(navDrawerController); + return navDrawerController; + } + + @ActivityScope + @Provides + BriarServiceConnection provideBriarServiceConnection() { + return new BriarServiceConnection(); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/ActivityScope.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/ActivityScope.java new file mode 100644 index 0000000000000000000000000000000000000000..dd0fc8bbba8f5b674dc8c2719e94cb35f4a3f08f --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/ActivityScope.java @@ -0,0 +1,11 @@ +package org.briarproject.mailbox.android.activity; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Scope; + +@Scope +@Retention(RetentionPolicy.RUNTIME) +public @interface ActivityScope { +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/BaseActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/BaseActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..a6b2a634e01b082ce0a4a1c13b8c822e2ee0e1b6 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/BaseActivity.java @@ -0,0 +1,273 @@ +package org.briarproject.mailbox.android.activity; + +import android.content.Context; +import android.os.Bundle; +import android.os.IBinder; +import android.support.annotation.LayoutRes; +import android.support.annotation.UiThread; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.view.inputmethod.InputMethodManager; + +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.AndroidComponent; +import org.briarproject.mailbox.android.DestroyableContext; +import org.briarproject.mailbox.android.Localizer; +import org.briarproject.mailbox.android.MailboxApplication; +import org.briarproject.mailbox.android.controller.ActivityLifecycleController; +import org.briarproject.mailbox.android.fragment.BaseFragment; +import org.briarproject.mailbox.android.fragment.ScreenFilterDialogFragment; +import org.briarproject.mailbox.android.util.UiUtils; +import org.briarproject.mailbox.android.widget.TapSafeFrameLayout; +import org.briarproject.mailbox.android.widget.TapSafeFrameLayout.OnTapFilteredListener; +import org.briarproject.mailbox.api.android.ScreenFilterMonitor; +import org.briarproject.mailbox.api.android.ScreenFilterMonitor.AppDetails; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.WindowManager.LayoutParams.FLAG_SECURE; +import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT; +import static org.briarproject.mailbox.android.TestingConstants.PREVENT_SCREENSHOTS; + +public abstract class BaseActivity extends AppCompatActivity + implements DestroyableContext, OnTapFilteredListener { + + @Inject + protected ScreenFilterMonitor screenFilterMonitor; + + protected ActivityComponent activityComponent; + + private final List<ActivityLifecycleController> lifecycleControllers = + new ArrayList<>(); + private boolean destroyed = false; + + @Nullable + private Toolbar toolbar = null; + private boolean searchedForToolbar = false; + + public abstract void injectActivity(ActivityComponent component); + + public void addLifecycleController(ActivityLifecycleController alc) { + lifecycleControllers.add(alc); + } + + @Override + public void onCreate(@Nullable Bundle state) { + super.onCreate(state); + + if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE); + + AndroidComponent applicationComponent = + ((MailboxApplication) getApplication()) + .getApplicationComponent(); + + activityComponent = DaggerActivityComponent.builder() + .androidComponent(applicationComponent) + .activityModule(getActivityModule()) + .build(); + + injectActivity(activityComponent); + + for (ActivityLifecycleController alc : lifecycleControllers) { + alc.onActivityCreate(this); + } + } + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext( + Localizer.getInstance().setLocale(base)); + } + + public ActivityComponent getActivityComponent() { + return activityComponent; + } + + // This exists to make test overrides easier + protected ActivityModule getActivityModule() { + return new ActivityModule(this); + } + + @Override + protected void onStart() { + super.onStart(); + for (ActivityLifecycleController alc : lifecycleControllers) { + alc.onActivityStart(); + } + protectToolbar(); + ScreenFilterDialogFragment f = findDialogFragment(); + if (f != null) f.setDismissListener(this::protectToolbar); + } + + @Nullable + private ScreenFilterDialogFragment findDialogFragment() { + Fragment f = getSupportFragmentManager().findFragmentByTag( + ScreenFilterDialogFragment.TAG); + return (ScreenFilterDialogFragment) f; + } + + @Override + protected void onStop() { + super.onStop(); + for (ActivityLifecycleController alc : lifecycleControllers) { + alc.onActivityStop(); + } + } + + protected void showInitialFragment(BaseFragment f) { + getSupportFragmentManager().beginTransaction() + .replace(R.id.fragmentContainer, f, f.getUniqueTag()) + .commit(); + } + + public void showNextFragment(BaseFragment f) { + getSupportFragmentManager().beginTransaction() + .setCustomAnimations(R.anim.step_next_in, + R.anim.step_previous_out, R.anim.step_previous_in, + R.anim.step_next_out) + .replace(R.id.fragmentContainer, f, f.getUniqueTag()) + .addToBackStack(f.getUniqueTag()) + .commit(); + } + + private boolean showScreenFilterWarning() { + // If the dialog is already visible, filter the tap + ScreenFilterDialogFragment f = findDialogFragment(); + if (f != null && f.isVisible()) return false; + Collection<AppDetails> apps = screenFilterMonitor.getApps(); + // If all overlay apps have been allowed, allow the tap + if (apps.isEmpty()) return true; + // Show dialog unless onSaveInstanceState() has been called, see #1112 + FragmentManager fm = getSupportFragmentManager(); + if (!fm.isStateSaved()) { + // Create dialog + f = ScreenFilterDialogFragment.newInstance(apps); + // When dialog is dismissed, update protection of toolbar + f.setDismissListener(this::protectToolbar); + // Hide soft keyboard when (re)showing dialog + View focus = getCurrentFocus(); + if (focus != null) hideSoftKeyboard(focus); + f.show(fm, ScreenFilterDialogFragment.TAG); + } + // Filter the tap + return false; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + destroyed = true; + for (ActivityLifecycleController alc : lifecycleControllers) { + alc.onActivityDestroy(); + } + } + + @Override + public void runOnUiThreadUnlessDestroyed(Runnable r) { + runOnUiThread(() -> { + if (!destroyed && !isFinishing()) r.run(); + }); + } + + public void showSoftKeyboard(View view) { + Object o = getSystemService(INPUT_METHOD_SERVICE); + ((InputMethodManager) o).showSoftInput(view, SHOW_IMPLICIT); + } + + public void hideSoftKeyboard(View view) { + IBinder token = view.getWindowToken(); + Object o = getSystemService(INPUT_METHOD_SERVICE); + ((InputMethodManager) o).hideSoftInputFromWindow(token, 0); + } + + @UiThread + public void handleDbException(DbException e) { + supportFinishAfterTransition(); + } + + /* + * Wraps the given view in a wrapper that notifies this activity when an + * obscured touch has been filtered, and returns the wrapper. + */ + private View makeTapSafeWrapper(View v) { + TapSafeFrameLayout wrapper = new TapSafeFrameLayout(this); + wrapper.setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT)); + wrapper.setOnTapFilteredListener(this); + wrapper.addView(v); + return wrapper; + } + + /* + * Finds the AppCompat toolbar, if any, and configures it to filter + * obscured touches. If a custom toolbar is used, it will be part of the + * content view and thus protected by the wrapper. But the default toolbar + * is outside the wrapper. + */ + private void protectToolbar() { + findToolbar(); + if (toolbar != null) { + boolean filter = !screenFilterMonitor.getApps().isEmpty(); + UiUtils.setFilterTouchesWhenObscured(toolbar, filter); + } + } + + private void findToolbar() { + if (searchedForToolbar) return; + View decorView = getWindow().getDecorView(); + if (decorView instanceof ViewGroup) + toolbar = findToolbar((ViewGroup) decorView); + searchedForToolbar = true; + } + + @Nullable + private Toolbar findToolbar(ViewGroup vg) { + // Views inside tap-safe layouts are already protected + if (vg instanceof TapSafeFrameLayout) return null; + for (int i = 0, len = vg.getChildCount(); i < len; i++) { + View child = vg.getChildAt(i); + if (child instanceof Toolbar) return (Toolbar) child; + if (child instanceof ViewGroup) { + Toolbar toolbar = findToolbar((ViewGroup) child); + if (toolbar != null) return toolbar; + } + } + return null; + } + + @Override + public void setContentView(@LayoutRes int layoutRes) { + setContentView(getLayoutInflater().inflate(layoutRes, null)); + } + + @Override + public void setContentView(View v) { + super.setContentView(makeTapSafeWrapper(v)); + } + + @Override + public void setContentView(View v, LayoutParams layoutParams) { + super.setContentView(makeTapSafeWrapper(v), layoutParams); + } + + @Override + public void addContentView(View v, LayoutParams layoutParams) { + super.addContentView(makeTapSafeWrapper(v), layoutParams); + } + + @Override + public boolean shouldAllowTap() { + return showScreenFilterWarning(); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/BriarActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/BriarActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..c9696409c866abb9d84702f6539815216c14766b --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/BriarActivity.java @@ -0,0 +1,213 @@ +package org.briarproject.mailbox.android.activity; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.Toolbar; +import android.transition.Slide; +import android.transition.Transition; +import android.view.Gravity; +import android.view.Window; +import android.widget.CheckBox; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.controller.BriarController; +import org.briarproject.mailbox.android.controller.DbController; +import org.briarproject.mailbox.android.controller.handler.UiResultHandler; +import org.briarproject.mailbox.android.login.PasswordActivity; +import org.briarproject.mailbox.android.login.UnlockActivity; +import org.briarproject.mailbox.android.logout.ExitActivity; +import org.briarproject.mailbox.api.android.LockManager; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; +import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; +import static android.os.Build.VERSION.SDK_INT; +import static org.briarproject.mailbox.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING; +import static org.briarproject.mailbox.android.activity.RequestCodes.REQUEST_PASSWORD; +import static org.briarproject.mailbox.android.activity.RequestCodes.REQUEST_UNLOCK; +import static org.briarproject.mailbox.android.util.UiUtils.getDozeWhitelistingIntent; +import static org.briarproject.mailbox.android.util.UiUtils.isSamsung7; + +@SuppressLint("Registered") +public abstract class BriarActivity extends BaseActivity { + + public static final String GROUP_ID = "briar.GROUP_ID"; + public static final String GROUP_NAME = "briar.GROUP_NAME"; + + private static final Logger LOG = + Logger.getLogger(BriarActivity.class.getName()); + + @Inject + BriarController briarController; + @Deprecated + @Inject + DbController dbController; + @Inject + protected LockManager lockManager; + + @Override + public void onStart() { + super.onStart(); + lockManager.onActivityStart(); + } + + @Override + protected void onActivityResult(int request, int result, Intent data) { + super.onActivityResult(request, result, data); + if (request == REQUEST_PASSWORD && result == RESULT_OK) { + // PasswordActivity finishes when password was entered correctly. + // When back button is pressed there, it will bring itself back, + // so that we never arrive here with a result that is not OK. + briarController.startAndBindService(); + } else if (request == REQUEST_UNLOCK && result != RESULT_OK) { + // We arrive here, if the user presses 'back' + // in the Keyguard unlock screen, because UnlockActivity finishes. + // If we don't finish here, isFinishing will be false in onResume() + // and we launch a new UnlockActivity causing a loop. + supportFinishAfterTransition(); + // If the result is OK, we don't need to do anything here + // and can resume normally. + } + } + + @Override + public void onResume() { + super.onResume(); + if (!briarController.accountSignedIn()) { + Intent i = new Intent(this, PasswordActivity.class); + startActivityForResult(i, REQUEST_PASSWORD); + } else if (lockManager.isLocked() && !isFinishing()) { + // Also check that the activity isn't finishing already. + // This is possible if finishing in onActivityResult(). + // Failure to do this check would cause an UnlockActivity loop. + Intent i = new Intent(this, UnlockActivity.class); + startActivityForResult(i, REQUEST_UNLOCK); + } else if (SDK_INT >= 23) { + briarController.hasDozed(new UiResultHandler<Boolean>(this) { + @Override + public void onResultUi(Boolean result) { + if (result) { + showDozeDialog(getString(R.string.warning_dozed, + getString(R.string.app_name))); + } + } + }); + } + } + + @Override + protected void onStop() { + super.onStop(); + lockManager.onActivityStop(); + } + + public void setSceneTransitionAnimation() { + if (SDK_INT < 21) return; + // workaround for #1007 + if (isSamsung7()) { + return; + } + Transition slide = new Slide(Gravity.RIGHT); + slide.excludeTarget(android.R.id.statusBarBackground, true); + slide.excludeTarget(android.R.id.navigationBarBackground, true); + Window window = getWindow(); + window.requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); + window.setExitTransition(slide); + window.setEnterTransition(slide); + window.setTransitionBackgroundFadeDuration(getResources() + .getInteger(android.R.integer.config_longAnimTime)); + } + + /** + * This should be called after the content view has been added in onCreate() + * + * @param ownLayout true if the custom toolbar brings its own layout + * @return the Toolbar object or null if content view did not contain one + */ + @Nullable + protected Toolbar setUpCustomToolbar(boolean ownLayout) { + // Custom Toolbar + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + ActionBar ab = getSupportActionBar(); + if (ab != null) { + ab.setDisplayShowHomeEnabled(true); + ab.setDisplayHomeAsUpEnabled(true); + ab.setDisplayShowCustomEnabled(ownLayout); + ab.setDisplayShowTitleEnabled(!ownLayout); + } + return toolbar; + } + + protected void showDozeDialog(String message) { + AlertDialog.Builder b = + new AlertDialog.Builder(this, R.style.BriarDialogTheme); + b.setMessage(message); + b.setView(R.layout.checkbox); + b.setPositiveButton(R.string.fix, + (dialog, which) -> { + Intent i = getDozeWhitelistingIntent(BriarActivity.this); + startActivityForResult(i, REQUEST_DOZE_WHITELISTING); + dialog.dismiss(); + }); + b.setNegativeButton(R.string.cancel, + (dialog, which) -> dialog.dismiss()); + b.setOnDismissListener(dialog -> { + CheckBox checkBox = + ((AlertDialog) dialog).findViewById(R.id.checkbox); + if (checkBox.isChecked()) + briarController.doNotAskAgainForDozeWhiteListing(); + }); + b.show(); + } + + protected void signOut(boolean removeFromRecentApps) { + if (briarController.accountSignedIn()) { + // Don't use UiResultHandler because we want the result even if + // this activity has been destroyed + briarController.signOut(result -> runOnUiThread( + () -> exit(removeFromRecentApps))); + } else { + exit(removeFromRecentApps); + } + } + + private void exit(boolean removeFromRecentApps) { + if (removeFromRecentApps) startExitActivity(); + else finishAndExit(); + } + + private void startExitActivity() { + Intent i = new Intent(this, ExitActivity.class); + i.addFlags(FLAG_ACTIVITY_NEW_TASK + | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | FLAG_ACTIVITY_NO_ANIMATION + | FLAG_ACTIVITY_CLEAR_TASK); + startActivity(i); + } + + private void finishAndExit() { + if (SDK_INT >= 21) finishAndRemoveTask(); + else supportFinishAfterTransition(); + LOG.info("Exiting"); + System.exit(0); + } + + @Deprecated + public void runOnDbThread(Runnable task) { + dbController.runOnDbThread(task); + } + + @Deprecated + protected void finishOnUiThread() { + runOnUiThreadUnlessDestroyed(this::supportFinishAfterTransition); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/RequestCodes.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/RequestCodes.java new file mode 100644 index 0000000000000000000000000000000000000000..7c4b76ed8eb7e70be504922b41b94033deb8216c --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/activity/RequestCodes.java @@ -0,0 +1,18 @@ +package org.briarproject.mailbox.android.activity; + +public interface RequestCodes { + + int REQUEST_PASSWORD = 1; + int REQUEST_INTRODUCTION = 2; + int REQUEST_GROUP_INVITE = 3; + int REQUEST_SHARE_FORUM = 4; + int REQUEST_WRITE_BLOG_POST = 5; + int REQUEST_SHARE_BLOG = 6; + int REQUEST_RINGTONE = 7; + int REQUEST_PERMISSION_CAMERA = 8; + int REQUEST_DOZE_WHITELISTING = 9; + int REQUEST_ENABLE_BLUETOOTH = 10; + int REQUEST_UNLOCK = 11; + int REQUEST_KEYGUARD_UNLOCK = 12; + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/ActivityLifecycleController.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/ActivityLifecycleController.java new file mode 100644 index 0000000000000000000000000000000000000000..fd910090e47391f4c262b42c2b62c6f4ca2c3f60 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/ActivityLifecycleController.java @@ -0,0 +1,14 @@ +package org.briarproject.mailbox.android.controller; + +import android.app.Activity; + +public interface ActivityLifecycleController { + + void onActivityCreate(Activity activity); + + void onActivityStart(); + + void onActivityStop(); + + void onActivityDestroy(); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/BriarController.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/BriarController.java new file mode 100644 index 0000000000000000000000000000000000000000..34245a4a503fb8fab2c34f593296db10fe2d6b61 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/BriarController.java @@ -0,0 +1,20 @@ +package org.briarproject.mailbox.android.controller; + +import org.briarproject.mailbox.android.controller.handler.ResultHandler; + +public interface BriarController extends ActivityLifecycleController { + + void startAndBindService(); + + boolean accountSignedIn(); + + /** + * Returns true via the handler when the app has dozed + * without being white-listed. + */ + void hasDozed(ResultHandler<Boolean> handler); + + void doNotAskAgainForDozeWhiteListing(); + + void signOut(ResultHandler<Void> eventHandler); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/BriarControllerImpl.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/BriarControllerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..ad183a5fb759d5a234ffd79f0ae315bcb064b9dc --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/BriarControllerImpl.java @@ -0,0 +1,146 @@ +package org.briarproject.mailbox.android.controller; + +import android.app.Activity; +import android.content.Intent; +import android.os.IBinder; +import android.support.annotation.CallSuper; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.db.DatabaseExecutor; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.settings.Settings; +import org.briarproject.bramble.api.settings.SettingsManager; +import org.briarproject.mailbox.android.BriarService; +import org.briarproject.mailbox.android.BriarService.BriarServiceConnection; +import org.briarproject.mailbox.android.controller.handler.ResultHandler; +import org.briarproject.mailbox.api.android.DozeWatchdog; + +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.mailbox.android.settings.SettingsFragment.SETTINGS_NAMESPACE; +import static org.briarproject.mailbox.android.util.UiUtils.needsDozeWhitelisting; + +public class BriarControllerImpl implements BriarController { + + private static final Logger LOG = + Logger.getLogger(BriarControllerImpl.class.getName()); + + public static final String DOZE_ASK_AGAIN = "dozeAskAgain"; + + private final BriarServiceConnection serviceConnection; + private final AccountManager accountManager; + private final Executor databaseExecutor; + private final SettingsManager settingsManager; + private final DozeWatchdog dozeWatchdog; + private final Activity activity; + + private boolean bound = false; + + @Inject + BriarControllerImpl(BriarServiceConnection serviceConnection, + AccountManager accountManager, + @DatabaseExecutor Executor databaseExecutor, + SettingsManager settingsManager, DozeWatchdog dozeWatchdog, + Activity activity) { + this.serviceConnection = serviceConnection; + this.accountManager = accountManager; + this.databaseExecutor = databaseExecutor; + this.settingsManager = settingsManager; + this.dozeWatchdog = dozeWatchdog; + this.activity = activity; + } + + @Override + @CallSuper + public void onActivityCreate(Activity activity) { + if (accountManager.hasDatabaseKey()) startAndBindService(); + } + + @Override + public void onActivityStart() { + } + + @Override + public void onActivityStop() { + } + + @Override + @CallSuper + public void onActivityDestroy() { + unbindService(); + } + + @Override + public void startAndBindService() { + activity.startService(new Intent(activity, BriarService.class)); + bound = activity.bindService(new Intent(activity, BriarService.class), + serviceConnection, 0); + } + + @Override + public boolean accountSignedIn() { + return accountManager.hasDatabaseKey(); + } + + @Override + public void hasDozed(ResultHandler<Boolean> handler) { + if (!dozeWatchdog.getAndResetDozeFlag() + || !needsDozeWhitelisting(activity)) { + handler.onResult(false); + return; + } + databaseExecutor.execute(() -> { + try { + Settings settings = + settingsManager.getSettings(SETTINGS_NAMESPACE); + boolean ask = settings.getBoolean(DOZE_ASK_AGAIN, true); + handler.onResult(ask); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + @Override + public void doNotAskAgainForDozeWhiteListing() { + databaseExecutor.execute(() -> { + try { + Settings settings = new Settings(); + settings.putBoolean(DOZE_ASK_AGAIN, false); + settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + @Override + public void signOut(ResultHandler<Void> eventHandler) { + new Thread(() -> { + try { + // Wait for the service to finish starting up + IBinder binder = serviceConnection.waitForBinder(); + BriarService service = + ((BriarService.BriarBinder) binder).getService(); + service.waitForStartup(); + // Shut down the service and wait for it to shut down + LOG.info("Shutting down service"); + service.shutdown(); + service.waitForShutdown(); + } catch (InterruptedException e) { + LOG.warning("Interrupted while waiting for service"); + } + eventHandler.onResult(null); + }).start(); + } + + private void unbindService() { + if (bound) activity.unbindService(serviceConnection); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/DbController.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/DbController.java new file mode 100644 index 0000000000000000000000000000000000000000..1ab7b460f60c3589b281b0e20ff54c0c09cdd177 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/DbController.java @@ -0,0 +1,9 @@ +package org.briarproject.mailbox.android.controller; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@NotNullByDefault +public interface DbController { + + void runOnDbThread(Runnable task); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/DbControllerImpl.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/DbControllerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..522542ada5a4a637865820947874f040493a88a7 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/DbControllerImpl.java @@ -0,0 +1,42 @@ +package org.briarproject.mailbox.android.controller; + +import org.briarproject.bramble.api.db.DatabaseExecutor; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +@Immutable +@NotNullByDefault +public class DbControllerImpl implements DbController { + + private static final Logger LOG = + Logger.getLogger(DbControllerImpl.class.getName()); + + protected final Executor dbExecutor; + private final LifecycleManager lifecycleManager; + + @Inject + public DbControllerImpl(@DatabaseExecutor Executor dbExecutor, + LifecycleManager lifecycleManager) { + this.dbExecutor = dbExecutor; + this.lifecycleManager = lifecycleManager; + } + + @Override + public void runOnDbThread(Runnable task) { + dbExecutor.execute(() -> { + try { + lifecycleManager.waitForDatabase(); + task.run(); + } catch (InterruptedException e) { + LOG.warning("Interrupted while waiting for database"); + Thread.currentThread().interrupt(); + } + }); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/SharingController.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/SharingController.java new file mode 100644 index 0000000000000000000000000000000000000000..c8c23d8b60c7c983ca4ed53c80d97d795a6ba909 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/SharingController.java @@ -0,0 +1,70 @@ +package org.briarproject.mailbox.android.controller; + +import android.support.annotation.UiThread; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.mailbox.android.DestroyableContext; + +import java.util.Collection; + +@NotNullByDefault +public interface SharingController { + + /** + * Sets the listener that is called when contacts go on or offline. + */ + @UiThread + void setSharingListener(SharingListener listener); + + /** + * Call this when your lifecycle starts, + * so the listener will be called when information changes. + */ + @UiThread + void onStart(); + + /** + * Call this when your lifecycle stops, + * so that the controller knows it can stops listening to events. + */ + @UiThread + void onStop(); + + /** + * Adds one contact to be tracked. + */ + @UiThread + void add(ContactId c); + + /** + * Adds a collection of contacts to be tracked. + */ + @UiThread + void addAll(Collection<ContactId> contacts); + + /** + * Call this when the contact identified by c is no longer sharing + * the given group identified by GroupId g. + */ + @UiThread + void remove(ContactId c); + + /** + * Returns the number of online contacts. + */ + @UiThread + int getOnlineCount(); + + /** + * Returns the total number of contacts that have been added. + */ + @UiThread + int getTotalCount(); + + interface SharingListener extends DestroyableContext { + @UiThread + void onSharingInfoUpdated(int total, int online); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/SharingControllerImpl.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/SharingControllerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..4ede2399fea2180e8359a8129fa49f726eb1d64f --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/SharingControllerImpl.java @@ -0,0 +1,100 @@ +package org.briarproject.mailbox.android.controller; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.event.EventListener; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.ConnectionRegistry; +import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent; +import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +@NotNullByDefault +public class SharingControllerImpl implements SharingController, EventListener { + + private final EventBus eventBus; + private final ConnectionRegistry connectionRegistry; + + @Nullable + private volatile SharingListener listener; + // only access on @UiThread + private final Set<ContactId> contacts = new HashSet<>(); + + @Inject + SharingControllerImpl(EventBus eventBus, + ConnectionRegistry connectionRegistry) { + this.eventBus = eventBus; + this.connectionRegistry = connectionRegistry; + } + + @Override + public void setSharingListener(SharingListener listener) { + this.listener = listener; + } + + @Override + public void onStart() { + eventBus.addListener(this); + } + + @Override + public void onStop() { + eventBus.removeListener(this); + } + + @Override + public void eventOccurred(Event e) { + if (e instanceof ContactConnectedEvent) { + setConnected(((ContactConnectedEvent) e).getContactId()); + } else if (e instanceof ContactDisconnectedEvent) { + setConnected(((ContactDisconnectedEvent) e).getContactId()); + } + } + + private void setConnected(ContactId c) { + if (listener == null) return; + listener.runOnUiThreadUnlessDestroyed(() -> { + if (contacts.contains(c)) { + int online = getOnlineCount(); + listener.onSharingInfoUpdated(contacts.size(), online); + } + }); + } + + @Override + public void addAll(Collection<ContactId> c) { + contacts.addAll(c); + } + + @Override + public void add(ContactId c) { + contacts.add(c); + } + + @Override + public void remove(ContactId c) { + contacts.remove(c); + } + + @Override + public int getOnlineCount() { + int online = 0; + for (ContactId c : contacts) { + if (connectionRegistry.isConnected(c)) online++; + } + return online; + } + + @Override + public int getTotalCount() { + return contacts.size(); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/ExceptionHandler.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/ExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..d0edd38b5b55dbb0607e3fb7e3124fc1a12081c1 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/ExceptionHandler.java @@ -0,0 +1,7 @@ +package org.briarproject.mailbox.android.controller.handler; + +public interface ExceptionHandler<E extends Exception> { + + void onException(E exception); + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/ResultExceptionHandler.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/ResultExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..80f8fa0ff1106373c553dd4232314394b1e0863a --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/ResultExceptionHandler.java @@ -0,0 +1,8 @@ +package org.briarproject.mailbox.android.controller.handler; + +public interface ResultExceptionHandler<R, E extends Exception> + extends ExceptionHandler<E> { + + void onResult(R result); + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/ResultHandler.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/ResultHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..203bcf5a82cea79e1ce0f8dcd8bce99fd49fc336 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/ResultHandler.java @@ -0,0 +1,6 @@ +package org.briarproject.mailbox.android.controller.handler; + +public interface ResultHandler<R> { + + void onResult(R result); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/UiExceptionHandler.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/UiExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..32541b7a87192b7eec3fd9a0b98c1197c323b560 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/UiExceptionHandler.java @@ -0,0 +1,29 @@ +package org.briarproject.mailbox.android.controller.handler; + +import android.support.annotation.UiThread; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.mailbox.android.DestroyableContext; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public abstract class UiExceptionHandler<E extends Exception> + implements ExceptionHandler<E> { + + protected final DestroyableContext listener; + + protected UiExceptionHandler(DestroyableContext listener) { + this.listener = listener; + } + + @Override + public void onException(E exception) { + listener.runOnUiThreadUnlessDestroyed(() -> onExceptionUi(exception)); + } + + @UiThread + public abstract void onExceptionUi(E exception); + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/UiResultExceptionHandler.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/UiResultExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..905d6931c8367bd905e6e3c76d8ac1af7abe08cc --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/UiResultExceptionHandler.java @@ -0,0 +1,27 @@ +package org.briarproject.mailbox.android.controller.handler; + +import android.support.annotation.UiThread; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.mailbox.android.DestroyableContext; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public abstract class UiResultExceptionHandler<R, E extends Exception> + extends UiExceptionHandler<E> implements ResultExceptionHandler<R, E> { + + protected UiResultExceptionHandler(DestroyableContext listener) { + super(listener); + } + + @Override + public void onResult(R result) { + listener.runOnUiThreadUnlessDestroyed(() -> onResultUi(result)); + } + + @UiThread + public abstract void onResultUi(R result); + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/UiResultHandler.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/UiResultHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..203e258db61d3b9d20b2b922b768346fb31fd0f9 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/controller/handler/UiResultHandler.java @@ -0,0 +1,22 @@ +package org.briarproject.mailbox.android.controller.handler; + +import android.support.annotation.UiThread; + +import org.briarproject.mailbox.android.DestroyableContext; + +public abstract class UiResultHandler<R> implements ResultHandler<R> { + + private final DestroyableContext listener; + + protected UiResultHandler(DestroyableContext listener) { + this.listener = listener; + } + + @Override + public void onResult(R result) { + listener.runOnUiThreadUnlessDestroyed(() -> onResultUi(result)); + } + + @UiThread + public abstract void onResultUi(R result); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/BaseEventFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/BaseEventFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..fdf5a8ccdd9e74eb2a78e2f7ec0e08a1ff407643 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/BaseEventFragment.java @@ -0,0 +1,25 @@ +package org.briarproject.mailbox.android.fragment; + +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.event.EventListener; + +import javax.inject.Inject; + +public abstract class BaseEventFragment extends BaseFragment implements + EventListener { + + @Inject + protected volatile EventBus eventBus; + + @Override + public void onStart() { + super.onStart(); + eventBus.addListener(this); + } + + @Override + public void onStop() { + super.onStop(); + eventBus.removeListener(this); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/BaseFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/BaseFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..fc6e425214716d0be2f8589ca4a15172c7d8b812 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/BaseFragment.java @@ -0,0 +1,105 @@ +package org.briarproject.mailbox.android.fragment; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.CallSuper; +import android.support.annotation.UiThread; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.view.MenuItem; + +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.mailbox.android.DestroyableContext; +import org.briarproject.mailbox.android.activity.ActivityComponent; + +import javax.annotation.Nullable; + +public abstract class BaseFragment extends Fragment + implements DestroyableContext { + + protected BaseFragmentListener listener; + + public abstract String getUniqueTag(); + + public abstract void injectFragment(ActivityComponent component); + + @Override + public void onAttach(Context context) { + super.onAttach(context); + listener = (BaseFragmentListener) context; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // allow for "up" button to act as back button + setHasOptionsMenu(true); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + injectFragment(listener.getActivityComponent()); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + listener.onBackPressed(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @UiThread + protected void finish() { + FragmentActivity activity = getActivity(); + if (activity != null) activity.supportFinishAfterTransition(); + } + + public interface BaseFragmentListener { + @Deprecated + void runOnDbThread(Runnable runnable); + + @UiThread + void onBackPressed(); + + @UiThread + ActivityComponent getActivityComponent(); + + @UiThread + void showNextFragment(BaseFragment f); + + @UiThread + void handleDbException(DbException e); + } + + @CallSuper + @Override + public void runOnUiThreadUnlessDestroyed(Runnable r) { + Activity activity = getActivity(); + if (activity != null) { + activity.runOnUiThread(() -> { + // Note that we don't have to check if the activity has + // been destroyed as the Fragment has not been detached yet + if (isAdded() && !activity.isFinishing()) { + r.run(); + } + }); + } + } + + protected void showNextFragment(BaseFragment f) { + listener.showNextFragment(f); + } + + @UiThread + protected void handleDbException(DbException e) { + listener.handleDbException(e); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/ErrorFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/ErrorFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..6e4fe8d746ab034d9b99517af8fa1d13335d22dc --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/ErrorFragment.java @@ -0,0 +1,65 @@ +package org.briarproject.mailbox.android.fragment; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; + + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class ErrorFragment extends BaseFragment { + + private static final String TAG = ErrorFragment.class.getName(); + + private static final String ERROR_MSG = "errorMessage"; + + public static ErrorFragment newInstance(String message) { + ErrorFragment f = new ErrorFragment(); + Bundle args = new Bundle(); + args.putString(ERROR_MSG, message); + f.setArguments(args); + return f; + } + + private String errorMessage; + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle args = getArguments(); + if (args == null) throw new AssertionError(); + errorMessage = args.getString(ERROR_MSG); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View v = inflater + .inflate(R.layout.fragment_error, container, false); + TextView msg = v.findViewById(R.id.errorMessage); + msg.setText(errorMessage); + return v; + } + + @Override + public void injectFragment(ActivityComponent component) { + // not necessary + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/ScreenFilterDialogFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/ScreenFilterDialogFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..5319651354b992f120df824b881486da090b197d --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/fragment/ScreenFilterDialogFragment.java @@ -0,0 +1,106 @@ +package org.briarproject.mailbox.android.fragment; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.support.v7.app.AlertDialog; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.CheckBox; +import android.widget.TextView; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.BaseActivity; +import org.briarproject.mailbox.api.android.ScreenFilterMonitor; +import org.briarproject.mailbox.api.android.ScreenFilterMonitor.AppDetails; + +import java.util.ArrayList; +import java.util.Collection; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class ScreenFilterDialogFragment extends DialogFragment { + + public static final String TAG = ScreenFilterDialogFragment.class.getName(); + + @Inject + ScreenFilterMonitor screenFilterMonitor; + + DismissListener dismissListener = null; + + public static ScreenFilterDialogFragment newInstance( + Collection<AppDetails> apps) { + ScreenFilterDialogFragment frag = new ScreenFilterDialogFragment(); + Bundle args = new Bundle(); + ArrayList<String> appNames = new ArrayList<>(); + for (AppDetails a : apps) appNames.add(a.name); + args.putStringArrayList("appNames", appNames); + ArrayList<String> packageNames = new ArrayList<>(); + for (AppDetails a : apps) packageNames.add(a.packageName); + args.putStringArrayList("packageNames", packageNames); + frag.setArguments(args); + return frag; + } + + public void setDismissListener(DismissListener dismissListener) { + this.dismissListener = dismissListener; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + Activity activity = getActivity(); + if (activity == null) throw new IllegalStateException(); + ((BaseActivity) activity).getActivityComponent().inject(this); + } + + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + Activity activity = getActivity(); + if (activity == null) throw new IllegalStateException(); + AlertDialog.Builder builder = new AlertDialog.Builder(activity, + R.style.BriarDialogThemeNoFilter); + builder.setTitle(R.string.screen_filter_title); + Bundle args = getArguments(); + if (args == null) throw new IllegalStateException(); + ArrayList<String> appNames = args.getStringArrayList("appNames"); + ArrayList<String> packageNames = + args.getStringArrayList("packageNames"); + if (appNames == null || packageNames == null) + throw new IllegalStateException(); + LayoutInflater inflater = activity.getLayoutInflater(); + // See https://stackoverflow.com/a/24720976/6314875 + @SuppressLint("InflateParams") + View dialogView = inflater.inflate(R.layout.dialog_screen_filter, null); + builder.setView(dialogView); + TextView message = dialogView.findViewById(R.id.screen_filter_message); + message.setText(getString(R.string.screen_filter_body, + TextUtils.join("\n", appNames))); + CheckBox allow = dialogView.findViewById(R.id.screen_filter_checkbox); + builder.setNeutralButton(R.string.continue_button, (dialog, which) -> { + if (allow.isChecked()) screenFilterMonitor.allowApps(packageNames); + dialog.dismiss(); + }); + builder.setCancelable(false); + return builder.create(); + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + if (dismissListener != null) dismissListener.onDialogDismissed(); + } + + public interface DismissListener { + void onDialogDismissed(); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/CameraException.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/CameraException.java new file mode 100644 index 0000000000000000000000000000000000000000..4b739551c1fabb9d140a3f9e76e562a79567a424 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/CameraException.java @@ -0,0 +1,14 @@ +package org.briarproject.mailbox.android.keyagreement; + +import java.io.IOException; + +class CameraException extends IOException { + + CameraException(String message) { + super(message); + } + + CameraException(Throwable cause) { + super(cause); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/CameraView.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/CameraView.java new file mode 100644 index 0000000000000000000000000000000000000000..ea98fbfffb9973a34d186ed55b811d342f0734f1 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/CameraView.java @@ -0,0 +1,524 @@ +package org.briarproject.mailbox.android.keyagreement; + +import android.content.Context; +import android.hardware.Camera; +import android.hardware.Camera.AutoFocusCallback; +import android.hardware.Camera.CameraInfo; +import android.hardware.Camera.Parameters; +import android.hardware.Camera.Size; +import android.support.annotation.Nullable; +import android.support.annotation.UiThread; +import android.util.AttributeSet; +import android.view.Display; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.WindowManager; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; + +import java.io.IOException; +import java.util.List; +import java.util.logging.Logger; + +import static android.content.Context.WINDOW_SERVICE; +import static android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK; +import static android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT; +import static android.hardware.Camera.Parameters.FLASH_MODE_OFF; +import static android.hardware.Camera.Parameters.FOCUS_MODE_AUTO; +import static android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE; +import static android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO; +import static android.hardware.Camera.Parameters.FOCUS_MODE_EDOF; +import static android.hardware.Camera.Parameters.FOCUS_MODE_FIXED; +import static android.hardware.Camera.Parameters.FOCUS_MODE_MACRO; +import static android.hardware.Camera.Parameters.SCENE_MODE_AUTO; +import static android.hardware.Camera.Parameters.SCENE_MODE_BARCODE; +import static android.os.Build.VERSION.SDK_INT; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; + +@SuppressWarnings("deprecation") +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class CameraView extends SurfaceView implements SurfaceHolder.Callback, + AutoFocusCallback, View.OnClickListener { + + // Heuristic for the ideal preview size - small previews don't have enough + // detail, large previews are slow to decode + private static final int IDEAL_PIXELS = 500 * 1000; + + private static final int AUTO_FOCUS_RETRY_DELAY = 5000; // Milliseconds + + private static final Logger LOG = + Logger.getLogger(CameraView.class.getName()); + + private final Runnable autoFocusRetry = this::retryAutoFocus; + + @Nullable + private Camera camera = null; + private int cameraIndex = 0; + private PreviewConsumer previewConsumer = null; + private Surface surface = null; + private int displayOrientation = 0, surfaceWidth = 0, surfaceHeight = 0; + private boolean previewStarted = false; + private boolean autoFocusSupported = false, autoFocusRunning = false; + + public CameraView(Context context) { + super(context); + } + + public CameraView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CameraView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @UiThread + public void setPreviewConsumer(PreviewConsumer previewConsumer) { + LOG.info("Setting preview consumer"); + this.previewConsumer = previewConsumer; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + setKeepScreenOn(true); + getHolder().addCallback(this); + setOnClickListener(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + setKeepScreenOn(false); + getHolder().removeCallback(this); + } + + @UiThread + public void start() throws CameraException { + LOG.info("Opening camera"); + try { + int cameras = Camera.getNumberOfCameras(); + if (cameras == 0) throw new CameraException("No camera"); + // Try to find a back-facing camera + for (int i = 0; i < cameras; i++) { + CameraInfo info = new CameraInfo(); + Camera.getCameraInfo(i, info); + if (info.facing == CAMERA_FACING_BACK) { + LOG.info("Using back-facing camera"); + camera = Camera.open(i); + cameraIndex = i; + break; + } + } + // If we can't find a back-facing camera, use a front-facing one + if (camera == null) { + LOG.info("Using front-facing camera"); + camera = Camera.open(0); + cameraIndex = 0; + } + } catch (RuntimeException e) { + throw new CameraException(e); + } + setDisplayOrientation(getScreenRotationDegrees()); + // Use barcode scene mode if it's available + Parameters params = camera.getParameters(); + params = setSceneMode(camera, params); + if (SCENE_MODE_BARCODE.equals(params.getSceneMode())) { + // If the scene mode enabled the flash, try to disable it + if (!FLASH_MODE_OFF.equals(params.getFlashMode())) + params = disableFlash(camera, params); + // If the flash is still enabled, disable the scene mode + if (!FLASH_MODE_OFF.equals(params.getFlashMode())) + params = disableSceneMode(camera, params); + } + // Use the best available focus mode, preview size and other options + params = setBestParameters(camera, params); + // Enable auto focus if the selected focus mode uses it + enableAutoFocus(params.getFocusMode()); + // Log the parameters that are being used (maybe not what we asked for) + logCameraParameters(); + // Start the preview when the camera and the surface are both ready + if (surface != null && !previewStarted) startPreview(getHolder()); + } + + @UiThread + public void stop() throws CameraException { + if (camera == null) return; + stopPreview(); + LOG.info("Releasing camera"); + try { + camera.release(); + } catch (RuntimeException e) { + throw new CameraException(e); + } + camera = null; + } + + /** + * See {@link Camera#setDisplayOrientation(int)}. + */ + private int getScreenRotationDegrees() { + WindowManager wm = + (WindowManager) getContext().getSystemService(WINDOW_SERVICE); + Display d = wm.getDefaultDisplay(); + switch (d.getRotation()) { + case Surface.ROTATION_0: + return 0; + case Surface.ROTATION_90: + return 90; + case Surface.ROTATION_180: + return 180; + case Surface.ROTATION_270: + return 270; + default: + throw new AssertionError(); + } + } + + @UiThread + private void startPreview(SurfaceHolder holder) throws CameraException { + LOG.info("Starting preview"); + if (camera == null) throw new CameraException("Camera is null"); + try { + camera.setPreviewDisplay(holder); + camera.startPreview(); + previewStarted = true; + startConsumer(); + } catch (IOException | RuntimeException e) { + throw new CameraException(e); + } + } + + @UiThread + private void stopPreview() throws CameraException { + LOG.info("Stopping preview"); + if (camera == null) throw new CameraException("Camera is null"); + try { + stopConsumer(); + camera.stopPreview(); + } catch (RuntimeException e) { + throw new CameraException(e); + } + previewStarted = false; + } + + @UiThread + private void startConsumer() throws CameraException { + if (camera == null) throw new CameraException("Camera is null"); + startAutoFocus(); + previewConsumer.start(camera, cameraIndex); + } + + @UiThread + private void startAutoFocus() throws CameraException { + if (camera != null && autoFocusSupported && !autoFocusRunning) { + try { + removeCallbacks(autoFocusRetry); + camera.autoFocus(this); + autoFocusRunning = true; + } catch (RuntimeException e) { + throw new CameraException(e); + } + } + } + + @UiThread + private void stopConsumer() throws CameraException { + if (camera == null) throw new CameraException("Camera is null"); + cancelAutoFocus(); + previewConsumer.stop(); + } + + @UiThread + private void cancelAutoFocus() throws CameraException { + if (camera != null && autoFocusSupported && autoFocusRunning) { + try { + removeCallbacks(autoFocusRetry); + camera.cancelAutoFocus(); + autoFocusRunning = false; + } catch (RuntimeException e) { + throw new CameraException(e); + } + } + } + + /** + * See {@link Camera#setDisplayOrientation(int)}. + */ + @UiThread + private void setDisplayOrientation(int rotationDegrees) + throws CameraException { + if (camera == null) throw new CameraException("Camera is null"); + int orientation; + CameraInfo info = new CameraInfo(); + try { + Camera.getCameraInfo(cameraIndex, info); + } catch (RuntimeException e) { + throw new CameraException(e); + } + if (info.facing == CAMERA_FACING_FRONT) { + orientation = (info.orientation + rotationDegrees) % 360; + orientation = (360 - orientation) % 360; + } else { + orientation = (info.orientation - rotationDegrees + 360) % 360; + } + if (LOG.isLoggable(INFO)) { + LOG.info("Screen rotation " + rotationDegrees + + " degrees, camera orientation " + orientation + + " degrees"); + } + try { + camera.setDisplayOrientation(orientation); + } catch (RuntimeException e) { + throw new CameraException(e); + } + displayOrientation = orientation; + } + + @UiThread + private Parameters setSceneMode(Camera camera, Parameters params) + throws CameraException { + List<String> sceneModes = params.getSupportedSceneModes(); + if (sceneModes == null) return params; + if (LOG.isLoggable(INFO)) LOG.info("Scene modes: " + sceneModes); + if (sceneModes.contains(SCENE_MODE_BARCODE)) { + params.setSceneMode(SCENE_MODE_BARCODE); + try { + camera.setParameters(params); + return camera.getParameters(); + } catch (RuntimeException e) { + throw new CameraException(e); + } + } + return params; + } + + @UiThread + private Parameters disableFlash(Camera camera, Parameters params) + throws CameraException { + params.setFlashMode(FLASH_MODE_OFF); + try { + camera.setParameters(params); + return camera.getParameters(); + } catch (RuntimeException e) { + throw new CameraException(e); + } + } + + @UiThread + private Parameters disableSceneMode(Camera camera, Parameters params) + throws CameraException { + params.setSceneMode(SCENE_MODE_AUTO); + try { + camera.setParameters(params); + return camera.getParameters(); + } catch (RuntimeException e) { + throw new CameraException(e); + } + } + + @UiThread + private Parameters setBestParameters(Camera camera, Parameters params) + throws CameraException { + setVideoStabilisation(params); + setFocusMode(params); + params.setFlashMode(FLASH_MODE_OFF); + setPreviewSize(params); + try { + camera.setParameters(params); + return camera.getParameters(); + } catch (RuntimeException e) { + throw new CameraException(e); + } + } + + @UiThread + private void setVideoStabilisation(Parameters params) { + if (SDK_INT >= 15 && params.isVideoStabilizationSupported()) { + params.setVideoStabilization(true); + } + } + + @UiThread + private void setFocusMode(Parameters params) { + List<String> focusModes = params.getSupportedFocusModes(); + if (LOG.isLoggable(INFO)) LOG.info("Focus modes: " + focusModes); + if (focusModes.contains(FOCUS_MODE_CONTINUOUS_PICTURE)) { + params.setFocusMode(FOCUS_MODE_CONTINUOUS_PICTURE); + } else if (focusModes.contains(FOCUS_MODE_CONTINUOUS_VIDEO)) { + params.setFocusMode(FOCUS_MODE_CONTINUOUS_VIDEO); + } else if (focusModes.contains(FOCUS_MODE_EDOF)) { + params.setFocusMode(FOCUS_MODE_EDOF); + } else if (focusModes.contains(FOCUS_MODE_MACRO)) { + params.setFocusMode(FOCUS_MODE_MACRO); + } else if (focusModes.contains(FOCUS_MODE_AUTO)) { + params.setFocusMode(FOCUS_MODE_AUTO); + } else if (focusModes.contains(FOCUS_MODE_FIXED)) { + params.setFocusMode(FOCUS_MODE_FIXED); + } + } + + @UiThread + private void setPreviewSize(Parameters params) { + if (surfaceWidth == 0 || surfaceHeight == 0) return; + // Choose a preview size that's close to the aspect ratio of the + // surface and close to the ideal size for decoding + float idealRatio = (float) surfaceWidth / surfaceHeight; + boolean rotatePreview = displayOrientation % 180 == 90; + List<Size> sizes = params.getSupportedPreviewSizes(); + Size bestSize = null; + float bestScore = 0; + for (Size size : sizes) { + int width = rotatePreview ? size.height : size.width; + int height = rotatePreview ? size.width : size.height; + float ratio = (float) width / height; + float stretch = Math.max(ratio / idealRatio, idealRatio / ratio); + float pixels = width * height; + float zoom = Math.max(pixels / IDEAL_PIXELS, IDEAL_PIXELS / pixels); + float score = 1 / (stretch * zoom); + if (LOG.isLoggable(INFO)) { + LOG.info("Size " + size.width + "x" + size.height + + ", stretch " + stretch + ", zoom " + zoom + + ", score " + score); + } + if (bestSize == null || score > bestScore) { + bestSize = size; + bestScore = score; + } + } + if (bestSize != null) { + if (LOG.isLoggable(INFO)) + LOG.info("Best size " + bestSize.width + "x" + bestSize.height); + params.setPreviewSize(bestSize.width, bestSize.height); + } + } + + @UiThread + private void enableAutoFocus(String focusMode) { + autoFocusSupported = FOCUS_MODE_AUTO.equals(focusMode) || + FOCUS_MODE_MACRO.equals(focusMode); + } + + @UiThread + private void logCameraParameters() throws CameraException { + if (camera == null) throw new AssertionError(); + if (LOG.isLoggable(INFO)) { + Parameters params; + try { + params = camera.getParameters(); + } catch (RuntimeException e) { + throw new CameraException(e); + } + if (SDK_INT >= 15) { + LOG.info("Video stabilisation enabled: " + + params.getVideoStabilization()); + } + LOG.info("Scene mode: " + params.getSceneMode()); + LOG.info("Focus mode: " + params.getFocusMode()); + LOG.info("Flash mode: " + params.getFlashMode()); + Size size = params.getPreviewSize(); + LOG.info("Preview size: " + size.width + "x" + size.height); + } + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + post(() -> { + try { + surfaceCreatedUi(holder); + } catch (CameraException e) { + logException(LOG, WARNING, e); + } + }); + } + + @UiThread + private void surfaceCreatedUi(SurfaceHolder holder) throws CameraException { + LOG.info("Surface created"); + if (surface != null && surface != holder.getSurface()) { + LOG.info("Releasing old surface"); + surface.release(); + } + surface = holder.getSurface(); + // We'll start the preview when surfaceChanged() is called + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + post(() -> { + try { + surfaceChangedUi(holder, w, h); + } catch (CameraException e) { + logException(LOG, WARNING, e); + } + }); + } + + @UiThread + private void surfaceChangedUi(SurfaceHolder holder, int w, int h) + throws CameraException { + if (LOG.isLoggable(INFO)) LOG.info("Surface changed: " + w + "x" + h); + if (surface != null && surface != holder.getSurface()) { + LOG.info("Releasing old surface"); + surface.release(); + } + surface = holder.getSurface(); + surfaceWidth = w; + surfaceHeight = h; + if (camera == null) return; // We are stopped + if (previewStarted) stopPreview(); + try { + Parameters params = camera.getParameters(); + setPreviewSize(params); + camera.setParameters(params); + logCameraParameters(); + } catch (RuntimeException e) { + throw new CameraException(e); + } + startPreview(holder); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + post(() -> surfaceDestroyedUi(holder)); + } + + @UiThread + private void surfaceDestroyedUi(SurfaceHolder holder) { + LOG.info("Surface destroyed"); + if (surface != null && surface != holder.getSurface()) { + LOG.info("Releasing old surface"); + surface.release(); + } + surface = null; + holder.getSurface().release(); + } + + @Override + public void onAutoFocus(boolean success, Camera camera) { + if (LOG.isLoggable(INFO)) + LOG.info("Auto focus succeeded: " + success); + autoFocusRunning = false; + postDelayed(autoFocusRetry, AUTO_FOCUS_RETRY_DELAY); + } + + @UiThread + private void retryAutoFocus() { + try { + startAutoFocus(); + } catch (CameraException e) { + logException(LOG, WARNING, e); + } + } + + @Override + public void onClick(View v) { + retryAutoFocus(); + } +} \ No newline at end of file diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/ContactExchangeErrorFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/ContactExchangeErrorFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..8e92cf357b50a284847a5abb4a9d9e6d8f0c33ea --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/ContactExchangeErrorFragment.java @@ -0,0 +1,87 @@ +package org.briarproject.mailbox.android.keyagreement; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.fragment.BaseFragment; +import org.briarproject.mailbox.android.util.UiUtils; + +import javax.inject.Inject; + +import static org.briarproject.mailbox.android.util.UiUtils.onSingleLinkClick; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class ContactExchangeErrorFragment extends BaseFragment { + + public static final String TAG = + ContactExchangeErrorFragment.class.getName(); + private static final String ERROR_MSG = "errorMessage"; + + public static ContactExchangeErrorFragment newInstance(String errorMsg) { + ContactExchangeErrorFragment f = new ContactExchangeErrorFragment(); + Bundle args = new Bundle(); + args.putString(ERROR_MSG, errorMsg); + f.setArguments(args); + return f; + } + + @Inject + AndroidExecutor androidExecutor; + + @Override + public String getUniqueTag() { + return TAG; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.fragment_error_contact_exchange, + container, false); + + // set humanized error message + TextView explanation = v.findViewById(R.id.errorMessage); + Bundle args = getArguments(); + if (args == null) { + throw new IllegalArgumentException("Use newInstance()"); + } + explanation.setText(args.getString(ERROR_MSG)); + + // make feedback link clickable + TextView sendFeedback = v.findViewById(R.id.sendFeedback); + onSingleLinkClick(sendFeedback, this::triggerFeedback); + + // buttons + Button tryAgain = v.findViewById(R.id.tryAgainButton); + tryAgain.setOnClickListener(view -> { + if (getActivity() != null) getActivity().onBackPressed(); + }); + Button cancel = v.findViewById(R.id.cancelButton); + cancel.setOnClickListener(view -> finish()); + return v; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + } + + private void triggerFeedback() { + finish(); + UiUtils.triggerFeedback(androidExecutor); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/IntroFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/IntroFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..02332452df64aad48f78102a8acd8d02e3a67600 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/IntroFragment.java @@ -0,0 +1,78 @@ +package org.briarproject.mailbox.android.keyagreement; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.fragment.BaseFragment; + +import javax.annotation.Nullable; + +import static android.view.View.FOCUS_DOWN; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class IntroFragment extends BaseFragment { + + interface IntroScreenSeenListener { + void showNextScreen(); + } + + public static final String TAG = IntroFragment.class.getName(); + + private IntroScreenSeenListener screenSeenListener; + private ScrollView scrollView; + + public static IntroFragment newInstance() { + + Bundle args = new Bundle(); + + IntroFragment fragment = new IntroFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + screenSeenListener = (IntroScreenSeenListener) context; + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + + View v = inflater.inflate(R.layout.fragment_keyagreement_id, container, + false); + scrollView = v.findViewById(R.id.scrollView); + View button = v.findViewById(R.id.continueButton); + button.setOnClickListener(view -> screenSeenListener.showNextScreen()); + return v; + } + + @Override + public void onStart() { + super.onStart(); + scrollView.post(() -> scrollView.fullScroll(FOCUS_DOWN)); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/KeyAgreementActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/KeyAgreementActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..f0d36a9dc3b9c618684afb07de082f618429f596 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/KeyAgreementActivity.java @@ -0,0 +1,267 @@ +package org.briarproject.mailbox.android.keyagreement; + +import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.support.annotation.StringRes; +import android.support.annotation.UiThread; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.FragmentManager; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog.Builder; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.widget.Toast; + +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.plugin.event.BluetoothEnabledEvent; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.R.string; +import org.briarproject.mailbox.R.style; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BriarActivity; +import org.briarproject.mailbox.android.fragment.BaseFragment; +import org.briarproject.mailbox.android.fragment.BaseFragment.BaseFragmentListener; +import org.briarproject.mailbox.android.keyagreement.IntroFragment.IntroScreenSeenListener; +import org.briarproject.mailbox.android.keyagreement.KeyAgreementFragment.KeyAgreementEventListener; +import org.briarproject.mailbox.android.util.UiUtils; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static android.Manifest.permission.CAMERA; +import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_ENABLE; +import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED; +import static android.bluetooth.BluetoothAdapter.EXTRA_STATE; +import static android.bluetooth.BluetoothAdapter.STATE_ON; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Build.VERSION.SDK_INT; +import static android.widget.Toast.LENGTH_LONG; +import static org.briarproject.mailbox.android.activity.RequestCodes.REQUEST_ENABLE_BLUETOOTH; +import static org.briarproject.mailbox.android.activity.RequestCodes.REQUEST_PERMISSION_CAMERA; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public abstract class KeyAgreementActivity extends BriarActivity implements + BaseFragmentListener, IntroScreenSeenListener, + KeyAgreementEventListener { + + private enum BluetoothState { + UNKNOWN, NO_ADAPTER, WAITING, REFUSED, ENABLED + } + + private static final Logger LOG = + Logger.getLogger(KeyAgreementActivity.class.getName()); + + @Inject + EventBus eventBus; + + private boolean isResumed = false, enableWasRequested = false; + private boolean continueClicked, gotCameraPermission; + private BluetoothState bluetoothState = BluetoothState.UNKNOWN; + private BroadcastReceiver bluetoothReceiver = null; + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + @SuppressWarnings("ConstantConditions") + @Override + public void onCreate(@Nullable Bundle state) { + super.onCreate(state); + setContentView(R.layout.activity_fragment_container_toolbar); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + if (state == null) { + showInitialFragment(IntroFragment.newInstance()); + } + IntentFilter filter = new IntentFilter(ACTION_STATE_CHANGED); + bluetoothReceiver = new BluetoothStateReceiver(); + registerReceiver(bluetoothReceiver, filter); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (bluetoothReceiver != null) unregisterReceiver(bluetoothReceiver); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + protected void onPostResume() { + super.onPostResume(); + isResumed = true; + // Workaround for + // https://code.google.com/p/android/issues/detail?id=190966 + if (canShowQrCodeFragment()) showQrCodeFragment(); + } + + private boolean canShowQrCodeFragment() { + return isResumed && continueClicked + && (SDK_INT < 23 || gotCameraPermission) + && bluetoothState != BluetoothState.UNKNOWN + && bluetoothState != BluetoothState.WAITING; + } + + @Override + protected void onPause() { + super.onPause(); + isResumed = false; + } + + @Override + public void showNextScreen() { + continueClicked = true; + if (checkPermissions()) { + if (shouldRequestEnableBluetooth()) requestEnableBluetooth(); + else if (canShowQrCodeFragment()) showQrCodeFragment(); + } + } + + private boolean shouldRequestEnableBluetooth() { + return bluetoothState == BluetoothState.UNKNOWN + || bluetoothState == BluetoothState.REFUSED; + } + + private void requestEnableBluetooth() { + BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); + if (bt == null) { + setBluetoothState(BluetoothState.NO_ADAPTER); + } else if (bt.isEnabled()) { + setBluetoothState(BluetoothState.ENABLED); + } else { + enableWasRequested = true; + setBluetoothState(BluetoothState.WAITING); + Intent i = new Intent(ACTION_REQUEST_ENABLE); + startActivityForResult(i, REQUEST_ENABLE_BLUETOOTH); + } + } + + private void setBluetoothState(BluetoothState bluetoothState) { + LOG.info("Setting Bluetooth state to " + bluetoothState); + this.bluetoothState = bluetoothState; + if (enableWasRequested && bluetoothState == BluetoothState.ENABLED) { + eventBus.broadcast(new BluetoothEnabledEvent()); + enableWasRequested = false; + } + if (canShowQrCodeFragment()) showQrCodeFragment(); + } + + @Override + public void onActivityResult(int request, int result, Intent data) { + // If the request was granted we'll catch the state change event + if (request == REQUEST_ENABLE_BLUETOOTH && result == RESULT_CANCELED) + setBluetoothState(BluetoothState.REFUSED); + } + + private void showQrCodeFragment() { + continueClicked = false; + // FIXME #824 + FragmentManager fm = getSupportFragmentManager(); + if (fm.findFragmentByTag(KeyAgreementFragment.TAG) == null) { + BaseFragment f = KeyAgreementFragment.newInstance(); + fm.beginTransaction() + .replace(R.id.fragmentContainer, f, f.getUniqueTag()) + .addToBackStack(f.getUniqueTag()) + .commit(); + } + } + + protected void showErrorFragment(@StringRes int errorResId) { + String errorMsg = getString(errorResId); + BaseFragment f = ContactExchangeErrorFragment.newInstance(errorMsg); + showNextFragment(f); + } + + private boolean checkPermissions() { + if (ContextCompat.checkSelfPermission(this, CAMERA) != + PERMISSION_GRANTED) { + // Should we show an explanation? + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + CAMERA)) { + OnClickListener continueListener = + (dialog, which) -> requestPermission(); + Builder builder = new Builder(this, style.BriarDialogTheme); + builder.setTitle(string.permission_camera_title); + builder.setMessage(string.permission_camera_request_body); + builder.setNeutralButton(string.continue_button, + continueListener); + builder.show(); + } else { + requestPermission(); + } + gotCameraPermission = false; + return false; + } else { + gotCameraPermission = true; + return true; + } + } + + private void requestPermission() { + ActivityCompat.requestPermissions(this, new String[] {CAMERA}, + REQUEST_PERMISSION_CAMERA); + } + + @Override + @UiThread + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + if (requestCode == REQUEST_PERMISSION_CAMERA) { + // If request is cancelled, the result arrays are empty. + if (grantResults.length > 0 && + grantResults[0] == PERMISSION_GRANTED) { + gotCameraPermission = true; + showNextScreen(); + } else { + if (!ActivityCompat.shouldShowRequestPermissionRationale(this, + CAMERA)) { + // The user has permanently denied the request + OnClickListener cancelListener = + (dialog, which) -> supportFinishAfterTransition(); + Builder builder = new Builder(this, style.BriarDialogTheme); + builder.setTitle(string.permission_camera_title); + builder.setMessage(string.permission_camera_denied_body); + builder.setPositiveButton(string.ok, + UiUtils.getGoToSettingsListener(this)); + builder.setNegativeButton(string.cancel, cancelListener); + builder.show(); + } else { + Toast.makeText(this, string.permission_camera_denied_toast, + LENGTH_LONG).show(); + supportFinishAfterTransition(); + } + } + } + } + + private class BluetoothStateReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + int state = intent.getIntExtra(EXTRA_STATE, 0); + if (state == STATE_ON) setBluetoothState(BluetoothState.ENABLED); + else setBluetoothState(BluetoothState.UNKNOWN); + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/KeyAgreementFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/KeyAgreementFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..1603de2c29f3db4cf13e4203002b73bab860a368 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/KeyAgreementFragment.java @@ -0,0 +1,371 @@ +package org.briarproject.mailbox.android.keyagreement; + +import android.content.Context; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.support.annotation.UiThread; +import android.util.DisplayMetrics; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.LinearLayout.LayoutParams; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.zxing.Result; + +import org.briarproject.bramble.api.UnsupportedVersionException; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.keyagreement.KeyAgreementResult; +import org.briarproject.bramble.api.keyagreement.KeyAgreementTask; +import org.briarproject.bramble.api.keyagreement.Payload; +import org.briarproject.bramble.api.keyagreement.PayloadEncoder; +import org.briarproject.bramble.api.keyagreement.PayloadParser; +import org.briarproject.bramble.api.keyagreement.event.KeyAgreementAbortedEvent; +import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFailedEvent; +import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFinishedEvent; +import org.briarproject.bramble.api.keyagreement.event.KeyAgreementListeningEvent; +import org.briarproject.bramble.api.keyagreement.event.KeyAgreementStartedEvent; +import org.briarproject.bramble.api.keyagreement.event.KeyAgreementWaitingEvent; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.fragment.BaseEventFragment; +import org.briarproject.mailbox.android.view.QrCodeView; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Provider; + +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.widget.LinearLayout.HORIZONTAL; +import static android.widget.Toast.LENGTH_LONG; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class KeyAgreementFragment extends BaseEventFragment + implements QrCodeDecoder.ResultCallback, QrCodeView.FullscreenListener { + + static final String TAG = KeyAgreementFragment.class.getName(); + + private static final Logger LOG = Logger.getLogger(TAG); + private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); + + @Inject + Provider<KeyAgreementTask> keyAgreementTaskProvider; + @Inject + PayloadEncoder payloadEncoder; + @Inject + PayloadParser payloadParser; + @Inject + @IoExecutor + Executor ioExecutor; + @Inject + EventBus eventBus; + + private CameraView cameraView; + private LinearLayout cameraOverlay; + private View statusView; + private QrCodeView qrCodeView; + private TextView status; + + private boolean gotRemotePayload; + private volatile boolean gotLocalPayload; + private KeyAgreementTask task; + private KeyAgreementEventListener listener; + + public static KeyAgreementFragment newInstance() { + Bundle args = new Bundle(); + KeyAgreementFragment fragment = new KeyAgreementFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + listener = (KeyAgreementEventListener) context; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_keyagreement_qr, container, + false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + cameraView = view.findViewById(R.id.camera_view); + cameraOverlay = view.findViewById(R.id.camera_overlay); + statusView = view.findViewById(R.id.status_container); + status = view.findViewById(R.id.connect_status); + qrCodeView = view.findViewById(R.id.qr_code_view); + qrCodeView.setFullscreenListener(this); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + getActivity().setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR); + cameraView.setPreviewConsumer(new QrCodeDecoder(this)); + } + + @Override + public void onStart() { + super.onStart(); + try { + cameraView.start(); + } catch (CameraException e) { + logCameraExceptionAndFinish(e); + } + startListening(); + } + + @Override + public void setFullscreen(boolean fullscreen) { + LayoutParams statusParams, qrCodeParams; + if (fullscreen) { + // Grow the QR code view to fill its parent + statusParams = new LayoutParams(0, 0, 0f); + qrCodeParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT, 1f); + } else { + // Shrink the QR code view to fill half its parent + if (cameraOverlay.getOrientation() == HORIZONTAL) { + statusParams = new LayoutParams(0, MATCH_PARENT, 1f); + qrCodeParams = new LayoutParams(0, MATCH_PARENT, 1f); + } else { + statusParams = new LayoutParams(MATCH_PARENT, 0, 1f); + qrCodeParams = new LayoutParams(MATCH_PARENT, 0, 1f); + } + } + statusView.setLayoutParams(statusParams); + qrCodeView.setLayoutParams(qrCodeParams); + cameraOverlay.invalidate(); + } + + @Override + public void onStop() { + super.onStop(); + stopListening(); + try { + cameraView.stop(); + } catch (CameraException e) { + logCameraExceptionAndFinish(e); + } + } + + @UiThread + private void logCameraExceptionAndFinish(CameraException e) { + logException(LOG, WARNING, e); + Toast.makeText(getActivity(), R.string.camera_error, + LENGTH_LONG).show(); + finish(); + } + + @UiThread + private void startListening() { + KeyAgreementTask oldTask = task; + KeyAgreementTask newTask = keyAgreementTaskProvider.get(); + task = newTask; + ioExecutor.execute(() -> { + if (oldTask != null) oldTask.stopListening(); + newTask.listen(); + }); + } + + @UiThread + private void stopListening() { + KeyAgreementTask oldTask = task; + ioExecutor.execute(() -> { + if (oldTask != null) oldTask.stopListening(); + }); + } + + @UiThread + private void reset() { + // If we've stopped the camera view, restart it + if (gotRemotePayload) { + try { + cameraView.start(); + } catch (CameraException e) { + logCameraExceptionAndFinish(e); + return; + } + } + statusView.setVisibility(INVISIBLE); + cameraView.setVisibility(VISIBLE); + gotRemotePayload = false; + gotLocalPayload = false; + startListening(); + } + + @UiThread + private void qrCodeScanned(String content) { + try { + byte[] payloadBytes = content.getBytes(ISO_8859_1); + if (LOG.isLoggable(INFO)) + LOG.info("Remote payload is " + payloadBytes.length + " bytes"); + Payload remotePayload = payloadParser.parse(payloadBytes); + gotRemotePayload = true; + cameraView.stop(); + cameraView.setVisibility(INVISIBLE); + statusView.setVisibility(VISIBLE); + status.setText(R.string.connecting_to_device); + task.connectAndRunProtocol(remotePayload); + } catch (UnsupportedVersionException e) { + reset(); + String msg = getString(R.string.qr_code_unsupported, + getString(R.string.app_name)); + showNextFragment(ContactExchangeErrorFragment.newInstance(msg)); + } catch (CameraException e) { + logCameraExceptionAndFinish(e); + } catch (IOException | IllegalArgumentException e) { + LOG.log(WARNING, "QR Code Invalid", e); + reset(); + Toast.makeText(getActivity(), R.string.qr_code_invalid, + LENGTH_LONG).show(); + } + } + + @Override + public void eventOccurred(Event e) { + if (e instanceof KeyAgreementListeningEvent) { + KeyAgreementListeningEvent event = (KeyAgreementListeningEvent) e; + gotLocalPayload = true; + setQrCode(event.getLocalPayload()); + } else if (e instanceof KeyAgreementFailedEvent) { + keyAgreementFailed(); + } else if (e instanceof KeyAgreementWaitingEvent) { + keyAgreementWaiting(); + } else if (e instanceof KeyAgreementStartedEvent) { + keyAgreementStarted(); + } else if (e instanceof KeyAgreementAbortedEvent) { + KeyAgreementAbortedEvent event = (KeyAgreementAbortedEvent) e; + keyAgreementAborted(event.didRemoteAbort()); + } else if (e instanceof KeyAgreementFinishedEvent) { + keyAgreementFinished(((KeyAgreementFinishedEvent) e).getResult()); + } + } + + private void keyAgreementFailed() { + runOnUiThreadUnlessDestroyed(() -> { + reset(); + listener.keyAgreementFailed(); + }); + } + + private void keyAgreementWaiting() { + runOnUiThreadUnlessDestroyed( + () -> status.setText(listener.keyAgreementWaiting())); + } + + private void keyAgreementStarted() { + runOnUiThreadUnlessDestroyed(() -> { + qrCodeView.setVisibility(INVISIBLE); + statusView.setVisibility(VISIBLE); + status.setText(listener.keyAgreementStarted()); + }); + } + + private void keyAgreementAborted(boolean remoteAborted) { + runOnUiThreadUnlessDestroyed(() -> { + reset(); + listener.keyAgreementAborted(remoteAborted); + }); + } + + private void keyAgreementFinished(KeyAgreementResult result) { + runOnUiThreadUnlessDestroyed(() -> { + statusView.setVisibility(VISIBLE); + status.setText(listener.keyAgreementFinished(result)); + }); + } + + private void setQrCode(Payload localPayload) { + Context context = getContext(); + if (context == null) return; + DisplayMetrics dm = context.getResources().getDisplayMetrics(); + ioExecutor.execute(() -> { + byte[] payloadBytes = payloadEncoder.encode(localPayload); + if (LOG.isLoggable(INFO)) { + LOG.info("Local payload is " + payloadBytes.length + + " bytes"); + } + // Use ISO 8859-1 to encode bytes directly as a string + String content = new String(payloadBytes, ISO_8859_1); + Bitmap qrCode = QrCodeUtils.createQrCode(dm, content); + runOnUiThreadUnlessDestroyed(() -> qrCodeView.setQrCode(qrCode)); + }); + } + + @Override + public void handleResult(Result result) { + runOnUiThreadUnlessDestroyed(() -> { + LOG.info("Got result from decoder"); + // Ignore results until the KeyAgreementTask is ready + if (!gotLocalPayload) return; + if (!gotRemotePayload) qrCodeScanned(result.getText()); + }); + } + + @Override + protected void finish() { + getActivity().getSupportFragmentManager().popBackStack(); + } + + @NotNullByDefault + interface KeyAgreementEventListener { + + @UiThread + void keyAgreementFailed(); + + // Should return a string to be displayed as status. + @UiThread + @Nullable + String keyAgreementWaiting(); + + // Should return a string to be displayed as status. + @UiThread + @Nullable + String keyAgreementStarted(); + + // Will show an error fragment. + @UiThread + void keyAgreementAborted(boolean remoteAborted); + + // Should return a string to be displayed as status. + @UiThread + @Nullable + String keyAgreementFinished(KeyAgreementResult result); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/MailboxExchangeActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/MailboxExchangeActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..9caeefa298d6f503f2fbf160add512bd1a0c91f7 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/MailboxExchangeActivity.java @@ -0,0 +1,132 @@ +package org.briarproject.mailbox.android.keyagreement; + +import android.os.Bundle; +import android.support.annotation.UiThread; +import android.widget.Toast; + +import org.briarproject.bramble.api.contact.ContactExchangeListener; +import org.briarproject.bramble.api.contact.ContactExchangeTask; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; +import org.briarproject.bramble.api.keyagreement.KeyAgreementResult; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static android.widget.Toast.LENGTH_LONG; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.api.contact.ContactType.MAILBOX_OWNER; +import static org.briarproject.bramble.api.contact.ContactType.PRIVATE_MAILBOX; +import static org.briarproject.bramble.util.LogUtils.logException; + +public class MailboxExchangeActivity extends KeyAgreementActivity implements + ContactExchangeListener { + + private static final Logger LOG = + Logger.getLogger(MailboxExchangeActivity.class.getName()); + + // Fields that are accessed from background threads must be volatile + @Inject + volatile ContactExchangeTask contactExchangeTask; + @Inject + volatile IdentityManager identityManager; + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + @Override + public void onCreate(@Nullable Bundle state) { + super.onCreate(state); + getSupportActionBar().setTitle(R.string.add_contact_title); + } + + protected void startContactExchange(KeyAgreementResult result) { + runOnDbThread(() -> { + LocalAuthor localAuthor; + // Load the local pseudonym + try { + localAuthor = identityManager.getLocalAuthor(); + } catch (DbException e) { + logException(LOG, WARNING, e); + contactExchangeFailed(); + return; + } + + // Exchange contact details + contactExchangeTask.startExchange(MailboxExchangeActivity.this, + localAuthor, result.getMasterKey(), + result.getConnection(), result.getTransportId(), + result.wasAlice(), PRIVATE_MAILBOX, MAILBOX_OWNER); + }); + } + + @Override + public void contactExchangeSucceeded(Author remoteAuthor) { + runOnUiThreadUnlessDestroyed(() -> { + String contactName = remoteAuthor.getName(); + String format = getString(R.string.contact_added_toast); + String text = String.format(format, contactName); + Toast.makeText(MailboxExchangeActivity.this, text, LENGTH_LONG) + .show(); + supportFinishAfterTransition(); + }); + } + + @Override + public void duplicateContact(Author remoteAuthor) { + runOnUiThreadUnlessDestroyed(() -> { + String contactName = remoteAuthor.getName(); + String format = getString(R.string.contact_already_exists); + String text = String.format(format, contactName); + Toast.makeText(MailboxExchangeActivity.this, text, LENGTH_LONG) + .show(); + finish(); + }); + } + + @Override + public void contactExchangeFailed() { + runOnUiThreadUnlessDestroyed(() -> { + showErrorFragment(R.string.connection_error_explanation); + }); + } + + @UiThread + @Override + public void keyAgreementFailed() { + showErrorFragment(R.string.connection_error_explanation); + } + + @UiThread + @Override + public String keyAgreementWaiting() { + return getString(R.string.waiting_for_contact_to_scan); + } + + @UiThread + @Override + public String keyAgreementStarted() { + return getString(R.string.authenticating_with_device); + } + + @UiThread + @Override + public void keyAgreementAborted(boolean remoteAborted) { + showErrorFragment(R.string.connection_error_explanation); + } + + @UiThread + @Override + public String keyAgreementFinished(KeyAgreementResult result) { + startContactExchange(result); + return getString(R.string.exchanging_contact_details); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/PreviewConsumer.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/PreviewConsumer.java new file mode 100644 index 0000000000000000000000000000000000000000..ebdd2a2cfb2a465a40924000f006c2358c06e945 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/PreviewConsumer.java @@ -0,0 +1,17 @@ +package org.briarproject.mailbox.android.keyagreement; + +import android.hardware.Camera; +import android.support.annotation.UiThread; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@SuppressWarnings("deprecation") +@NotNullByDefault +interface PreviewConsumer { + + @UiThread + void start(Camera camera, int cameraIndex); + + @UiThread + void stop(); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/QrCodeDecoder.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/QrCodeDecoder.java new file mode 100644 index 0000000000000000000000000000000000000000..aea3ba143c66500a53782ce06a3f94018668666f --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/QrCodeDecoder.java @@ -0,0 +1,148 @@ +package org.briarproject.mailbox.android.keyagreement; + +import android.hardware.Camera; +import android.hardware.Camera.CameraInfo; +import android.hardware.Camera.PreviewCallback; +import android.hardware.Camera.Size; +import android.os.AsyncTask; +import android.support.annotation.UiThread; + +import com.google.zxing.BinaryBitmap; +import com.google.zxing.LuminanceSource; +import com.google.zxing.PlanarYUVLuminanceSource; +import com.google.zxing.Reader; +import com.google.zxing.ReaderException; +import com.google.zxing.Result; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.qrcode.QRCodeReader; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; + +import java.util.logging.Logger; + +import static com.google.zxing.DecodeHintType.CHARACTER_SET; +import static java.util.Collections.singletonMap; +import static java.util.logging.Level.WARNING; + +@SuppressWarnings("deprecation") +@MethodsNotNullByDefault +@ParametersNotNullByDefault +class QrCodeDecoder implements PreviewConsumer, PreviewCallback { + + private static final Logger LOG = + Logger.getLogger(QrCodeDecoder.class.getName()); + + private final Reader reader = new QRCodeReader(); + private final ResultCallback callback; + + private Camera camera = null; + private int cameraIndex = 0; + + QrCodeDecoder(ResultCallback callback) { + this.callback = callback; + } + + @Override + public void start(Camera camera, int cameraIndex) { + this.camera = camera; + this.cameraIndex = cameraIndex; + askForPreviewFrame(); + } + + @Override + public void stop() { + camera = null; + cameraIndex = 0; + } + + @UiThread + private void askForPreviewFrame() { + if (camera != null) camera.setOneShotPreviewCallback(this); + } + + @UiThread + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + if (camera == this.camera) { + try { + Size size = camera.getParameters().getPreviewSize(); + // The preview should be in NV21 format: width * height bytes of + // Y followed by width * height / 2 bytes of interleaved U and V + if (data.length == size.width * size.height * 3 / 2) { + CameraInfo info = new CameraInfo(); + Camera.getCameraInfo(cameraIndex, info); + new DecoderTask(data, size.width, size.height, + info.orientation).execute(); + } else { + // Camera parameters have changed - ask for a new preview + LOG.info("Preview size does not match camera parameters"); + askForPreviewFrame(); + } + } catch (RuntimeException e) { + LOG.log(WARNING, "Error getting camera parameters.", e); + } + } else { + LOG.info("Camera has changed, ignoring preview frame"); + } + } + + private class DecoderTask extends AsyncTask<Void, Void, Void> { + + private final byte[] data; + private final int width, height, orientation; + + private DecoderTask(byte[] data, int width, int height, + int orientation) { + this.data = data; + this.width = width; + this.height = height; + this.orientation = orientation; + } + + @Override + protected Void doInBackground(Void... params) { + BinaryBitmap bitmap = binarize(data, width, height, orientation); + Result result; + try { + result = reader.decode(bitmap, + singletonMap(CHARACTER_SET, "ISO8859_1")); + } catch (ReaderException e) { + // No barcode found + return null; + } catch (RuntimeException e) { + LOG.warning("Invalid preview frame"); + return null; + } finally { + reader.reset(); + } + callback.handleResult(result); + return null; + } + + @Override + protected void onPostExecute(Void result) { + askForPreviewFrame(); + } + } + + private static BinaryBitmap binarize(byte[] data, int width, int height, + int orientation) { + // Crop to a square at the top (portrait) or left (landscape) of the + // screen - this will be faster to decode and should include + // everything visible in the viewfinder + int crop = Math.min(width, height); + int left = orientation >= 180 ? width - crop : 0; + int top = orientation >= 180 ? height - crop : 0; + LuminanceSource src = new PlanarYUVLuminanceSource(data, width, + height, left, top, crop, crop, false); + return new BinaryBitmap(new HybridBinarizer(src)); + } + + @NotNullByDefault + interface ResultCallback { + + void handleResult(Result result); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/QrCodeUtils.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/QrCodeUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..0ec03fab4bbd6290a998a3f6f6706beb1ea90323 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/keyagreement/QrCodeUtils.java @@ -0,0 +1,56 @@ +package org.briarproject.mailbox.android.keyagreement; + +import android.graphics.Bitmap; +import android.util.DisplayMetrics; + +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; + +import static android.graphics.Bitmap.Config.ARGB_8888; +import static android.graphics.Color.BLACK; +import static android.graphics.Color.WHITE; +import static com.google.zxing.BarcodeFormat.QR_CODE; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; + +@NotNullByDefault +class QrCodeUtils { + + private static final Logger LOG = + Logger.getLogger(QrCodeUtils.class.getName()); + + @Nullable + static Bitmap createQrCode(DisplayMetrics dm, String input) { + int smallestDimen = Math.min(dm.widthPixels, dm.heightPixels); + try { + // Generate QR code + BitMatrix encoded = new QRCodeWriter().encode(input, QR_CODE, + smallestDimen, smallestDimen); + return renderQrCode(encoded); + } catch (WriterException e) { + logException(LOG, WARNING, e); + return null; + } + } + + private static Bitmap renderQrCode(BitMatrix matrix) { + int width = matrix.getWidth(); + int height = matrix.getHeight(); + int[] pixels = new int[width * height]; + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + pixels[y * width + x] = matrix.get(x, y) ? BLACK : WHITE; + } + } + Bitmap qr = Bitmap.createBitmap(width, height, ARGB_8888); + qr.setPixels(pixels, 0, width, 0, 0, width, height); + return qr; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/logging/BriefLogFormatter.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/logging/BriefLogFormatter.java new file mode 100644 index 0000000000000000000000000000000000000000..15cca9873716c5a857dc055765d13df3d0087381 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/logging/BriefLogFormatter.java @@ -0,0 +1,63 @@ +package org.briarproject.mailbox.android.logging; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; +import java.util.logging.Formatter; +import java.util.logging.LogRecord; + +import javax.annotation.concurrent.ThreadSafe; + +import static java.util.Locale.US; + +@ThreadSafe +@NotNullByDefault +public class BriefLogFormatter extends Formatter { + + private final Object lock = new Object(); + private final DateFormat dateFormat; // Locking: lock + private final Date date; // Locking: lock + + public BriefLogFormatter() { + synchronized (lock) { + dateFormat = new SimpleDateFormat("MM-dd HH:mm:ss.SSS ", US); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + date = new Date(); + } + } + + @Override + public String format(LogRecord record) { + String dateString; + synchronized (lock) { + date.setTime(record.getMillis()); + dateString = dateFormat.format(date); + } + StringBuilder sb = new StringBuilder(dateString); + sb.append(record.getLevel().getName().charAt(0)).append('/'); + String tag = record.getLoggerName(); + tag = tag.substring(tag.lastIndexOf('.') + 1); + sb.append(tag).append(": "); + sb.append(record.getMessage()); + Throwable t = record.getThrown(); + if (t != null) { + sb.append('\n'); + appendThrowable(sb, t); + } + return sb.toString(); + } + + private void appendThrowable(StringBuilder sb, Throwable t) { + sb.append(t); + for (StackTraceElement e : t.getStackTrace()) + sb.append("\n at ").append(e); + Throwable cause = t.getCause(); + if (cause != null) { + sb.append("\n Caused by: "); + appendThrowable(sb, cause); + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/logging/CachingLogHandler.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/logging/CachingLogHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..46f968740d79129797906f232071d9580d40957c --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/logging/CachingLogHandler.java @@ -0,0 +1,48 @@ +package org.briarproject.mailbox.android.logging; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.Queue; +import java.util.logging.Handler; +import java.util.logging.LogRecord; + +import javax.annotation.concurrent.ThreadSafe; + +@ThreadSafe +@NotNullByDefault +public class CachingLogHandler extends Handler { + + private static final int MAX_RECENT_RECORDS = 100; + + private final Object lock = new Object(); + // Locking: lock + private final Queue<LogRecord> recent = new LinkedList<>(); + + @Override + public void publish(LogRecord record) { + synchronized (lock) { + recent.add(record); + if (recent.size() > MAX_RECENT_RECORDS) recent.poll(); + } + } + + @Override + public void flush() { + } + + @Override + public void close() { + synchronized (lock) { + recent.clear(); + } + } + + public Collection<LogRecord> getRecentLogRecords() { + synchronized (lock) { + return new ArrayList<>(recent); + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/AuthorNameFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/AuthorNameFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..b5f09e9adda7479bdd317390575f642001baf99b --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/AuthorNameFragment.java @@ -0,0 +1,88 @@ +package org.briarproject.mailbox.android.login; + +import android.os.Bundle; +import android.support.design.widget.TextInputEditText; +import android.support.design.widget.TextInputLayout; +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.bramble.util.StringUtils; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; + +import javax.annotation.Nullable; + +import static android.view.inputmethod.EditorInfo.IME_ACTION_NEXT; +import static android.view.inputmethod.EditorInfo.IME_ACTION_NONE; +import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; +import static org.briarproject.mailbox.android.util.UiUtils.setError; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class AuthorNameFragment extends SetupFragment { + + private final static String TAG = AuthorNameFragment.class.getName(); + + private TextInputLayout authorNameWrapper; + private TextInputEditText authorNameInput; + private Button nextButton; + + public static AuthorNameFragment newInstance() { + return new AuthorNameFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + getActivity().setTitle(getString(R.string.setup_title)); + View v = inflater.inflate(R.layout.fragment_setup_author_name, + container, false); + authorNameWrapper = v.findViewById(R.id.nickname_entry_wrapper); + authorNameInput = v.findViewById(R.id.nickname_entry); + nextButton = v.findViewById(R.id.next); + + authorNameInput.addTextChangedListener(this); + nextButton.setOnClickListener(this); + + return v; + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + } + + @Override + protected String getHelpText() { + return getString(R.string.setup_name_explanation); + } + + @Override + public void onTextChanged(CharSequence authorName, int i, int i1, int i2) { + int authorNameLength = StringUtils.toUtf8(authorName.toString()).length; + boolean error = authorNameLength > MAX_AUTHOR_NAME_LENGTH; + setError(authorNameWrapper, getString(R.string.name_too_long), error); + boolean enabled = authorNameLength > 0 && !error; + authorNameInput + .setImeOptions(enabled ? IME_ACTION_NEXT : IME_ACTION_NONE); + authorNameInput.setOnEditorActionListener(enabled ? this : null); + nextButton.setEnabled(enabled); + } + + @Override + public void onClick(View view) { + setupController.setAuthorName(authorNameInput.getText().toString()); + setupController.showPasswordFragment(); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/ChangePasswordActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/ChangePasswordActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..5dd01c0f0203ef242a94350a287fd6b338b539e1 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/ChangePasswordActivity.java @@ -0,0 +1,154 @@ +package org.briarproject.mailbox.android.login; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.TextInputLayout; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; +import android.widget.Toast; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BriarActivity; +import org.briarproject.mailbox.android.controller.handler.UiResultHandler; +import org.briarproject.mailbox.android.util.UiUtils; + +import javax.inject.Inject; + +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK; + +public class ChangePasswordActivity extends BriarActivity + implements OnClickListener, OnEditorActionListener { + + @Inject + protected PasswordController passwordController; + + private TextInputLayout currentPasswordEntryWrapper; + private TextInputLayout newPasswordEntryWrapper; + private TextInputLayout newPasswordConfirmationWrapper; + private EditText currentPassword; + private EditText newPassword; + private EditText newPasswordConfirmation; + private StrengthMeter strengthMeter; + private Button changePasswordButton; + private ProgressBar progress; + + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + setContentView(R.layout.activity_change_password); + + currentPasswordEntryWrapper = + findViewById(R.id.current_password_entry_wrapper); + newPasswordEntryWrapper = findViewById(R.id.new_password_entry_wrapper); + newPasswordConfirmationWrapper = + findViewById(R.id.new_password_confirm_wrapper); + currentPassword = findViewById(R.id.current_password_entry); + newPassword = findViewById(R.id.new_password_entry); + newPasswordConfirmation = findViewById(R.id.new_password_confirm); + strengthMeter = findViewById(R.id.strength_meter); + changePasswordButton = findViewById(R.id.change_password); + progress = findViewById(R.id.progress_wheel); + + TextWatcher tw = new TextWatcher() { + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + enableOrDisableContinueButton(); + } + + @Override + public void afterTextChanged(Editable s) { + } + }; + + currentPassword.addTextChangedListener(tw); + newPassword.addTextChangedListener(tw); + newPasswordConfirmation.addTextChangedListener(tw); + newPasswordConfirmation.setOnEditorActionListener(this); + changePasswordButton.setOnClickListener(this); + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + private void enableOrDisableContinueButton() { + if (progress == null) return; // Not created yet + if (newPassword.getText().length() > 0 && newPassword.hasFocus()) + strengthMeter.setVisibility(VISIBLE); + else strengthMeter.setVisibility(INVISIBLE); + String firstPassword = newPassword.getText().toString(); + String secondPassword = newPasswordConfirmation.getText().toString(); + boolean passwordsMatch = firstPassword.equals(secondPassword); + float strength = + passwordController.estimatePasswordStrength(firstPassword); + strengthMeter.setStrength(strength); + UiUtils.setError(newPasswordEntryWrapper, + getString(R.string.password_too_weak), + firstPassword.length() > 0 && strength < QUITE_WEAK); + UiUtils.setError(newPasswordConfirmationWrapper, + getString(R.string.passwords_do_not_match), + secondPassword.length() > 0 && !passwordsMatch); + changePasswordButton.setEnabled( + !currentPassword.getText().toString().isEmpty() && + passwordsMatch && strength >= QUITE_WEAK); + } + + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + hideSoftKeyboard(v); + return true; + } + + @Override + public void onClick(View view) { + // Replace the button with a progress bar + changePasswordButton.setVisibility(INVISIBLE); + progress.setVisibility(VISIBLE); + passwordController.changePassword(currentPassword.getText().toString(), + newPassword.getText().toString(), + new UiResultHandler<Boolean>(this) { + @Override + public void onResultUi(@NonNull Boolean result) { + if (result) { + Toast.makeText(ChangePasswordActivity.this, + R.string.password_changed, + Toast.LENGTH_LONG).show(); + setResult(RESULT_OK); + supportFinishAfterTransition(); + } else { + tryAgain(); + } + } + }); + } + + private void tryAgain() { + UiUtils.setError(currentPasswordEntryWrapper, + getString(R.string.try_again), true); + changePasswordButton.setVisibility(VISIBLE); + progress.setVisibility(INVISIBLE); + currentPassword.setText(""); + + // show the keyboard again + showSoftKeyboard(currentPassword); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/DozeFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/DozeFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..4991af61b7b5c27e2d0f00c0633cc0e023a462d7 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/DozeFragment.java @@ -0,0 +1,114 @@ +package org.briarproject.mailbox.android.login; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ProgressBar; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.login.PowerView.OnCheckedChangedListener; +import org.briarproject.mailbox.android.util.UiUtils; + +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static org.briarproject.mailbox.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING; +import static org.briarproject.mailbox.android.util.UiUtils.showOnboardingDialog; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class DozeFragment extends SetupFragment + implements OnCheckedChangedListener { + + private final static String TAG = DozeFragment.class.getName(); + + private DozeView dozeView; + private HuaweiView huaweiView; + private Button next; + private ProgressBar progressBar; + private boolean secondAttempt = false; + + public static DozeFragment newInstance() { + return new DozeFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + getActivity().setTitle(getString(R.string.setup_doze_title)); + setHasOptionsMenu(false); + View v = inflater.inflate(R.layout.fragment_setup_doze, container, + false); + dozeView = v.findViewById(R.id.dozeView); + dozeView.setOnCheckedChangedListener(this); + huaweiView = v.findViewById(R.id.huaweiView); + huaweiView.setOnCheckedChangedListener(this); + next = v.findViewById(R.id.next); + progressBar = v.findViewById(R.id.progress); + + dozeView.setOnButtonClickListener(this::askForDozeWhitelisting); + next.setOnClickListener(this); + + return v; + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + } + + @Override + protected String getHelpText() { + return getString(R.string.setup_doze_explanation); + } + + @Override + public void onActivityResult(int request, int result, Intent data) { + super.onActivityResult(request, result, data); + if (request == REQUEST_DOZE_WHITELISTING) { + if (!dozeView.needsToBeShown() || secondAttempt) { + dozeView.setChecked(true); + } else if (getContext() != null) { + secondAttempt = true; + showOnboardingDialog(getContext(), getHelpText()); + } + } + } + + @Override + public void onCheckedChanged() { + if (dozeView.isChecked() && huaweiView.isChecked()) { + next.setEnabled(true); + } else { + next.setEnabled(false); + } + } + + @SuppressLint("BatteryLife") + private void askForDozeWhitelisting() { + if (getContext() == null) return; + Intent i = UiUtils.getDozeWhitelistingIntent(getContext()); + startActivityForResult(i, REQUEST_DOZE_WHITELISTING); + } + + @Override + public void onClick(View view) { + next.setVisibility(INVISIBLE); + progressBar.setVisibility(VISIBLE); + setupController.createAccount(); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/DozeView.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/DozeView.java new file mode 100644 index 0000000000000000000000000000000000000000..41c8de5ed300bfa3e8369b556806d52058e3073a --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/DozeView.java @@ -0,0 +1,60 @@ +package org.briarproject.mailbox.android.login; + + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.annotation.UiThread; +import android.util.AttributeSet; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.mailbox.R; + +import static org.briarproject.mailbox.android.util.UiUtils.needsDozeWhitelisting; + +@UiThread +@NotNullByDefault +class DozeView extends PowerView { + + @Nullable + private Runnable onButtonClickListener; + + public DozeView(Context context) { + this(context, null); + } + + public DozeView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public DozeView(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + setText(R.string.setup_doze_intro); + setButtonText(R.string.setup_doze_button); + } + + @Override + public boolean needsToBeShown() { + return needsToBeShown(getContext()); + } + + public static boolean needsToBeShown(Context context) { + return needsDozeWhitelisting(context); + } + + @Override + protected int getHelpText() { + return R.string.setup_doze_explanation; + } + + @Override + protected void onButtonClick() { + if (onButtonClickListener == null) throw new IllegalStateException(); + onButtonClickListener.run(); + } + + public void setOnButtonClickListener(Runnable runnable) { + onButtonClickListener = runnable; + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/HuaweiView.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/HuaweiView.java new file mode 100644 index 0000000000000000000000000000000000000000..016ce5affac59edcfd76fb7d93e607afa1878606 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/HuaweiView.java @@ -0,0 +1,76 @@ +package org.briarproject.mailbox.android.login; + + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.support.annotation.StringRes; +import android.support.annotation.UiThread; +import android.util.AttributeSet; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.mailbox.R; + +import java.util.List; + +import javax.annotation.Nullable; + +import static android.os.Build.VERSION.SDK_INT; + +@UiThread +@NotNullByDefault +class HuaweiView extends PowerView { + + private final static String PACKAGE_NAME = "com.huawei.systemmanager"; + private final static String CLASS_NAME = + PACKAGE_NAME + ".optimize.process.ProtectActivity"; + + public HuaweiView(Context context) { + this(context, null); + } + + public HuaweiView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public HuaweiView(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + setText(R.string.setup_huawei_text); + setButtonText(R.string.setup_huawei_button); + } + + @Override + public boolean needsToBeShown() { + return needsToBeShown(getContext()); + } + + public static boolean needsToBeShown(Context context) { + // "Protected apps" no longer exists on Huawei EMUI 5.0 (Android 7.0) + if (SDK_INT >= 24) return false; + PackageManager pm = context.getPackageManager(); + List<ResolveInfo> resolveInfos = pm.queryIntentActivities(getIntent(), + PackageManager.MATCH_DEFAULT_ONLY); + return !resolveInfos.isEmpty(); + } + + @Override + @StringRes + protected int getHelpText() { + return R.string.setup_huawei_help; + } + + @Override + protected void onButtonClick() { + getContext().startActivity(getIntent()); + setChecked(true); + } + + private static Intent getIntent() { + Intent intent = new Intent(); + intent.setClassName(PACKAGE_NAME, CLASS_NAME); + return intent; + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/OpenDatabaseActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/OpenDatabaseActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..7910a31eaf055d36c29de51002b51b139eefbcd8 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/OpenDatabaseActivity.java @@ -0,0 +1,93 @@ +package org.briarproject.mailbox.android.login; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.widget.ImageView; +import android.widget.TextView; + +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.event.EventListener; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState; +import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BriarActivity; +import org.briarproject.mailbox.android.navdrawer.NavDrawerActivity; + +import javax.annotation.ParametersAreNonnullByDefault; +import javax.inject.Inject; + +import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE; +import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES; + +@ParametersAreNonnullByDefault +public class OpenDatabaseActivity extends BriarActivity + implements EventListener { + + @Inject + LifecycleManager lifecycleManager; + @Inject + EventBus eventBus; + + private TextView textView; + private ImageView imageView; + private boolean showingMigration = false; + + @Override + public void onCreate(@Nullable Bundle state) { + super.onCreate(state); + setContentView(R.layout.activity_open_database); + textView = findViewById(R.id.textView); + imageView = findViewById(R.id.imageView); + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + @Override + public void onStart() { + super.onStart(); + LifecycleState state = lifecycleManager.getLifecycleState(); + if (state.isAfter(STARTING_SERVICES)) { + finishAndStartApp(); + } else { + if (state == MIGRATING_DATABASE) showMigration(); + eventBus.addListener(this); + } + } + + @Override + protected void onStop() { + super.onStop(); + eventBus.removeListener(this); + } + + @Override + public void eventOccurred(Event e) { + if (e instanceof LifecycleEvent) { + LifecycleState state = ((LifecycleEvent) e).getLifecycleState(); + if (state.isAfter(STARTING_SERVICES)) + runOnUiThreadUnlessDestroyed(this::finishAndStartApp); + else if (state == MIGRATING_DATABASE) + runOnUiThreadUnlessDestroyed(this::showMigration); + } + } + + private void showMigration() { + if (showingMigration) return; + textView.setText(R.string.startup_migrate_database); + imageView.setImageResource(R.drawable.startup_migration); + showingMigration = true; + } + + private void finishAndStartApp() { + startActivity(new Intent(this, NavDrawerActivity.class)); + supportFinishAfterTransition(); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..0cbba3a3b29476bb24b4f8f3fa1601a2dadfc58b --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordActivity.java @@ -0,0 +1,171 @@ +package org.briarproject.mailbox.android.login; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.TextInputLayout; +import android.support.v7.app.AlertDialog; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BaseActivity; +import org.briarproject.mailbox.android.controller.BriarController; +import org.briarproject.mailbox.android.controller.handler.UiResultHandler; +import org.briarproject.mailbox.android.util.UiUtils; +import org.briarproject.mailbox.api.android.AndroidNotificationManager; + +import javax.inject.Inject; + +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; + +public class PasswordActivity extends BaseActivity { + + @Inject + AccountManager accountManager; + + @Inject + AndroidNotificationManager notificationManager; + + @Inject + PasswordController passwordController; + + @Inject + BriarController briarController; + + private Button signInButton; + private ProgressBar progress; + private TextInputLayout input; + private EditText password; + + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + // fade-in after splash screen instead of default animation + overridePendingTransition(R.anim.fade_in, R.anim.fade_out); + + if (!accountManager.accountExists()) { + // TODO: Finish instead of deleting account? + deleteAccount(); + return; + } + + setContentView(R.layout.activity_password); + signInButton = findViewById(R.id.btn_sign_in); + progress = findViewById(R.id.progress_wheel); + input = findViewById(R.id.password_layout); + password = findViewById(R.id.edit_password); + password.setOnEditorActionListener((v, actionId, event) -> { + validatePassword(); + return true; + }); + password.addTextChangedListener(new TextWatcher() { + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + if (count > 0) UiUtils.setError(input, null, false); + } + + @Override + public void afterTextChanged(Editable s) { + } + }); + } + + @Override + public void onStart() { + super.onStart(); + // If the user has already signed in, clean up this instance + if (briarController.accountSignedIn()) { + setResult(RESULT_OK); + finish(); + } else { + notificationManager.blockSignInNotification(); + notificationManager.clearSignInNotification(); + } + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + @Override + public void onBackPressed() { + // Move task and activity to the background instead of showing another + // password prompt. onActivityResult() won't be called in BriarActivity + moveTaskToBack(true); + } + + private void deleteAccount() { + accountManager.deleteAccount(); + setResult(RESULT_CANCELED); + Intent i = new Intent(this, SetupActivity.class); + i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); + startActivity(i); + } + + public void onSignInClick(View v) { + validatePassword(); + } + + public void onForgottenPasswordClick(View v) { + // TODO Encapsulate the dialog in a re-usable fragment + AlertDialog.Builder builder = new AlertDialog.Builder(this, + R.style.BriarDialogTheme); + builder.setTitle(R.string.dialog_title_lost_password); + builder.setMessage(R.string.dialog_message_lost_password); + builder.setPositiveButton(R.string.cancel, null); + builder.setNegativeButton(R.string.delete, + (dialog, which) -> deleteAccount()); + AlertDialog dialog = builder.create(); + dialog.show(); + } + + private void validatePassword() { + hideSoftKeyboard(password); + signInButton.setVisibility(INVISIBLE); + progress.setVisibility(VISIBLE); + passwordController.validatePassword(password.getText().toString(), + new UiResultHandler<Boolean>(this) { + @Override + public void onResultUi(@NonNull Boolean result) { + if (result) { + setResult(RESULT_OK); + supportFinishAfterTransition(); + // don't show closing animation, + // but one for opening NavDrawerActivity + overridePendingTransition(R.anim.screen_new_in, + R.anim.screen_old_out); + } else { + tryAgain(); + } + } + }); + } + + private void tryAgain() { + UiUtils.setError(input, getString(R.string.try_again), true); + signInButton.setVisibility(VISIBLE); + progress.setVisibility(INVISIBLE); + password.setText(""); + + // show the keyboard again + showSoftKeyboard(password); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordController.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordController.java new file mode 100644 index 0000000000000000000000000000000000000000..1264522d1f5533f0f8485655e232f849faf65fa6 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordController.java @@ -0,0 +1,17 @@ +package org.briarproject.mailbox.android.login; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.mailbox.android.controller.handler.ResultHandler; + +@NotNullByDefault +public interface PasswordController { + + float estimatePasswordStrength(String password); + + void validatePassword(String password, + ResultHandler<Boolean> resultHandler); + + void changePassword(String oldPassword, String newPassword, + ResultHandler<Boolean> resultHandler); + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordControllerImpl.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordControllerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..c0f42c0d7beeb0a33009eec77669044c165286cd --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordControllerImpl.java @@ -0,0 +1,50 @@ +package org.briarproject.mailbox.android.login; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.mailbox.android.controller.handler.ResultHandler; + +import java.util.concurrent.Executor; + +import javax.inject.Inject; + +@NotNullByDefault +public class PasswordControllerImpl implements PasswordController { + + protected final AccountManager accountManager; + protected final Executor ioExecutor; + private final PasswordStrengthEstimator strengthEstimator; + + @Inject + PasswordControllerImpl(AccountManager accountManager, + @IoExecutor Executor ioExecutor, + PasswordStrengthEstimator strengthEstimator) { + this.accountManager = accountManager; + this.ioExecutor = ioExecutor; + this.strengthEstimator = strengthEstimator; + } + + @Override + public float estimatePasswordStrength(String password) { + return strengthEstimator.estimateStrength(password); + } + + @Override + public void validatePassword(String password, + ResultHandler<Boolean> resultHandler) { + ioExecutor.execute(() -> + resultHandler.onResult(accountManager.signIn(password))); + } + + @Override + public void changePassword(String oldPassword, String newPassword, + ResultHandler<Boolean> resultHandler) { + ioExecutor.execute(() -> { + boolean changed = + accountManager.changePassword(oldPassword, newPassword); + resultHandler.onResult(changed); + }); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..fea2ecc23e73627f70b90d163f1fa07b4129bab9 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PasswordFragment.java @@ -0,0 +1,128 @@ +package org.briarproject.mailbox.android.login; + +import android.os.Bundle; +import android.os.IBinder; +import android.support.design.widget.TextInputEditText; +import android.support.design.widget.TextInputLayout; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.ProgressBar; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.util.UiUtils; + +import javax.annotation.Nullable; + +import static android.content.Context.INPUT_METHOD_SERVICE; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class PasswordFragment extends SetupFragment { + + private final static String TAG = PasswordFragment.class.getName(); + + private TextInputLayout passwordEntryWrapper; + private TextInputLayout passwordConfirmationWrapper; + private TextInputEditText passwordEntry; + private TextInputEditText passwordConfirmation; + private StrengthMeter strengthMeter; + private Button nextButton; + private ProgressBar progressBar; + + public static PasswordFragment newInstance() { + return new PasswordFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + getActivity().setTitle(getString(R.string.setup_password_intro)); + View v = inflater.inflate(R.layout.fragment_setup_password, container, + false); + + strengthMeter = v.findViewById(R.id.strength_meter); + passwordEntryWrapper = v.findViewById(R.id.password_entry_wrapper); + passwordEntry = v.findViewById(R.id.password_entry); + passwordConfirmationWrapper = + v.findViewById(R.id.password_confirm_wrapper); + passwordConfirmation = v.findViewById(R.id.password_confirm); + nextButton = v.findViewById(R.id.next); + progressBar = v.findViewById(R.id.progress); + + passwordEntry.addTextChangedListener(this); + passwordConfirmation.addTextChangedListener(this); + nextButton.setOnClickListener(this); + + return v; + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + + // the controller is not yet available in onCreateView() + if (!setupController.needToShowDozeFragment()) { + nextButton.setText(R.string.create_account_button); + } + } + + @Override + protected String getHelpText() { + return getString(R.string.setup_password_explanation); + } + + @Override + public void onTextChanged(CharSequence authorName, int i, int i1, int i2) { + String password1 = passwordEntry.getText().toString(); + String password2 = passwordConfirmation.getText().toString(); + boolean passwordsMatch = password1.equals(password2); + + strengthMeter + .setVisibility(password1.length() > 0 ? VISIBLE : INVISIBLE); + float strength = setupController.estimatePasswordStrength(password1); + strengthMeter.setStrength(strength); + boolean strongEnough = strength >= QUITE_WEAK; + + UiUtils.setError(passwordEntryWrapper, + getString(R.string.password_too_weak), + password1.length() > 0 && !strongEnough); + UiUtils.setError(passwordConfirmationWrapper, + getString(R.string.passwords_do_not_match), + password2.length() > 0 && !passwordsMatch); + + boolean enabled = passwordsMatch && strongEnough; + nextButton.setEnabled(enabled); + passwordConfirmation.setOnEditorActionListener(enabled ? this : null); + } + + @Override + public void onClick(View view) { + IBinder token = passwordEntry.getWindowToken(); + Object o = getContext().getSystemService(INPUT_METHOD_SERVICE); + ((InputMethodManager) o).hideSoftInputFromWindow(token, 0); + setupController.setPassword(passwordEntry.getText().toString()); + if (setupController.needToShowDozeFragment()) { + setupController.showDozeFragment(); + } else { + nextButton.setVisibility(INVISIBLE); + progressBar.setVisibility(VISIBLE); + setupController.createAccount(); + } + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PowerView.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PowerView.java new file mode 100644 index 0000000000000000000000000000000000000000..e38cbfd77e6702aa346e8fdbb6fbaf27352cbca4 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/PowerView.java @@ -0,0 +1,162 @@ +package org.briarproject.mailbox.android.login; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.Nullable; +import android.support.annotation.StringRes; +import android.support.annotation.UiThread; +import android.support.constraint.ConstraintLayout; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.mailbox.R; + +import static android.content.Context.LAYOUT_INFLATER_SERVICE; +import static org.briarproject.mailbox.android.util.UiUtils.showOnboardingDialog; + +@UiThread +@NotNullByDefault +abstract class PowerView extends ConstraintLayout { + + private final TextView textView; + private final ImageView checkImage; + private final Button button; + + private boolean checked = false; + + @Nullable + private OnCheckedChangedListener onCheckedChangedListener; + + public PowerView(Context context) { + this(context, null); + } + + public PowerView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + @SuppressWarnings("ConstantConditions") + public PowerView(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(LAYOUT_INFLATER_SERVICE); + View v = inflater.inflate(R.layout.power_view, this, true); + + textView = v.findViewById(R.id.textView); + checkImage = v.findViewById(R.id.checkImage); + button = v.findViewById(R.id.button); + button.setOnClickListener(view -> onButtonClick()); + ImageButton helpButton = v.findViewById(R.id.helpButton); + helpButton.setOnClickListener(view -> onHelpButtonClick()); + + // we need to manage the checkImage state ourselves, because automatic + // state saving is done based on the view's ID and there can be + // multiple ImageViews with the same ID in the view hierarchy + setSaveFromParentEnabled(true); + + if (!isInEditMode() && !needsToBeShown()) { + setVisibility(GONE); + } + } + + @Nullable + @Override + protected Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + ss.value = new boolean[] {checked}; + return ss; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + setChecked(ss.value[0]); // also calls listener + } + + public abstract boolean needsToBeShown(); + + public void setChecked(boolean checked) { + this.checked = checked; + if (checked) { + checkImage.setVisibility(VISIBLE); + } else { + checkImage.setVisibility(INVISIBLE); + } + if (onCheckedChangedListener != null) { + onCheckedChangedListener.onCheckedChanged(); + } + } + + public boolean isChecked() { + return getVisibility() == GONE || checked; + } + + public void setOnCheckedChangedListener( + OnCheckedChangedListener onCheckedChangedListener) { + this.onCheckedChangedListener = onCheckedChangedListener; + } + + @StringRes + protected abstract int getHelpText(); + + protected void setText(@StringRes int res) { + textView.setText(res); + } + + protected void setButtonText(@StringRes int res) { + button.setText(res); + } + + protected abstract void onButtonClick(); + + private void onHelpButtonClick() { + showOnboardingDialog(getContext(), + getContext().getString(getHelpText())); + } + + private static class SavedState extends BaseSavedState { + private boolean[] value = {false}; + + private SavedState(@Nullable Parcelable superState) { + super(superState); + } + + private SavedState(Parcel in) { + super(in); + in.readBooleanArray(value); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeBooleanArray(value); + } + + static final Creator<SavedState> CREATOR + = new Creator<SavedState>() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + interface OnCheckedChangedListener { + void onCheckedChanged(); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..5eb024a83485a63933db5706843689b23d777bbf --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupActivity.java @@ -0,0 +1,113 @@ +package org.briarproject.mailbox.android.login; + +import android.annotation.TargetApi; +import android.content.Intent; +import android.os.Bundle; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BaseActivity; +import org.briarproject.mailbox.android.fragment.BaseFragment.BaseFragmentListener; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class SetupActivity extends BaseActivity + implements BaseFragmentListener { + + private static final String STATE_KEY_AUTHOR_NAME = "authorName"; + private static final String STATE_KEY_PASSWORD = "password"; + + @Inject + AccountManager accountManager; + + @Inject + SetupController setupController; + + @Nullable + private String authorName, password; + + @Override + public void onCreate(@Nullable Bundle state) { + super.onCreate(state); + // fade-in after splash screen instead of default animation + overridePendingTransition(R.anim.fade_in, R.anim.fade_out); + setContentView(R.layout.activity_fragment_container); + + if (state == null) { + if (accountManager.accountExists()) throw new AssertionError(); + showInitialFragment(AuthorNameFragment.newInstance()); + } else { + authorName = state.getString(STATE_KEY_AUTHOR_NAME); + password = state.getString(STATE_KEY_PASSWORD); + } + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + setupController.setSetupActivity(this); + } + + @Override + protected void onSaveInstanceState(Bundle state) { + super.onSaveInstanceState(state); + if (authorName != null) + state.putString(STATE_KEY_AUTHOR_NAME, authorName); + if (password != null) + state.putString(STATE_KEY_PASSWORD, password); + } + + @Nullable + String getAuthorName() { + return authorName; + } + + void setAuthorName(String authorName) { + this.authorName = authorName; + } + + @Nullable + String getPassword() { + return password; + } + + void setPassword(String password) { + this.password = password; + } + + void showPasswordFragment() { + if (authorName == null) throw new IllegalStateException(); + showNextFragment(PasswordFragment.newInstance()); + } + + @TargetApi(23) + void showDozeFragment() { + if (authorName == null) throw new IllegalStateException(); + if (password == null) throw new IllegalStateException(); + showNextFragment(DozeFragment.newInstance()); + } + + void showApp() { + Intent i = new Intent(this, OpenDatabaseActivity.class); + i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME); + startActivity(i); + supportFinishAfterTransition(); + overridePendingTransition(R.anim.screen_new_in, R.anim.screen_old_out); + } + + @Override + @Deprecated + public void runOnDbThread(Runnable runnable) { + throw new RuntimeException("Don't use this deprecated method here."); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupController.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupController.java new file mode 100644 index 0000000000000000000000000000000000000000..2c622782c4bb87c15a8b92092f6f48899c831c11 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupController.java @@ -0,0 +1,32 @@ +package org.briarproject.mailbox.android.login; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@NotNullByDefault +public interface SetupController extends PasswordController { + + void setSetupActivity(SetupActivity setupActivity); + + boolean needToShowDozeFragment(); + + void setAuthorName(String authorName); + + void setPassword(String password); + + /** + * This should be called after the author name has been set. + */ + void showPasswordFragment(); + + /** + * This should be called after the author name and the password have been + * set. + */ + void showDozeFragment(); + + /** + * This should be called after the author name and the password have been + * set. + */ + void createAccount(); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupControllerImpl.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupControllerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..82ab5b6abec84492b900228d0c4c71f61a5ea0f9 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupControllerImpl.java @@ -0,0 +1,105 @@ +package org.briarproject.mailbox.android.login; + +import android.support.annotation.Nullable; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.mailbox.android.controller.handler.ResultHandler; +import org.briarproject.mailbox.android.controller.handler.UiResultHandler; + +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.inject.Inject; + +@NotNullByDefault +public class SetupControllerImpl extends PasswordControllerImpl + implements SetupController { + + private static final Logger LOG = + Logger.getLogger(SetupControllerImpl.class.getName()); + + @Nullable + private volatile SetupActivity setupActivity; + + @Inject + SetupControllerImpl(AccountManager accountManager, + @IoExecutor Executor ioExecutor, + PasswordStrengthEstimator strengthEstimator) { + super(accountManager, ioExecutor, strengthEstimator); + } + + @Override + public void setSetupActivity(SetupActivity setupActivity) { + this.setupActivity = setupActivity; + } + + @Override + public boolean needToShowDozeFragment() { + SetupActivity setupActivity = this.setupActivity; + if (setupActivity == null) throw new IllegalStateException(); + return DozeView.needsToBeShown(setupActivity) || + HuaweiView.needsToBeShown(setupActivity); + } + + @Override + public void setAuthorName(String authorName) { + SetupActivity setupActivity = this.setupActivity; + if (setupActivity == null) throw new IllegalStateException(); + setupActivity.setAuthorName(authorName); + } + + @Override + public void setPassword(String password) { + SetupActivity setupActivity = this.setupActivity; + if (setupActivity == null) throw new IllegalStateException(); + setupActivity.setPassword(password); + } + + @Override + public void showPasswordFragment() { + SetupActivity setupActivity = this.setupActivity; + if (setupActivity == null) throw new IllegalStateException(); + setupActivity.showPasswordFragment(); + } + + @Override + public void showDozeFragment() { + SetupActivity setupActivity = this.setupActivity; + if (setupActivity == null) throw new IllegalStateException(); + setupActivity.showDozeFragment(); + } + + @Override + public void createAccount() { + SetupActivity setupActivity = this.setupActivity; + UiResultHandler<Boolean> resultHandler = + new UiResultHandler<Boolean>(setupActivity) { + @Override + public void onResultUi(Boolean result) { + // TODO: Show an error if result is false + if (setupActivity == null) + throw new IllegalStateException(); + setupActivity.showApp(); + } + }; + createAccount(resultHandler); + } + + // Package access for testing + void createAccount(ResultHandler<Boolean> resultHandler) { + SetupActivity setupActivity = this.setupActivity; + if (setupActivity == null) throw new IllegalStateException(); + String authorName = setupActivity.getAuthorName(); + if (authorName == null) throw new IllegalStateException(); + String password = setupActivity.getPassword(); + if (password == null) throw new IllegalStateException(); + ioExecutor.execute(() -> { + LOG.info("Creating account"); + resultHandler.onResult(accountManager.createAccount(authorName, + password)); + }); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..660232f647e4ac0cfdc5ef6de4c32825cec2e36f --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SetupFragment.java @@ -0,0 +1,68 @@ +package org.briarproject.mailbox.android.login; + +import android.text.Editable; +import android.text.TextWatcher; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View.OnClickListener; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.fragment.BaseFragment; + +import javax.inject.Inject; + +import static org.briarproject.mailbox.android.util.UiUtils.showOnboardingDialog; + +abstract class SetupFragment extends BaseFragment implements TextWatcher, + OnEditorActionListener, OnClickListener { + + @Inject + SetupController setupController; + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.help_action, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.action_help) { + showOnboardingDialog(getContext(), getHelpText()); + return true; + } else { + return super.onOptionsItemSelected(item); + } + } + + protected abstract String getHelpText(); + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + // noop + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + // noop + } + + @Override + public boolean onEditorAction(TextView textView, int actionId, + KeyEvent keyEvent) { + onClick(textView); + return true; + } + + @Override + public void afterTextChanged(Editable editable) { + // noop + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SignInReminderReceiver.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SignInReminderReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..bb39c06a530db76234cdaa34bd86dfca9819af20 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/SignInReminderReceiver.java @@ -0,0 +1,52 @@ +package org.briarproject.mailbox.android.login; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.mailbox.android.AndroidComponent; +import org.briarproject.mailbox.android.MailboxApplication; +import org.briarproject.mailbox.api.android.AndroidNotificationManager; + +import javax.inject.Inject; + +import static android.content.Intent.ACTION_BOOT_COMPLETED; +import static android.content.Intent.ACTION_MY_PACKAGE_REPLACED; +import static org.briarproject.mailbox.android.TestingConstants.FEATURE_FLAG_SIGN_IN_REMINDER; +import static org.briarproject.mailbox.android.settings.SettingsFragment.NOTIFY_SIGN_IN; +import static org.briarproject.mailbox.api.android.AndroidNotificationManager.ACTION_DISMISS_REMINDER; + +public class SignInReminderReceiver extends BroadcastReceiver { + + @Inject + AccountManager accountManager; + @Inject + AndroidNotificationManager notificationManager; + + @Override + public void onReceive(Context ctx, Intent intent) { + if (!FEATURE_FLAG_SIGN_IN_REMINDER) return; + + MailboxApplication app = (MailboxApplication) ctx.getApplicationContext(); + AndroidComponent applicationComponent = app.getApplicationComponent(); + applicationComponent.inject(this); + + String action = intent.getAction(); + if (action == null) return; + if (action.equals(ACTION_BOOT_COMPLETED) || + action.equals(ACTION_MY_PACKAGE_REPLACED)) { + if (accountManager.accountExists() && + !accountManager.hasDatabaseKey()) { + SharedPreferences prefs = app.getDefaultSharedPreferences(); + if (prefs.getBoolean(NOTIFY_SIGN_IN, true)) { + notificationManager.showSignInNotification(); + } + } + } else if (action.equals(ACTION_DISMISS_REMINDER)) { + notificationManager.clearSignInNotification(); + } + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/StrengthMeter.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/StrengthMeter.java new file mode 100644 index 0000000000000000000000000000000000000000..b3f5ce942d6229d6447a7b7412225da78e00af65 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/StrengthMeter.java @@ -0,0 +1,75 @@ +package org.briarproject.mailbox.android.login; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.ClipDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.graphics.drawable.ShapeDrawable; +import android.util.AttributeSet; +import android.widget.ProgressBar; + +import static android.graphics.Color.BLACK; +import static android.graphics.Paint.Style.FILL; +import static android.graphics.Paint.Style.STROKE; +import static android.graphics.drawable.ClipDrawable.HORIZONTAL; +import static android.view.Gravity.LEFT; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_STRONG; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.STRONG; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.WEAK; + +public class StrengthMeter extends ProgressBar { + + private static final int MAX = 100; + public static final int RED = Color.rgb(255, 0, 0); + public static final int ORANGE = Color.rgb(255, 160, 0); + public static final int YELLOW = Color.rgb(255, 255, 0); + public static final int LIME = Color.rgb(180, 255, 0); + public static final int GREEN = Color.rgb(0, 255, 0); + + private final ShapeDrawable bar; + + public StrengthMeter(Context context) { + this(context, null); + } + + public StrengthMeter(Context context, AttributeSet attrs) { + super(context, attrs, android.R.attr.progressBarStyleHorizontal); + bar = new ShapeDrawable(); + bar.getPaint().setColor(RED); + ClipDrawable clip = new ClipDrawable(bar, LEFT, HORIZONTAL); + ShapeDrawable background = new ShapeDrawable(); + Paint p = background.getPaint(); + p.setStyle(FILL); + p.setColor(getResources().getColor(android.R.color.transparent)); + p.setStyle(STROKE); + p.setStrokeWidth(1); + p.setColor(BLACK); + Drawable[] layers = new Drawable[] { clip, background }; + setProgressDrawable(new LayerDrawable(layers)); + setIndeterminate(false); + } + + @Override + public int getMax() { + return MAX; + } + + public int getColor() { + return bar.getPaint().getColor(); + } + + public void setStrength(float strength) { + if (strength < 0 || strength > 1) throw new IllegalArgumentException(); + int colour; + if (strength < WEAK) colour = RED; + else if (strength < QUITE_WEAK) colour = ORANGE; + else if (strength < QUITE_STRONG) colour = YELLOW; + else if (strength < STRONG) colour = LIME; + else colour = GREEN; + bar.getPaint().setColor(colour); + setProgress((int) (strength * MAX)); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/UnlockActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/UnlockActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..02c609cc81573aad8464864d216c3dea4bff3d2a --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/login/UnlockActivity.java @@ -0,0 +1,123 @@ +package org.briarproject.mailbox.android.login; + +import android.app.KeyguardManager; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.annotation.RequiresApi; +import android.widget.Button; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BaseActivity; +import org.briarproject.mailbox.api.android.LockManager; + +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static android.os.Build.VERSION.SDK_INT; +import static org.briarproject.mailbox.android.activity.RequestCodes.REQUEST_KEYGUARD_UNLOCK; + +@RequiresApi(21) +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class UnlockActivity extends BaseActivity { + + private static final Logger LOG = + Logger.getLogger(UnlockActivity.class.getName()); + private static final String KEYGUARD_SHOWN = "keyguardShown"; + + @Inject + LockManager lockManager; + + private boolean keyguardShown = false; + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + public void onCreate(@Nullable Bundle state) { + super.onCreate(state); + overridePendingTransition(0, 0); + setContentView(R.layout.activity_unlock); + + Button button = findViewById(R.id.unlock); + button.setOnClickListener(view -> requestKeyguardUnlock()); + + keyguardShown = state != null && state.getBoolean(KEYGUARD_SHOWN); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + // Saving whether we've shown the keyguard already is necessary + // for Android 6 when this activity gets destroyed. + // + // This will not help Android 5. + // There the system will show the keyguard once again. + // So if this activity was destroyed, the user needs to enter PIN twice. + outState.putBoolean(KEYGUARD_SHOWN, keyguardShown); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, + Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_KEYGUARD_UNLOCK) { + if (resultCode == RESULT_OK) unlock(); + else { + finish(); + overridePendingTransition(0, 0); + } + } + } + + @Override + protected void onResume() { + super.onResume(); + // Show keyguard after onActivityResult() as been called. + // Check if app is still locked, lockable + // and not finishing (which is possible if recreated) + if (!keyguardShown && lockManager.isLocked() && !isFinishing()) { + requestKeyguardUnlock(); + } else if (!lockManager.isLocked()) { + setResult(RESULT_OK); + finish(); + } + } + + @Override + public void onBackPressed() { + moveTaskToBack(true); + } + + private void requestKeyguardUnlock() { + KeyguardManager keyguardManager = + (KeyguardManager) getSystemService(KEYGUARD_SERVICE); + if (keyguardManager == null) throw new AssertionError(); + Intent intent = keyguardManager.createConfirmDeviceCredentialIntent( + SDK_INT < 23 ? getString(R.string.lock_unlock_verbose) : + getString(R.string.lock_unlock), null); + if (intent == null) { + // the user must have removed the screen lock since locked + LOG.warning("Unlocking without keyguard"); + unlock(); + } else { + keyguardShown = true; + startActivityForResult(intent, REQUEST_KEYGUARD_UNLOCK); + overridePendingTransition(0, 0); + } + } + + private void unlock() { + lockManager.setLocked(false); + setResult(RESULT_OK); + finish(); + overridePendingTransition(0, 0); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/logout/ExitActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/logout/ExitActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..2c321e2c1118ef67939be668b1f8f9d12070eea6 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/logout/ExitActivity.java @@ -0,0 +1,29 @@ +package org.briarproject.mailbox.android.logout; + +import android.os.Build; +import android.os.Bundle; + +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BaseActivity; + +import java.util.logging.Logger; + +public class ExitActivity extends BaseActivity { + + private static final Logger LOG = + Logger.getLogger(ExitActivity.class.getName()); + + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + if (Build.VERSION.SDK_INT >= 21) finishAndRemoveTask(); + else finish(); + LOG.info("Exiting"); + System.exit(0); + } + + @Override + public void injectActivity(ActivityComponent component) { + + } +} \ No newline at end of file diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/logout/HideUiActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/logout/HideUiActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..a25d1941abd494c6b68f6e0b8a4892be27db2d04 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/logout/HideUiActivity.java @@ -0,0 +1,20 @@ +package org.briarproject.mailbox.android.logout; + +import android.os.Bundle; + +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BaseActivity; + +public class HideUiActivity extends BaseActivity { + + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + finish(); + } + + @Override + public void injectActivity(ActivityComponent component) { + + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/logout/SignOutFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/logout/SignOutFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..0042d780e7debbbd0693e7eee61e93d0769ae4ad --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/logout/SignOutFragment.java @@ -0,0 +1,35 @@ +package org.briarproject.mailbox.android.logout; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.fragment.BaseFragment; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class SignOutFragment extends BaseFragment { + + public static final String TAG = SignOutFragment.class.getName(); + + @Override + public View onCreateView(@Nonnull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_sign_out, container, false); + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + public void injectFragment(ActivityComponent component) { + // no need to inject + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/NavDrawerActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/NavDrawerActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..f3ffb83d192bff1111665902f3d4344c64d430fa --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/NavDrawerActivity.java @@ -0,0 +1,435 @@ +package org.briarproject.mailbox.android.navdrawer; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.NavigationView; +import android.support.design.widget.NavigationView.OnNavigationItemSelectedListener; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBarDrawerToggle; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.TextView; + +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.plugin.BluetoothConstants; +import org.briarproject.bramble.api.plugin.LanTcpConstants; +import org.briarproject.bramble.api.plugin.TorConstants; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BriarActivity; +import org.briarproject.mailbox.android.controller.handler.UiResultHandler; +import org.briarproject.mailbox.android.fragment.BaseFragment; +import org.briarproject.mailbox.android.fragment.BaseFragment.BaseFragmentListener; +import org.briarproject.mailbox.android.logout.SignOutFragment; +import org.briarproject.mailbox.android.navdrawer.NavDrawerController.ExpiryWarning; +import org.briarproject.mailbox.android.overview.OverviewFragment; +import org.briarproject.mailbox.android.settings.SettingsActivity; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static android.support.v4.app.FragmentManager.POP_BACK_STACK_INCLUSIVE; +import static android.support.v4.view.GravityCompat.START; +import static android.support.v4.widget.DrawerLayout.LOCK_MODE_LOCKED_CLOSED; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; +import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING; +import static org.briarproject.mailbox.android.BriarService.EXTRA_STARTUP_FAILED; +import static org.briarproject.mailbox.android.activity.RequestCodes.REQUEST_PASSWORD; +import static org.briarproject.mailbox.android.navdrawer.NavDrawerController.ExpiryWarning.NO; +import static org.briarproject.mailbox.android.navdrawer.NavDrawerController.ExpiryWarning.UPDATE; +import static org.briarproject.mailbox.android.util.UiUtils.getDaysUntilExpiry; + +public class NavDrawerActivity extends BriarActivity implements + BaseFragmentListener, TransportStateListener, + OnNavigationItemSelectedListener { + + public static final String INTENT_SIGN_OUT = "intent_sign_out"; + + private static final Logger LOG = + Logger.getLogger(NavDrawerActivity.class.getName()); + + private ActionBarDrawerToggle drawerToggle; + + @Inject + NavDrawerController controller; + @Inject + LifecycleManager lifecycleManager; + + private DrawerLayout drawerLayout; + private NavigationView navigation; + + private List<Transport> transports; + private BaseAdapter transportsAdapter; + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + exitIfStartupFailed(intent); + // TODO don't create new instances if they are on the stack (#606) + if (intent.getBooleanExtra(INTENT_SIGN_OUT, false)) { + signOut(false); + } + setIntent(null); + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + @SuppressWarnings("ConstantConditions") + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + exitIfStartupFailed(getIntent()); + setContentView(R.layout.activity_nav_drawer); + + Toolbar toolbar = findViewById(R.id.toolbar); + drawerLayout = findViewById(R.id.drawer_layout); + navigation = findViewById(R.id.navigation); + GridView transportsView = findViewById(R.id.transportsView); + + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); + + drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, + R.string.nav_drawer_open_description, + R.string.nav_drawer_close_description); + drawerLayout.addDrawerListener(drawerToggle); + navigation.setNavigationItemSelectedListener(this); + + initializeTransports(getLayoutInflater()); + transportsView.setAdapter(transportsAdapter); + + lockManager.isLockable().observe(this, this::setLockVisible); + + if (lifecycleManager.getLifecycleState().isAfter(RUNNING)) { + showSignOutFragment(); + } else if (state == null) { + startFragment(OverviewFragment.newInstance(), + R.id.nav_btn_overview); + } + if (getIntent() != null) { + onNewIntent(getIntent()); + } + } + + @Override + @SuppressLint("NewApi") + public void onStart() { + super.onStart(); + updateTransports(); + lockManager.checkIfLockable(); + controller.showExpiryWarning(new UiResultHandler<ExpiryWarning>(this) { + @Override + public void onResultUi(ExpiryWarning expiry) { + if (expiry != NO) showExpiryWarning(expiry); + } + }); + } + + @Override + protected void onActivityResult(int request, int result, Intent data) { + super.onActivityResult(request, result, data); + if (request == REQUEST_PASSWORD && result == RESULT_OK) { + controller.shouldAskForDozeWhitelisting(this, + new UiResultHandler<Boolean>(this) { + @Override + public void onResultUi(Boolean ask) { + if (ask) { + showDozeDialog( + getString(R.string.setup_doze_intro)); + } + } + }); + } + } + + private void exitIfStartupFailed(Intent intent) { + if (intent.getBooleanExtra(EXTRA_STARTUP_FAILED, false)) { + finish(); + LOG.info("Exiting"); + System.exit(0); + } + } + + private void loadFragment(int fragmentId) { + // TODO re-use fragments from the manager when possible (#606) + switch (fragmentId) { + case R.id.nav_btn_settings: + startActivity(new Intent(this, SettingsActivity.class)); + break; + case R.id.nav_btn_signout: + signOut(); + break; + } + } + + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + drawerLayout.closeDrawer(START); + clearBackStack(); + if (item.getItemId() == R.id.nav_btn_lock) { + lockManager.setLocked(true); + ActivityCompat.finishAfterTransition(this); + return false; + } else { + loadFragment(item.getItemId()); + // Don't display the Settings item as checked + return item.getItemId() != R.id.nav_btn_settings; + } + } + + @Override + public void onBackPressed() { + if (drawerLayout.isDrawerOpen(START)) { + drawerLayout.closeDrawer(START); + } else { + FragmentManager fm = getSupportFragmentManager(); + if (fm.findFragmentByTag(SignOutFragment.TAG) != null) { + finish(); + } else if (fm.getBackStackEntryCount() == 0 + && fm.findFragmentByTag(OverviewFragment.TAG) == null) { + /* + * This makes sure that the first fragment (ContactListFragment) the + * user sees is the same as the last fragment the user sees before + * exiting. This models the typical Google navigation behaviour such + * as in Gmail/Inbox. + */ + startFragment(OverviewFragment.newInstance(), + R.id.nav_btn_overview); + } else { + super.onBackPressed(); + } + } + } + + @Override + public void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + drawerToggle.syncState(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + drawerToggle.onConfigurationChanged(newConfig); + } + + private void showSignOutFragment() { + drawerLayout.setDrawerLockMode(LOCK_MODE_LOCKED_CLOSED); + startFragment(new SignOutFragment()); + } + + private void signOut() { + drawerLayout.setDrawerLockMode(LOCK_MODE_LOCKED_CLOSED); + signOut(false); + finish(); + } + + private void startFragment(BaseFragment fragment, int itemId) { + navigation.setCheckedItem(itemId); + startFragment(fragment); + } + + private void startFragment(BaseFragment fragment) { + if (getSupportFragmentManager().getBackStackEntryCount() == 0) + startFragment(fragment, false); + else startFragment(fragment, true); + } + + private void startFragment(BaseFragment fragment, + boolean isAddedToBackStack) { + FragmentTransaction trans = + getSupportFragmentManager().beginTransaction() + .setCustomAnimations(R.anim.fade_in, + R.anim.fade_out, R.anim.fade_in, + R.anim.fade_out) + .replace(R.id.fragmentContainer, fragment, + fragment.getUniqueTag()); + if (isAddedToBackStack) { + trans.addToBackStack(fragment.getUniqueTag()); + } + trans.commit(); + } + + private void clearBackStack() { + getSupportFragmentManager().popBackStackImmediate(null, + POP_BACK_STACK_INCLUSIVE); + } + + @Override + public void handleDbException(DbException e) { + // Do nothing for now + } + + private void setLockVisible(boolean visible) { + MenuItem item = navigation.getMenu().findItem(R.id.nav_btn_lock); + if (item != null) item.setVisible(visible); + } + + @SuppressWarnings("ConstantConditions") + private void showExpiryWarning(ExpiryWarning expiry) { + int daysUntilExpiry = getDaysUntilExpiry(); + if (daysUntilExpiry < 0) signOut(); + + // show expiry warning text + ViewGroup expiryWarning = findViewById(R.id.expiryWarning); + TextView expiryWarningText = + expiryWarning.findViewById(R.id.expiryWarningText); + // make close button functional + ImageView expiryWarningClose = + expiryWarning.findViewById(R.id.expiryWarningClose); + + // show a different snackbar in green if this is an update + if (expiry == UPDATE) { + expiryWarning.setBackgroundColor( + ContextCompat.getColor(this, R.color.briar_green_light)); + expiryWarningText.setText( + getString(R.string.expiry_update, daysUntilExpiry)); + expiryWarningText.setTextColor( + ContextCompat.getColor(this, android.R.color.black)); + expiryWarningClose.setColorFilter( + ContextCompat.getColor(this, android.R.color.black)); + } else { + expiryWarningText.setText(getResources() + .getQuantityString(R.plurals.expiry_warning, + daysUntilExpiry, daysUntilExpiry)); + } + + expiryWarningClose.setOnClickListener(v -> { + controller.expiryWarningDismissed(); + expiryWarning.setVisibility(GONE); + }); + + expiryWarning.setVisibility(VISIBLE); + } + + private void initializeTransports(LayoutInflater inflater) { + transports = new ArrayList<>(3); + + Transport tor = new Transport(); + tor.id = TorConstants.ID; + tor.enabled = controller.isTransportRunning(tor.id); + tor.iconId = R.drawable.transport_tor; + tor.textId = R.string.transport_tor; + transports.add(tor); + + Transport bt = new Transport(); + bt.id = BluetoothConstants.ID; + bt.enabled = controller.isTransportRunning(bt.id); + bt.iconId = R.drawable.transport_bt; + bt.textId = R.string.transport_bt; + transports.add(bt); + + Transport lan = new Transport(); + lan.id = LanTcpConstants.ID; + lan.enabled = controller.isTransportRunning(lan.id); + lan.iconId = R.drawable.transport_lan; + lan.textId = R.string.transport_lan; + transports.add(lan); + + transportsAdapter = new BaseAdapter() { + @Override + public int getCount() { + return transports.size(); + } + + @Override + public Transport getItem(int position) { + return transports.get(position); + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, + ViewGroup parent) { + View view; + if (convertView != null) { + view = convertView; + } else { + view = inflater.inflate(R.layout.list_item_transport, + parent, false); + } + + Transport t = getItem(position); + int c; + if (t.enabled) { + c = ContextCompat.getColor(NavDrawerActivity.this, + R.color.briar_green_light); + } else { + c = ContextCompat.getColor(NavDrawerActivity.this, + android.R.color.tertiary_text_light); + } + + ImageView icon = view.findViewById(R.id.imageView); + icon.setImageDrawable(ContextCompat + .getDrawable(NavDrawerActivity.this, t.iconId)); + icon.setColorFilter(c); + + TextView text = view.findViewById(R.id.textView); + text.setText(getString(t.textId)); + + return view; + } + }; + } + + private void setTransport(TransportId id, boolean enabled) { + runOnUiThreadUnlessDestroyed(() -> { + if (transports == null || transportsAdapter == null) return; + for (Transport t : transports) { + if (t.id.equals(id)) { + t.enabled = enabled; + transportsAdapter.notifyDataSetChanged(); + break; + } + } + }); + } + + private void updateTransports() { + if (transports == null || transportsAdapter == null) return; + for (Transport t : transports) { + t.enabled = controller.isTransportRunning(t.id); + } + transportsAdapter.notifyDataSetChanged(); + } + + @Override + public void stateUpdate(TransportId id, boolean enabled) { + setTransport(id, enabled); + } + + private static class Transport { + + private TransportId id; + private boolean enabled; + private int iconId; + private int textId; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/NavDrawerController.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/NavDrawerController.java new file mode 100644 index 0000000000000000000000000000000000000000..fc5c14a4f7787013c8d25c065d9726c8e2bdf09e --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/NavDrawerController.java @@ -0,0 +1,24 @@ +package org.briarproject.mailbox.android.navdrawer; + +import android.content.Context; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.mailbox.android.controller.ActivityLifecycleController; +import org.briarproject.mailbox.android.controller.handler.ResultHandler; + +@NotNullByDefault +public interface NavDrawerController extends ActivityLifecycleController { + + enum ExpiryWarning { SHOW, NO, UPDATE } + + boolean isTransportRunning(TransportId transportId); + + void showExpiryWarning(ResultHandler<ExpiryWarning> handler); + + void expiryWarningDismissed(); + + void shouldAskForDozeWhitelisting(Context ctx, + ResultHandler<Boolean> handler); + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/NavDrawerControllerImpl.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/NavDrawerControllerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..032c004311e095e64537da76405ba27cb3c1c02e --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/NavDrawerControllerImpl.java @@ -0,0 +1,195 @@ +package org.briarproject.mailbox.android.navdrawer; + +import android.app.Activity; +import android.content.Context; + +import org.briarproject.bramble.api.db.DatabaseExecutor; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.event.EventListener; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.plugin.Plugin; +import org.briarproject.bramble.api.plugin.PluginManager; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent; +import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent; +import org.briarproject.bramble.api.settings.Settings; +import org.briarproject.bramble.api.settings.SettingsManager; +import org.briarproject.mailbox.android.controller.DbControllerImpl; +import org.briarproject.mailbox.android.controller.handler.ResultHandler; + +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.mailbox.android.TestingConstants.EXPIRY_DATE; +import static org.briarproject.mailbox.android.TestingConstants.IS_BETA_BUILD; +import static org.briarproject.mailbox.android.TestingConstants.IS_DEBUG_BUILD; +import static org.briarproject.mailbox.android.controller.BriarControllerImpl.DOZE_ASK_AGAIN; +import static org.briarproject.mailbox.android.navdrawer.NavDrawerController.ExpiryWarning.NO; +import static org.briarproject.mailbox.android.navdrawer.NavDrawerController.ExpiryWarning.SHOW; +import static org.briarproject.mailbox.android.navdrawer.NavDrawerController.ExpiryWarning.UPDATE; +import static org.briarproject.mailbox.android.settings.SettingsFragment.SETTINGS_NAMESPACE; +import static org.briarproject.mailbox.android.util.UiUtils.needsDozeWhitelisting; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class NavDrawerControllerImpl extends DbControllerImpl + implements NavDrawerController, EventListener { + + private static final Logger LOG = + Logger.getLogger(NavDrawerControllerImpl.class.getName()); + private static final String EXPIRY_DATE_WARNING = "expiryDateWarning"; + private static final String EXPIRY_SHOW_UPDATE = "expiryShowUpdate"; + + private final PluginManager pluginManager; + private final SettingsManager settingsManager; + private final EventBus eventBus; + + private volatile TransportStateListener listener; + + @Inject + NavDrawerControllerImpl(@DatabaseExecutor Executor dbExecutor, + LifecycleManager lifecycleManager, PluginManager pluginManager, + SettingsManager settingsManager, EventBus eventBus) { + super(dbExecutor, lifecycleManager); + this.pluginManager = pluginManager; + this.settingsManager = settingsManager; + this.eventBus = eventBus; + } + + @Override + public void onActivityCreate(Activity activity) { + listener = (TransportStateListener) activity; + } + + @Override + public void onActivityStart() { + eventBus.addListener(this); + } + + @Override + public void onActivityStop() { + eventBus.removeListener(this); + } + + @Override + public void onActivityDestroy() { + + } + + @Override + public void eventOccurred(Event e) { + if (e instanceof TransportEnabledEvent) { + TransportId id = ((TransportEnabledEvent) e).getTransportId(); + if (LOG.isLoggable(INFO)) { + LOG.info("TransportEnabledEvent: " + id.getString()); + } + transportStateUpdate(id, true); + } else if (e instanceof TransportDisabledEvent) { + TransportId id = ((TransportDisabledEvent) e).getTransportId(); + if (LOG.isLoggable(INFO)) { + LOG.info("TransportDisabledEvent: " + id.getString()); + } + transportStateUpdate(id, false); + } + } + + private void transportStateUpdate(TransportId id, boolean enabled) { + listener.runOnUiThreadUnlessDestroyed( + () -> listener.stateUpdate(id, enabled)); + } + + @Override + public void showExpiryWarning(ResultHandler<ExpiryWarning> handler) { + if (!IS_DEBUG_BUILD && !IS_BETA_BUILD) { + handler.onResult(NO); + return; + } + runOnDbThread(() -> { + try { + Settings settings = + settingsManager.getSettings(SETTINGS_NAMESPACE); + int warningInt = settings.getInt(EXPIRY_DATE_WARNING, 0); + boolean showUpdate = + settings.getBoolean(EXPIRY_SHOW_UPDATE, true); + + if (warningInt == 0) { + // we have not warned before + handler.onResult(SHOW); + } else { + long warningLong = warningInt * 1000L; + long now = System.currentTimeMillis(); + long daysSinceLastWarning = + (now - warningLong) / 1000 / 60 / 60 / 24; + long daysBeforeExpiry = + (EXPIRY_DATE - now) / 1000 / 60 / 60 / 24; + + if (showUpdate) { + handler.onResult(UPDATE); + } else if (daysSinceLastWarning >= 30) { + handler.onResult(SHOW); + } else if (daysBeforeExpiry <= 3 && + daysSinceLastWarning > 0) { + handler.onResult(SHOW); + } else { + handler.onResult(NO); + } + } + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + @Override + public void expiryWarningDismissed() { + runOnDbThread(() -> { + try { + Settings settings = new Settings(); + int date = (int) (System.currentTimeMillis() / 1000L); + settings.putInt(EXPIRY_DATE_WARNING, date); + settings.putBoolean(EXPIRY_SHOW_UPDATE, false); + settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + @Override + public void shouldAskForDozeWhitelisting(Context ctx, + ResultHandler<Boolean> handler) { + // check this first, to hit the DbThread only when really necessary + if (!needsDozeWhitelisting(ctx)) { + handler.onResult(false); + return; + } + runOnDbThread(() -> { + try { + Settings settings = + settingsManager.getSettings(SETTINGS_NAMESPACE); + boolean ask = settings.getBoolean(DOZE_ASK_AGAIN, true); + handler.onResult(ask); + } catch (DbException e) { + logException(LOG, WARNING, e); + handler.onResult(true); + } + }); + } + + @Override + public boolean isTransportRunning(TransportId transportId) { + Plugin plugin = pluginManager.getPlugin(transportId); + + return plugin != null && plugin.isRunning(); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/TransportStateListener.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/TransportStateListener.java new file mode 100644 index 0000000000000000000000000000000000000000..c0b42c19b0ea3942de36720489b490e2a02e041e --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/navdrawer/TransportStateListener.java @@ -0,0 +1,9 @@ +package org.briarproject.mailbox.android.navdrawer; + +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.mailbox.android.DestroyableContext; + +interface TransportStateListener extends DestroyableContext { + + void stateUpdate(TransportId id, boolean enabled); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/overview/OverviewFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/overview/OverviewFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..3e833f6d51f3ac91880d5ac05dd65618ebada7f6 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/overview/OverviewFragment.java @@ -0,0 +1,129 @@ +package org.briarproject.mailbox.android.overview; + +import android.arch.lifecycle.ViewModelProviders; +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.fragment.BaseEventFragment; +import org.briarproject.mailbox.android.keyagreement.MailboxExchangeActivity; +import org.briarproject.mailbox.android.viewmodels.MailboxOwnerStatusViewModel; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static org.briarproject.mailbox.R.drawable.contact_offline; +import static org.briarproject.mailbox.R.drawable.contact_online; + +@MethodsNotNullByDefault +@ParametersAreNonnullByDefault +public class OverviewFragment extends BaseEventFragment { + + public static final String TAG = OverviewFragment.class.getName(); + private static final Logger LOG = Logger.getLogger(TAG); + + private ImageView ownerStatus; + private TextView ownerName; + + public static OverviewFragment newInstance() { + OverviewFragment f = new OverviewFragment(); + Bundle bundle = new Bundle(); + f.setArguments(bundle); + return f; + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + getActivity().setTitle(R.string.overview); + return inflater.inflate(R.layout.fragment_overview, container, false); + } + + @Override + public void onViewCreated(View view, + @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + ownerStatus = view.findViewById(R.id.ownerStatus); + ownerName = view.findViewById(R.id.ownerName); + final MailboxOwnerStatusViewModel + viewModel = ViewModelProviders.of(this) + .get(MailboxOwnerStatusViewModel.class); + viewModel.mailboxOwnerStatusLiveData.observe(this, + mailboxOwnerStatus -> { + if (mailboxOwnerStatus == null) { + ownerName.setText(R.string.mailbox_unpaired); + ownerStatus.setVisibility(INVISIBLE); + } else { + ownerName.setText(mailboxOwnerStatus.getName()); + ownerStatus.setVisibility(VISIBLE); + if (mailboxOwnerStatus.isOnline()) + ownerStatus.setImageResource(contact_online); + else + ownerStatus.setImageResource(contact_offline); + } + }); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.overview_actions, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public void onStart() { + super.onStart(); + } + + @Override + public void eventOccurred(Event e) { + + } + + private void displayOwnerStatus() { + runOnUiThreadUnlessDestroyed(() -> { + + }); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle presses on the action bar items + switch (item.getItemId()) { + case R.id.action_add_contact: + Intent intent = + new Intent(getContext(), MailboxExchangeActivity.class); + startActivity(intent); + return true; + default: + return super.onOptionsItemSelected(item); + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/panic/PanicPreferencesActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/panic/PanicPreferencesActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..c637bacf057842fa518ab3e37dec87883f7d92c2 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/panic/PanicPreferencesActivity.java @@ -0,0 +1,39 @@ +package org.briarproject.mailbox.android.panic; + +import android.os.Bundle; +import android.support.v7.app.ActionBar; +import android.view.MenuItem; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BriarActivity; + +public class PanicPreferencesActivity extends BriarActivity { + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setHomeButtonEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(true); + } + + setContentView(R.layout.activity_panic_preferences); + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return false; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/panic/PanicPreferencesFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/panic/PanicPreferencesFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..ff319da595161f1cf5b3d5afcd58f5459dcbfa71 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/panic/PanicPreferencesFragment.java @@ -0,0 +1,252 @@ +package org.briarproject.mailbox.android.panic; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.os.Bundle; +import android.support.v14.preference.SwitchPreference; +import android.support.v7.app.AlertDialog; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.PreferenceFragmentCompat; +import android.text.TextUtils; + +import org.briarproject.mailbox.R; + +import java.util.ArrayList; +import java.util.logging.Logger; + +import javax.annotation.Nullable; + +import info.guardianproject.panic.Panic; +import info.guardianproject.panic.PanicResponder; + +public class PanicPreferencesFragment extends PreferenceFragmentCompat + implements SharedPreferences.OnSharedPreferenceChangeListener { + + public static final String KEY_LOCK = "pref_key_lock"; + public static final String KEY_PANIC_APP = "pref_key_panic_app"; + public static final String KEY_PURGE = "pref_key_purge"; + public static final String KEY_UNINSTALL = "pref_key_uninstall"; + + private static final Logger LOG = + Logger.getLogger(PanicPreferencesFragment.class.getName()); + + private PackageManager pm; + private SwitchPreference lockPref, purgePref, uninstallPref; + private ListPreference panicAppPref; + + @Override + public void onCreatePreferences(Bundle bundle, String s) { + addPreferencesFromResource(R.xml.panic_preferences); + + pm = getActivity().getPackageManager(); + + lockPref = (SwitchPreference) findPreference(KEY_LOCK); + panicAppPref = (ListPreference) findPreference(KEY_PANIC_APP); + purgePref = (SwitchPreference) findPreference(KEY_PURGE); + uninstallPref = (SwitchPreference) findPreference(KEY_UNINSTALL); + + // check for connect/disconnect intents from panic trigger apps + if (PanicResponder.checkForDisconnectIntent(getActivity())) { + LOG.info("Received DISCONNECT intent from Panic Trigger App."); + // the necessary action should have been performed by the check + getActivity().finish(); + } else { + // check if we got a connect intent from a not yet connected app + String packageName = + PanicResponder.getConnectIntentSender(getActivity()); + if (!TextUtils.isEmpty((packageName)) && + !TextUtils.equals(packageName, + PanicResponder + .getTriggerPackageName(getActivity()))) { + + // A new panic trigger app asks us to connect + LOG.info("Received CONNECT intent from new Panic Trigger App."); + + // Show dialog allowing the user to opt-in + showOptInDialog(); + } + } + + ArrayList<CharSequence> entries = new ArrayList<>(); + ArrayList<CharSequence> entryValues = new ArrayList<>(); + entries.add(0, getString(R.string.panic_app_setting_none)); + entryValues.add(0, Panic.PACKAGE_NAME_NONE); + + for (ResolveInfo resolveInfo : PanicResponder.resolveTriggerApps(pm)) { + if (resolveInfo.activityInfo == null) + continue; + entries.add(resolveInfo.activityInfo.loadLabel(pm)); + entryValues.add(resolveInfo.activityInfo.packageName); + } + + panicAppPref.setEntries( + entries.toArray(new CharSequence[entries.size()])); + panicAppPref.setEntryValues( + entryValues.toArray(new CharSequence[entryValues.size()])); + panicAppPref.setDefaultValue(Panic.PACKAGE_NAME_NONE); + + panicAppPref.setOnPreferenceChangeListener((preference, newValue) -> { + String packageName = (String) newValue; + PanicResponder.setTriggerPackageName(getActivity(), packageName); + showPanicApp(packageName); + + if (packageName.equals(Panic.PACKAGE_NAME_NONE)) { + lockPref.setEnabled(false); + purgePref.setChecked(false); + purgePref.setEnabled(false); + uninstallPref.setChecked(false); + uninstallPref.setEnabled(false); + getActivity().setResult(Activity.RESULT_CANCELED); + } else { + lockPref.setEnabled(true); + purgePref.setEnabled(true); + uninstallPref.setEnabled(true); + } + + return true; + }); + + if (entries.size() <= 1) { + panicAppPref.setOnPreferenceClickListener(preference -> { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse( + "market://details?id=info.guardianproject.ripple")); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (intent.resolveActivity(getActivity().getPackageManager()) + != null) { + startActivity(intent); + } + return true; + }); + } + } + + @Override + public void onStart() { + super.onStart(); + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); + showPanicApp(PanicResponder.getTriggerPackageName(getActivity())); + } + + @Override + public void onStop() { + super.onStop(); + getPreferenceScreen().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + if (key.equals(KEY_PURGE)) { + // enable locking if purging gets enabled + if (sharedPreferences.getBoolean(KEY_PURGE, false)) { + lockPref.setChecked(true); + } + // disable uninstall if purging gets disabled + else { + uninstallPref.setChecked(false); + } + } + // enable purging and locking if uninstall gets enabled + if (key.equals(KEY_UNINSTALL) && + sharedPreferences.getBoolean(KEY_UNINSTALL, false)) { + lockPref.setChecked(true); + purgePref.setChecked(true); + } + // disable purging and uninstalling if locking gets disabled + if (key.equals(KEY_LOCK) && + !sharedPreferences.getBoolean(KEY_LOCK, true)) { + purgePref.setChecked(false); + uninstallPref.setChecked(false); + } + } + + private void showPanicApp(String triggerPackageName) { + if (TextUtils.isEmpty(triggerPackageName) + || triggerPackageName.equals(Panic.PACKAGE_NAME_NONE)) { + // no panic app set + panicAppPref.setValue(Panic.PACKAGE_NAME_NONE); + panicAppPref + .setSummary(getString(R.string.panic_app_setting_summary)); + panicAppPref.setIcon( + android.R.drawable.ic_menu_close_clear_cancel); + + // disable panic actions + lockPref.setEnabled(false); + purgePref.setEnabled(false); + uninstallPref.setEnabled(false); + } else { + // display connected panic app + try { + panicAppPref.setValue(triggerPackageName); + panicAppPref.setSummary(pm.getApplicationLabel( + pm.getApplicationInfo(triggerPackageName, 0))); + panicAppPref.setIcon( + pm.getApplicationIcon(triggerPackageName)); + + // enable panic actions + lockPref.setEnabled(true); + purgePref.setEnabled(true); + uninstallPref.setEnabled(true); + } catch (PackageManager.NameNotFoundException e) { + // revert back to no app, just to be safe + PanicResponder.setTriggerPackageName(getActivity(), + Panic.PACKAGE_NAME_NONE); + showPanicApp(Panic.PACKAGE_NAME_NONE); + } + } + } + + private void showOptInDialog() { + DialogInterface.OnClickListener okListener = (dialog, which) -> { + PanicResponder.setTriggerPackageName(getActivity()); + showPanicApp(PanicResponder.getTriggerPackageName(getActivity())); + getActivity().setResult(Activity.RESULT_OK); + }; + DialogInterface.OnClickListener cancelListener = (dialog, which) -> { + getActivity().setResult(Activity.RESULT_CANCELED); + getActivity().finish(); + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), + R.style.BriarDialogTheme); + builder.setTitle(getString(R.string.dialog_title_connect_panic_app)); + + CharSequence app = getString(R.string.unknown_app); + String packageName = getCallingPackageName(); + if (packageName != null) { + try { + app = pm.getApplicationLabel( + pm.getApplicationInfo(packageName, 0)); + } catch (PackageManager.NameNotFoundException e) { + LOG.warning(e.toString()); + } + } + + String text = String.format( + getString(R.string.dialog_message_connect_panic_app), app); + builder.setMessage(text); + builder.setNegativeButton(R.string.allow, okListener); + builder.setPositiveButton(R.string.cancel, cancelListener); + builder.show(); + } + + @Nullable + private String getCallingPackageName() { + ComponentName componentName = getActivity().getCallingActivity(); + String packageName = null; + if (componentName != null) { + packageName = componentName.getPackageName(); + } + return packageName; + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/panic/PanicResponderActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/panic/PanicResponderActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..75202247255ffc55cb3e278c5e22c464e142694c --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/panic/PanicResponderActivity.java @@ -0,0 +1,107 @@ +package org.briarproject.mailbox.android.panic; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.support.v7.preference.PreferenceManager; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BriarActivity; +import org.iilab.IilabEngineeringRSA2048Pin; + +import java.util.logging.Logger; + +import javax.inject.Inject; + +import info.guardianproject.GuardianProjectRSA4096; +import info.guardianproject.panic.Panic; +import info.guardianproject.panic.PanicResponder; +import info.guardianproject.trustedintents.TrustedIntents; + +import static android.content.Intent.ACTION_DELETE; +import static org.briarproject.mailbox.android.panic.PanicPreferencesFragment.KEY_LOCK; +import static org.briarproject.mailbox.android.panic.PanicPreferencesFragment.KEY_PURGE; +import static org.briarproject.mailbox.android.panic.PanicPreferencesFragment.KEY_UNINSTALL; + +public class PanicResponderActivity extends BriarActivity { + + private static final Logger LOG = + Logger.getLogger(PanicResponderActivity.class.getName()); + + @Inject + protected AccountManager accountManager; + @Inject + protected AndroidExecutor androidExecutor; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + TrustedIntents trustedIntents = TrustedIntents.get(this); + // Guardian Project Ripple + trustedIntents.addTrustedSigner(GuardianProjectRSA4096.class); + // Amnesty International's Panic Button, made by iilab.org + trustedIntents.addTrustedSigner(IilabEngineeringRSA2048Pin.class); + + Intent intent = trustedIntents.getIntentFromTrustedSender(this); + if (intent != null) { + // received intent from trusted app + if (Panic.isTriggerIntent(intent)) { + SharedPreferences sharedPref = PreferenceManager + .getDefaultSharedPreferences(this); + + LOG.info("Received Panic Trigger..."); + + if (PanicResponder.receivedTriggerFromConnectedApp(this)) { + LOG.info("Panic Trigger came from connected app"); + + // Performing panic responses + if (sharedPref.getBoolean(KEY_UNINSTALL, false)) { + LOG.info("Purging all data..."); + deleteAllData(); + + LOG.info("Uninstalling..."); + Intent uninstall = new Intent(ACTION_DELETE); + uninstall.setData( + Uri.parse("package:" + getPackageName())); + startActivity(uninstall); + } else if (sharedPref.getBoolean(KEY_PURGE, false)) { + LOG.info("Purging all data..."); + deleteAllData(); + } else if (sharedPref.getBoolean(KEY_LOCK, true)) { + LOG.info("Signing out..."); + signOut(true); + } + } + } + } + + if (Build.VERSION.SDK_INT >= 21) { + finishAndRemoveTask(); + } else { + finish(); + } + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + private void deleteAllData() { + androidExecutor.runOnBackgroundThread(() -> { + accountManager.deleteAccount(); + // TODO somehow delete/shred the database more thoroughly + PanicResponder.deleteAllAppData(PanicResponderActivity.this); + + // nothing left to do after everything is deleted, + // so still sign out + LOG.info("Signing out..."); + signOut(true); + }); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/BriarReportPrimer.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/BriarReportPrimer.java new file mode 100644 index 0000000000000000000000000000000000000000..2d7fdb8049277ad1e9ba8ecddacd7fc736c69915 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/BriarReportPrimer.java @@ -0,0 +1,281 @@ +package org.briarproject.mailbox.android.reporting; + +import android.app.ActivityManager; +import android.bluetooth.BluetoothAdapter; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Build; +import android.os.Environment; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; +import android.support.annotation.NonNull; + +import org.acra.builder.ReportBuilder; +import org.acra.builder.ReportPrimer; +import org.briarproject.bramble.util.StringUtils; +import org.briarproject.mailbox.BuildConfig; +import org.briarproject.mailbox.android.MailboxApplication; +import org.briarproject.mailbox.android.logging.BriefLogFormatter; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; +import java.util.logging.Formatter; +import java.util.logging.LogRecord; + +import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE; +import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; +import static android.content.Context.ACTIVITY_SERVICE; +import static android.content.Context.CONNECTIVITY_SERVICE; +import static android.content.Context.WIFI_P2P_SERVICE; +import static android.content.Context.WIFI_SERVICE; +import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; +import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress; + +public class BriarReportPrimer implements ReportPrimer { + + @Override + public void primeReport(@NonNull Context ctx, + @NonNull ReportBuilder builder) { + CustomDataTask task = new CustomDataTask(ctx); + FutureTask<Map<String, String>> futureTask = new FutureTask<>(task); + // Use a new thread as the Android executor thread may have died + new SingleShotAndroidExecutor(futureTask).start(); + try { + builder.customData(futureTask.get()); + } catch (InterruptedException | ExecutionException e) { + builder.customData("Custom data exception", e.toString()); + } + } + + private static class CustomDataTask + implements Callable<Map<String, String>> { + + private final Context ctx; + + private CustomDataTask(Context ctx) { + this.ctx = ctx; + } + + @Override + public Map<String, String> call() { + Map<String, String> customData = new LinkedHashMap<>(); + + // Log + MailboxApplication app = + (MailboxApplication) ctx.getApplicationContext(); + StringBuilder sb = new StringBuilder(); + Formatter formatter = new BriefLogFormatter(); + for (LogRecord record : app.getRecentLogRecords()) { + sb.append(formatter.format(record)).append('\n'); + } + customData.put("Log", sb.toString()); + + // System memory + Object o = ctx.getSystemService(ACTIVITY_SERVICE); + ActivityManager am = (ActivityManager) o; + ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo(); + am.getMemoryInfo(mem); + String systemMemory; + if (Build.VERSION.SDK_INT >= 16) { + systemMemory = (mem.totalMem / 1024 / 1024) + " MiB total, " + + (mem.availMem / 1024 / 1204) + " MiB free, " + + (mem.threshold / 1024 / 1024) + " MiB threshold"; + } else { + systemMemory = (mem.availMem / 1024 / 1204) + " MiB free, " + + (mem.threshold / 1024 / 1024) + " MiB threshold"; + } + customData.put("System memory", systemMemory); + + // Virtual machine memory + Runtime runtime = Runtime.getRuntime(); + long heap = runtime.totalMemory(); + long heapFree = runtime.freeMemory(); + long heapMax = runtime.maxMemory(); + String vmMemory = (heap / 1024 / 1024) + " MiB allocated, " + + (heapFree / 1024 / 1024) + " MiB free, " + + (heapMax / 1024 / 1024) + " MiB maximum"; + customData.put("Virtual machine memory", vmMemory); + + // Internal storage + File root = Environment.getRootDirectory(); + long rootTotal = root.getTotalSpace(); + long rootFree = root.getFreeSpace(); + String internal = (rootTotal / 1024 / 1024) + " MiB total, " + + (rootFree / 1024 / 1024) + " MiB free"; + customData.put("Internal storage", internal); + + // External storage (SD card) + File sd = Environment.getExternalStorageDirectory(); + long sdTotal = sd.getTotalSpace(); + long sdFree = sd.getFreeSpace(); + String external = (sdTotal / 1024 / 1024) + " MiB total, " + + (sdFree / 1024 / 1024) + " MiB free"; + customData.put("External storage", external); + + // Is mobile data available? + o = ctx.getSystemService(CONNECTIVITY_SERVICE); + ConnectivityManager cm = (ConnectivityManager) o; + NetworkInfo mobile = cm.getNetworkInfo(TYPE_MOBILE); + boolean mobileAvailable = mobile != null && mobile.isAvailable(); + // Is mobile data enabled? + boolean mobileEnabled = false; + try { + Class<?> clazz = Class.forName(cm.getClass().getName()); + Method method = clazz.getDeclaredMethod("getMobileDataEnabled"); + method.setAccessible(true); + mobileEnabled = (Boolean) method.invoke(cm); + } catch (ClassNotFoundException + | NoSuchMethodException + | IllegalArgumentException + | InvocationTargetException + | IllegalAccessException e) { + customData.put("Mobile data reflection exception", + e.toString()); + } + // Is mobile data connected ? + boolean mobileConnected = mobile != null && mobile.isConnected(); + + String mobileStatus; + if (mobileAvailable) mobileStatus = "Available, "; + else mobileStatus = "Not available, "; + if (mobileEnabled) mobileStatus += "enabled, "; + else mobileStatus += "not enabled, "; + if (mobileConnected) mobileStatus += "connected"; + else mobileStatus += "not connected"; + customData.put("Mobile data status", mobileStatus); + + // Is wifi available? + NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI); + boolean wifiAvailable = wifi != null && wifi.isAvailable(); + // Is wifi enabled? + o = ctx.getApplicationContext().getSystemService(WIFI_SERVICE); + WifiManager wm = (WifiManager) o; + boolean wifiEnabled = wm != null && + wm.getWifiState() == WIFI_STATE_ENABLED; + // Is wifi connected? + boolean wifiConnected = wifi != null && wifi.isConnected(); + + String wifiStatus; + if (wifiAvailable) wifiStatus = "Available, "; + else wifiStatus = "Not available, "; + if (wifiEnabled) wifiStatus += "enabled, "; + else wifiStatus += "not enabled, "; + if (wifiConnected) wifiStatus += "connected"; + else wifiStatus += "not connected"; + customData.put("Wi-Fi status", wifiStatus); + + // Is wifi direct supported? + String wifiDirectStatus = "Supported"; + if (ctx.getSystemService(WIFI_P2P_SERVICE) == null) + wifiDirectStatus = "Not supported"; + customData.put("Wi-Fi Direct", wifiDirectStatus); + + if (wm != null) { + WifiInfo wifiInfo = wm.getConnectionInfo(); + if (wifiInfo != null) { + int ip = wifiInfo.getIpAddress(); // Nice API, Google + int ip1 = ip & 0xFF; + int ip2 = (ip >> 8) & 0xFF; + int ip3 = (ip >> 16) & 0xFF; + int ip4 = (ip >> 24) & 0xFF; + String address = ip1 + "." + ip2 + "." + ip3 + "." + ip4; + customData.put("Wi-Fi address", address); + } + } + + // Is Bluetooth available? + BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); + boolean btAvailable = bt != null; + // Is Bluetooth enabled? + boolean btEnabled = bt != null && bt.isEnabled() && + !StringUtils.isNullOrEmpty(bt.getAddress()); + // Is Bluetooth connectable? + boolean btConnectable = bt != null && + (bt.getScanMode() == SCAN_MODE_CONNECTABLE || + bt.getScanMode() == + SCAN_MODE_CONNECTABLE_DISCOVERABLE); + // Is Bluetooth discoverable? + boolean btDiscoverable = bt != null && + bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE; + // Is Bluetooth LE scanning and advertising supported? + boolean btLeApi = false, btLeScan = false, btLeAdvertise = false; + if (bt != null && Build.VERSION.SDK_INT >= 21) { + btLeApi = true; + btLeScan = bt.getBluetoothLeScanner() != null; + btLeAdvertise = bt.getBluetoothLeAdvertiser() != null; + } + + String btStatus; + if (btAvailable) btStatus = "Available, "; + else btStatus = "Not available, "; + if (btEnabled) btStatus += "enabled, "; + else btStatus += "not enabled, "; + if (btConnectable) btStatus += "connectable, "; + else btStatus += "not connectable, "; + if (btDiscoverable) btStatus += "discoverable"; + else btStatus += "not discoverable"; + customData.put("Bluetooth status", btStatus); + if (btLeApi) { + String btLeStatus; + if (btLeScan) btLeStatus = "Scanning, "; + else btLeStatus = "No scanning, "; + if (btLeAdvertise) btLeStatus += "advertising"; + else btLeStatus += "no advertising"; + customData.put("Bluetooth LE status", btLeStatus); + } + + if (bt != null) { + customData.put("Bluetooth address", + scrubMacAddress(bt.getAddress())); + } + String btSettingsAddr; + try { + btSettingsAddr = Settings.Secure.getString( + ctx.getContentResolver(), "bluetooth_address"); + } catch (SecurityException e) { + btSettingsAddr = "Could not get address from settings"; + } + customData.put("Bluetooth address from settings", + scrubMacAddress(btSettingsAddr)); + + // Git commit ID + customData.put("Commit ID", BuildConfig.GitHash); + + return Collections.unmodifiableMap(customData); + } + } + + private static class SingleShotAndroidExecutor extends Thread { + + private final Runnable runnable; + + private SingleShotAndroidExecutor(Runnable runnable) { + this.runnable = runnable; + } + + @Override + public void run() { + Looper.prepare(); + Handler handler = new Handler(); + handler.post(runnable); + handler.post(() -> { + Looper looper = Looper.myLooper(); + if (looper != null) looper.quit(); + }); + Looper.loop(); + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/BriarReportSender.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/BriarReportSender.java new file mode 100644 index 0000000000000000000000000000000000000000..b26609d91f1390ef62a8892cd83065481ed3d9dc --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/BriarReportSender.java @@ -0,0 +1,51 @@ +package org.briarproject.mailbox.android.reporting; + +import android.content.Context; +import android.support.annotation.NonNull; + +import org.acra.collector.CrashReportData; +import org.acra.sender.ReportSender; +import org.acra.sender.ReportSenderException; +import org.acra.util.JSONReportBuilder.JSONReportException; +import org.briarproject.bramble.api.reporting.DevReporter; +import org.briarproject.bramble.util.AndroidUtils; +import org.briarproject.mailbox.android.AndroidComponent; + +import java.io.File; +import java.io.FileNotFoundException; + +import javax.inject.Inject; + +import static org.acra.ReportField.REPORT_ID; + +public class BriarReportSender implements ReportSender { + + private final AndroidComponent component; + + @Inject + DevReporter reporter; + + BriarReportSender(AndroidComponent component) { + this.component = component; + } + + @Override + public void send(@NonNull Context ctx, + @NonNull CrashReportData errorContent) + throws ReportSenderException { + component.inject(this); + String crashReport; + try { + crashReport = errorContent.toJSON().toString(); + } catch (JSONReportException e) { + throw new ReportSenderException("Couldn't create JSON", e); + } + try { + File reportDir = AndroidUtils.getReportDir(ctx); + String reportId = errorContent.getProperty(REPORT_ID); + reporter.encryptReportToFile(reportDir, reportId, crashReport); + } catch (FileNotFoundException e) { + throw new ReportSenderException("Failed to encrypt report", e); + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/BriarReportSenderFactory.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/BriarReportSenderFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..8a2874d801f2965a81a1b8bcd417b40221ba5ea2 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/BriarReportSenderFactory.java @@ -0,0 +1,21 @@ +package org.briarproject.mailbox.android.reporting; + +import android.content.Context; +import android.support.annotation.NonNull; + +import org.acra.config.ACRAConfiguration; +import org.acra.sender.ReportSender; +import org.acra.sender.ReportSenderFactory; +import org.briarproject.mailbox.android.MailboxApplication; + +public class BriarReportSenderFactory implements ReportSenderFactory { + + @NonNull + @Override + public ReportSender create(@NonNull Context ctx, + @NonNull ACRAConfiguration config) { + // ACRA passes in the Application as context + MailboxApplication app = (MailboxApplication) ctx; + return new BriarReportSender(app.getApplicationComponent()); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/DevReportActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/DevReportActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..4a38b17c6afe178d6ab8eb1c6deb806adb03461d --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/reporting/DevReportActivity.java @@ -0,0 +1,374 @@ +package org.briarproject.mailbox.android.reporting; + +import android.content.res.Configuration; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatDelegate; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.acra.ReportField; +import org.acra.collector.CrashReportData; +import org.acra.dialog.BaseCrashReportDialog; +import org.acra.file.CrashReportPersister; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.util.UserFeedback; + +import java.io.File; +import java.io.IOException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; +import java.util.logging.Logger; + +import static android.os.Build.VERSION.SDK_INT; +import static android.view.View.GONE; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static android.view.inputmethod.InputMethodManager.SHOW_FORCED; +import static java.util.logging.Level.WARNING; +import static org.acra.ACRAConstants.EXTRA_REPORT_FILE; +import static org.acra.ReportField.ANDROID_VERSION; +import static org.acra.ReportField.APP_VERSION_CODE; +import static org.acra.ReportField.APP_VERSION_NAME; +import static org.acra.ReportField.PACKAGE_NAME; +import static org.acra.ReportField.REPORT_ID; +import static org.acra.ReportField.STACK_TRACE; + +public class DevReportActivity extends BaseCrashReportDialog + implements CompoundButton.OnCheckedChangeListener { + + private static final Logger LOG = + Logger.getLogger(DevReportActivity.class.getName()); + + private static final String STATE_REVIEWING = "reviewing"; + private static final Set<ReportField> requiredFields = new HashSet<>(); + + static { + requiredFields.add(REPORT_ID); + requiredFields.add(APP_VERSION_CODE); + requiredFields.add(APP_VERSION_NAME); + requiredFields.add(PACKAGE_NAME); + requiredFields.add(ANDROID_VERSION); + requiredFields.add(STACK_TRACE); + } + + private AppCompatDelegate delegate; + private Set<ReportField> excludedFields = new HashSet<>(); + private EditText userCommentView = null; + private EditText userEmailView = null; + private CheckBox includeDebugReport = null; + private Button chevron = null; + private LinearLayout report = null; + private View progress = null; + private MenuItem sendReport = null; + private boolean reviewing = false; + + private AppCompatDelegate getDelegate() { + if (delegate == null) { + delegate = AppCompatDelegate.create(this, null); + } + return delegate; + } + + @Override + protected void preInit(@Nullable Bundle savedInstanceState) { + super.preInit(savedInstanceState); + getDelegate().installViewFactory(); + getDelegate().onCreate(savedInstanceState); + if (getDelegate().applyDayNight()) { + // If DayNight has been applied, we need to re-apply the theme for + // the changes to take effect. On API 23+, we should bypass + // setTheme(), which will no-op if the theme ID is identical to the + // current theme ID. + int theme = R.style.BriarTheme_NoActionBar; + if (SDK_INT >= 23) { + onApplyThemeResource(getTheme(), theme, false); + } else { + setTheme(theme); + } + } + } + + @Override + public void init(Bundle state) { + super.init(state); + + getDelegate().setContentView(R.layout.activity_dev_report); + + Toolbar tb = findViewById(R.id.toolbar); + getDelegate().setSupportActionBar(tb); + + View requestReport = findViewById(R.id.request_report); + View reportForm = findViewById(R.id.report_form); + userCommentView = findViewById(R.id.user_comment); + userEmailView = findViewById(R.id.user_email); + includeDebugReport = findViewById(R.id.include_debug_report); + chevron = findViewById(R.id.chevron); + report = findViewById(R.id.report_content); + progress = findViewById(R.id.progress_wheel); + + //noinspection ConstantConditions + getDelegate().getSupportActionBar().setTitle( + isFeedback() ? R.string.feedback_title : + R.string.crash_report_title); + userCommentView.setHint(isFeedback() ? R.string.enter_feedback : + R.string.describe_crash); + + if (isFeedback()) { + includeDebugReport + .setText(getString(R.string.include_debug_report_feedback)); + reportForm.setVisibility(VISIBLE); + requestReport.setVisibility(INVISIBLE); + } else { + includeDebugReport.setChecked(true); + reportForm.setVisibility(INVISIBLE); + requestReport.setVisibility(VISIBLE); + } + + findViewById(R.id.acceptButton).setOnClickListener(v -> { + reviewing = true; + reportForm.setVisibility(VISIBLE); + requestReport.setVisibility(INVISIBLE); + ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)) + .showSoftInput(userCommentView, SHOW_FORCED); + }); + findViewById(R.id.declineButton).setOnClickListener(v -> closeReport()); + chevron.setOnClickListener(v -> { + boolean show = + chevron.getText().equals(getString(R.string.show)); + if (show) { + chevron.setText(R.string.hide); + refresh(); + } else { + chevron.setText(R.string.show); + report.setVisibility(GONE); + } + }); + + if (state != null) + reviewing = state.getBoolean(STATE_REVIEWING, isFeedback()); + + if (!isFeedback() && !reviewing) + requestReport.setVisibility(VISIBLE); + } + + @Override + public void onPostCreate(Bundle state) { + super.onPostCreate(state); + getDelegate().onPostCreate(state); + } + + @Override + public void onStart() { + super.onStart(); + if (chevron.isSelected()) refresh(); + } + + @Override + protected void onPostResume() { + super.onPostResume(); + getDelegate().onPostResume(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu items for use in the action bar + MenuInflater inflater = getDelegate().getMenuInflater(); + inflater.inflate(R.menu.dev_report_actions, menu); + sendReport = menu.findItem(R.id.action_send_report); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle presses on the action bar items + switch (item.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + case R.id.action_send_report: + processReport(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + public void onTitleChanged(CharSequence title, int color) { + super.onTitleChanged(title, color); + getDelegate().setTitle(title); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + getDelegate().onConfigurationChanged(newConfig); + } + + @Override + public void onSaveInstanceState(Bundle state) { + super.onSaveInstanceState(state); + state.putBoolean(STATE_REVIEWING, reviewing); + } + + @Override + public void onStop() { + super.onStop(); + getDelegate().onStop(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + getDelegate().onDestroy(); + } + + @Override + public void onBackPressed() { + closeReport(); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + ReportField field = (ReportField) buttonView.getTag(); + if (field != null) { + if (isChecked) excludedFields.remove(field); + else excludedFields.add(field); + } + } + + @SuppressWarnings("ThrowableResultOfMethodCallIgnored") + private boolean isFeedback() { + return getException() instanceof UserFeedback; + } + + private void refresh() { + report.setVisibility(INVISIBLE); + progress.setVisibility(VISIBLE); + report.removeAllViews(); + new AsyncTask<Void, Void, CrashReportData>() { + + @Override + protected CrashReportData doInBackground(Void... args) { + File reportFile = (File) getIntent().getSerializableExtra( + EXTRA_REPORT_FILE); + CrashReportPersister persister = new CrashReportPersister(); + try { + return persister.load(reportFile); + } catch (IOException e) { + LOG.log(WARNING, "Could not load report file", e); + return null; + } + } + + @Override + protected void onPostExecute(CrashReportData crashData) { + LayoutInflater inflater = getLayoutInflater(); + if (crashData != null) { + for (Entry<ReportField, String> e : crashData.entrySet()) { + ReportField field = e.getKey(); + String value = e.getValue().replaceAll("\\\\n", "\n"); + boolean required = requiredFields.contains(field); + boolean excluded = excludedFields.contains(field); + View v = inflater.inflate(R.layout.list_item_crash, + report, false); + CheckBox cb = v.findViewById(R.id.include_in_report); + cb.setTag(field); + cb.setChecked(required || !excluded); + cb.setEnabled(!required); + cb.setOnCheckedChangeListener(DevReportActivity.this); + TextView title = v.findViewById(R.id.title); + title.setText(field.toString()); + TextView content = v.findViewById(R.id.content); + content.setText(value); + report.addView(v); + } + } else { + View v = inflater.inflate( + android.R.layout.simple_list_item_1, report, false); + TextView error = v.findViewById(android.R.id.text1); + error.setText(R.string.could_not_load_report_data); + report.addView(v); + } + report.setVisibility(VISIBLE); + progress.setVisibility(GONE); + } + }.execute(); + } + + private void processReport() { + userCommentView.setEnabled(false); + userEmailView.setEnabled(false); + sendReport.setEnabled(false); + progress.setVisibility(VISIBLE); + boolean includeReport = !isFeedback() || includeDebugReport.isChecked(); + new AsyncTask<Void, Void, Boolean>() { + + @Override + protected Boolean doInBackground(Void... args) { + File reportFile = (File) getIntent().getSerializableExtra( + EXTRA_REPORT_FILE); + CrashReportPersister persister = new CrashReportPersister(); + try { + CrashReportData data = persister.load(reportFile); + if (includeReport) { + for (ReportField field : excludedFields) { + LOG.info("Removing field " + field.name()); + data.remove(field); + } + } else { + Iterator<Entry<ReportField, String>> iter = + data.entrySet().iterator(); + while (iter.hasNext()) { + Entry<ReportField, String> e = iter.next(); + if (!requiredFields.contains(e.getKey())) { + iter.remove(); + } + } + } + persister.store(data, reportFile); + return true; + } catch (IOException e) { + LOG.log(WARNING, "Error processing report file", e); + return false; + } + } + + @Override + protected void onPostExecute(Boolean success) { + if (success) { + // Retrieve user's comment and email address, if any + String comment = ""; + if (userCommentView != null) + comment = userCommentView.getText().toString(); + String email = ""; + if (userEmailView != null) { + email = userEmailView.getText().toString(); + } + sendCrash(comment, email); + } + finish(); + } + }.execute(); + } + + private void closeReport() { + cancelReports(); + finish(); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/settings/SettingsActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/settings/SettingsActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..b8a563277cf5d8ffe03bc91f18e78a3129f13342 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/settings/SettingsActivity.java @@ -0,0 +1,39 @@ +package org.briarproject.mailbox.android.settings; + +import android.os.Bundle; +import android.support.v7.app.ActionBar; +import android.view.MenuItem; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BriarActivity; + +public class SettingsActivity extends BriarActivity { + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setHomeButtonEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(true); + } + + setContentView(R.layout.activity_settings); + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return false; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/settings/SettingsFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/settings/SettingsFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..ea03b41cc0adf4a11a9242a229b7a623df868c83 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/settings/SettingsFragment.java @@ -0,0 +1,603 @@ +package org.briarproject.mailbox.android.settings; + +import android.annotation.TargetApi; +import android.app.AlertDialog; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.ColorDrawable; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.StringRes; +import android.support.v14.preference.SwitchPreference; +import android.support.v4.content.ContextCompat; +import android.support.v4.text.TextUtilsCompat; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.Preference; +import android.support.v7.preference.Preference.OnPreferenceChangeListener; +import android.support.v7.preference.PreferenceFragmentCompat; +import android.support.v7.preference.PreferenceGroup; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.event.EventListener; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.plugin.BluetoothConstants; +import org.briarproject.bramble.api.plugin.TorConstants; +import org.briarproject.bramble.api.settings.Settings; +import org.briarproject.bramble.api.settings.SettingsManager; +import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.plugin.tor.CircumventionProvider; +import org.briarproject.bramble.util.StringUtils; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.Localizer; +import org.briarproject.mailbox.android.navdrawer.NavDrawerActivity; +import org.briarproject.mailbox.android.util.UiUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static android.app.Activity.RESULT_OK; +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.media.RingtoneManager.ACTION_RINGTONE_PICKER; +import static android.media.RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI; +import static android.media.RingtoneManager.EXTRA_RINGTONE_EXISTING_URI; +import static android.media.RingtoneManager.EXTRA_RINGTONE_PICKED_URI; +import static android.media.RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT; +import static android.media.RingtoneManager.EXTRA_RINGTONE_TITLE; +import static android.media.RingtoneManager.EXTRA_RINGTONE_TYPE; +import static android.media.RingtoneManager.TYPE_NOTIFICATION; +import static android.os.Build.VERSION.SDK_INT; +import static android.provider.Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS; +import static android.provider.Settings.EXTRA_APP_PACKAGE; +import static android.provider.Settings.EXTRA_CHANNEL_ID; +import static android.provider.Settings.System.DEFAULT_NOTIFICATION_URI; +import static android.support.v4.view.ViewCompat.LAYOUT_DIRECTION_LTR; +import static android.widget.Toast.LENGTH_SHORT; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_BT_ENABLE; +import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_MOBILE; +import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK; +import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_AUTOMATIC; +import static org.briarproject.bramble.util.LogUtils.logDuration; +import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.bramble.util.LogUtils.now; +import static org.briarproject.mailbox.android.TestingConstants.FEATURE_FLAG_DARK_THEME; +import static org.briarproject.mailbox.android.TestingConstants.FEATURE_FLAG_PIN_LOCK; +import static org.briarproject.mailbox.android.TestingConstants.FEATURE_FLAG_SIGN_IN_REMINDER; +import static org.briarproject.mailbox.android.TestingConstants.IS_DEBUG_BUILD; +import static org.briarproject.mailbox.android.activity.RequestCodes.REQUEST_RINGTONE; +import static org.briarproject.mailbox.android.navdrawer.NavDrawerActivity.INTENT_SIGN_OUT; +import static org.briarproject.mailbox.android.util.UiUtils.hasScreenLock; +import static org.briarproject.mailbox.android.util.UiUtils.triggerFeedback; +import static org.briarproject.mailbox.api.android.AndroidNotificationManager.PREF_NOTIFY_LOCK_SCREEN; +import static org.briarproject.mailbox.api.android.AndroidNotificationManager.PREF_NOTIFY_RINGTONE_NAME; +import static org.briarproject.mailbox.api.android.AndroidNotificationManager.PREF_NOTIFY_RINGTONE_URI; +import static org.briarproject.mailbox.api.android.AndroidNotificationManager.PREF_NOTIFY_SOUND; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class SettingsFragment extends PreferenceFragmentCompat + implements EventListener, OnPreferenceChangeListener { + + public static final String SETTINGS_NAMESPACE = "android-ui"; + public static final String BT_NAMESPACE = BluetoothConstants.ID.getString(); + public static final String TOR_NAMESPACE = TorConstants.ID.getString(); + public static final String LANGUAGE = "pref_key_language"; + public static final String PREF_SCREEN_LOCK = "pref_key_lock"; + public static final String PREF_SCREEN_LOCK_TIMEOUT = + "pref_key_lock_timeout"; + public static final String NOTIFY_SIGN_IN = "pref_key_notify_sign_in"; + public static final String TOR_NETWORK = "pref_key_tor_network"; + public static final String TOR_MOBILE = "pref_key_tor_mobile_data"; + + private static final Logger LOG = + Logger.getLogger(SettingsFragment.class.getName()); + + private SettingsActivity listener; + private ListPreference language; + private ListPreference enableBluetooth; + private ListPreference torNetwork; + private SwitchPreference torMobile; + private SwitchPreference screenLock; + private ListPreference screenLockTimeout; + private SwitchPreference notifyPrivateMessages; + private SwitchPreference notifyGroupMessages; + private SwitchPreference notifyForumPosts; + private SwitchPreference notifyBlogPosts; + private SwitchPreference notifyVibration; + private SwitchPreference notifyLockscreen; + + private Preference notifySound; + + // Fields that are accessed from background threads must be volatile + volatile Settings settings; + @Inject + volatile SettingsManager settingsManager; + @Inject + volatile EventBus eventBus; + @Inject + LocationUtils locationUtils; + @Inject + CircumventionProvider circumventionProvider; + + @Inject + AndroidExecutor androidExecutor; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + listener = (SettingsActivity) context; + // we need to inject here, + // because onActivityCreated() is called after onCreatePreferences() + listener.getActivityComponent().inject(this); + } + + @Override + public void onCreatePreferences(Bundle bundle, String s) { + addPreferencesFromResource(R.xml.settings); + + language = (ListPreference) findPreference(LANGUAGE); + setLanguageEntries(); + ListPreference theme = + (ListPreference) findPreference("pref_key_theme"); + enableBluetooth = (ListPreference) findPreference("pref_key_bluetooth"); + torNetwork = (ListPreference) findPreference(TOR_NETWORK); + torMobile = (SwitchPreference) findPreference(TOR_MOBILE); + SwitchPreference notifySignIn = + (SwitchPreference) findPreference(NOTIFY_SIGN_IN); + screenLock = (SwitchPreference) findPreference(PREF_SCREEN_LOCK); + screenLockTimeout = + (ListPreference) findPreference(PREF_SCREEN_LOCK_TIMEOUT); + notifyPrivateMessages = (SwitchPreference) findPreference( + "pref_key_notify_private_messages"); + notifyGroupMessages = (SwitchPreference) findPreference( + "pref_key_notify_group_messages"); + notifyForumPosts = (SwitchPreference) findPreference( + "pref_key_notify_forum_posts"); + notifyBlogPosts = (SwitchPreference) findPreference( + "pref_key_notify_blog_posts"); + notifyVibration = (SwitchPreference) findPreference( + "pref_key_notify_vibration"); + notifyLockscreen = (SwitchPreference) findPreference( + "pref_key_notify_lock_screen"); + notifySound = findPreference("pref_key_notify_sound"); + + language.setOnPreferenceChangeListener(this); + theme.setOnPreferenceChangeListener((preference, newValue) -> { + if (getActivity() != null) { + // activate new theme + UiUtils.setTheme(getActivity(), (String) newValue); + // bring up parent activity, so it can change its theme as well + // upstream bug: https://issuetracker.google.com/issues/38352704 + Intent intent = + new Intent(getActivity(), NavDrawerActivity.class); + intent.setFlags( + FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + // bring this activity back to the foreground + intent = new Intent(getActivity(), getActivity().getClass()); + startActivity(intent); + getActivity().finish(); + } + return true; + }); + enableBluetooth.setOnPreferenceChangeListener(this); + torNetwork.setOnPreferenceChangeListener(this); + torMobile.setOnPreferenceChangeListener(this); + screenLock.setOnPreferenceChangeListener(this); + screenLockTimeout.setOnPreferenceChangeListener(this); + if (SDK_INT >= 21) { + notifyLockscreen.setVisible(true); + notifyLockscreen.setOnPreferenceChangeListener(this); + } + + findPreference("pref_key_send_feedback").setOnPreferenceClickListener( + preference -> { + triggerFeedback(androidExecutor); + return true; + }); + + if (IS_DEBUG_BUILD) { + findPreference("pref_key_explode").setOnPreferenceClickListener( + preference -> { + throw new RuntimeException("Boom!"); + } + ); + } else { + theme.setVisible(FEATURE_FLAG_DARK_THEME); + notifySignIn.setVisible(FEATURE_FLAG_SIGN_IN_REMINDER); + screenLock.setVisible(FEATURE_FLAG_PIN_LOCK); + screenLockTimeout.setVisible(FEATURE_FLAG_PIN_LOCK); + + findPreference("pref_key_explode").setVisible(false); + findPreference("pref_key_test_data").setVisible(false); + PreferenceGroup testing = + findPreference("pref_key_explode").getParent(); + if (testing == null) throw new AssertionError(); + testing.setVisible(false); + } + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + ColorDrawable divider = new ColorDrawable( + ContextCompat.getColor(getContext(), R.color.divider)); + setDivider(divider); + return view; + } + + @Override + public void onStart() { + super.onStart(); + eventBus.addListener(this); + setSettingsEnabled(false); + loadSettings(); + } + + @Override + public void onStop() { + super.onStop(); + eventBus.removeListener(this); + } + + private void setLanguageEntries() { + CharSequence[] tags = language.getEntryValues(); + List<CharSequence> entries = new ArrayList<>(tags.length); + List<CharSequence> entryValues = new ArrayList<>(tags.length); + for (CharSequence cs : tags) { + String tag = cs.toString(); + if (tag.equals("default")) { + entries.add(getString(R.string.pref_language_default)); + entryValues.add(tag); + continue; + } + Locale locale = Localizer.getLocaleFromTag(tag); + if (locale == null) + throw new IllegalStateException(); + // Exclude RTL locales on API < 17, they won't be laid out correctly + if (SDK_INT < 17 && !isLeftToRight(locale)) { + if (LOG.isLoggable(INFO)) + LOG.info("Skipping RTL locale " + tag); + continue; + } + String nativeName = locale.getDisplayName(locale); + // Fallback to English if the name is unknown in both native and + // current locale. + if (nativeName.equals(tag)) { + String tmp = locale.getDisplayLanguage(Locale.ENGLISH); + if (!tmp.isEmpty() && !tmp.equals(nativeName)) + nativeName = tmp; + } + // Prefix with LRM marker to prevent any RTL direction + entries.add("\u200E" + nativeName.substring(0, 1).toUpperCase() + + nativeName.substring(1)); + entryValues.add(tag); + } + language.setEntries(entries.toArray(new CharSequence[0])); + language.setEntryValues(entryValues.toArray(new CharSequence[0])); + } + + private boolean isLeftToRight(Locale locale) { + // TextUtilsCompat returns the wrong direction for Hebrew on some phones + String language = locale.getLanguage(); + if (language.equals("iw") || language.equals("he")) return false; + int direction = TextUtilsCompat.getLayoutDirectionFromLocale(locale); + return direction == LAYOUT_DIRECTION_LTR; + } + + private void setTorNetworkSummary(int torNetworkSetting) { + if (torNetworkSetting != PREF_TOR_NETWORK_AUTOMATIC) { + torNetwork.setSummary("%s"); // use setting value + return; + } + + // Look up country name in the user's chosen language if available + String country = locationUtils.getCurrentCountry(); + String countryName = country; + for (Locale locale : Locale.getAvailableLocales()) { + if (locale.getCountry().equalsIgnoreCase(country)) { + countryName = locale.getDisplayCountry(); + break; + } + } + boolean blocked = + circumventionProvider.isTorProbablyBlocked(country); + boolean useBridges = circumventionProvider.doBridgesWork(country); + String setting = + getString(R.string.tor_network_setting_without_bridges); + if (blocked && useBridges) { + setting = getString(R.string.tor_network_setting_with_bridges); + } else if (blocked) { + setting = getString(R.string.tor_network_setting_never); + } + torNetwork.setSummary( + getString(R.string.tor_network_setting_summary, setting, + countryName)); + } + + private void loadSettings() { + listener.runOnDbThread(() -> { + try { + long start = now(); + settings = settingsManager.getSettings(SETTINGS_NAMESPACE); + Settings btSettings = settingsManager.getSettings(BT_NAMESPACE); + Settings torSettings = + settingsManager.getSettings(TOR_NAMESPACE); + logDuration(LOG, "Loading settings", start); + boolean btSetting = + btSettings.getBoolean(PREF_BT_ENABLE, false); + int torNetworkSetting = torSettings.getInt(PREF_TOR_NETWORK, + PREF_TOR_NETWORK_AUTOMATIC); + boolean torMobileSetting = + torSettings.getBoolean(PREF_TOR_MOBILE, true); + displaySettings(btSetting, torNetworkSetting, torMobileSetting); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + private void displaySettings(boolean btSetting, int torNetworkSetting, + boolean torMobileSetting) { + listener.runOnUiThreadUnlessDestroyed(() -> { + enableBluetooth.setValue(Boolean.toString(btSetting)); + torNetwork.setValue(Integer.toString(torNetworkSetting)); + setTorNetworkSummary(torNetworkSetting); + torMobile.setChecked(torMobileSetting); + displayScreenLockSetting(); + + if (SDK_INT < 26) { + notifyLockscreen.setChecked(settings.getBoolean( + PREF_NOTIFY_LOCK_SCREEN, false)); + } else { + notifyLockscreen.setVisible(false); + } + setSettingsEnabled(true); + }); + } + + private void setSettingsEnabled(boolean enabled) { + // preferences not needed here, because handled by SharedPreferences: + // - pref_key_theme + // - pref_key_notify_sign_in + // preferences partly needed here, because they have their own logic + // - pref_key_lock (screenLock -> displayScreenLockSetting()) + // - pref_key_lock_timeout (screenLockTimeout) + enableBluetooth.setEnabled(enabled); + torNetwork.setEnabled(enabled); + torMobile.setEnabled(enabled); + if (!enabled) screenLock.setEnabled(false); + notifyPrivateMessages.setEnabled(enabled); + notifyGroupMessages.setEnabled(enabled); + notifyForumPosts.setEnabled(enabled); + notifyBlogPosts.setEnabled(enabled); + notifyVibration.setEnabled(enabled); + notifyLockscreen.setEnabled(enabled); + notifySound.setEnabled(enabled); + } + + private void displayScreenLockSetting() { + if (SDK_INT < 21) { + screenLock.setVisible(false); + screenLockTimeout.setVisible(false); + } else { + if (getActivity() != null && hasScreenLock(getActivity())) { + screenLock.setEnabled(true); + screenLock.setChecked( + settings.getBoolean(PREF_SCREEN_LOCK, false)); + screenLock.setSummary(R.string.pref_lock_summary); + } else { + screenLock.setEnabled(false); + screenLock.setChecked(false); + screenLock.setSummary(R.string.pref_lock_disabled_summary); + } + // timeout depends on screenLock and gets disabled automatically + int timeout = settings.getInt(PREF_SCREEN_LOCK_TIMEOUT, + Integer.valueOf(getString( + R.string.pref_lock_timeout_value_default))); + String newValue = String.valueOf(timeout); + screenLockTimeout.setValue(newValue); + setScreenLockTimeoutSummary(newValue); + } + } + + private void setScreenLockTimeoutSummary(String timeout) { + String never = getString(R.string.pref_lock_timeout_value_never); + if (timeout.equals(never)) { + screenLockTimeout + .setSummary(R.string.pref_lock_timeout_never_summary); + } else { + screenLockTimeout + .setSummary(R.string.pref_lock_timeout_summary); + } + } + + @TargetApi(26) + private void setupNotificationPreference(SwitchPreference pref, + String channelId, @StringRes int summary) { + pref.setWidgetLayoutResource(0); + pref.setSummary(summary); + pref.setOnPreferenceClickListener(clickedPref -> { + Intent intent = new Intent(ACTION_CHANNEL_NOTIFICATION_SETTINGS) + .putExtra(EXTRA_APP_PACKAGE, getContext().getPackageName()) + .putExtra(EXTRA_CHANNEL_ID, channelId); + startActivity(intent); + return true; + }); + } + + private boolean onNotificationSoundClicked() { + String title = getString(R.string.choose_ringtone_title); + Intent i = new Intent(ACTION_RINGTONE_PICKER); + i.putExtra(EXTRA_RINGTONE_TYPE, TYPE_NOTIFICATION); + i.putExtra(EXTRA_RINGTONE_TITLE, title); + i.putExtra(EXTRA_RINGTONE_DEFAULT_URI, + DEFAULT_NOTIFICATION_URI); + i.putExtra(EXTRA_RINGTONE_SHOW_SILENT, true); + if (settings.getBoolean(PREF_NOTIFY_SOUND, true)) { + Uri uri; + String ringtoneUri = + settings.get(PREF_NOTIFY_RINGTONE_URI); + if (StringUtils.isNullOrEmpty(ringtoneUri)) + uri = DEFAULT_NOTIFICATION_URI; + else uri = Uri.parse(ringtoneUri); + i.putExtra(EXTRA_RINGTONE_EXISTING_URI, uri); + } + startActivityForResult(i, REQUEST_RINGTONE); + return true; + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (preference == language) { + if (!language.getValue().equals(newValue)) + languageChanged((String) newValue); + return false; + } else if (preference == enableBluetooth) { + boolean btSetting = Boolean.valueOf((String) newValue); + storeBluetoothSettings(btSetting); + } else if (preference == torNetwork) { + int torNetworkSetting = Integer.valueOf((String) newValue); + storeTorNetworkSetting(torNetworkSetting); + setTorNetworkSummary(torNetworkSetting); + } else if (preference == torMobile) { + boolean torMobileSetting = (Boolean) newValue; + storeTorMobileSetting(torMobileSetting); + } else if (preference == screenLock) { + Settings s = new Settings(); + s.putBoolean(PREF_SCREEN_LOCK, (Boolean) newValue); + storeSettings(s); + } else if (preference == screenLockTimeout) { + Settings s = new Settings(); + String value = (String) newValue; + s.putInt(PREF_SCREEN_LOCK_TIMEOUT, Integer.valueOf(value)); + storeSettings(s); + setScreenLockTimeoutSummary(value); + } else if (preference == notifyLockscreen) { + Settings s = new Settings(); + s.putBoolean(PREF_NOTIFY_LOCK_SCREEN, (Boolean) newValue); + storeSettings(s); + } + return true; + } + + private void languageChanged(String newValue) { + AlertDialog.Builder builder = + new AlertDialog.Builder(getActivity()); + builder.setTitle(R.string.pref_language_title); + builder.setMessage(R.string.pref_language_changed); + builder.setPositiveButton(R.string.sign_out_button, + (dialogInterface, i) -> { + language.setValue(newValue); + Intent intent = new Intent(getContext(), + NavDrawerActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.putExtra(INTENT_SIGN_OUT, true); + getActivity().startActivity(intent); + getActivity().finish(); + }); + builder.setNegativeButton(R.string.cancel, null); + builder.setCancelable(false); + builder.show(); + } + + private void storeTorNetworkSetting(int torNetworkSetting) { + Settings s = new Settings(); + s.putInt(PREF_TOR_NETWORK, torNetworkSetting); + mergeSettings(s, TOR_NAMESPACE); + } + + private void storeTorMobileSetting(boolean torMobileSetting) { + Settings s = new Settings(); + s.putBoolean(PREF_TOR_MOBILE, torMobileSetting); + mergeSettings(s, TOR_NAMESPACE); + } + + private void storeBluetoothSettings(boolean btSetting) { + Settings s = new Settings(); + s.putBoolean(PREF_BT_ENABLE, btSetting); + mergeSettings(s, BT_NAMESPACE); + } + + private void storeSettings(Settings s) { + mergeSettings(s, SETTINGS_NAMESPACE); + } + + private void mergeSettings(Settings s, String namespace) { + listener.runOnDbThread(() -> { + try { + long start = now(); + settingsManager.mergeSettings(s, namespace); + logDuration(LOG, "Merging settings", start); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + @Override + public void onActivityResult(int request, int result, Intent data) { + super.onActivityResult(request, result, data); + if (request == REQUEST_RINGTONE && result == RESULT_OK) { + Settings s = new Settings(); + Uri uri = data.getParcelableExtra(EXTRA_RINGTONE_PICKED_URI); + if (uri == null) { + // The user chose silence + s.putBoolean(PREF_NOTIFY_SOUND, false); + s.put(PREF_NOTIFY_RINGTONE_NAME, ""); + s.put(PREF_NOTIFY_RINGTONE_URI, ""); + } else if (RingtoneManager.isDefault(uri)) { + // The user chose the default + s.putBoolean(PREF_NOTIFY_SOUND, true); + s.put(PREF_NOTIFY_RINGTONE_NAME, ""); + s.put(PREF_NOTIFY_RINGTONE_URI, ""); + } else { + // The user chose a ringtone other than the default + Ringtone r = RingtoneManager.getRingtone(getContext(), uri); + if (r == null) { + Toast.makeText(getContext(), R.string.cannot_load_ringtone, + LENGTH_SHORT).show(); + } else { + String name = r.getTitle(getContext()); + s.putBoolean(PREF_NOTIFY_SOUND, true); + s.put(PREF_NOTIFY_RINGTONE_NAME, name); + s.put(PREF_NOTIFY_RINGTONE_URI, uri.toString()); + } + } + storeSettings(s); + } + } + + @Override + public void eventOccurred(Event e) { + if (e instanceof SettingsUpdatedEvent) { + String namespace = ((SettingsUpdatedEvent) e).getNamespace(); + if (namespace.equals(BT_NAMESPACE) + || namespace.equals(TOR_NAMESPACE) + || namespace.equals(SETTINGS_NAMESPACE)) { + LOG.info("Settings updated"); + loadSettings(); + } + } + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/splash/ExpiredActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/splash/ExpiredActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..e14d58840ec8f72010fc684afaf6b49655f45141 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/splash/ExpiredActivity.java @@ -0,0 +1,35 @@ +package org.briarproject.mailbox.android.splash; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.View.OnClickListener; + +import org.briarproject.mailbox.R; + +import static android.content.Intent.ACTION_VIEW; +import static android.view.WindowManager.LayoutParams.FLAG_SECURE; +import static org.briarproject.mailbox.android.TestingConstants.PREVENT_SCREENSHOTS; + +public class ExpiredActivity extends AppCompatActivity + implements OnClickListener { + + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + + if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE); + + setContentView(R.layout.activity_expired); + findViewById(R.id.download_briar_button).setOnClickListener(this); + } + + @Override + public void onClick(View v) { + Uri uri = Uri.parse("https://briarproject.org/download.html"); + startActivity(new Intent(ACTION_VIEW, uri)); + finish(); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/splash/SplashScreenActivity.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/splash/SplashScreenActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..76ccb5defb6df2b577e5b81a031cb44a46e2b930 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/splash/SplashScreenActivity.java @@ -0,0 +1,102 @@ +package org.briarproject.mailbox.android.splash; + +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.support.v7.preference.PreferenceManager; +import android.transition.Fade; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.activity.ActivityComponent; +import org.briarproject.mailbox.android.activity.BaseActivity; +import org.briarproject.mailbox.android.login.OpenDatabaseActivity; +import org.briarproject.mailbox.android.login.SetupActivity; +import org.briarproject.mailbox.android.navdrawer.NavDrawerActivity; +import org.briarproject.mailbox.api.android.LockManager; + +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static org.briarproject.mailbox.android.TestingConstants.EXPIRY_DATE; + +public class SplashScreenActivity extends BaseActivity { + + private static final Logger LOG = + Logger.getLogger(SplashScreenActivity.class.getName()); + + @Inject + protected AccountManager accountManager; + @Inject + protected LockManager lockManager; + @Inject + protected AndroidExecutor androidExecutor; + + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + + if (Build.VERSION.SDK_INT >= 21) { + getWindow().setExitTransition(new Fade()); + } + + setPreferencesDefaults(); + + setContentView(R.layout.splash); + + if (accountManager.hasDatabaseKey()) { + Intent i; + if (lockManager.isLocked()) { + // The database needs to be opened for the app to be locked. + // Start main activity right away. It will open UnlockActivity. + // Otherwise, we would end up with two screen unlock inputs. + i = new Intent(this, NavDrawerActivity.class); + } else { + i = new Intent(this, OpenDatabaseActivity.class); + } + startActivity(i); + finish(); + } else { + new Handler().postDelayed(() -> { + startNextActivity(); + supportFinishAfterTransition(); + }, 500); + } + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + protected void startNextActivity() { + if (System.currentTimeMillis() >= EXPIRY_DATE) { + LOG.info("Expired"); + startActivity(new Intent(this, ExpiredActivity.class)); + } else { + if (accountManager.accountExists()) { + LOG.info("Account exists"); + startActivity(new Intent(this, OpenDatabaseActivity.class)); + } else { + LOG.info("Account does not exist"); + accountManager.deleteAccount(); + startActivity(new Intent(this, SetupActivity.class)); + } + } + } + + private void setPreferencesDefaults() { + androidExecutor.runOnBackgroundThread(() -> + PreferenceManager.setDefaultValues(SplashScreenActivity.this, + R.xml.panic_preferences, false)); + } + + // Don't show any warnings here + @Override + public boolean shouldAllowTap() { + return true; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/BriarAdapter.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/BriarAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..38bc5e50298cd734fabfc576e4057536e47d0e7b --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/BriarAdapter.java @@ -0,0 +1,127 @@ +package org.briarproject.mailbox.android.util; + +import android.content.Context; +import android.support.annotation.UiThread; +import android.support.v7.util.SortedList; +import android.support.v7.widget.RecyclerView.Adapter; +import android.support.v7.widget.RecyclerView.ViewHolder; + +import java.util.Collection; + +import javax.annotation.Nullable; + +import static android.support.v7.util.SortedList.INVALID_POSITION; + +public abstract class BriarAdapter<T, V extends ViewHolder> + extends Adapter<V> implements VersionedAdapter { + + protected final Context ctx; + protected final SortedList<T> items; + + private volatile int revision = 0; + + public BriarAdapter(Context ctx, Class<T> c) { + this.ctx = ctx; + this.items = new SortedList<>(c, new SortedList.Callback<T>() { + @Override + public int compare(T item1, T item2) { + return BriarAdapter.this.compare(item1, item2); + } + + @Override + public void onInserted(int position, int count) { + notifyItemRangeInserted(position, count); + } + + @Override + public void onRemoved(int position, int count) { + notifyItemRangeRemoved(position, count); + } + + @Override + public void onMoved(int fromPosition, int toPosition) { + notifyItemMoved(fromPosition, toPosition); + } + + @Override + public void onChanged(int position, int count) { + notifyItemRangeChanged(position, count); + } + + @Override + public boolean areContentsTheSame(T item1, T item2) { + return BriarAdapter.this.areContentsTheSame(item1, item2); + } + + @Override + public boolean areItemsTheSame(T item1, T item2) { + return BriarAdapter.this.areItemsTheSame(item1, item2); + } + }); + } + + public abstract int compare(T item1, T item2); + + public abstract boolean areContentsTheSame(T item1, T item2); + + public abstract boolean areItemsTheSame(T item1, T item2); + + @Override + public int getItemCount() { + return items.size(); + } + + public void add(T item) { + items.add(item); + } + + public void addAll(Collection<T> items) { + this.items.addAll(items); + } + + public void setItems(Collection<T> items) { + this.items.beginBatchedUpdates(); + this.items.clear(); + this.items.addAll(items); + this.items.endBatchedUpdates(); + } + + @Nullable + public T getItemAt(int position) { + if (position == INVALID_POSITION || position >= items.size()) { + return null; + } + return items.get(position); + } + + public int findItemPosition(T item) { + return items.indexOf(item); + } + + public void updateItemAt(int position, T item) { + items.updateItemAt(position, item); + } + + public void remove(T item) { + items.remove(item); + } + + public void clear() { + items.clear(); + } + + public boolean isEmpty() { + return items.size() == 0; + } + + @Override + public int getRevision() { + return revision; + } + + @UiThread + @Override + public void incrementRevision() { + revision++; + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/BriarNotificationBuilder.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/BriarNotificationBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..a1dd8b965e0d04ce4d177958f5a76f9c32cc366c --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/BriarNotificationBuilder.java @@ -0,0 +1,42 @@ +package org.briarproject.mailbox.android.util; + +import android.content.Context; +import android.os.Build; +import android.support.annotation.ColorRes; +import android.support.v4.app.NotificationCompat; +import android.support.v4.content.ContextCompat; + +import org.briarproject.mailbox.R; + +import static android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE; +import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET; + + +public class BriarNotificationBuilder extends NotificationCompat.Builder { + + public BriarNotificationBuilder(Context context, String channelId) { + super(context, channelId); + // Auto-cancel does not fire the delete intent, see + // https://issuetracker.google.com/issues/36961721 + setAutoCancel(true); + + setLights(ContextCompat.getColor(context, R.color.briar_green_light), + 750, 500); + } + + public BriarNotificationBuilder setColorRes(@ColorRes int res) { + setColor(ContextCompat.getColor(mContext, res)); + return this; + } + + public BriarNotificationBuilder setLockscreenVisibility(String category, + boolean show) { + if (Build.VERSION.SDK_INT >= 21) { + setCategory(category); + if (show) setVisibility(VISIBILITY_PRIVATE); + else setVisibility(VISIBILITY_SECRET); + } + return this; + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/UiUtils.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/UiUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..920ee1aafbd0e3226d877858ffc4fcb075af9f67 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/UiUtils.java @@ -0,0 +1,280 @@ +package org.briarproject.mailbox.android.util; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.KeyguardManager; +import android.content.Context; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.net.Uri; +import android.os.PowerManager; +import android.support.annotation.AttrRes; +import android.support.annotation.ColorInt; +import android.support.annotation.ColorRes; +import android.support.design.widget.TextInputLayout; +import android.support.v4.app.FragmentManager; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog; +import android.text.Html; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.format.DateUtils; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +import android.text.style.ForegroundColorSpan; +import android.text.style.URLSpan; +import android.util.TypedValue; +import android.view.View; +import android.widget.TextView; + +import org.acra.ACRA; +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.view.ArticleMovementMethod; +import org.briarproject.mailbox.android.widget.LinkDialogFragment; + +import javax.annotation.Nullable; + +import static android.content.Context.KEYGUARD_SERVICE; +import static android.content.Context.POWER_SERVICE; +import static android.content.Intent.CATEGORY_DEFAULT; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.os.Build.MANUFACTURER; +import static android.os.Build.VERSION.SDK_INT; +import static android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS; +import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_AUTO; +import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM; +import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_NO; +import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_YES; +import static android.support.v7.app.AppCompatDelegate.setDefaultNightMode; +import static android.text.format.DateUtils.DAY_IN_MILLIS; +import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH; +import static android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE; +import static android.text.format.DateUtils.FORMAT_ABBREV_TIME; +import static android.text.format.DateUtils.FORMAT_SHOW_DATE; +import static android.text.format.DateUtils.MINUTE_IN_MILLIS; +import static android.text.format.DateUtils.WEEK_IN_MILLIS; +import static org.briarproject.mailbox.BuildConfig.APPLICATION_ID; +import static org.briarproject.mailbox.android.TestingConstants.EXPIRY_DATE; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class UiUtils { + + public static final long MIN_DATE_RESOLUTION = MINUTE_IN_MILLIS; + public static final int TEASER_LENGTH = 320; + public static final float GREY_OUT = 0.5f; + + public static void setError(TextInputLayout til, @Nullable String error, + boolean set) { + if (set) { + if (til.getError() == null) til.setError(error); + } else { + til.setError(null); + } + } + + public static String formatDate(Context ctx, long time) { + int flags = FORMAT_ABBREV_RELATIVE | + FORMAT_SHOW_DATE | FORMAT_ABBREV_TIME | FORMAT_ABBREV_MONTH; + + long diff = System.currentTimeMillis() - time; + if (diff < MIN_DATE_RESOLUTION) return ctx.getString(R.string.now); + if (diff >= DAY_IN_MILLIS && diff < WEEK_IN_MILLIS) { + // also show time when older than a day, but newer than a week + return DateUtils.getRelativeDateTimeString(ctx, time, + MIN_DATE_RESOLUTION, WEEK_IN_MILLIS, flags).toString(); + } + // otherwise just show "...ago" or date string + return DateUtils.getRelativeTimeSpanString(time, + System.currentTimeMillis(), + MIN_DATE_RESOLUTION, flags).toString(); + } + + public static int getDaysUntilExpiry() { + long now = System.currentTimeMillis(); + long daysBeforeExpiry = (EXPIRY_DATE - now) / 1000 / 60 / 60 / 24; + return (int) daysBeforeExpiry; + } + + public static SpannableStringBuilder getTeaser(Context ctx, Spanned body) { + if (body.length() < TEASER_LENGTH) + throw new IllegalArgumentException( + "String is shorter than TEASER_LENGTH"); + + SpannableStringBuilder builder = + new SpannableStringBuilder(body.subSequence(0, TEASER_LENGTH)); + String ellipsis = ctx.getString(R.string.ellipsis); + builder.append(ellipsis).append(" "); + + Spannable readMore = new SpannableString( + ctx.getString(R.string.read_more) + ellipsis); + ForegroundColorSpan fg = new ForegroundColorSpan( + ContextCompat.getColor(ctx, R.color.briar_text_link)); + readMore.setSpan(fg, 0, readMore.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.append(readMore); + + return builder; + } + + public static Spanned getSpanned(String s) { + return Html.fromHtml(s); + } + + public static void makeLinksClickable(TextView v, + @Nullable FragmentManager fm) { + if (fm == null) return; + SpannableStringBuilder ssb = new SpannableStringBuilder(v.getText()); + URLSpan[] spans = ssb.getSpans(0, ssb.length(), URLSpan.class); + for (URLSpan span : spans) { + int start = ssb.getSpanStart(span); + int end = ssb.getSpanEnd(span); + String url = span.getURL(); + ssb.removeSpan(span); + ClickableSpan cSpan = new ClickableSpan() { + @Override + public void onClick(View v2) { + LinkDialogFragment f = LinkDialogFragment.newInstance(url); + f.show(fm, f.getUniqueTag()); + } + }; + ssb.setSpan(cSpan, start, end, 0); + } + v.setText(ssb); + v.setMovementMethod(ArticleMovementMethod.getInstance()); + } + + /** + * Executes the runnable when clicking the link in the textView's text. + * + * Attention: This assumes that there's only <b>one</b> link in the text. + */ + public static void onSingleLinkClick(TextView textView, Runnable runnable) { + SpannableStringBuilder ssb = + new SpannableStringBuilder(textView.getText()); + ClickableSpan[] spans = + ssb.getSpans(0, ssb.length(), ClickableSpan.class); + if (spans.length != 1) throw new AssertionError(); + ClickableSpan span = spans[0]; + int start = ssb.getSpanStart(span); + int end = ssb.getSpanEnd(span); + ssb.removeSpan(span); + ClickableSpan cSpan = new ClickableSpan() { + @Override + public void onClick(View v) { + runnable.run(); + } + }; + ssb.setSpan(cSpan, start + 1, end, 0); + textView.setText(ssb); + textView.setMovementMethod(new LinkMovementMethod()); + } + + public static String getAvatarTransitionName(ContactId c) { + return "avatar" + c.getInt(); + } + + public static String getBulbTransitionName(ContactId c) { + return "bulb" + c.getInt(); + } + + public static OnClickListener getGoToSettingsListener(Context context) { + return (dialog, which) -> { + Intent i = new Intent(); + i.setAction("android.settings.APPLICATION_DETAILS_SETTINGS"); + i.addCategory(CATEGORY_DEFAULT); + i.setData(Uri.parse("package:" + APPLICATION_ID)); + i.addFlags(FLAG_ACTIVITY_NEW_TASK); + context.startActivity(i); + }; + } + + public static void showOnboardingDialog(Context ctx, String text) { + new AlertDialog.Builder(ctx, R.style.OnboardingDialogTheme) + .setMessage(text) + .setNeutralButton(R.string.got_it, + (dialog, which) -> dialog.cancel()) + .show(); + } + + public static boolean needsDozeWhitelisting(Context ctx) { + if (SDK_INT < 23) return false; + PowerManager pm = (PowerManager) ctx.getSystemService(POWER_SERVICE); + String packageName = ctx.getPackageName(); + if (pm == null) throw new AssertionError(); + return !pm.isIgnoringBatteryOptimizations(packageName); + } + + @TargetApi(23) + @SuppressLint("BatteryLife") + public static Intent getDozeWhitelistingIntent(Context ctx) { + Intent i = new Intent(); + i.setAction(ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); + i.setData(Uri.parse("package:" + ctx.getPackageName())); + return i; + } + + public static boolean isSamsung7() { + return SDK_INT == 24 && MANUFACTURER.equalsIgnoreCase("Samsung"); + } + + public static void setFilterTouchesWhenObscured(View v, boolean filter) { + v.setFilterTouchesWhenObscured(filter); + // Workaround for Android bug #13530806, see + // https://android.googlesource.com/platform/frameworks/base/+/aba566589e0011c4b973c0d4f77be4e9ee176089%5E%21/core/java/android/view/View.java + if (v.getFilterTouchesWhenObscured() != filter) + v.setFilterTouchesWhenObscured(!filter); + } + + public static void setTheme(Context ctx, String theme) { + if (theme.equals(ctx.getString(R.string.pref_theme_light_value))) { + setDefaultNightMode(MODE_NIGHT_NO); + } else if (theme + .equals(ctx.getString(R.string.pref_theme_dark_value))) { + setDefaultNightMode(MODE_NIGHT_YES); + } else if (theme + .equals(ctx.getString(R.string.pref_theme_auto_value))) { + setDefaultNightMode(MODE_NIGHT_AUTO); + } else if (theme + .equals(ctx.getString(R.string.pref_theme_system_value))) { + setDefaultNightMode(MODE_NIGHT_FOLLOW_SYSTEM); + } + } + + public static int resolveAttribute(Context ctx, @AttrRes int attr) { + TypedValue outValue = new TypedValue(); + ctx.getTheme().resolveAttribute(attr, outValue, true); + return outValue.resourceId; + } + + @ColorInt + public static int resolveColorAttribute(Context ctx, @AttrRes int res) { + @ColorRes + int color = resolveAttribute(ctx, res); + return ContextCompat.getColor(ctx, color); + } + + public static boolean hasScreenLock(Context ctx) { + if (SDK_INT < 21) return false; + KeyguardManager keyguardManager = + (KeyguardManager) ctx.getSystemService(KEYGUARD_SERVICE); + if (keyguardManager == null) return false; + // check if there's a lock mechanism we can use + // first one is true if SIM card is locked, so use second if available + return (SDK_INT < 23 && keyguardManager.isKeyguardSecure()) || + (SDK_INT >= 23 && keyguardManager.isDeviceSecure()); + } + + public static void triggerFeedback(AndroidExecutor androidExecutor) { + androidExecutor.runOnBackgroundThread( + () -> ACRA.getErrorReporter() + .handleException(new UserFeedback(), false)); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/UserFeedback.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/UserFeedback.java new file mode 100644 index 0000000000000000000000000000000000000000..8e5b844192fd9515215f84b786d562e262a03148 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/UserFeedback.java @@ -0,0 +1,5 @@ +package org.briarproject.mailbox.android.util; + +public class UserFeedback extends Exception { + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/VersionedAdapter.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/VersionedAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..a59093077203f7a47d1e8d4134641e7a99d045bc --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/util/VersionedAdapter.java @@ -0,0 +1,26 @@ +package org.briarproject.mailbox.android.util; + +import android.support.annotation.UiThread; + +public interface VersionedAdapter { + + /** + * Returns the adapter's revision counter. This method should be called on + * any thread before starting an asynchronous load that could overwrite + * other changes to the adapter, and called again on the UI thread before + * applying the changes from the asynchronous load. If the revision has + * changed between the two calls, the asynchronous load should be restarted + * without applying its changes. Otherwise {@link #incrementRevision()} + * should be called before applying the changes. + */ + int getRevision(); + + /** + * Increments the adapter's revision counter. This method should be called + * on the UI thread before applying any changes to the adapter that could + * be overwritten by an asynchronous load. + */ + @UiThread + void incrementRevision(); + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/ArticleMovementMethod.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/ArticleMovementMethod.java new file mode 100644 index 0000000000000000000000000000000000000000..d75a3039be11c021714ee8d09c10080aabfe4e18 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/ArticleMovementMethod.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.briarproject.mailbox.android.view; + +import android.text.Layout; +import android.text.Spannable; +import android.text.method.ArrowKeyMovementMethod; +import android.text.method.MovementMethod; +import android.text.style.ClickableSpan; +import android.view.MotionEvent; +import android.widget.TextView; + +public class ArticleMovementMethod extends ArrowKeyMovementMethod { + + private static ArticleMovementMethod sInstance; + + public static MovementMethod getInstance() { + if (sInstance == null) { + sInstance = new ArticleMovementMethod(); + } + return sInstance; + } + + @Override + public boolean onTouchEvent(TextView widget, Spannable buffer, + MotionEvent event) { + int action = event.getAction(); + + if (action == MotionEvent.ACTION_UP) { + int x = (int) event.getX(); + int y = (int) event.getY(); + + x -= widget.getTotalPaddingLeft(); + y -= widget.getTotalPaddingTop(); + + x += widget.getScrollX(); + y += widget.getScrollY(); + + Layout layout = widget.getLayout(); + int line = layout.getLineForVertical(y); + int off = layout.getOffsetForHorizontal(line, x); + + ClickableSpan[] link = + buffer.getSpans(off, off, ClickableSpan.class); + + if (link.length != 0) { + link[0].onClick(widget); + } + } + return super.onTouchEvent(widget, buffer, event); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/AuthorView.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/AuthorView.java new file mode 100644 index 0000000000000000000000000000000000000000..4928058d3dea7f5a80d9228fdd78b29cf60312ff --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/AuthorView.java @@ -0,0 +1,203 @@ +package org.briarproject.mailbox.android.view; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Typeface; +import android.support.annotation.DimenRes; +import android.support.annotation.UiThread; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.Author.Status; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.util.UiUtils; + +import javax.annotation.Nullable; + +import de.hdodenhof.circleimageview.CircleImageView; +import im.delight.android.identicons.IdenticonDrawable; + +import static android.content.Context.LAYOUT_INFLATER_SERVICE; +import static android.graphics.Typeface.BOLD; +import static android.util.TypedValue.COMPLEX_UNIT_PX; +import static org.briarproject.bramble.api.identity.Author.Status.NONE; +import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES; +import static org.briarproject.mailbox.android.util.UiUtils.resolveAttribute; + +@UiThread +public class AuthorView extends RelativeLayout { + + public static final int NORMAL = 0; + public static final int REBLOGGER = 1; + public static final int COMMENTER = 2; + public static final int LIST = 3; + public static final int RSS_FEED = 4; + public static final int RSS_FEED_REBLOGGED = 5; + + private final CircleImageView avatar; + private final ImageView avatarIcon; + private final TextView authorName; + private final Typeface authorNameTypeface; + private final TextView date; + private final TrustIndicatorView trustIndicator; + + public AuthorView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.author_view, this, true); + + avatar = findViewById(R.id.avatar); + avatarIcon = findViewById(R.id.avatarIcon); + authorName = findViewById(R.id.authorName); + authorNameTypeface = authorName.getTypeface(); + date = findViewById(R.id.dateView); + trustIndicator = findViewById(R.id.trustIndicator); + + TypedArray attributes = + context.obtainStyledAttributes(attrs, R.styleable.AuthorView); + int persona = attributes.getInteger(R.styleable.AuthorView_persona, 0); + setPersona(persona); + attributes.recycle(); + } + + public AuthorView(Context context) { + this(context, null); + } + + public void setAuthor(Author author) { + authorName.setText(author.getName()); + IdenticonDrawable d = new IdenticonDrawable(author.getId().getBytes()); + avatar.setImageDrawable(d); + + invalidate(); + requestLayout(); + } + + public void setAuthorStatus(Status status) { + if (status != NONE) { + trustIndicator.setTrustLevel(status); + trustIndicator.setVisibility(VISIBLE); + } else { + trustIndicator.setVisibility(GONE); + } + + if (status == OURSELVES) { + authorName.setTypeface(authorNameTypeface, BOLD); + } else { + authorName.setTypeface(authorNameTypeface, NORMAL); + } + + invalidate(); + requestLayout(); + } + + public void setDate(long date) { + this.date.setText(UiUtils.formatDate(getContext(), date)); + + invalidate(); + requestLayout(); + } + + public void setAuthorClickable(OnClickListener listener) { + setClickable(true); + int res = + resolveAttribute(getContext(), R.attr.selectableItemBackground); + setBackgroundResource(res); + setOnClickListener(listener); + } + + public void setAuthorNotClickable() { + setClickable(false); + setBackgroundResource(0); + setOnClickListener(null); + } + + /** + * Styles this view for a different persona. + * + * Attention: RSS_FEED and RSS_FEED_REBLOGGED change the avatar + * and override the one set by + * {@link AuthorView#setAuthor(Author)}. + */ + public void setPersona(int persona) { + switch (persona) { + case NORMAL: + avatarIcon.setVisibility(INVISIBLE); + date.setVisibility(VISIBLE); + setAvatarSize(R.dimen.blogs_avatar_normal_size); + setTextSize(authorName, R.dimen.text_size_small); + setCenterVertical(authorName, false); + setCenterVertical(trustIndicator, false); + break; + case REBLOGGER: + avatarIcon.setVisibility(VISIBLE); + date.setVisibility(VISIBLE); + setAvatarSize(R.dimen.blogs_avatar_normal_size); + setTextSize(authorName, R.dimen.text_size_small); + setCenterVertical(authorName, false); + setCenterVertical(trustIndicator, false); + break; + case COMMENTER: + avatarIcon.setVisibility(INVISIBLE); + date.setVisibility(VISIBLE); + setAvatarSize(R.dimen.blogs_avatar_comment_size); + setTextSize(authorName, R.dimen.text_size_tiny); + setCenterVertical(authorName, false); + setCenterVertical(trustIndicator, false); + break; + case LIST: + avatarIcon.setVisibility(INVISIBLE); + date.setVisibility(GONE); + setAvatarSize(R.dimen.listitem_picture_size_small); + setTextSize(authorName, R.dimen.text_size_medium); + setCenterVertical(authorName, true); + setCenterVertical(trustIndicator, true); + break; + case RSS_FEED: + avatarIcon.setVisibility(INVISIBLE); + date.setVisibility(VISIBLE); + avatar.setImageResource(R.drawable.ic_rss_feed); + setAvatarSize(R.dimen.blogs_avatar_normal_size); + setTextSize(authorName, R.dimen.text_size_small); + setCenterVertical(authorName, false); + setCenterVertical(trustIndicator, false); + break; + case RSS_FEED_REBLOGGED: + avatarIcon.setVisibility(INVISIBLE); + date.setVisibility(VISIBLE); + avatar.setImageResource(R.drawable.ic_rss_feed); + setAvatarSize(R.dimen.blogs_avatar_comment_size); + setTextSize(authorName, R.dimen.text_size_tiny); + setCenterVertical(authorName, false); + setCenterVertical(trustIndicator, false); + break; + } + } + + private void setAvatarSize(@DimenRes int res) { + LayoutParams params = (LayoutParams) avatar.getLayoutParams(); + int size = getResources().getDimensionPixelSize(res); + params.height = size; + params.width = size; + avatar.setLayoutParams(params); + } + + private void setTextSize(TextView v, @DimenRes int res) { + float textSize = getResources().getDimensionPixelSize(res); + v.setTextSize(COMPLEX_UNIT_PX, textSize); + } + + private void setCenterVertical(View v, boolean center) { + LayoutParams params = (LayoutParams) v.getLayoutParams(); + params.addRule(CENTER_VERTICAL, center ? RelativeLayout.TRUE : 0); + v.setLayoutParams(params); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/BriarRecyclerView.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/BriarRecyclerView.java new file mode 100644 index 0000000000000000000000000000000000000000..2ffb5909e0d38a3ceb96d7efde4dbcd1255d3e48 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/BriarRecyclerView.java @@ -0,0 +1,237 @@ +package org.briarproject.mailbox.android.view; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Looper; +import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; +import android.support.constraint.Group; +import android.support.v7.widget.AppCompatImageView; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.Adapter; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +import org.briarproject.mailbox.R; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; + +import static org.briarproject.mailbox.android.util.UiUtils.MIN_DATE_RESOLUTION; + +public class BriarRecyclerView extends FrameLayout { + + private static final Logger LOG = + Logger.getLogger(BriarRecyclerView.class.getName()); + + private final Handler handler = new Handler(Looper.getMainLooper()); + + private RecyclerView recyclerView; + private Group emptyState; + private AppCompatImageView emptyImage; + private TextView emptyText, emptyAction; + private ProgressBar progressBar; + private RecyclerView.AdapterDataObserver emptyObserver; + private Runnable refresher = null; + private boolean isScrollingToEnd = false; + + public BriarRecyclerView(Context context) { + this(context, null, 0); + } + + public BriarRecyclerView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public BriarRecyclerView(Context context, @Nullable AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + + TypedArray attributes = context.obtainStyledAttributes(attrs, + R.styleable.BriarRecyclerView); + isScrollingToEnd = attributes + .getBoolean(R.styleable.BriarRecyclerView_scrollToEnd, true); + Drawable drawable = attributes + .getDrawable(R.styleable.BriarRecyclerView_emptyImage); + if (drawable != null) setEmptyImage(drawable); + String emtpyText = + attributes.getString(R.styleable.BriarRecyclerView_emptyText); + if (emtpyText != null) setEmptyText(emtpyText); + String emtpyAction = + attributes.getString(R.styleable.BriarRecyclerView_emptyAction); + if (emtpyAction != null) setEmptyAction(emtpyAction); + attributes.recycle(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + stopPeriodicUpdate(); + } + + private void initViews() { + View v = LayoutInflater.from(getContext()).inflate( + R.layout.briar_recycler_view, this, true); + + recyclerView = v.findViewById(R.id.recyclerView); + emptyState = v.findViewById(R.id.emptyState); + emptyImage = v.findViewById(R.id.emptyImage); + emptyText = v.findViewById(R.id.emptyText); + emptyAction = v.findViewById(R.id.emptyAction); + progressBar = v.findViewById(R.id.progressBar); + + showProgressBar(); + + // scroll down when opening keyboard + if (isScrollingToEnd) { + addLayoutChangeListener(); + } + + emptyObserver = new RecyclerView.AdapterDataObserver() { + @Override + public void onItemRangeInserted(int positionStart, int itemCount) { + super.onItemRangeInserted(positionStart, itemCount); + if (itemCount > 0) showData(); + } + + @Override + public void onItemRangeRemoved(int positionStart, int itemCount) { + super.onItemRangeRemoved(positionStart, itemCount); + if (itemCount > 0) showData(); + } + }; + } + + private void addLayoutChangeListener() { + recyclerView.addOnLayoutChangeListener((v, left, top, right, bottom, + oldLeft, oldTop, oldRight, oldBottom) -> { + if (bottom < oldBottom) { + recyclerView.postDelayed(() -> scrollToPosition( + recyclerView.getAdapter().getItemCount() - 1), 100); + } + }); + } + + public void setLayoutManager(RecyclerView.LayoutManager layout) { + if (recyclerView == null) initViews(); + recyclerView.setLayoutManager(layout); + } + + public void setAdapter(Adapter adapter) { + if (recyclerView == null) initViews(); + + Adapter oldAdapter = recyclerView.getAdapter(); + if (oldAdapter != null) { + oldAdapter.unregisterAdapterDataObserver(emptyObserver); + } + + recyclerView.setAdapter(adapter); + + if (adapter != null) { + adapter.registerAdapterDataObserver(emptyObserver); + + if (adapter.getItemCount() > 0) { + // only show data if adapter has data already + // otherwise progress bar is shown + emptyObserver.onChanged(); + } + } + } + + public void setEmptyImage(Drawable drawable) { + if (recyclerView == null) initViews(); + emptyImage.setImageDrawable(drawable); + } + + public void setEmptyImage(@DrawableRes int res) { + if (recyclerView == null) initViews(); + emptyImage.setImageResource(res); + } + + public void setEmptyText(String text) { + if (recyclerView == null) initViews(); + emptyText.setText(text); + } + + public void setEmptyText(@StringRes int res) { + if (recyclerView == null) initViews(); + emptyText.setText(res); + } + + public void setEmptyAction(String text) { + if (recyclerView == null) initViews(); + emptyAction.setText(text); + } + + public void setEmptyAction(@StringRes int res) { + if (recyclerView == null) initViews(); + emptyAction.setText(res); + } + + public void showProgressBar() { + if (recyclerView == null) initViews(); + recyclerView.setVisibility(INVISIBLE); + emptyState.setVisibility(INVISIBLE); + progressBar.setVisibility(VISIBLE); + } + + public void showData() { + if (recyclerView == null) initViews(); + Adapter adapter = recyclerView.getAdapter(); + if (adapter != null) { + if (adapter.getItemCount() == 0) { + emptyState.setVisibility(VISIBLE); + recyclerView.setVisibility(INVISIBLE); + } else { + // use GONE here so empty view doesn't use space on small lists + emptyState.setVisibility(GONE); + recyclerView.setVisibility(VISIBLE); + } + progressBar.setVisibility(GONE); + } + } + + public void scrollToPosition(int position) { + if (recyclerView == null) initViews(); + recyclerView.scrollToPosition(position); + } + + public void smoothScrollToPosition(int position) { + if (recyclerView == null) initViews(); + recyclerView.smoothScrollToPosition(position); + } + + public RecyclerView getRecyclerView() { + return this.recyclerView; + } + + public void startPeriodicUpdate() { + if (recyclerView == null || recyclerView.getAdapter() == null) { + throw new IllegalStateException("Need to call setAdapter() first!"); + } + refresher = () -> { + LOG.info("Updating Content..."); + Adapter adapter = recyclerView.getAdapter(); + adapter.notifyItemRangeChanged(0, adapter.getItemCount()); + handler.postDelayed(refresher, MIN_DATE_RESOLUTION); + }; + LOG.info("Adding Handler Callback"); + handler.postDelayed(refresher, MIN_DATE_RESOLUTION); + } + + public void stopPeriodicUpdate() { + if (refresher != null) { + LOG.info("Removing Handler Callback"); + handler.removeCallbacks(refresher); + refresher = null; + } + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/BriarRecyclerViewBehavior.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/BriarRecyclerViewBehavior.java new file mode 100644 index 0000000000000000000000000000000000000000..565015242c0be78fc2ff8e09e3cb110ab3af9326 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/BriarRecyclerViewBehavior.java @@ -0,0 +1,44 @@ +package org.briarproject.mailbox.android.view; + +import android.content.Context; +import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.Snackbar; +import android.util.AttributeSet; +import android.view.View; + +public class BriarRecyclerViewBehavior + extends CoordinatorLayout.Behavior<BriarRecyclerView> { + + public BriarRecyclerViewBehavior(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onDependentViewChanged(CoordinatorLayout parent, + BriarRecyclerView child, View dependency) { + + // FIXME the below code works, but does not reset margin when snackbar is dismissed +/* + int margin = 0; + if (dependency.isShown()) margin = dependency.getHeight(); + + // set snackbar height as bottom margin if it is shown + CoordinatorLayout.LayoutParams params = + (CoordinatorLayout.LayoutParams) child.getLayoutParams(); + params.setMargins(0, 0, 0, margin); + child.setLayoutParams(params); + + child.scrollToPosition(0); +*/ + return true; + } + + @Override + public boolean layoutDependsOn(CoordinatorLayout parent, + BriarRecyclerView child, View dependency) { + // we only want to trigger the change + // only when the changes is from a snackbar + return dependency instanceof Snackbar.SnackbarLayout; + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/LargeTextInputView.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/LargeTextInputView.java new file mode 100644 index 0000000000000000000000000000000000000000..91ad5923b83a9e3724d024eb909e1f234f274df0 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/LargeTextInputView.java @@ -0,0 +1,75 @@ +package org.briarproject.mailbox.android.view; + +import android.content.Context; +import android.content.res.TypedArray; +import android.support.annotation.UiThread; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.Button; + +import org.briarproject.mailbox.R; + +import javax.annotation.Nullable; + +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; + +@UiThread +public class LargeTextInputView extends TextInputView { + + public LargeTextInputView(Context context) { + this(context, null); + } + + public LargeTextInputView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public LargeTextInputView(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void inflateLayout(Context context) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.text_input_view_large, this, true); + } + + @Override + protected void setUpViews(Context context, @Nullable AttributeSet attrs) { + super.setUpViews(context, attrs); + + // get attributes + TypedArray attributes = context.obtainStyledAttributes(attrs, + R.styleable.LargeTextInputView); + String buttonText = + attributes.getString(R.styleable.LargeTextInputView_buttonText); + int maxLines = + attributes + .getInteger(R.styleable.LargeTextInputView_maxLines, 0); + boolean fillHeight = attributes + .getBoolean(R.styleable.LargeTextInputView_fillHeight, + false); + attributes.recycle(); + + if (buttonText != null) setButtonText(buttonText); + if (maxLines > 0) ui.editText.setMaxLines(maxLines); + if (fillHeight) { + ViewGroup layout = findViewById(R.id.input_layout); + LayoutParams params = (LayoutParams) layout.getLayoutParams(); + params.height = 0; + params.weight = 1; + layout.setLayoutParams(params); + ViewGroup.LayoutParams editParams = ui.editText.getLayoutParams(); + editParams.height = MATCH_PARENT; + ui.editText.setLayoutParams(editParams); + } + } + + public void setButtonText(String text) { + ((Button) ui.sendButton).setText(text); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/QrCodeView.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/QrCodeView.java new file mode 100644 index 0000000000000000000000000000000000000000..d6dbc7ee56852151afe9881e0da14cdc4b7210d3 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/QrCodeView.java @@ -0,0 +1,63 @@ +package org.briarproject.mailbox.android.view; + +import android.content.Context; +import android.graphics.Bitmap; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.UiThread; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.animation.AlphaAnimation; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import org.briarproject.mailbox.R; + +public class QrCodeView extends FrameLayout { + + private final ImageView qrCodeImageView; + private boolean fullscreen = false; + private FullscreenListener listener; + + public QrCodeView(@NonNull Context context, + @Nullable AttributeSet attrs) { + super(context, attrs); + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.qr_code_view, this, true); + qrCodeImageView = findViewById(R.id.qr_code); + ImageView fullscreenButton = findViewById(R.id.fullscreen_button); + fullscreenButton.setOnClickListener(v -> { + fullscreen = !fullscreen; + if (!fullscreen) { + fullscreenButton.setImageResource( + R.drawable.ic_fullscreen_black_48dp); + } else { + fullscreenButton.setImageResource( + R.drawable.ic_fullscreen_exit_black_48dp); + } + if (listener != null) + listener.setFullscreen(fullscreen); + } + ); + } + + @UiThread + public void setQrCode(Bitmap qrCode) { + qrCodeImageView.setImageBitmap(qrCode); + // Simple fade-in animation + AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f); + anim.setDuration(200); + qrCodeImageView.startAnimation(anim); + } + + @UiThread + public void setFullscreenListener(FullscreenListener listener) { + this.listener = listener; + } + + public interface FullscreenListener { + void setFullscreen(boolean fullscreen); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/TextAvatarView.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/TextAvatarView.java new file mode 100644 index 0000000000000000000000000000000000000000..80207202b266bfd6837f1eac2524f8d1141ceb02 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/TextAvatarView.java @@ -0,0 +1,81 @@ +package org.briarproject.mailbox.android.view; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.support.annotation.UiThread; +import android.support.v7.widget.AppCompatTextView; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.mailbox.R; + +import javax.annotation.Nullable; + +import de.hdodenhof.circleimageview.CircleImageView; +import im.delight.android.identicons.IdenticonDrawable; + +@UiThread +public class TextAvatarView extends FrameLayout { + + private final AppCompatTextView character; + private final CircleImageView background; + private final TextView badge; + + public TextAvatarView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.text_avatar_view, this, true); + character = findViewById(R.id.textAvatarView); + background = findViewById(R.id.avatarBackground); + badge = findViewById(R.id.unreadCountView); + badge.setVisibility(INVISIBLE); + } + + public TextAvatarView(Context context) { + this(context, null); + } + + public void setText(String text) { + character.setText(text.toUpperCase()); + } + + public void setUnreadCount(int count) { + if (count > 0) { + badge.setText(String.valueOf(count)); + badge.setVisibility(VISIBLE); + } else { + badge.setVisibility(INVISIBLE); + } + } + + public void setBackgroundBytes(byte[] bytes) { + int r = getByte(bytes, 0) * 3 / 4 + 96; + int g = getByte(bytes, 1) * 3 / 4 + 96; + int b = getByte(bytes, 2) * 3 / 4 + 96; + int color = Color.rgb(r, g, b); + + background.setImageDrawable(new ColorDrawable(color)); + } + + private byte getByte(byte[] bytes, int index) { + if (bytes == null) { + return -128; + } else { + return bytes[index % bytes.length]; + } + } + + public void setAuthorAvatar(Author author) { + Drawable drawable = new IdenticonDrawable(author.getId().getBytes()); + background.setImageDrawable(drawable); + character.setVisibility(GONE); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/TextInputView.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/TextInputView.java new file mode 100644 index 0000000000000000000000000000000000000000..30ef213072ae369d9579831dcaab7a374f90fd56 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/TextInputView.java @@ -0,0 +1,214 @@ +package org.briarproject.mailbox.android.view; + +import android.animation.LayoutTransition; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Rect; +import android.os.IBinder; +import android.support.annotation.CallSuper; +import android.support.annotation.StringRes; +import android.support.annotation.UiThread; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +import org.briarproject.mailbox.R; +import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout; +import org.thoughtcrime.securesms.components.emoji.EmojiDrawer; +import org.thoughtcrime.securesms.components.emoji.EmojiDrawer.EmojiEventListener; +import org.thoughtcrime.securesms.components.emoji.EmojiEditText; +import org.thoughtcrime.securesms.components.emoji.EmojiToggle; + +import javax.annotation.Nullable; + +import static android.content.Context.INPUT_METHOD_SERVICE; +import static android.content.Context.LAYOUT_INFLATER_SERVICE; +import static android.view.KeyEvent.KEYCODE_BACK; +import static android.view.KeyEvent.KEYCODE_ENTER; +import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT; + +@UiThread +public class TextInputView extends KeyboardAwareLinearLayout + implements EmojiEventListener { + + protected final ViewHolder ui; + protected TextInputListener listener; + + public TextInputView(Context context) { + this(context, null); + } + + public TextInputView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public TextInputView(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + setOrientation(VERTICAL); + setLayoutTransition(new LayoutTransition()); + + inflateLayout(context); + ui = new ViewHolder(); + setUpViews(context, attrs); + } + + protected void inflateLayout(Context context) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.text_input_view, this, true); + } + + @CallSuper + protected void setUpViews(Context context, @Nullable AttributeSet attrs) { + // get attributes + TypedArray attributes = context.obtainStyledAttributes(attrs, + R.styleable.TextInputView); + String hint = attributes.getString(R.styleable.TextInputView_hint); + attributes.recycle(); + + if (hint != null) { + ui.editText.setHint(hint); + } + + ui.emojiToggle.attach(ui.emojiDrawer); + ui.emojiToggle.setOnClickListener(v -> onEmojiToggleClicked()); + ui.editText.setOnClickListener(v -> showSoftKeyboard()); + ui.editText.setOnKeyListener((v, keyCode, event) -> { + if (keyCode == KEYCODE_BACK && isEmojiDrawerOpen()) { + hideEmojiDrawer(); + return true; + } + if (keyCode == KEYCODE_ENTER && event.isCtrlPressed()) { + trySendMessage(); + return true; + } + return false; + }); + ui.sendButton.setOnClickListener(v -> trySendMessage()); + ui.emojiDrawer.setEmojiEventListener(this); + } + + private void trySendMessage() { + if (listener != null) { + listener.onSendClick(ui.editText.getText().toString()); + } + } + + @Override + public void setVisibility(int visibility) { + if (visibility == GONE && isKeyboardOpen()) { + onKeyboardClose(); + } + super.setVisibility(visibility); + } + + @Override + public void onKeyEvent(KeyEvent keyEvent) { + ui.editText.dispatchKeyEvent(keyEvent); + } + + @Override + public void onEmojiSelected(String emoji) { + ui.editText.insertEmoji(emoji); + } + + @Override + public boolean requestFocus(int direction, Rect previouslyFocusedRect) { + return ui.editText.requestFocus(direction, previouslyFocusedRect); + } + + private void onEmojiToggleClicked() { + if (isEmojiDrawerOpen()) { + showSoftKeyboard(); + } else { + showEmojiDrawer(); + } + } + + public void setText(String text) { + ui.editText.setText(text); + } + + public Editable getText() { + return ui.editText.getText(); + } + + public void setHint(@StringRes int res) { + ui.editText.setHint(res); + } + + public void setSendButtonEnabled(boolean enabled) { + ui.sendButton.setEnabled(enabled); + } + + public void addTextChangedListener(TextWatcher watcher) { + ui.editText.addTextChangedListener(watcher); + } + + public void setListener(TextInputListener listener) { + this.listener = listener; + } + + public void showSoftKeyboard() { + if (isKeyboardOpen()) return; + + if (ui.emojiDrawer.isShowing()) { + postOnKeyboardOpen(this::hideEmojiDrawer); + } + ui.editText.post(() -> { + ui.editText.requestFocus(); + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(INPUT_METHOD_SERVICE); + imm.showSoftInput(ui.editText, SHOW_IMPLICIT); + }); + } + + public void hideSoftKeyboard() { + IBinder token = ui.editText.getWindowToken(); + Object o = getContext().getSystemService(INPUT_METHOD_SERVICE); + ((InputMethodManager) o).hideSoftInputFromWindow(token, 0); + } + + public void showEmojiDrawer() { + if (isKeyboardOpen()) { + postOnKeyboardClose(() -> ui.emojiDrawer.show(getKeyboardHeight())); + hideSoftKeyboard(); + } else { + ui.emojiDrawer.show(getKeyboardHeight()); + ui.editText.requestFocus(); + } + } + + public void hideEmojiDrawer() { + ui.emojiDrawer.hide(); + } + + public boolean isEmojiDrawerOpen() { + return ui.emojiDrawer.isShowing(); + } + + protected class ViewHolder { + + private final EmojiToggle emojiToggle; + final EmojiEditText editText; + final View sendButton; + final EmojiDrawer emojiDrawer; + + private ViewHolder() { + emojiToggle = findViewById(R.id.emoji_toggle); + editText = findViewById(R.id.input_text); + emojiDrawer = findViewById(R.id.emoji_drawer); + sendButton = findViewById(R.id.btn_send); + } + } + + public interface TextInputListener { + void onSendClick(String text); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/TrustIndicatorView.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/TrustIndicatorView.java new file mode 100644 index 0000000000000000000000000000000000000000..a2c545c454a6a28e30ced46e8dcf06590926f5ac --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/TrustIndicatorView.java @@ -0,0 +1,53 @@ +package org.briarproject.mailbox.android.view; + +import android.content.Context; +import android.support.annotation.UiThread; +import android.support.v4.content.ContextCompat; +import android.util.AttributeSet; +import android.widget.ImageView; + +import org.briarproject.bramble.api.identity.Author.Status; +import org.briarproject.mailbox.R; + +@UiThread +public class TrustIndicatorView extends ImageView { + + public TrustIndicatorView(Context context) { + super(context); + } + + public TrustIndicatorView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public TrustIndicatorView(Context context, AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public void setTrustLevel(Status status) { + int res; + switch (status) { + case ANONYMOUS: + res = R.drawable.trust_indicator_anonymous; + break; + case UNVERIFIED: + res = R.drawable.trust_indicator_unverified; + break; + case VERIFIED: + res = R.drawable.trust_indicator_verified; + break; + case OURSELVES: + res = R.drawable.ic_our_identity; + break; + default: + res = R.drawable.trust_indicator_unknown; + } + setImageDrawable(ContextCompat.getDrawable(getContext(), res)); + setVisibility(VISIBLE); + + invalidate(); + requestLayout(); + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/UnreadMessageButton.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/UnreadMessageButton.java new file mode 100644 index 0000000000000000000000000000000000000000..ad4318453ef9c0a4d31867f9d15ae7c23ecff945 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/view/UnreadMessageButton.java @@ -0,0 +1,76 @@ +package org.briarproject.mailbox.android.view; + +import android.content.Context; +import android.content.res.TypedArray; +import android.support.annotation.UiThread; +import android.support.design.widget.FloatingActionButton; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.mailbox.R; + +import javax.annotation.Nullable; + +@UiThread +@NotNullByDefault +public class UnreadMessageButton extends FrameLayout { + + private final static int UP = 0, DOWN = 1; + + private final FloatingActionButton fab; + private final TextView unread; + + public UnreadMessageButton(Context context) { + this(context, null); + } + + public UnreadMessageButton(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public UnreadMessageButton(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.unread_message_button, this, true); + + fab = findViewById(R.id.fab); + unread = findViewById(R.id.unreadCountView); + + TypedArray attributes = context.obtainStyledAttributes(attrs, + R.styleable.UnreadMessageButton); + int direction = attributes + .getInteger(R.styleable.UnreadMessageButton_direction, DOWN); + setDirection(direction); + attributes.recycle(); + + setUnreadCount(0); + } + + private void setDirection(int direction) { + if (direction == UP) { + fab.setImageResource(R.drawable.chevron_up_white); + } else if (direction == DOWN) { + fab.setImageResource(R.drawable.chevron_down_white); + } else { + throw new IllegalArgumentException(); + } + } + + public void setUnreadCount(int count) { + if (count == 0) { + setVisibility(INVISIBLE); + } else { + // FIXME: Use animations when upgrading to support library 24.2.0 + // https://code.google.com/p/android/issues/detail?id=216469 + setVisibility(VISIBLE); + unread.setText(String.valueOf(count)); + } + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/BaseViewModel.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/BaseViewModel.java new file mode 100644 index 0000000000000000000000000000000000000000..c2e3a1b15465ca06147037b57bac9abb61d90570 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/BaseViewModel.java @@ -0,0 +1,32 @@ +package org.briarproject.mailbox.android.viewmodels; + +import android.app.Application; +import android.arch.lifecycle.AndroidViewModel; +import android.support.annotation.NonNull; + +import org.briarproject.mailbox.android.AndroidComponent; +import org.briarproject.mailbox.android.MailboxApplication; + +public abstract class BaseViewModel extends AndroidViewModel { + + public BaseViewModel( + @NonNull + Application application) { + super(application); + AndroidComponent applicationComponent = + ((MailboxApplication) getApplication()) + .getApplicationComponent(); + + ViewModelComponent viewModelComponent = + DaggerViewModelComponent.builder() + .androidComponent(applicationComponent) + .viewModelModule(new ViewModelModule()) + .build(); + + injectViewModel(viewModelComponent); + + } + + abstract void injectViewModel(ViewModelComponent viewModelComponent); + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/MailboxOwnerStatusViewModel.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/MailboxOwnerStatusViewModel.java new file mode 100644 index 0000000000000000000000000000000000000000..8f39116d36206a10a48f870cd146b4bfd49780e0 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/MailboxOwnerStatusViewModel.java @@ -0,0 +1,147 @@ +package org.briarproject.mailbox.android.viewmodels; + +import android.app.Application; +import android.arch.lifecycle.MutableLiveData; +import android.support.annotation.NonNull; + +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.contact.MailboxOwner; +import org.briarproject.bramble.api.contact.event.ContactAddedEvent; +import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; +import org.briarproject.bramble.api.db.DatabaseExecutor; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.event.EventListener; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.plugin.ConnectionRegistry; +import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent; +import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent; + +import java.util.Collection; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.api.contact.ContactType.MAILBOX_OWNER; +import static org.briarproject.bramble.util.LogUtils.logException; + +public class MailboxOwnerStatusViewModel extends BaseViewModel implements + EventListener { + + public static final String TAG = + MailboxOwnerStatusViewModel.class.getName(); + private static final Logger LOG = Logger.getLogger(TAG); + public final MutableLiveData<MailboxOwnerStatus> + mailboxOwnerStatusLiveData = new MutableLiveData<>(); + @Inject + volatile ContactManager contactManager; + @Inject + volatile ConnectionRegistry connectionRegistry; + @Inject + volatile LifecycleManager lifecycleManager; + @Inject + @DatabaseExecutor + Executor databaseExecutor; + @Inject + EventBus eventBus; + private volatile MailboxOwnerStatus mailboxOwnerStatus; + + public MailboxOwnerStatusViewModel(@NonNull Application application) { + super(application); + loadOwner(); + eventBus.addListener(this); + } + + @Override + protected void onCleared() { + super.onCleared(); + eventBus.removeListener(this); + } + + @Override + void injectViewModel(ViewModelComponent viewModelComponent) { + viewModelComponent.inject(this); + } + + @Override + public void eventOccurred(Event e) { + if (e instanceof ContactConnectedEvent) + updateStatus(((ContactConnectedEvent) e).getContactId()); + else if (e instanceof ContactDisconnectedEvent) + updateStatus(((ContactDisconnectedEvent) e).getContactId()); + else if (e instanceof ContactAddedEvent) { + if (mailboxOwnerStatus == null) + loadOwner(); + } else if (e instanceof ContactRemovedEvent) { + if (mailboxOwnerStatus != null && + ((ContactRemovedEvent) e).getContactId() + .equals(mailboxOwnerStatus.getId())) { + mailboxOwnerStatus = null; + mailboxOwnerStatusLiveData.postValue(mailboxOwnerStatus); + } + } + + } + + private void updateStatus(ContactId contactId) { + if (mailboxOwnerStatus != null && + mailboxOwnerStatus.getId().equals(contactId)) { + mailboxOwnerStatus + .setOnline(connectionRegistry.isConnected(contactId)); + mailboxOwnerStatusLiveData.postValue(mailboxOwnerStatus); + } + } + + private void loadOwner() { + databaseExecutor.execute(() -> { + try { + lifecycleManager.waitForDatabase(); + Collection<Contact> result = + contactManager.getContactsByType(MAILBOX_OWNER); + if (!result.isEmpty()) { + MailboxOwner owner = + (MailboxOwner) result.iterator().next(); + mailboxOwnerStatus = + new MailboxOwnerStatus(owner, getStatus(owner)); + mailboxOwnerStatusLiveData.postValue(mailboxOwnerStatus); + } + } catch (Exception e) { + logException(LOG, WARNING, e); + } + }); + } + + private boolean getStatus(Contact owner) { + return connectionRegistry.isConnected(owner.getId()); + } + + public class MailboxOwnerStatus { + private final MailboxOwner mailboxOwner; + private boolean online; + + MailboxOwnerStatus(MailboxOwner mailboxOwner, boolean online) { + this.mailboxOwner = mailboxOwner; + this.online = online; + } + + public String getName() { + return mailboxOwner.getAuthor().getName(); + } + + public ContactId getId() { + return mailboxOwner.getId(); + } + + public boolean isOnline() { + return online; + } + + public void setOnline(boolean isOnline) { + online = isOnline; + } + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/ViewModelComponent.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/ViewModelComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..823a49b398b2aa6d40cfbac4cb182f7aa613a995 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/ViewModelComponent.java @@ -0,0 +1,14 @@ +package org.briarproject.mailbox.android.viewmodels; + +import org.briarproject.mailbox.android.AndroidComponent; + +import dagger.Component; + +@ViewModelScope +@Component(modules = {ViewModelModule.class}, + dependencies = {AndroidComponent.class}) +public interface ViewModelComponent { + + void inject(MailboxOwnerStatusViewModel mailboxOwnerStatusViewModel); + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/ViewModelModule.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/ViewModelModule.java new file mode 100644 index 0000000000000000000000000000000000000000..944dabbbaa5e35c7f9d264f70afc6f84f9f566b3 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/ViewModelModule.java @@ -0,0 +1,7 @@ +package org.briarproject.mailbox.android.viewmodels; + +import dagger.Module; + +@Module +public class ViewModelModule { +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/ViewModelScope.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/ViewModelScope.java new file mode 100644 index 0000000000000000000000000000000000000000..60dc74e7edeb276f6ef9c29af72432768baae243 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/viewmodels/ViewModelScope.java @@ -0,0 +1,11 @@ +package org.briarproject.mailbox.android.viewmodels; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Scope; + +@Scope +@Retention(RetentionPolicy.RUNTIME) +public @interface ViewModelScope { +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/widget/LinkDialogFragment.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/widget/LinkDialogFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..8cec946a4e1bb34bcb517ebeed3fbd40a2fa09d9 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/widget/LinkDialogFragment.java @@ -0,0 +1,79 @@ +package org.briarproject.mailbox.android.widget; + + +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import org.briarproject.mailbox.R; + +import java.util.List; + +public class LinkDialogFragment extends DialogFragment { + + private static final String TAG = LinkDialogFragment.class.getName(); + + private String url; + + public static LinkDialogFragment newInstance(String url) { + LinkDialogFragment f = new LinkDialogFragment(); + + Bundle args = new Bundle(); + args.putString("url", url); + f.setArguments(args); + + return f; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + url = getArguments().getString("url"); + + setStyle(STYLE_NO_TITLE, R.style.BriarDialogTheme); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View v = inflater.inflate(R.layout.fragment_link_dialog, container, + false); + + TextView urlView = v.findViewById(R.id.urlView); + urlView.setText(url); + + // prepare normal intent or intent chooser + Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + PackageManager packageManager = getContext().getPackageManager(); + List activities = packageManager.queryIntentActivities(i, + PackageManager.MATCH_DEFAULT_ONLY); + boolean choice = activities.size() > 1; + Intent intent = choice ? Intent.createChooser(i, + getString(R.string.link_warning_open_link)) : i; + + Button openButton = v.findViewById(R.id.openButton); + openButton.setOnClickListener(v1 -> { + startActivity(intent); + getDialog().dismiss(); + }); + + Button cancelButton = v.findViewById(R.id.cancelButton); + cancelButton.setOnClickListener(v1 -> getDialog().cancel()); + + return v; + } + + public String getUniqueTag() { + return TAG; + } + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/widget/TapSafeFrameLayout.java b/mailbox-android/src/main/java/org/briarproject/mailbox/android/widget/TapSafeFrameLayout.java new file mode 100644 index 0000000000000000000000000000000000000000..d7e60e47009375ad06de64c2b8c1fb9c903dcf43 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/widget/TapSafeFrameLayout.java @@ -0,0 +1,52 @@ +package org.briarproject.mailbox.android.widget; + +import android.content.Context; +import android.support.annotation.AttrRes; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.widget.FrameLayout; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.mailbox.android.util.UiUtils; + +import javax.annotation.Nullable; + +import static android.view.MotionEvent.FLAG_WINDOW_IS_OBSCURED; + +@NotNullByDefault +public class TapSafeFrameLayout extends FrameLayout { + + @Nullable + private OnTapFilteredListener listener; + + public TapSafeFrameLayout(Context context) { + super(context); + UiUtils.setFilterTouchesWhenObscured(this, false); + } + + public TapSafeFrameLayout(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + UiUtils.setFilterTouchesWhenObscured(this, false); + } + + public TapSafeFrameLayout(Context context, @Nullable AttributeSet attrs, + @AttrRes int defStyleAttr) { + super(context, attrs, defStyleAttr); + UiUtils.setFilterTouchesWhenObscured(this, false); + } + + public void setOnTapFilteredListener(OnTapFilteredListener listener) { + this.listener = listener; + } + + @Override + public boolean onFilterTouchEventForSecurity(MotionEvent e) { + boolean obscured = (e.getFlags() & FLAG_WINDOW_IS_OBSCURED) != 0; + if (obscured && listener != null) return listener.shouldAllowTap(); + else return !obscured; + } + + public interface OnTapFilteredListener { + boolean shouldAllowTap(); + } +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/AndroidNotificationManager.java b/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/AndroidNotificationManager.java new file mode 100644 index 0000000000000000000000000000000000000000..4c84f2e9374c3a1b9c797ac93b55bc96bca6e7ac --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/AndroidNotificationManager.java @@ -0,0 +1,41 @@ +package org.briarproject.mailbox.api.android; + +import android.app.Notification; + +/** + * Manages notifications for private messages, forum posts, blog posts and + * introductions. + */ +public interface AndroidNotificationManager { + + String PREF_NOTIFY_SOUND = "notifySound"; + String PREF_NOTIFY_RINGTONE_NAME = "notifyRingtoneName"; + String PREF_NOTIFY_RINGTONE_URI = "notifyRingtoneUri"; + String PREF_NOTIFY_VIBRATION = "notifyVibration"; + String PREF_NOTIFY_LOCK_SCREEN = "notifyLockScreen"; + + // Notification IDs + int ONGOING_NOTIFICATION_ID = 1; + int FAILURE_NOTIFICATION_ID = 2; + int REMINDER_NOTIFICATION_ID = 3; + + // Channel IDs + // Channels are sorted by channel ID in the Settings app, so use IDs + // that will sort below the main channels such as contacts + String ONGOING_CHANNEL_ID = "zForegroundService"; + String FAILURE_CHANNEL_ID = "zStartupFailure"; + String REMINDER_CHANNEL_ID = "zSignInReminder"; + + // Actions for pending intents + String ACTION_DISMISS_REMINDER = "dismissReminder"; + + Notification getForegroundNotification(); + + void updateForegroundNotification(boolean locked); + + void showSignInNotification(); + + void clearSignInNotification(); + + void blockSignInNotification(); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/DozeWatchdog.java b/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/DozeWatchdog.java new file mode 100644 index 0000000000000000000000000000000000000000..f6cc5f20c6cb621d0ba6a0571ea29c48d6934044 --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/DozeWatchdog.java @@ -0,0 +1,6 @@ +package org.briarproject.mailbox.api.android; + +public interface DozeWatchdog { + + boolean getAndResetDozeFlag(); +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/LockManager.java b/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/LockManager.java new file mode 100644 index 0000000000000000000000000000000000000000..c5d1218ca7665893fcecaa8333e765ecad67357b --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/LockManager.java @@ -0,0 +1,50 @@ +package org.briarproject.mailbox.api.android; + +import android.app.Activity; +import android.arch.lifecycle.LiveData; +import android.support.annotation.UiThread; + +public interface LockManager { + + String ACTION_LOCK = "lock"; + + /** + * Stops the inactivity timer when the user interacts with the app. + * Should typically be called by {@link Activity#onStart()} + */ + @UiThread + void onActivityStart(); + + /** + * Starts the inactivity timer which will lock the app. + * Should typically be called by {@link Activity#onStop()} + */ + @UiThread + void onActivityStop(); + + /** + * Returns an observable LiveData to indicate whether the app can be locked. + */ + LiveData<Boolean> isLockable(); + + /** + * Updates the LiveData returned by {@link #isLockable()}. + * It checks whether a device screen lock is available and + * whether the app setting is checked. + */ + @UiThread + void checkIfLockable(); + + /** + * Returns true if app is currently locked, false otherwise. + * If the device's screen lock was removed while the app was locked, + * calling this will unlock the app automatically. + */ + boolean isLocked(); + + /** + * Locks the app if true is passed, otherwise unlocks the app. + */ + void setLocked(boolean locked); + +} diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/ScreenFilterMonitor.java b/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/ScreenFilterMonitor.java new file mode 100644 index 0000000000000000000000000000000000000000..40ecc0e8b6f416cfeec98afd973aee59d699583f --- /dev/null +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/api/android/ScreenFilterMonitor.java @@ -0,0 +1,38 @@ +package org.briarproject.mailbox.api.android; + +import android.support.annotation.UiThread; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.util.Collection; + +@NotNullByDefault +public interface ScreenFilterMonitor { + + /** + * Returns the details of all apps that have requested the + * SYSTEM_ALERT_WINDOW permission, excluding system apps, Google Play + * Services, and any apps that have been allowed by calling + * {@link #allowApps(Collection)}. + */ + @UiThread + Collection<AppDetails> getApps(); + + /** + * Allows the apps with the given package names to use overlay windows. + * They will not be returned by future calls to {@link #getApps()}. + */ + @UiThread + void allowApps(Collection<String> packageNames); + + class AppDetails { + + public final String name; + public final String packageName; + + public AppDetails(String name, String packageName) { + this.name = name; + this.packageName = packageName; + } + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/LICENSE b/mailbox-android/src/main/java/org/thoughtcrime/securesms/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..94a045322262546cfb9d72561e1d587b5c2ffb1e --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/LICENSE @@ -0,0 +1,621 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/KeyboardAwareLinearLayout.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/KeyboardAwareLinearLayout.java new file mode 100644 index 0000000000000000000000000000000000000000..57a7a28246af4c686aa088efa92e8107cafc0547 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/KeyboardAwareLinearLayout.java @@ -0,0 +1,272 @@ +package org.thoughtcrime.securesms.components; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Rect; +import android.os.Build; +import android.preference.PreferenceManager; +import android.support.annotation.UiThread; +import android.util.AttributeSet; +import android.view.View; +import android.view.WindowManager; +import android.widget.LinearLayout; + +import org.briarproject.mailbox.R; + +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Logger; + +import javax.annotation.Nullable; + +import static android.content.Context.WINDOW_SERVICE; +import static android.view.Surface.ROTATION_270; +import static android.view.Surface.ROTATION_90; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; + +/** + * RelativeLayout that, when a view container, will report back when it thinks + * a soft keyboard has been opened and what its height would be. + */ +@UiThread +public class KeyboardAwareLinearLayout extends LinearLayout { + + private static final Logger LOG = + Logger.getLogger(KeyboardAwareLinearLayout.class.getName()); + + private final Rect rect = new Rect(); + private final Set<OnKeyboardHiddenListener> hiddenListeners = + new HashSet<>(); + private final Set<OnKeyboardShownListener> shownListeners = new HashSet<>(); + private final int minKeyboardSize; + private final int minCustomKeyboardSize; + private final int defaultCustomKeyboardSize; + private final int minCustomKeyboardTopMargin; + private final int statusBarHeight; + + private int viewInset; + + private boolean keyboardOpen = false; + private int rotation = -1; + + public KeyboardAwareLinearLayout(Context context) { + this(context, null); + } + + public KeyboardAwareLinearLayout(Context context, + @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public KeyboardAwareLinearLayout(Context context, + @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + rotation = getDeviceRotation(); + int statusBarRes = getResources() + .getIdentifier("status_bar_height", "dimen", "android"); + minKeyboardSize = + getResources().getDimensionPixelSize(R.dimen.min_keyboard_size); + minCustomKeyboardSize = getResources() + .getDimensionPixelSize(R.dimen.min_custom_keyboard_size); + defaultCustomKeyboardSize = getResources() + .getDimensionPixelSize(R.dimen.default_custom_keyboard_size); + minCustomKeyboardTopMargin = getResources() + .getDimensionPixelSize(R.dimen.min_custom_keyboard_top_margin); + statusBarHeight = statusBarRes > 0 ? + getResources().getDimensionPixelSize(statusBarRes) : 0; + viewInset = getViewInset(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + updateRotation(); + updateKeyboardState(); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + private void updateRotation() { + int oldRotation = rotation; + rotation = getDeviceRotation(); + if (oldRotation != rotation) { + LOG.info("Rotation changed"); + onKeyboardClose(); + } + } + + private void updateKeyboardState() { + if (isLandscape()) { + if (keyboardOpen) onKeyboardClose(); + return; + } + + if (viewInset == 0 && Build.VERSION.SDK_INT >= 21) + viewInset = getViewInset(); + int availableHeight = + getRootView().getHeight() - statusBarHeight - viewInset; + getWindowVisibleDisplayFrame(rect); + + int keyboardHeight = availableHeight - (rect.bottom - rect.top); + + if (keyboardHeight > minKeyboardSize) { + if (getKeyboardHeight() != keyboardHeight) + setKeyboardPortraitHeight(keyboardHeight); + if (!keyboardOpen) onKeyboardOpen(keyboardHeight); + } else if (keyboardOpen) { + onKeyboardClose(); + } + } + + @TargetApi(21) + private int getViewInset() { + try { + Field attachInfoField = View.class.getDeclaredField("mAttachInfo"); + attachInfoField.setAccessible(true); + Object attachInfo = attachInfoField.get(this); + if (attachInfo != null) { + Field stableInsetsField = + attachInfo.getClass().getDeclaredField("mStableInsets"); + stableInsetsField.setAccessible(true); + Rect insets = (Rect) stableInsetsField.get(attachInfo); + return insets.bottom; + } + } catch (NoSuchFieldException e) { + LOG.log(WARNING, + "field reflection error when measuring view inset", e); + } catch (IllegalAccessException e) { + LOG.log(WARNING, + "access reflection error when measuring view inset", e); + } + return 0; + } + + protected void onKeyboardOpen(int keyboardHeight) { + if (LOG.isLoggable(INFO)) + LOG.info("onKeyboardOpen(" + keyboardHeight + ")"); + keyboardOpen = true; + + notifyShownListeners(); + } + + protected void onKeyboardClose() { + LOG.info("onKeyboardClose()"); + keyboardOpen = false; + notifyHiddenListeners(); + } + + public boolean isKeyboardOpen() { + return keyboardOpen; + } + + public int getKeyboardHeight() { + return isLandscape() ? getKeyboardLandscapeHeight() : + getKeyboardPortraitHeight(); + } + + public boolean isLandscape() { + int rotation = getDeviceRotation(); + return rotation == ROTATION_90 || rotation == ROTATION_270; + } + + private int getDeviceRotation() { + WindowManager windowManager = + (WindowManager) getContext().getSystemService(WINDOW_SERVICE); + return windowManager.getDefaultDisplay().getRotation(); + } + + private int getKeyboardLandscapeHeight() { + return Math.max(getHeight(), getRootView().getHeight()) / 2; + } + + private int getKeyboardPortraitHeight() { + SharedPreferences prefs = + PreferenceManager.getDefaultSharedPreferences(getContext()); + int keyboardHeight = prefs.getInt("keyboard_height_portrait", + defaultCustomKeyboardSize); + return clamp(keyboardHeight, minCustomKeyboardSize, + getRootView().getHeight() - minCustomKeyboardTopMargin); + } + + private int clamp(int value, int min, int max) { + return Math.min(Math.max(value, min), max); + } + + private void setKeyboardPortraitHeight(int height) { + SharedPreferences prefs = + PreferenceManager.getDefaultSharedPreferences(getContext()); + prefs.edit().putInt("keyboard_height_portrait", height).apply(); + } + + public void postOnKeyboardClose(Runnable runnable) { + if (keyboardOpen) { + addOnKeyboardHiddenListener(new OnKeyboardHiddenListener() { + @Override + public void onKeyboardHidden() { + removeOnKeyboardHiddenListener(this); + runnable.run(); + } + }); + } else { + runnable.run(); + } + } + + public void postOnKeyboardOpen(Runnable runnable) { + if (!keyboardOpen) { + addOnKeyboardShownListener(new OnKeyboardShownListener() { + @Override + public void onKeyboardShown() { + removeOnKeyboardShownListener(this); + runnable.run(); + } + }); + } else { + runnable.run(); + } + } + + public void addOnKeyboardHiddenListener(OnKeyboardHiddenListener listener) { + hiddenListeners.add(listener); + } + + public void removeOnKeyboardHiddenListener( + OnKeyboardHiddenListener listener) { + hiddenListeners.remove(listener); + } + + public void addOnKeyboardShownListener(OnKeyboardShownListener listener) { + shownListeners.add(listener); + } + + public void removeOnKeyboardShownListener( + OnKeyboardShownListener listener) { + shownListeners.remove(listener); + } + + private void notifyHiddenListeners() { + // Make a copy as listeners may remove themselves when called + Set<OnKeyboardHiddenListener> listeners = + new HashSet<>(hiddenListeners); + for (OnKeyboardHiddenListener listener : listeners) { + listener.onKeyboardHidden(); + } + } + + private void notifyShownListeners() { + // Make a copy as listeners may remove themselves when called + Set<OnKeyboardShownListener> listeners = new HashSet<>(shownListeners); + for (OnKeyboardShownListener listener : listeners) { + listener.onKeyboardShown(); + } + } + + public interface OnKeyboardHiddenListener { + void onKeyboardHidden(); + } + + public interface OnKeyboardShownListener { + void onKeyboardShown(); + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/RepeatableImageKey.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/RepeatableImageKey.java new file mode 100644 index 0000000000000000000000000000000000000000..51e74018694be4f99ced649318a187affff4d514 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/RepeatableImageKey.java @@ -0,0 +1,94 @@ +package org.thoughtcrime.securesms.components; + +import android.content.Context; +import android.support.annotation.UiThread; +import android.support.v7.widget.AppCompatImageButton; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; + +import static android.view.HapticFeedbackConstants.KEYBOARD_TAP; +import static android.view.MotionEvent.ACTION_CANCEL; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_UP; + +@UiThread +public class RepeatableImageKey extends AppCompatImageButton { + + private KeyEventListener listener; + + public RepeatableImageKey(Context context) { + super(context); + init(); + } + + public RepeatableImageKey(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public RepeatableImageKey(Context context, AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + setOnClickListener(new RepeaterClickListener()); + setOnTouchListener(new RepeaterTouchListener()); + } + + public void setOnKeyEventListener(KeyEventListener listener) { + this.listener = listener; + } + + private void notifyListener() { + if (listener != null) listener.onKeyEvent(); + } + + private class RepeaterClickListener implements OnClickListener { + @Override + public void onClick(View v) { + notifyListener(); + } + } + + private class Repeater implements Runnable { + @Override + public void run() { + notifyListener(); + postDelayed(this, ViewConfiguration.getKeyRepeatDelay()); + } + } + + private class RepeaterTouchListener implements OnTouchListener { + + private final Repeater repeater; + + private RepeaterTouchListener() { + repeater = new Repeater(); + } + + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + switch (motionEvent.getAction()) { + case ACTION_DOWN: + view.postDelayed(repeater, + ViewConfiguration.getKeyRepeatTimeout()); + performHapticFeedback(KEYBOARD_TAP); + return false; + case ACTION_CANCEL: + case ACTION_UP: + view.removeCallbacks(repeater); + return false; + default: + return false; + } + } + } + + public interface KeyEventListener { + void onKeyEvent(); + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/AnimatingImageSpan.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/AnimatingImageSpan.java new file mode 100644 index 0000000000000000000000000000000000000000..28a71933f274d115dbf4e438a4db2c79ffcc257f --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/AnimatingImageSpan.java @@ -0,0 +1,15 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.graphics.drawable.Drawable; +import android.graphics.drawable.Drawable.Callback; +import android.support.annotation.UiThread; +import android.text.style.ImageSpan; + +@UiThread +class AnimatingImageSpan extends ImageSpan { + + AnimatingImageSpan(Drawable drawable, Callback callback) { + super(drawable, ALIGN_BOTTOM); + drawable.setCallback(callback); + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java new file mode 100644 index 0000000000000000000000000000000000000000..5da4c3e59bfa36f1e2f978f49484c5f6bd15dc2d --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiDrawer.java @@ -0,0 +1,202 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.support.annotation.NonNull; +import android.support.annotation.UiThread; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.support.v7.widget.AppCompatImageView; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.astuetz.PagerSlidingTabStrip; +import com.astuetz.PagerSlidingTabStrip.CustomTabProvider; + +import org.briarproject.mailbox.R; +import org.thoughtcrime.securesms.components.RepeatableImageKey; +import org.thoughtcrime.securesms.components.emoji.EmojiPageView.EmojiSelectionListener; + +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Logger; + +import javax.annotation.Nullable; + +import static android.support.v4.widget.ImageViewCompat.setImageTintList; +import static android.view.KeyEvent.ACTION_DOWN; +import static android.view.KeyEvent.KEYCODE_DEL; +import static android.widget.ImageView.ScaleType.CENTER_INSIDE; +import static java.util.logging.Level.INFO; + +@UiThread +public class EmojiDrawer extends LinearLayout { + + private static final Logger LOG = + Logger.getLogger(EmojiDrawer.class.getName()); + private static final KeyEvent DELETE_KEY_EVENT = + new KeyEvent(ACTION_DOWN, KEYCODE_DEL); + + private ViewPager pager; + private List<EmojiPageModel> models; + private PagerSlidingTabStrip strip; + private RecentEmojiPageModel recentModel; + private EmojiEventListener listener; + private EmojiDrawerListener drawerListener; + + public EmojiDrawer(Context context) { + this(context, null); + } + + public EmojiDrawer(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + setOrientation(VERTICAL); + } + + private void initView() { + View v = LayoutInflater.from(getContext()) + .inflate(R.layout.emoji_drawer, this, true); + initializeResources(v); + initializePageModels(); + initializeEmojiGrid(); + } + + public void setEmojiEventListener(EmojiEventListener listener) { + this.listener = listener; + } + + public void setDrawerListener(EmojiDrawerListener listener) { + this.drawerListener = listener; + } + + private void initializeResources(View v) { + this.pager = v.findViewById(R.id.emoji_pager); + this.strip = v.findViewById(R.id.tabs); + + RepeatableImageKey backspace = v.findViewById(R.id.backspace); + backspace.setOnKeyEventListener(() -> { + if (listener != null) listener.onKeyEvent(DELETE_KEY_EVENT); + }); + } + + public boolean isShowing() { + return getVisibility() == VISIBLE; + } + + public void show(int height) { + if (this.pager == null) initView(); + ViewGroup.LayoutParams params = getLayoutParams(); + params.height = height; + if (LOG.isLoggable(INFO)) + LOG.info("Showing emoji drawer with height " + params.height); + setLayoutParams(params); + setVisibility(VISIBLE); + if (drawerListener != null) drawerListener.onShown(); + } + + public void hide() { + setVisibility(GONE); + if (drawerListener != null) drawerListener.onHidden(); + } + + private void initializeEmojiGrid() { + pager.setAdapter(new EmojiPagerAdapter(getContext(), models, + emoji -> { + recentModel.onCodePointSelected(emoji); + if (listener != null) listener.onEmojiSelected(emoji); + })); + + if (recentModel.getEmoji().length == 0) { + pager.setCurrentItem(1); + } + strip.setViewPager(pager); + } + + private void initializePageModels() { + this.models = new LinkedList<>(); + this.recentModel = new RecentEmojiPageModel(getContext()); + this.models.add(recentModel); + this.models.addAll(EmojiProvider.getInstance(getContext()) + .getStaticPages()); + } + + public static class EmojiPagerAdapter extends PagerAdapter + implements CustomTabProvider { + private Context context; + private List<EmojiPageModel> pages; + private EmojiSelectionListener listener; + + private EmojiPagerAdapter(@NonNull Context context, + @NonNull List<EmojiPageModel> pages, + @Nullable EmojiSelectionListener listener) { + super(); + this.context = context; + this.pages = pages; + this.listener = listener; + } + + @Override + public int getCount() { + return pages.size(); + } + + @NonNull + @Override + public Object instantiateItem(@NonNull ViewGroup container, + int position) { + EmojiPageView page = new EmojiPageView(context); + page.setModel(pages.get(position)); + page.setEmojiSelectedListener(listener); + container.addView(page); + return page; + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, + @NonNull Object object) { + container.removeView((View) object); + } + + @Override + public boolean isViewFromObject(@NonNull View view, + @NonNull Object object) { + return view == object; + } + + @Override + public View getCustomTabView(ViewGroup viewGroup, int i) { + ImageView image = new AppCompatImageView(context); + image.setScaleType(CENTER_INSIDE); + image.setImageResource(pages.get(i).getIcon()); + setImageTintList(image, ColorStateList.valueOf( + ContextCompat.getColor(context, R.color.color_primary))); + return image; + } + + @Override + public void tabSelected(View view) { + view.animate().setDuration(300).alpha(1); + } + + @Override + public void tabUnselected(View view) { + view.animate().setDuration(400).alpha(0.4f); + } + } + + public interface EmojiEventListener extends EmojiSelectionListener { + void onKeyEvent(KeyEvent keyEvent); + } + + public interface EmojiDrawerListener { + void onShown(); + + void onHidden(); + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java new file mode 100644 index 0000000000000000000000000000000000000000..a888956c4e6262309d8129bbed49507eada8fa19 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java @@ -0,0 +1,48 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.UiThread; +import android.support.v7.widget.AppCompatEditText; +import android.text.InputFilter; +import android.util.AttributeSet; + +import org.briarproject.mailbox.R; +import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable; + +import javax.annotation.Nullable; + +@UiThread +public class EmojiEditText extends AppCompatEditText { + + public EmojiEditText(Context context) { + this(context, null); + } + + public EmojiEditText(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, R.attr.editTextStyle); + } + + public EmojiEditText(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + // this ensures the view is redrawn when invalidated + setLayerType(LAYER_TYPE_SOFTWARE, null); + setFilters(new InputFilter[] {new EmojiFilter(this)}); + } + + public void insertEmoji(String emoji) { + int start = getSelectionStart(); + int end = getSelectionEnd(); + + getText().replace(Math.min(start, end), Math.max(start, end), emoji); + setSelection(start + emoji.length()); + } + + @Override + public void invalidateDrawable(@NonNull Drawable drawable) { + if (drawable instanceof EmojiDrawable) invalidate(); + else super.invalidateDrawable(drawable); + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiFilter.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..3afc44c2fe6d3a45a66e71d81d15cc3bbff7c7d5 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiFilter.java @@ -0,0 +1,36 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.support.annotation.UiThread; +import android.text.InputFilter; +import android.text.Spannable; +import android.text.Spanned; +import android.text.TextUtils; +import android.widget.TextView; + +import javax.annotation.Nullable; + +@UiThread +class EmojiFilter implements InputFilter { + + private final TextView view; + + EmojiFilter(TextView view) { + this.view = view; + } + + @Nullable + @Override + public CharSequence filter(CharSequence source, int start, int end, + Spanned dest, int dstart, int dend) { + + char[] v = new char[end - start]; + TextUtils.getChars(source, start, end, v, 0); + Spannable emojified = EmojiProvider.getInstance(view.getContext()) + .emojify(new String(v), view); + if (source instanceof Spanned && emojified != null) { + TextUtils.copySpansFrom((Spanned) source, start, end, null, + emojified, 0); + } + return emojified; + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageModel.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageModel.java new file mode 100644 index 0000000000000000000000000000000000000000..eeaf12409474d64b8833f262ca7905e659086f6e --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageModel.java @@ -0,0 +1,20 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; + +import javax.annotation.Nullable; + +interface EmojiPageModel { + + @DrawableRes + int getIcon(); + + @NonNull + String[] getEmoji(); + + boolean hasSpriteMap(); + + @Nullable + String getSprite(); +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java new file mode 100644 index 0000000000000000000000000000000000000000..8a727a7cdf369120b65dd77c3c3ed82b8895ef1e --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java @@ -0,0 +1,111 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.content.Context; +import android.support.annotation.UiThread; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.BaseAdapter; +import android.widget.FrameLayout; +import android.widget.GridView; + +import org.briarproject.mailbox.R; + +import javax.annotation.Nullable; + +@UiThread +public class EmojiPageView extends FrameLayout { + + private final GridView grid; + + private EmojiSelectionListener listener; + + public EmojiPageView(Context context) { + this(context, null); + } + + public EmojiPageView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public EmojiPageView(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + View view = LayoutInflater.from(getContext()) + .inflate(R.layout.emoji_grid_layout, this, true); + grid = view.findViewById(R.id.emoji); + grid.setColumnWidth(getResources() + .getDimensionPixelSize(R.dimen.emoji_drawer_size) + 2 * + getResources().getDimensionPixelSize( + R.dimen.emoji_drawer_item_padding)); + grid.setOnItemClickListener((parent, view1, position, id) -> { + if (listener != null) + listener.onEmojiSelected(((EmojiView) view1).getEmoji()); + }); + } + + public void setModel(EmojiPageModel model) { + grid.setAdapter(new EmojiGridAdapter(getContext(), model)); + } + + public void setEmojiSelectedListener(EmojiSelectionListener listener) { + this.listener = listener; + } + + private static class EmojiGridAdapter extends BaseAdapter { + + private final Context context; + private final EmojiPageModel model; + private final int emojiSize; + + private EmojiGridAdapter(Context context, EmojiPageModel model) { + this.context = context; + this.model = model; + emojiSize = (int) context.getResources() + .getDimension(R.dimen.emoji_drawer_size); + } + + @Override + public int getCount() { + return model.getEmoji().length; + } + + @Nullable + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + EmojiView view; + int pad = context.getResources() + .getDimensionPixelSize(R.dimen.emoji_drawer_item_padding); + if (convertView != null && convertView instanceof EmojiView) { + view = (EmojiView) convertView; + } else { + EmojiView emojiView = new EmojiView(context); + emojiView.setPadding(pad, pad, pad, pad); + emojiView.setLayoutParams( + new AbsListView.LayoutParams(emojiSize + 2 * pad, + emojiSize + 2 * pad)); + view = emojiView; + } + String emoji = model.getEmoji()[position]; + view.setEmoji(emoji); + + return view; + } + } + + interface EmojiSelectionListener { + void onEmojiSelected(String emoji); + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPages.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPages.java new file mode 100644 index 0000000000000000000000000000000000000000..e5ca67c61c60df3d04f2176d2390cb6088366b2a --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPages.java @@ -0,0 +1,65 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.content.Context; + +import org.briarproject.mailbox.R; + +import java.util.Arrays; +import java.util.List; + +class EmojiPages { + + static List<EmojiPageModel> getPages(Context ctx) { + return Arrays.asList( + new StaticEmojiPageModel(ctx, R.drawable.ic_emoji_smiley_people, + R.array.emoji_smiley_people, + "emoji_smiley_people.png"), + new StaticEmojiPageModel(ctx, + R.drawable.ic_emoji_animals_nature, + R.array.emoji_animals_nature, + "emoji_animals_nature.png"), + new StaticEmojiPageModel(ctx, R.drawable.ic_emoji_food_drink, + R.array.emoji_food_drink, + "emoji_food_drink.png"), + new StaticEmojiPageModel(ctx, R.drawable.ic_emoji_travel_places, + R.array.emoji_travel_places, + "emoji_travel_places.png"), + new StaticEmojiPageModel(ctx, R.drawable.ic_emoji_activity, + R.array.emoji_activity, + "emoji_activity.png"), + new StaticEmojiPageModel(ctx, R.drawable.ic_emoji_objects, + R.array.emoji_objects, + "emoji_objects.png"), + new StaticEmojiPageModel(ctx, R.drawable.ic_emoji_symbols, + R.array.emoji_symbols, + "emoji_symbols.png"), + new StaticEmojiPageModel(ctx, R.drawable.ic_emoji_flags, + R.array.emoji_flags, + "emoji_flags.png"), + + new StaticEmojiPageModel(R.drawable.ic_emoji_emoticons, + new String[] { + ":-)", ";-)", "(-:", ":->", ":-D", "\\o/", + ":-P", "B-)", ":-$", ":-*", "O:-)", "=-O", + "O_O", "O_o", "o_O", ":O", ":-!", ":-x", + ":-|", ":-\\", ":-(", ":'(", ":-[", ">:-(", + "^.^", "^_^", "\\(\u02c6\u02da\u02c6)/", + "\u30fd(\u00b0\u25c7\u00b0 )\u30ce", + "\u00af\\(\u00b0_o)/\u00af", + "\u00af\\_(\u30c4)_/\u00af", "(\u00ac_\u00ac)", + "(>_<)", "(\u2565\ufe4f\u2565)", + "(\u261e\uff9f\u30ee\uff9f)\u261e", + "\u261c(\uff9f\u30ee\uff9f\u261c)", + "\u261c(\u2312\u25bd\u2312)\u261e", + "(\u256f\u00b0\u25a1\u00b0)\u256f\ufe35", + "\u253b\u2501\u253b", + "\u252c\u2500\u252c", + "\u30ce(\u00b0\u2013\u00b0\u30ce)", + "(^._.^)\uff89", + "\u0e05^\u2022\ufecc\u2022^\u0e05", + "(\u2022_\u2022)", + " \u25a0-\u25a0\u00ac <(\u2022_\u2022) ", + "(\u25a0_\u25a0\u00ac)" + }, null)); + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..c5edf9c1792d558b448831e8c2e2cc8c05c206e6 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java @@ -0,0 +1,306 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.support.annotation.UiThread; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.util.SparseArray; +import android.widget.TextView; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.MailboxApplication; +import org.thoughtcrime.securesms.components.util.FutureTaskListener; +import org.thoughtcrime.securesms.components.util.ListenableFutureTask; +import org.thoughtcrime.securesms.util.BitmapDecodingException; +import org.thoughtcrime.securesms.util.BitmapUtil; + +import java.io.IOException; +import java.lang.ref.SoftReference; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static android.graphics.Paint.ANTI_ALIAS_FLAG; +import static android.graphics.Paint.FILTER_BITMAP_FLAG; +import static android.graphics.PixelFormat.TRANSLUCENT; +import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class EmojiProvider { + + private static volatile EmojiProvider INSTANCE = null; + + private static final Paint PAINT = + new Paint(FILTER_BITMAP_FLAG | ANTI_ALIAS_FLAG); + + @Inject + AndroidExecutor androidExecutor; + + private static final Logger LOG = + Logger.getLogger(EmojiProvider.class.getName()); + + private final SparseArray<DrawInfo> offsets = new SparseArray<>(); + + private static final Pattern EMOJI_RANGE = Pattern.compile( + // 0x203c,0x2049 0x20a0-0x32ff 0x1f00-0x1fff 0xfe4e5-0xfe4ee + // |=== !!, ?! ===||==== misc ===||========= emoticons =======||========== flags ==========| + "[\\u203c\\u2049\\u20a0-\\u32ff\\ud83c\\udc00-\\ud83f\\udfff\\udbb9\\udce5-\\udbb9\\udcee]"); + + private static final int EMOJI_RAW_HEIGHT = 64; + private static final int EMOJI_RAW_WIDTH = 64; + private static final int EMOJI_VERT_PAD = 0; + private static final int EMOJI_PER_ROW = 32; + + private final Context context; + private final float decodeScale; + private final List<EmojiPageModel> staticPages; + + static EmojiProvider getInstance(Context context) { + if (INSTANCE == null) { + synchronized (EmojiProvider.class) { + if (INSTANCE == null) { + LOG.info("Creating new instance of EmojiProvider"); + INSTANCE = new EmojiProvider(context); + MailboxApplication app = + (MailboxApplication) context.getApplicationContext(); + app.getApplicationComponent().inject(INSTANCE); + } + } + } + return INSTANCE; + } + + private EmojiProvider(Context context) { + this.context = context.getApplicationContext(); + float drawerSize = + context.getResources().getDimension(R.dimen.emoji_drawer_size); + decodeScale = Math.min(1f, drawerSize / EMOJI_RAW_HEIGHT); + staticPages = EmojiPages.getPages(context); + for (EmojiPageModel page : staticPages) { + if (page.hasSpriteMap()) { + EmojiPageBitmap pageBitmap = new EmojiPageBitmap(page); + for (int i = 0; i < page.getEmoji().length; i++) { + offsets.put(Character.codePointAt(page.getEmoji()[i], 0), + new DrawInfo(pageBitmap, i)); + } + } + } + } + + @Nullable + @UiThread + Spannable emojify(@Nullable CharSequence text, TextView tv) { + if (text == null) return null; + Matcher matches = EMOJI_RANGE.matcher(text); + SpannableStringBuilder builder = new SpannableStringBuilder(text); + + while (matches.find()) { + int codePoint = matches.group().codePointAt(0); + Drawable drawable = getEmojiDrawable(codePoint); + if (drawable != null) { + builder.setSpan(new EmojiSpan(drawable, tv), matches.start(), + matches.end(), SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + return builder; + } + + @Nullable + @UiThread + Drawable getEmojiDrawable(int emojiCode) { + return getEmojiDrawable(offsets.get(emojiCode)); + } + + @Nullable + private Drawable getEmojiDrawable(@Nullable DrawInfo drawInfo) { + if (drawInfo == null) { + return null; + } + + EmojiDrawable drawable = new EmojiDrawable(drawInfo, decodeScale); + drawInfo.page.get().addListener(new FutureTaskListener<Bitmap>() { + @Override + public void onSuccess(Bitmap result) { + androidExecutor.runOnUiThread(() -> drawable.setBitmap(result)); + } + + @Override + public void onFailure(Throwable error) { + logException(LOG, WARNING, error); + } + }); + return drawable; + } + + List<EmojiPageModel> getStaticPages() { + return staticPages; + } + + + static class EmojiDrawable extends Drawable { + + private final DrawInfo info; + private final float intrinsicWidth, intrinsicHeight, verticalPad; + + private Bitmap bmp; + + private EmojiDrawable(DrawInfo info, float decodeScale) { + this.info = info; + intrinsicWidth = EMOJI_RAW_WIDTH * decodeScale; + intrinsicHeight = EMOJI_RAW_HEIGHT * decodeScale; + verticalPad = EMOJI_VERT_PAD * decodeScale; + } + + @Override + public int getIntrinsicWidth() { + return (int) intrinsicWidth; + } + + @Override + public int getIntrinsicHeight() { + return (int) intrinsicHeight; + } + + @Override + public void draw(Canvas canvas) { + if (bmp == null) { + return; + } + + int row = info.index / EMOJI_PER_ROW; + int rowIndex = info.index % EMOJI_PER_ROW; + + int left = (int) (rowIndex * intrinsicWidth); + int top = (int) (row * intrinsicHeight + row * verticalPad); + int right = (int) ((rowIndex + 1) * intrinsicWidth); + int bottom = + (int) ((row + 1) * intrinsicHeight + row * verticalPad); + canvas.drawBitmap(bmp, new Rect(left, top, right, bottom), + getBounds(), PAINT); + } + + void setBitmap(Bitmap bitmap) { + if (bmp == null || !bmp.sameAs(bitmap)) { + bmp = bitmap; + invalidateSelf(); + } + } + + @Override + public int getOpacity() { + return TRANSLUCENT; + } + + @Override + public void setAlpha(int alpha) { + } + + @Override + public void setColorFilter(@Nullable ColorFilter cf) { + } + } + + + private static class DrawInfo { + + private final EmojiPageBitmap page; + private final int index; + + private DrawInfo(EmojiPageBitmap page, int index) { + this.page = page; + this.index = index; + } + + @Override + public String toString() { + return "DrawInfo{ " + "page = " + page + ", index = " + index + '}'; + } + } + + private class EmojiPageBitmap { + + private final EmojiPageModel model; + + private ListenableFutureTask<Bitmap> task; + + private volatile SoftReference<Bitmap> bitmapReference; + + private EmojiPageBitmap(EmojiPageModel model) { + this.model = model; + } + + @UiThread + private ListenableFutureTask<Bitmap> get() { + if (bitmapReference != null) { + Bitmap bitmap = bitmapReference.get(); + if (bitmap != null) return new ListenableFutureTask<>(bitmap); + } + if (task != null) return task; + Callable<Bitmap> callable = () -> { + if (LOG.isLoggable(INFO)) + LOG.info("Loading page " + model.getSprite()); + return loadPage(); + }; + task = new ListenableFutureTask<>(callable); + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + task.run(); + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + task = null; + } + }.execute(); + return task; + } + + private Bitmap loadPage() throws IOException { + if (bitmapReference != null) { + Bitmap bitmap = bitmapReference.get(); + if (bitmap != null) return bitmap; + } + + try { + Bitmap bitmap = BitmapUtil.createScaledBitmap(context, + "file:///android_asset/" + model.getSprite(), + decodeScale); + bitmapReference = new SoftReference<>(bitmap); + if (LOG.isLoggable(INFO)) + LOG.info("Loaded page " + model.getSprite()); + return bitmap; + } catch (BitmapDecodingException e) { + logException(LOG, WARNING, e); + throw new IOException(e); + } + } + + @Nullable + @Override + public String toString() { + return model.getSprite(); + } + } + +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiSpan.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiSpan.java new file mode 100644 index 0000000000000000000000000000000000000000..824b0a2ee65101ddcd725117f9427c85951ddac0 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiSpan.java @@ -0,0 +1,40 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.graphics.Paint; +import android.graphics.Paint.FontMetricsInt; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.UiThread; +import android.widget.TextView; + +import org.briarproject.mailbox.R; + +@UiThread +class EmojiSpan extends AnimatingImageSpan { + + private final int size; + private final FontMetricsInt fm; + + EmojiSpan(@NonNull Drawable drawable, @NonNull TextView tv) { + super(drawable, tv); + fm = tv.getPaint().getFontMetricsInt(); + size = fm != null ? Math.abs(fm.descent) + Math.abs(fm.ascent) + : tv.getResources().getDimensionPixelSize( + R.dimen.conversation_item_body_text_size); + getDrawable().setBounds(0, 0, size, size); + } + + @Override + public int getSize(Paint paint, CharSequence text, int start, int end, + FontMetricsInt fm) { + if (fm != null && this.fm != null) { + fm.ascent = this.fm.ascent; + fm.descent = this.fm.descent; + fm.top = this.fm.top; + fm.bottom = this.fm.bottom; + return size; + } else { + return super.getSize(paint, text, start, end, fm); + } + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java new file mode 100644 index 0000000000000000000000000000000000000000..76458decf5434b3c645af2f0449d527ba3be9df3 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java @@ -0,0 +1,62 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.UiThread; +import android.support.v7.widget.AppCompatTextView; +import android.util.AttributeSet; +import android.view.ViewConfiguration; + +import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable; + +import javax.annotation.Nullable; + +import static android.widget.TextView.BufferType.SPANNABLE; + +@UiThread +public class EmojiTextView extends AppCompatTextView { + + public EmojiTextView(Context context) { + this(context, null); + } + + public EmojiTextView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public EmojiTextView(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + // this ensures the view is redrawn when invalidated + setLayerType(LAYER_TYPE_SOFTWARE, null); + } + + @Override + public void setText(@Nullable CharSequence text, BufferType type) { + CharSequence source = + EmojiProvider.getInstance(getContext()).emojify(text, this); + super.setText(source, SPANNABLE); + } + + @Override + public void invalidateDrawable(@NonNull Drawable drawable) { + if (drawable instanceof EmojiDrawable) invalidate(); + else super.invalidateDrawable(drawable); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, + int bottom) { + // disable software layer if cache size is too small for it + int drawingCacheSize = ViewConfiguration.get(getContext()) + .getScaledMaximumDrawingCacheSize(); + int width = right - left; + int height = bottom - top; + int size = width * height * 4; + if (size > drawingCacheSize) { + setLayerType(LAYER_TYPE_NONE, null); + } + super.onLayout(changed, left, top, right, bottom); + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiToggle.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiToggle.java new file mode 100644 index 0000000000000000000000000000000000000000..d1f03b518bb0e95eef69a018de89dae137905a92 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiToggle.java @@ -0,0 +1,62 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.annotation.UiThread; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.AppCompatImageButton; +import android.util.AttributeSet; + +import org.briarproject.mailbox.R; +import org.thoughtcrime.securesms.components.emoji.EmojiDrawer.EmojiDrawerListener; + +import javax.annotation.Nullable; + +@UiThread +public class EmojiToggle extends AppCompatImageButton + implements EmojiDrawerListener { + + private final Drawable emojiToggle; + private final Drawable imeToggle; + + public EmojiToggle(Context context) { + this(context, null); + } + + public EmojiToggle(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public EmojiToggle(Context context, @Nullable AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + + emojiToggle = ContextCompat + .getDrawable(getContext(), R.drawable.ic_emoji_toggle); + imeToggle = ContextCompat + .getDrawable(getContext(), R.drawable.ic_keyboard); + setToEmoji(); + } + + public void setToEmoji() { + setImageDrawable(emojiToggle); + } + + public void setToIme() { + setImageDrawable(imeToggle); + } + + public void attach(EmojiDrawer drawer) { + drawer.setDrawerListener(this); + } + + @Override + public void onShown() { + setToIme(); + } + + @Override + public void onHidden() { + setToEmoji(); + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiView.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiView.java new file mode 100644 index 0000000000000000000000000000000000000000..e3e06a3d3985ebd7b1659ba6b1f067d6295d9a95 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiView.java @@ -0,0 +1,88 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.UiThread; +import android.util.AttributeSet; +import android.view.View; + +import javax.annotation.Nullable; + +import static android.graphics.Paint.ANTI_ALIAS_FLAG; +import static android.graphics.Paint.Align.CENTER; +import static android.graphics.Paint.FILTER_BITMAP_FLAG; +import static org.briarproject.mailbox.android.util.UiUtils.resolveColorAttribute; + +@UiThread +public class EmojiView extends View implements Drawable.Callback { + + private final Paint paint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG); + + private String emoji; + private Drawable drawable; + + public EmojiView(Context context) { + this(context, null); + } + + public EmojiView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public EmojiView(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public void setEmoji(String emoji) { + this.emoji = emoji; + this.drawable = EmojiProvider.getInstance(getContext()) + .getEmojiDrawable(Character.codePointAt(emoji, 0)); + postInvalidate(); + } + + public String getEmoji() { + return emoji; + } + + @Override + protected void onDraw(Canvas canvas) { + if (drawable != null) { + drawable.setBounds(getPaddingLeft(), + getPaddingTop(), + getWidth() - getPaddingRight(), + getHeight() - getPaddingBottom()); + drawable.setCallback(this); + drawable.draw(canvas); + } else { + float targetFontSize = + 0.75f * getHeight() - getPaddingTop() - getPaddingBottom(); + paint.setTextSize(targetFontSize); + int color = resolveColorAttribute(getContext(), + android.R.attr.textColorPrimary); + paint.setColor(color); + paint.setTextAlign(CENTER); + int xPos = (canvas.getWidth() / 2); + int yPos = (int) ((canvas.getHeight() / 2) - + ((paint.descent() + paint.ascent()) / 2)); + + float overflow = paint.measureText(emoji) / + (getWidth() - getPaddingLeft() - getPaddingRight()); + if (overflow > 1f) { + paint.setTextSize(targetFontSize / overflow); + yPos = (int) ((canvas.getHeight() / 2) - + ((paint.descent() + paint.ascent()) / 2)); + } + canvas.drawText(emoji, xPos, yPos, paint); + } + } + + @Override + public void invalidateDrawable(@NonNull Drawable drawable) { + super.invalidateDrawable(drawable); + postInvalidate(); + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel.java new file mode 100644 index 0000000000000000000000000000000000000000..b6cf01868357adf78af88eb6a34b575d7c9171e7 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel.java @@ -0,0 +1,133 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.content.Context; +import android.support.annotation.DrawableRes; + +import org.briarproject.bramble.api.db.DatabaseExecutor; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.settings.Settings; +import org.briarproject.bramble.api.settings.SettingsManager; +import org.briarproject.bramble.util.StringUtils; +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.MailboxApplication; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.mailbox.android.settings.SettingsFragment.SETTINGS_NAMESPACE; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class RecentEmojiPageModel implements EmojiPageModel { + + private static final Logger LOG = + Logger.getLogger(RecentEmojiPageModel.class.getName()); + + private static final String EMOJI_LRU_PREFERENCE = "pref_emoji_recent2"; + private static final int EMOJI_LRU_SIZE = 50; + + private final LinkedHashSet<String> recentlyUsed; // UI thread + + @Inject + SettingsManager settingsManager; + + @Inject + @DatabaseExecutor + Executor dbExecutor; + + RecentEmojiPageModel(Context context) { + MailboxApplication app = + (MailboxApplication) context.getApplicationContext(); + app.getApplicationComponent().inject(this); + recentlyUsed = getPersistedCache(); + } + + private LinkedHashSet<String> getPersistedCache() { + String serialized; + try { + // FIXME: Don't make DB calls on the UI thread + Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE); + serialized = settings.get(EMOJI_LRU_PREFERENCE); + } catch (DbException e) { + logException(LOG, WARNING, e); + serialized = null; + } + return deserialize(serialized); + } + + @DrawableRes + @Override + public int getIcon() { + return R.drawable.ic_emoji_recent; + } + + @Override + public String[] getEmoji() { + return toReversePrimitiveArray(recentlyUsed); + } + + @Override + public boolean hasSpriteMap() { + return false; + } + + @Override + public String getSprite() { + return null; + } + + void onCodePointSelected(String emoji) { + recentlyUsed.remove(emoji); + recentlyUsed.add(emoji); + + if (recentlyUsed.size() > EMOJI_LRU_SIZE) { + Iterator<String> iterator = recentlyUsed.iterator(); + iterator.next(); + iterator.remove(); + } + save(serialize(recentlyUsed)); + } + + private String serialize(LinkedHashSet<String> emojis) { + return StringUtils.join(emojis, "\t"); + } + + private LinkedHashSet<String> deserialize(@Nullable String serialized) { + if (serialized == null) return new LinkedHashSet<>(); + String[] list = serialized.split("\t"); + LinkedHashSet<String> result = new LinkedHashSet<>(list.length); + Collections.addAll(result, list); + return result; + } + + private void save(String serialized) { + dbExecutor.execute(() -> { + Settings settings = new Settings(); + settings.put(EMOJI_LRU_PREFERENCE, serialized); + try { + settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + private String[] toReversePrimitiveArray(LinkedHashSet<String> emojiSet) { + String[] emojis = new String[emojiSet.size()]; + int i = emojiSet.size() - 1; + for (String emoji : emojiSet) { + emojis[i--] = emoji; + } + return emojis; + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java new file mode 100644 index 0000000000000000000000000000000000000000..4f9c9b94c66482de567acbe0865dd9c4487e2149 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel.java @@ -0,0 +1,74 @@ +package org.thoughtcrime.securesms.components.emoji; + +import android.content.Context; +import android.support.annotation.ArrayRes; +import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; +import android.support.annotation.UiThread; + +import javax.annotation.Nullable; + +@UiThread +class StaticEmojiPageModel implements EmojiPageModel { + + @DrawableRes + private final int icon; + @NonNull + private final String[] emoji; + @Nullable + private final String sprite; + + StaticEmojiPageModel(@DrawableRes int icon, @NonNull String[] emoji, + @Nullable String sprite) { + this.icon = icon; + this.emoji = emoji; + this.sprite = sprite; + } + + StaticEmojiPageModel(Context ctx, @DrawableRes int icon, + @ArrayRes int res, @Nullable String sprite) { + this(icon, getEmoji(ctx, res), sprite); + } + + @DrawableRes + @Override + public int getIcon() { + return icon; + } + + @Override + @NonNull + public String[] getEmoji() { + return emoji; + } + + @Override + public boolean hasSpriteMap() { + return sprite != null; + } + + @Nullable + @Override + public String getSprite() { + return sprite; + } + + @NonNull + private static String[] getEmoji(Context ctx, @ArrayRes int res) { + String[] rawStrings = ctx.getResources().getStringArray(res); + String[] emoji = new String[rawStrings.length]; + int i = 0; + for (String codePoint : rawStrings) { + String[] bytes = codePoint.split(","); + int[] codePoints = new int[bytes.length]; + int j = 0; + for (String b : bytes) { + codePoints[j] = Integer.valueOf(b, 16); + } + emoji[i] = new String(codePoints, 0, codePoints.length); + i++; + } + return emoji; + } + +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/util/FutureTaskListener.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/util/FutureTaskListener.java new file mode 100644 index 0000000000000000000000000000000000000000..80da2eccf6420c4c9f597eccbba39035cb0b7759 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/util/FutureTaskListener.java @@ -0,0 +1,23 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.thoughtcrime.securesms.components.util; + +public interface FutureTaskListener<V> { + void onSuccess(V result); + + void onFailure(Throwable error); +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/util/ListenableFutureTask.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/util/ListenableFutureTask.java new file mode 100644 index 0000000000000000000000000000000000000000..3d8303f07d7762f4fcb4bcbed61b0406e50cfb72 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/components/util/ListenableFutureTask.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.thoughtcrime.securesms.components.util; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; + +import javax.annotation.Nullable; + +public class ListenableFutureTask<V> extends FutureTask<V> { + + private final List<FutureTaskListener<V>> listeners = new LinkedList<>(); + + @Nullable + private final Object identifier; + + public ListenableFutureTask(Callable<V> callable) { + this(callable, null); + } + + private ListenableFutureTask(Callable<V> callable, + @Nullable Object identifier) { + super(callable); + this.identifier = identifier; + } + + public ListenableFutureTask(V result) { + this(result, null); + } + + private ListenableFutureTask(V result, @Nullable Object identifier) { + super(() -> result); + this.identifier = identifier; + this.run(); + } + + public synchronized void addListener(FutureTaskListener<V> listener) { + if (this.isDone()) { + callback(listener); + } else { + this.listeners.add(listener); + } + } + + public synchronized void removeListener(FutureTaskListener<V> listener) { + this.listeners.remove(listener); + } + + @Override + protected synchronized void done() { + callback(); + } + + private void callback() { + for (FutureTaskListener<V> listener : listeners) { + callback(listener); + } + } + + private void callback(FutureTaskListener<V> listener) { + if (listener != null) { + try { + listener.onSuccess(get()); + } catch (InterruptedException e) { + throw new AssertionError(e); + } catch (ExecutionException e) { + listener.onFailure(e); + } + } + } + + @Override + public boolean equals(Object other) { + if (other != null && other instanceof ListenableFutureTask && + this.identifier != null) { + return identifier.equals(other); + } else { + return super.equals(other); + } + } + + @Override + public int hashCode() { + if (identifier != null) return identifier.hashCode(); + else return super.hashCode(); + } + +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/util/BitmapDecodingException.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/util/BitmapDecodingException.java new file mode 100644 index 0000000000000000000000000000000000000000..777fdfb2ead9fe8cc8c140432cbc35ff522281c4 --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/util/BitmapDecodingException.java @@ -0,0 +1,12 @@ +package org.thoughtcrime.securesms.util; + +public class BitmapDecodingException extends Exception { + + BitmapDecodingException(String s) { + super(s); + } + + BitmapDecodingException(Exception nested) { + super(nested); + } +} diff --git a/mailbox-android/src/main/java/org/thoughtcrime/securesms/util/BitmapUtil.java b/mailbox-android/src/main/java/org/thoughtcrime/securesms/util/BitmapUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..32d924d7b21d3af19cf3c664fa3c746ab5adcd9d --- /dev/null +++ b/mailbox-android/src/main/java/org/thoughtcrime/securesms/util/BitmapUtil.java @@ -0,0 +1,96 @@ +package org.thoughtcrime.securesms.util; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.Pair; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.Priority; +import com.bumptech.glide.load.DecodeFormat; +import com.bumptech.glide.load.engine.Resource; +import com.bumptech.glide.load.resource.bitmap.BitmapResource; +import com.bumptech.glide.load.resource.bitmap.Downsampler; +import com.bumptech.glide.load.resource.bitmap.FitCenter; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Logger; + +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; + +public class BitmapUtil { + + private static final Logger LOG = + Logger.getLogger(BitmapUtil.class.getName()); + + private static <T> InputStream getInputStreamForModel(Context context, + T model) + throws BitmapDecodingException { + try { + return Glide.buildStreamModelLoader(model, context) + .getResourceFetcher(model, -1, -1) + .loadData(Priority.NORMAL); + } catch (Exception e) { + throw new BitmapDecodingException(e); + } + } + + private static <T> Bitmap createScaledBitmapInto(Context context, T model, + int width, int height) + throws BitmapDecodingException { + Bitmap rough = Downsampler.AT_LEAST + .decode(getInputStreamForModel(context, model), + Glide.get(context).getBitmapPool(), + width, height, DecodeFormat.PREFER_RGB_565); + + Resource<Bitmap> resource = BitmapResource + .obtain(rough, Glide.get(context).getBitmapPool()); + Resource<Bitmap> result = + new FitCenter(context).transform(resource, width, height); + + if (result == null) { + throw new BitmapDecodingException("unable to transform Bitmap"); + } + return result.get(); + } + + public static <T> Bitmap createScaledBitmap(Context context, T model, + float scale) throws BitmapDecodingException { + Pair<Integer, Integer> dimens = + getDimensions(getInputStreamForModel(context, model)); + return createScaledBitmapInto(context, model, + (int) (dimens.first * scale), (int) (dimens.second * scale)); + } + + private static BitmapFactory.Options getImageDimensions( + InputStream inputStream) + throws BitmapDecodingException { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BufferedInputStream fis = new BufferedInputStream(inputStream); + BitmapFactory.decodeStream(fis, null, options); + try { + fis.close(); + } catch (IOException e) { + logException(LOG, WARNING, e); + } + + if (options.outWidth == -1 || options.outHeight == -1) { + throw new BitmapDecodingException( + "Failed to decode image dimensions: " + options.outWidth + + ", " + options.outHeight); + } + + return options; + } + + private static Pair<Integer, Integer> getDimensions(InputStream inputStream) + throws BitmapDecodingException { + BitmapFactory.Options options = getImageDimensions(inputStream); + return new Pair<>(options.outWidth, options.outHeight); + } + +} diff --git a/mailbox-android/src/main/res/anim/fade_in.xml b/mailbox-android/src/main/res/anim/fade_in.xml new file mode 100644 index 0000000000000000000000000000000000000000..4d3bef4a381f2bc23b53a600fc47608e9a65a8a7 --- /dev/null +++ b/mailbox-android/src/main/res/anim/fade_in.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<alpha + xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="@android:integer/config_longAnimTime" + android:fromAlpha="0.0" + android:interpolator="@android:interpolator/decelerate_quad" + android:toAlpha="1.0"/> diff --git a/mailbox-android/src/main/res/anim/fade_out.xml b/mailbox-android/src/main/res/anim/fade_out.xml new file mode 100644 index 0000000000000000000000000000000000000000..84bad946f7b5b9c4c2f59ff106f1b079af96b4be --- /dev/null +++ b/mailbox-android/src/main/res/anim/fade_out.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<alpha + xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="@android:integer/config_mediumAnimTime" + android:fromAlpha="1.0" + android:interpolator="@android:interpolator/accelerate_quad" + android:toAlpha="0.0"/> diff --git a/mailbox-android/src/main/res/anim/screen_new_in.xml b/mailbox-android/src/main/res/anim/screen_new_in.xml new file mode 100644 index 0000000000000000000000000000000000000000..6bdf53b16d438e3b8312164f3ee48ac4b43fd545 --- /dev/null +++ b/mailbox-android/src/main/res/anim/screen_new_in.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<set + xmlns:android="http://schemas.android.com/apk/res/android"> + + <!-- slide in from right --> + <translate + android:duration="@android:integer/config_mediumAnimTime" + android:fromXDelta="100%p" + android:interpolator="@android:interpolator/decelerate_quad" + android:toXDelta="0"/> + +</set> diff --git a/mailbox-android/src/main/res/anim/screen_new_out.xml b/mailbox-android/src/main/res/anim/screen_new_out.xml new file mode 100644 index 0000000000000000000000000000000000000000..5411fa11baa7c16b1651f5f3354f38ffff187302 --- /dev/null +++ b/mailbox-android/src/main/res/anim/screen_new_out.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<set + xmlns:android="http://schemas.android.com/apk/res/android"> + + <!-- slide out to right --> + <translate + android:duration="@android:integer/config_mediumAnimTime" + android:fromXDelta="0" + android:interpolator="@android:interpolator/accelerate_quad" + android:toXDelta="100%p"/> + +</set> diff --git a/mailbox-android/src/main/res/anim/screen_old_in.xml b/mailbox-android/src/main/res/anim/screen_old_in.xml new file mode 100644 index 0000000000000000000000000000000000000000..2360d85b58d6b8f1372873804879fc1dfc65376c --- /dev/null +++ b/mailbox-android/src/main/res/anim/screen_old_in.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<alpha + xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="@android:integer/config_mediumAnimTime" + android:fromAlpha="0.0" + android:interpolator="@android:interpolator/decelerate_quad" + android:toAlpha="1.0"/> diff --git a/mailbox-android/src/main/res/anim/screen_old_out.xml b/mailbox-android/src/main/res/anim/screen_old_out.xml new file mode 100644 index 0000000000000000000000000000000000000000..84bad946f7b5b9c4c2f59ff106f1b079af96b4be --- /dev/null +++ b/mailbox-android/src/main/res/anim/screen_old_out.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<alpha + xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="@android:integer/config_mediumAnimTime" + android:fromAlpha="1.0" + android:interpolator="@android:interpolator/accelerate_quad" + android:toAlpha="0.0"/> diff --git a/mailbox-android/src/main/res/anim/step_next_in.xml b/mailbox-android/src/main/res/anim/step_next_in.xml new file mode 100644 index 0000000000000000000000000000000000000000..6bdf53b16d438e3b8312164f3ee48ac4b43fd545 --- /dev/null +++ b/mailbox-android/src/main/res/anim/step_next_in.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<set + xmlns:android="http://schemas.android.com/apk/res/android"> + + <!-- slide in from right --> + <translate + android:duration="@android:integer/config_mediumAnimTime" + android:fromXDelta="100%p" + android:interpolator="@android:interpolator/decelerate_quad" + android:toXDelta="0"/> + +</set> diff --git a/mailbox-android/src/main/res/anim/step_next_out.xml b/mailbox-android/src/main/res/anim/step_next_out.xml new file mode 100644 index 0000000000000000000000000000000000000000..5411fa11baa7c16b1651f5f3354f38ffff187302 --- /dev/null +++ b/mailbox-android/src/main/res/anim/step_next_out.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<set + xmlns:android="http://schemas.android.com/apk/res/android"> + + <!-- slide out to right --> + <translate + android:duration="@android:integer/config_mediumAnimTime" + android:fromXDelta="0" + android:interpolator="@android:interpolator/accelerate_quad" + android:toXDelta="100%p"/> + +</set> diff --git a/mailbox-android/src/main/res/anim/step_previous_in.xml b/mailbox-android/src/main/res/anim/step_previous_in.xml new file mode 100644 index 0000000000000000000000000000000000000000..2360d85b58d6b8f1372873804879fc1dfc65376c --- /dev/null +++ b/mailbox-android/src/main/res/anim/step_previous_in.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<alpha + xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="@android:integer/config_mediumAnimTime" + android:fromAlpha="0.0" + android:interpolator="@android:interpolator/decelerate_quad" + android:toAlpha="1.0"/> diff --git a/mailbox-android/src/main/res/anim/step_previous_out.xml b/mailbox-android/src/main/res/anim/step_previous_out.xml new file mode 100644 index 0000000000000000000000000000000000000000..84bad946f7b5b9c4c2f59ff106f1b079af96b4be --- /dev/null +++ b/mailbox-android/src/main/res/anim/step_previous_out.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<alpha + xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="@android:integer/config_mediumAnimTime" + android:fromAlpha="1.0" + android:interpolator="@android:interpolator/accelerate_quad" + android:toAlpha="0.0"/> diff --git a/mailbox-android/src/main/res/color/button_text.xml b/mailbox-android/src/main/res/color/button_text.xml new file mode 100644 index 0000000000000000000000000000000000000000..1f1c03e9fe14711ca42acaa2cd7800b8afb99f1a --- /dev/null +++ b/mailbox-android/src/main/res/color/button_text.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:color="@color/briar_button_text_disabled" + android:state_enabled="false"/> + <item + android:color="#ffffffff"/> +</selector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable-night/contact_connected.xml b/mailbox-android/src/main/res/drawable-night/contact_connected.xml new file mode 100644 index 0000000000000000000000000000000000000000..e4e45826a2f1dad3bf9d9ab5149b7beb3719a946 --- /dev/null +++ b/mailbox-android/src/main/res/drawable-night/contact_connected.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + + <path + android:fillColor="#abffffff" + android:pathData="M12,2 C6.48,2,2,6.48,2,12 S6.48,22,12,22 S22,17.52,22,12 S17.52,2,12,2 Z M12,20 +C7.58,20,4,16.42,4,12 S7.58,4,12,4 S20,7.58,20,12 S16.42,20,12,20 Z"/> + + <path + android:fillColor="#95d220" + android:pathData="M10.8972,19.9503 C6.5514,19.3493,3.43091,15.2154,4.0625,10.896 +C4.55452,7.53099,7.09451,4.8236,10.394,4.14714 +C14.2569,3.35517,18.1698,5.54347,19.5236,9.25295 +C20.0698,10.7495,20.1616,12.4612,19.777,13.9758 +C19.5457,14.8864,18.8106,16.3388,18.2072,17.0771 +C16.4904,19.1779,13.581,20.3215,10.8973,19.9503 Z" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="0.76779664"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable-night/contact_disconnected.xml b/mailbox-android/src/main/res/drawable-night/contact_disconnected.xml new file mode 100644 index 0000000000000000000000000000000000000000..1dd34144faca351c564681df936ce4f8fe3a97f3 --- /dev/null +++ b/mailbox-android/src/main/res/drawable-night/contact_disconnected.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#abffffff" + android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm0,18c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable-night/ic_our_identity.xml b/mailbox-android/src/main/res/drawable-night/ic_our_identity.xml new file mode 100644 index 0000000000000000000000000000000000000000..685ad6b8c090f007a1121796aa4cd60853de3358 --- /dev/null +++ b/mailbox-android/src/main/res/drawable-night/ic_our_identity.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="16dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFF" + android:pathData="M12,5.9c1.16,0 2.1,0.94 2.1,2.1s-0.94,2.1 -2.1,2.1S9.9,9.16 9.9,8s0.94,-2.1 2.1,-2.1m0,9c2.97,0 6.1,1.46 6.1,2.1v1.1L5.9,18.1L5.9,17c0,-0.64 3.13,-2.1 6.1,-2.1M12,4C9.79,4 8,5.79 8,8s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,13c-2.67,0 -8,1.34 -8,4v3h16v-3c0,-2.66 -5.33,-4 -8,-4z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable-night/navigation_drawer_header.xml b/mailbox-android/src/main/res/drawable-night/navigation_drawer_header.xml new file mode 100644 index 0000000000000000000000000000000000000000..cc811098a79fd3949c2ffe50c92a410adab70724 --- /dev/null +++ b/mailbox-android/src/main/res/drawable-night/navigation_drawer_header.xml @@ -0,0 +1,15 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="146dp" + android:height="50dp" + android:viewportHeight="50" + android:viewportWidth="146"> + <path + android:fillColor="#95d220" + android:pathData="m65.098,15.35v19.301h9.068c4.226,0 6.475,-2.124 6.496,-5.479 0,-2.145 -1.018,-3.78 -3.014,-4.672v-0.041c1.508,-0.934 2.166,-2.103 2.166,-3.908 0,-2.739 -1.848,-5.201 -5.861,-5.201h-8.855zM83.848,15.35v19.301h2.271v-7.729l-0.232,-0.234h4.586c2.548,0 4.013,0.914 4.947,2.889l2.4,5.074h2.547l-2.93,-6.031c-0.637,-1.359 -1.614,-2.208 -2.527,-2.59v-0.043c2.123,-0.552 3.865,-2.42 3.865,-4.947 0,-3.801 -2.952,-5.689 -6.477,-5.689h-8.451zM102.725,15.35v19.301h2.273v-19.301zM116.145,15.35 L107.65,34.65h2.484l2.039,-4.65 -0.127,-0.234h10.574l-0.127,0.234 2.039,4.65h2.484l-8.473,-19.301zM129.48,15.35v19.301h2.271v-7.729l-0.234,-0.234h4.588c2.548,0 4.013,0.914 4.947,2.889l2.398,5.074L146,34.65l-2.93,-6.031c-0.637,-1.359 -1.614,-2.208 -2.527,-2.59v-0.043c2.123,-0.552 3.865,-2.42 3.865,-4.947 0,-3.801 -2.952,-5.689 -6.477,-5.689h-8.451zM67.158,17.494h6.561c2.463,0 3.76,0.997 3.76,3.035 0,1.72 -0.999,3.102 -3.76,3.102h-6.561l0.234,-0.234v-5.67zM85.887,17.494h6.434c2.378,0 4.141,0.975 4.162,3.523 0,2.038 -1.634,3.504 -4.416,3.504h-6.18l0.232,-0.232v-6.563zM131.539,17.494h6.434c2.357,0 4.141,0.975 4.141,3.523 0,2.038 -1.613,3.504 -4.395,3.504h-6.18l0.234,-0.232v-6.563zM117.334,17.705h0.043l0.572,1.934 3.398,7.75 0.232,0.232h-8.471l0.232,-0.232 3.398,-7.75 0.594,-1.934zM67.137,25.775h7.008c2.845,0 4.162,1.315 4.162,3.375 0,2.145 -1.189,3.334 -4.141,3.334h-7.029l0.234,-0.234v-6.242z"/> + <path + android:fillColor="#87c214" + android:pathData="m13.809,0c-2.064,0 -3.766,1.702 -3.766,3.766L10.042,8.553h9.277L19.319,3.766C19.319,1.702 17.638,0 15.574,0ZM34.447,0c-2.064,0 -3.766,1.702 -3.766,3.766L30.681,29.191h9.277L39.958,3.766C39.958,1.702 38.276,0 36.213,0ZM10.042,20.809v25.426c0,2.064 1.681,3.766 3.766,3.766h1.766c2.064,0 3.766,-1.702 3.766,-3.766L19.341,20.809ZM30.681,41.447v4.787c0,2.064 1.702,3.766 3.766,3.766h1.766c2.064,0 3.766,-1.702 3.766,-3.766v-4.787z"/> + <path + android:fillColor="#95d220" + android:pathData="M3.766,10.042C1.702,10.042 0,11.723 0,13.809v1.766c0,2.064 1.681,3.766 3.766,3.766L29.191,19.341v-9.298zM41.447,10.042v9.298h4.787c2.064,0 3.766,-1.681 3.766,-3.766v-1.766c0,-2.085 -1.702,-3.766 -3.766,-3.766zM3.766,30.681C1.702,30.681 0,32.362 0,34.447v1.766c0,2.064 1.681,3.766 3.766,3.766h4.787v-9.298zM20.809,30.681v9.298h25.426c2.064,0 3.766,-1.702 3.766,-3.766L50,34.447c0,-2.085 -1.702,-3.766 -3.766,-3.766z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable-night/navigation_item_background.xml b/mailbox-android/src/main/res/drawable-night/navigation_item_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..deac89913cfcac844e44301684322648d6e11419 --- /dev/null +++ b/mailbox-android/src/main/res/drawable-night/navigation_item_background.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@color/item_background_highlight" android:state_checked="true"/> + <item android:drawable="@color/window_background" android:state_checked="false"/> +</selector> diff --git a/mailbox-android/src/main/res/drawable-night/qr_code_explanation.xml b/mailbox-android/src/main/res/drawable-night/qr_code_explanation.xml new file mode 100644 index 0000000000000000000000000000000000000000..433179877b000633f2bedaea0daa14e0c0d15f7c --- /dev/null +++ b/mailbox-android/src/main/res/drawable-night/qr_code_explanation.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="400dp" + android:height="100dp" + android:viewportHeight="49.5" + android:viewportWidth="194.8"> + <path + android:fillColor="#ffffff" + android:pathData="M30.1 16.5l-9 0 0 -5c0 -2.4 -2 -4.4 -4.4 -4.4L4.4 7.1C2 7.1 0 9.1 0 11.5l0 24.2c0 2.4 2 4.4 4.4 4.4l9 0 0 5c0 2.4 2 4.4 4.4 4.4l12.2 0c2.4 0 4.4 -2 4.4 -4.4l0 -24.2c0.1 -2.4 -1.9 -4.4 -4.3 -4.4zm-27.4 16.1l0 -20.9 15.8 0 0 20.9 -15.8 0zm10.7 4.6l-5.8 0 0 -1.5 5.8 0 0 1.5zm13.5 9.4l-5.8 0 0 -1.5 5.8 0 0 1.5zm5 -4.6l-15.8 0 0 -1.9 0.5 0c2.4 0 4.4 -2 4.4 -4.4l0 -14.6 10.8 0 0 20.9z"/> + <path + android:fillColor="#ffffff" + android:pathData="M101.2 16.5l-8.3 0 0 -4.4c0 -1.4 -1.2 -2.6 -2.6 -2.6l-3.9 0 -2.1 -2.5 -6.9 0 -2.2 2.5 -3.8 0c-1.4 0 -2.6 1.2 -2.6 2.6l0 13.3c0 1.4 1.2 2.6 2.6 2.6l13.1 0 0 17.2c0 2.4 2 4.4 4.4 4.4l12.2 0c2.4 0 4.4 -2 4.4 -4.4l0 -24.3c0.2 -2.4 -1.8 -4.4 -4.3 -4.4zm-26.4 2.4c0 -3.3 2.7 -6 6 -6 3.3 0 6 2.7 6 6 0 3.3 -2.7 6 -6 6 -3.3 0 -6 -2.7 -6 -6zm23.2 27.7l-5.8 0 0 -1.5 5.8 0 0 1.5zm5 -4.6l-15.8 0 0 -14.1 3.1 0c1.4 0 2.6 -1.2 2.6 -2.6l0 -4.2 10.1 0 0 20.9z"/> + <path + android:fillColor="#ffffff" + android:pathData="M84.600003 18.9a3.8 3.8 0 0 1 -3.8 3.8 3.8 3.8 0 0 1 -3.8 -3.8 3.8 3.8 0 0 1 3.8 -3.8 3.8 3.8 0 0 1 3.8 3.8z"/> + <path + android:fillColor="#ffffff" + android:pathData="M175.3 16.5l-9.8 0 0 -5.7c0 -1.4 -1.2 -2.6 -2.6 -2.6l-19.3 0c-1.4 0 -2.6 1.2 -2.6 2.6l0 14.4c0 1.4 1.2 2.6 2.6 2.6l15.1 0 0 17.3c0 2.4 2 4.4 4.4 4.4l12.2 0c2.4 0 4.4 -2 4.4 -4.4l0 -24.2c0.1 -2.4 -1.9 -4.4 -4.4 -4.4zm-12.4 -5.9l-9.6 6 -9.6 -6 19.2 0zm-19.4 14.8l0 -12.3 9.8 6.1 9.8 -6.1 0 12.3 -19.6 0zm28.6 21.2l-5.8 0 0 -1.5 5.8 0 0 1.5zm5 -4.6l-15.8 0 0 -14.2 1.6 0c1.4 0 2.6 -1.2 2.6 -2.6l0 -4.1 11.6 0 0 20.9z"/> + <path + android:fillColor="#ff0000" + android:pathData="M101.4 17.8l2 2 7.4 -7.3 7.3 7.3 2.1 -2 -7.4 -7.4 7.4 -7.3 -2.1 -2.1 -7.3 7.4 -7.4 -7.4 -2 2.1 7.3 7.3z"/> + <path + android:fillColor="#ff0000" + android:pathData="M176 17.8l2.1 2 7.3 -7.3 7.4 7.3 2 -2 -7.3 -7.4 7.3 -7.3 -2 -2.1 -7.4 7.4 -7.3 -7.4 -2.1 2.1 7.3 7.3z"/> + <path + android:fillColor="#08b124" + android:pathData="M35.8 18.8l0 0L52.5 2.1 50.5 0 35.6 14.8 28.5 7.7l-2.1 2.1 9.2 9.1z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable-night/splash_screen.xml b/mailbox-android/src/main/res/drawable-night/splash_screen.xml new file mode 100644 index 0000000000000000000000000000000000000000..b1904b00398b7951297ee102d4591169e272c95c --- /dev/null +++ b/mailbox-android/src/main/res/drawable-night/splash_screen.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="235dp" + android:height="310dp" + android:viewportHeight="310" + android:viewportWidth="235"> + + <path + android:fillColor="#87c214" + android:pathData="M47.2,47.2 L90.9,47.2 L90.9,90.9 L47.2,90.9 L47.2,47.2 Z"/> + <path + android:fillColor="#87c214" + android:pathData="M64.9004,0 C55.2004,0,47.1992,7.99922,47.1992,17.6992 L47.1992,40.1992 +L90.8008,40.1992 L90.8008,17.6992 +C90.8008,7.99922,82.8992,0,73.1992,0 L64.9004,0 Z M161.9,0 +C152.2,0,144.199,7.99922,144.199,17.6992 L144.199,137.199 L187.801,137.199 +L187.801,17.6992 C187.801,7.99922,179.899,0,170.199,0 L161.9,0 Z +M47.1992,97.8008 L47.1992,217.301 C47.1992,227.001,55.1004,235,64.9004,235 +L73.1992,235 C82.8992,235,90.9004,227.001,90.9004,217.301 L90.9004,97.8008 +L47.1992,97.8008 Z M144.199,194.801 L144.199,217.301 +C144.199,227.001,152.2,235,161.9,235 L170.199,235 +C179.899,235,187.9,227.001,187.9,217.301 L187.9,194.801 L144.199,194.801 Z"/> + <path + android:fillColor="#87c214" + android:pathData="M144.2,144.2 L187.9,144.2 L187.9,187.9 L144.2,187.9 L144.2,144.2 Z"/> + <path + android:fillColor="#95d220" + android:pathData="M17.6992,47.1992 C7.99922,47.1992,0,55.1004,0,64.9004 L0,73.1992 +C0,82.8992,7.89922,90.9004,17.6992,90.9004 L137.199,90.9004 L137.199,47.1992 +L17.6992,47.1992 Z M194.801,47.1992 L194.801,90.9004 L217.301,90.9004 +C227.001,90.9004,235,82.9992,235,73.1992 L235,64.9004 +C235,55.1004,227.001,47.1992,217.301,47.1992 L194.801,47.1992 Z M17.6992,144.199 +C7.99922,144.199,0,152.1,0,161.9 L0,170.199 +C0,179.899,7.89922,187.9,17.6992,187.9 L40.1992,187.9 L40.1992,144.199 +L17.6992,144.199 Z M97.8008,144.199 L97.8008,187.9 L217.301,187.9 +C227.001,187.9,235,179.899,235,170.199 L235,161.9 +C235,152.1,227.001,144.199,217.301,144.199 L97.8008,144.199 Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M0,253.9 L0,310 L26.2656,310 C38.6498,310,45.1426,303.8,45.1426,294.1 +C45.1426,287.8,42.2457,283.1,36.4531,280.5 L36.4531,280.4 +C40.8475,277.7,42.7461,274.3,42.7461,269 C42.7461,261,37.2532,253.9,25.668,253.9 +L0,253.9 Z M54.5313,253.9 L54.5313,310 L61.1211,310 L61.1211,287.5 +L60.4238,286.801 L73.7051,286.801 +C81.0956,286.801,85.2917,289.399,87.9883,295.199 L94.9785,310 L102.369,310 +L94.0801,292.5 C92.2824,288.6,89.3857,286.1,86.7891,285 L86.7891,284.9 +C92.8813,283.3,97.9746,277.8,97.9746,270.5 +C97.9746,259.4,89.3865,253.9,79.0996,253.9 L54.5313,253.9 Z M109.26,253.9 +L109.26,310 L115.852,310 L115.852,253.9 L109.26,253.9 Z M148.012,253.9 +L123.342,310 L130.533,310 L136.525,296.5 L136.227,295.801 L166.887,295.801 +L166.588,296.5 L172.58,310 L179.771,310 L155.002,253.9 L148.012,253.9 Z +M187.16,253.9 L187.16,310 L193.752,310 L193.752,287.5 L193.053,286.801 +L206.336,286.801 C213.727,286.801,217.923,289.399,220.619,295.199 L227.609,310 +L235,310 L226.711,292.5 C224.913,288.6,222.017,286.1,219.42,285 L219.42,284.9 +C225.512,283.3,230.605,277.8,230.605,270.5 +C230.605,259.4,222.017,253.9,211.73,253.9 L187.16,253.9 Z M5.89258,260.1 +L24.9688,260.1 C32.1596,260.1,35.9531,263,35.9531,269 +C35.9531,274,32.9585,278,24.9688,278 L5.89258,278 L6.5918,277.301 +L6.5918,260.801 L5.89258,260.1 Z M60.4238,260.1 L79.0996,260.1 +C85.8909,260.1,91.0837,262.9,91.1836,270.4 +C91.1836,276.4,86.4901,280.6,78.4004,280.6 L60.4238,280.6 L61.1211,279.9 +L61.1211,260.801 L60.4238,260.1 Z M192.953,260.1 L211.629,260.1 +C218.52,260.1,223.715,262.9,223.715,270.4 +C223.715,276.4,219.021,280.6,210.932,280.6 L192.953,280.6 L193.652,279.9 +L193.652,260.801 L192.953,260.1 Z M151.605,260.801 L151.707,260.801 +L153.404,266.4 L163.291,288.9 L163.99,289.6 L139.322,289.6 L140.021,288.9 +L149.908,266.4 L151.605,260.801 Z M5.89258,284.199 L26.2656,284.199 +C34.555,284.199,38.3516,288,38.3516,294.1 +C38.3516,300.3,34.8547,303.801,26.2656,303.801 L5.89258,303.801 L6.5918,303.1 +L6.5918,284.9 L5.89258,284.199 Z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/action_delete_black.xml b/mailbox-android/src/main/res/drawable/action_delete_black.xml new file mode 100644 index 0000000000000000000000000000000000000000..2cedb57ffb284f04221c928c12efaff010ef71bf --- /dev/null +++ b/mailbox-android/src/main/res/drawable/action_delete_black.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#000000" + android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/action_delete_white.xml b/mailbox-android/src/main/res/drawable/action_delete_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..ad17d75a762d98f3c8a5da70fa9caecc927f5c2c --- /dev/null +++ b/mailbox-android/src/main/res/drawable/action_delete_white.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" + android:viewportHeight="24.0" android:viewportWidth="24.0" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FFFFFFFF" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/alerts_and_states_error.xml b/mailbox-android/src/main/res/drawable/alerts_and_states_error.xml new file mode 100644 index 0000000000000000000000000000000000000000..02056c85cec5acdaae01308058a264b1c07b4a3f --- /dev/null +++ b/mailbox-android/src/main/res/drawable/alerts_and_states_error.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="128dp" + android:height="128dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M15.73,3L8.27,3L3,8.27v7.46L8.27,21h7.46L21,15.73L21,8.27L15.73,3zM12,17.3c-0.72,0 -1.3,-0.58 -1.3,-1.3 0,-0.72 0.58,-1.3 1.3,-1.3 0.72,0 1.3,0.58 1.3,1.3 0,0.72 -0.58,1.3 -1.3,1.3zM13,13h-2L11,7h2v6z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/blogs.xml b/mailbox-android/src/main/res/drawable/blogs.xml new file mode 100644 index 0000000000000000000000000000000000000000..551d200455949a566b1f3bb98c62bde999a90466 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/blogs.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M13,12h7v1.5h-7zM13,9.5h7L20,11h-7zM13,14.5h7L20,16h-7zM21,4L3,4c-1.1,0 -2,0.9 -2,2v13c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,6c0,-1.1 -0.9,-2 -2,-2zM21,19h-9L12,6h9v13z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/border_explanation.xml b/mailbox-android/src/main/res/drawable/border_explanation.xml new file mode 100644 index 0000000000000000000000000000000000000000..f545133765c9a0f461e0bd666b372abf1a441006 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/border_explanation.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + + <solid + android:color="@android:color/transparent"/> + + <stroke + android:width="2dp" + android:color="@color/color_primary"/> + +</shape> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/bubble.xml b/mailbox-android/src/main/res/drawable/bubble.xml new file mode 100644 index 0000000000000000000000000000000000000000..8d2dd0c8088eae5f37ae0ab57dedeb32982512b2 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/bubble.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + + <corners + android:radius="@dimen/unread_bubble_size"/> + + <padding + android:left="@dimen/unread_bubble_padding_horizontal" + android:right="@dimen/unread_bubble_padding_horizontal" + android:bottom="1px"/> + + <solid + android:color="@color/briar_accent"/> + + <stroke + android:color="@color/briar_text_primary_inverse" + android:width="@dimen/avatar_border_width"/> + +</shape> + diff --git a/mailbox-android/src/main/res/drawable/bubble_white.xml b/mailbox-android/src/main/res/drawable/bubble_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..bb79ab2fa740c59bac6b65c5c7d15713ac047ac7 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/bubble_white.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + + <corners + android:radius="@dimen/unread_bubble_size"/> + + <solid + android:color="@color/briar_text_primary_inverse"/> + + <stroke + android:color="@color/briar_text_primary" + android:width="1dp"/> + +</shape> diff --git a/mailbox-android/src/main/res/drawable/chevron_down_white.xml b/mailbox-android/src/main/res/drawable/chevron_down_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..c7c475fea449154373e23019cccb1f7c82114402 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/chevron_down_white.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M7.41,7.84L12,12.42l4.59,-4.58L18,9.25l-6,6 -6,-6z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/chevron_up_white.xml b/mailbox-android/src/main/res/drawable/chevron_up_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..3715aa2f0d95d75993d5d987e5d76c3838058b3a --- /dev/null +++ b/mailbox-android/src/main/res/drawable/chevron_up_white.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/contact_connected.xml b/mailbox-android/src/main/res/drawable/contact_connected.xml new file mode 100644 index 0000000000000000000000000000000000000000..a5314250998a4145187e5b153dc1a676f07d930d --- /dev/null +++ b/mailbox-android/src/main/res/drawable/contact_connected.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:alpha="0.56" + android:viewportHeight="24" + android:viewportWidth="24"> + + <path + android:fillColor="#FF000000" + android:pathData="M12,2 C6.48,2,2,6.48,2,12 S6.48,22,12,22 S22,17.52,22,12 S17.52,2,12,2 Z M12,20 +C7.58,20,4,16.42,4,12 S7.58,4,12,4 S20,7.58,20,12 S16.42,20,12,20 Z"/> + <path + android:pathData="M0,0 L24,0 L24,24 L0,24 Z"/> + <path + android:fillColor="#95d220" + android:pathData="M10.8972,19.9503 C6.5514,19.3493,3.43091,15.2154,4.0625,10.896 +C4.55452,7.53099,7.09451,4.8236,10.394,4.14714 +C14.2569,3.35517,18.1698,5.54347,19.5236,9.25295 +C20.0698,10.7495,20.1616,12.4612,19.777,13.9758 +C19.5457,14.8864,18.8106,16.3388,18.2072,17.0771 +C16.4904,19.1779,13.581,20.3215,10.8973,19.9503 Z" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="0.76779664"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/contact_disconnected.xml b/mailbox-android/src/main/res/drawable/contact_disconnected.xml new file mode 100644 index 0000000000000000000000000000000000000000..c1a088235a0df4d82940327128b21f2e79211d69 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/contact_disconnected.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:alpha="0.56" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm0,18c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/contact_offline.xml b/mailbox-android/src/main/res/drawable/contact_offline.xml new file mode 100644 index 0000000000000000000000000000000000000000..ac18913fcb5eb66321d44729888b43d03680cde3 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/contact_offline.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + + <path + android:fillColor="#2D3E50" + android:pathData="M10.8972,19.9503 C6.5514,19.3493,3.43091,15.2154,4.0625,10.896 +C4.55452,7.53099,7.09451,4.8236,10.394,4.14714 +C14.2569,3.35517,18.1698,5.54347,19.5236,9.25295 +C20.0698,10.7495,20.1616,12.4612,19.777,13.9758 +C19.5457,14.8864,18.8106,16.3388,18.2072,17.0771 +C16.4904,19.1779,13.581,20.3215,10.8973,19.9503 Z" + android:strokeColor="#FFFFFF" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="1"/> + +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/contact_online.xml b/mailbox-android/src/main/res/drawable/contact_online.xml new file mode 100644 index 0000000000000000000000000000000000000000..f68b831022c7acbe802b7f76664c1a4ddc13cec0 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/contact_online.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + + <path + android:fillColor="#95D220" + android:pathData="M10.8972,19.9503 C6.5514,19.3493,3.43091,15.2154,4.0625,10.896 +C4.55452,7.53099,7.09451,4.8236,10.394,4.14714 +C14.2569,3.35517,18.1698,5.54347,19.5236,9.25295 +C20.0698,10.7495,20.1616,12.4612,19.777,13.9758 +C19.5457,14.8864,18.8106,16.3388,18.2072,17.0771 +C16.4904,19.1779,13.581,20.3215,10.8973,19.9503 Z" + android:strokeColor="#FFFFFF" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="1.5"/> + +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/forum_item_create_white.xml b/mailbox-android/src/main/res/drawable/forum_item_create_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..2a963d9abab1e68b4f0bfe009ead011584165c07 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/forum_item_create_white.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_add_white.xml b/mailbox-android/src/main/res/drawable/ic_add_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..b242968999731a98068dc0ee2d8d280ed251fede --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_add_white.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" + android:viewportHeight="24.0" android:viewportWidth="24.0" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FFFFFFFF" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_backspace.xml b/mailbox-android/src/main/res/drawable/ic_backspace.xml new file mode 100644 index 0000000000000000000000000000000000000000..e4ecae7b16911a1c5dfd81e4cbc3832a5da3b771 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_backspace.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0,12l5.41,8.11c0.36,0.53 0.9,0.89 1.59,0.89h15c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM19,15.59L17.59,17 14,13.41 10.41,17 9,15.59 12.59,12 9,8.41 10.41,7 14,10.59 17.59,7 19,8.41 15.41,12 19,15.59z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_check_white.xml b/mailbox-android/src/main/res/drawable/ic_check_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..59f823220d2daf783d765923dad866a8f68653cc --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_check_white.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_close.xml b/mailbox-android/src/main/res/drawable/ic_close.xml new file mode 100644 index 0000000000000000000000000000000000000000..bcc722dc42a76809f8d47b85eeb852b14a7cbc29 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_close.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="18dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_contact_introduction.xml b/mailbox-android/src/main/res/drawable/ic_contact_introduction.xml new file mode 100644 index 0000000000000000000000000000000000000000..077ce4189f5bc8fda752a1aab9e1039493c1bcd0 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_contact_introduction.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M9.01,14L2,14v2h7.01v3L13,15l-3.99,-4v3zM14.99,13v-3L22,10L22,8h-7.01L14.99,5L11,9l3.99,4z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_contacts.xml b/mailbox-android/src/main/res/drawable/ic_contacts.xml new file mode 100644 index 0000000000000000000000000000000000000000..c033a04befa44faa962ae56aa8d62439f4596115 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_contacts.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M20,0L4,0v2h16L20,0zM4,24h16v-2L4,22v2zM20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM12,6.75c1.24,0 2.25,1.01 2.25,2.25s-1.01,2.25 -2.25,2.25S9.75,10.24 9.75,9 10.76,6.75 12,6.75zM17,17L7,17v-1.5c0,-1.67 3.33,-2.5 5,-2.5s5,0.83 5,2.5L17,17z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_emoji_activity.xml b/mailbox-android/src/main/res/drawable/ic_emoji_activity.xml new file mode 100644 index 0000000000000000000000000000000000000000..3b74969d39614e1080ffcdf9bd7bc82b5994f4e8 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_emoji_activity.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + <path + android:fillColor="#000000" + android:pathData="M7.5,7.5C9.17,5.87 11.29,4.69 13.37,4.18C15.46,3.67 17.5,3.83 18.6,4C19.71,4.15 19.87,4.31 20.03,5.41C20.18,6.5 20.33,8.55 19.82,10.63C19.31,12.71 18.13,14.83 16.5,16.5C14.83,18.13 12.71,19.31 10.63,19.82C8.55,20.33 6.5,20.18 5.41,20.03C4.31,19.87 4.15,19.71 4,18.6C3.83,17.5 3.67,15.46 4.18,13.37C4.69,11.29 5.87,9.17 7.5,7.5M7.3,15.79L8.21,16.7L9.42,15.5L10.63,16.7L11.54,15.79L10.34,14.58L12,12.91L13.21,14.12L14.12,13.21L12.91,12L14.58,10.34L15.79,11.54L16.7,10.63L15.5,9.42L16.7,8.21L15.79,7.3L14.58,8.5L13.37,7.3L12.46,8.21L13.66,9.42L12,11.09L10.79,9.88L9.88,10.79L11.09,12L9.42,13.66L8.21,12.46L7.3,13.37L8.5,14.58L7.3,15.79Z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/ic_emoji_animals_nature.xml b/mailbox-android/src/main/res/drawable/ic_emoji_animals_nature.xml new file mode 100644 index 0000000000000000000000000000000000000000..29b9c0c452ba6226b4bd32d35df50c2fd5d2cb5e --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_emoji_animals_nature.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#000000" + android:pathData="M18.7,12.4c-0.28,-0.16 -0.57,-0.29 -0.86,-0.4 0.29,-0.11 0.58,-0.24 0.86,-0.4 1.92,-1.11 2.99,-3.12 3,-5.19 -1.79,-1.03 -4.07,-1.11 -6,0 -0.28,0.16 -0.54,0.35 -0.78,0.54 0.05,-0.31 0.08,-0.63 0.08,-0.95 0,-2.22 -1.21,-4.15 -3,-5.19C10.21,1.85 9,3.78 9,6c0,0.32 0.03,0.64 0.08,0.95 -0.24,-0.2 -0.5,-0.39 -0.78,-0.55 -1.92,-1.11 -4.2,-1.03 -6,0 0,2.07 1.07,4.08 3,5.19 0.28,0.16 0.57,0.29 0.86,0.4 -0.29,0.11 -0.58,0.24 -0.86,0.4 -1.92,1.11 -2.99,3.12 -3,5.19 1.79,1.03 4.07,1.11 6,0 0.28,-0.16 0.54,-0.35 0.78,-0.54 -0.05,0.32 -0.08,0.64 -0.08,0.96 0,2.22 1.21,4.15 3,5.19 1.79,-1.04 3,-2.97 3,-5.19 0,-0.32 -0.03,-0.64 -0.08,-0.95 0.24,0.2 0.5,0.38 0.78,0.54 1.92,1.11 4.2,1.03 6,0 -0.01,-2.07 -1.08,-4.08 -3,-5.19zM12,16c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_emoji_emoticons.xml b/mailbox-android/src/main/res/drawable/ic_emoji_emoticons.xml new file mode 100644 index 0000000000000000000000000000000000000000..262be839facc62684e026abd8e1f5c0ecd7ae81a --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_emoji_emoticons.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + + <path + android:fillColor="#000000" + android:pathData="M15.4839,3.8557 C14.8224,3.89611,14.9476,5.06823,15.4034,5.47978 +C16.7652,6.93176,17.1508,8.98786,17.299,10.9051 +C17.4081,13.1214,17.2144,15.4608,16.1275,17.4387 +C15.7657,18.1699,14.7879,18.7118,14.9747,19.6345 +C15.2618,20.6719,16.1617,19.8774,16.5955,19.4508 +C18.5872,17.7088,19.4632,15.0228,19.5268,12.4373 +C19.5469,10.5193,19.295,8.516,18.3141,6.8329 +C17.6499,5.74222,16.9234,4.59896,15.8167,3.91355 +C15.6887,3.86763,15.5784,3.84987,15.4839,3.85564 Z M5.91182,7.65831 +A1.3631614,1.3631614,0,0,0,4.54866,9.02147 +A1.3631614,1.3631614,0,0,0,5.91182,10.3846 +A1.3631614,1.3631614,0,0,0,7.27498,9.02147 +A1.3631614,1.3631614,0,0,0,5.91182,7.65831 Z M8.98492,10.6595 L8.98492,12.7042 +L13.756,12.7042 L13.756,10.6595 L8.98494,10.6595 Z M5.83527,14.1306 +A1.3631614,1.3631614,0,0,0,4.47211,15.4938 +A1.3631614,1.3631614,0,0,0,5.83527,16.857 +A1.3631614,1.3631614,0,0,0,7.19843,15.4938 +A1.3631614,1.3631614,0,0,0,5.83527,14.1306 Z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/ic_emoji_flags.xml b/mailbox-android/src/main/res/drawable/ic_emoji_flags.xml new file mode 100644 index 0000000000000000000000000000000000000000..c4b56853f89354bbb1f58e548189eb3eca3c9671 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_emoji_flags.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#000000" + android:pathData="M14.4,6L14,4H5v17h2v-7h5.6l0.4,2h7V6z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_emoji_food_drink.xml b/mailbox-android/src/main/res/drawable/ic_emoji_food_drink.xml new file mode 100644 index 0000000000000000000000000000000000000000..625a7c12b4b128ece6dc3de898974d1ff969439e --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_emoji_food_drink.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#000000" + android:pathData="M12,6c1.11,0 2,-0.9 2,-2 0,-0.38 -0.1,-0.73 -0.29,-1.03L12,0l-1.71,2.97c-0.19,0.3 -0.29,0.65 -0.29,1.03 0,1.1 0.9,2 2,2zM16.6,15.99l-1.07,-1.07 -1.08,1.07c-1.3,1.3 -3.58,1.31 -4.89,0l-1.07,-1.07 -1.09,1.07C6.75,16.64 5.88,17 4.96,17c-0.73,0 -1.4,-0.23 -1.96,-0.61L3,21c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v-4.61c-0.56,0.38 -1.23,0.61 -1.96,0.61 -0.92,0 -1.79,-0.36 -2.44,-1.01zM18,9h-5L13,7h-2v2L6,9c-1.66,0 -3,1.34 -3,3v1.54c0,1.08 0.88,1.96 1.96,1.96 0.52,0 1.02,-0.2 1.38,-0.57l2.14,-2.13 2.13,2.13c0.74,0.74 2.03,0.74 2.77,0l2.14,-2.13 2.13,2.13c0.37,0.37 0.86,0.57 1.38,0.57 1.08,0 1.96,-0.88 1.96,-1.96L20.99,12C21,10.34 19.66,9 18,9z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_emoji_objects.xml b/mailbox-android/src/main/res/drawable/ic_emoji_objects.xml new file mode 100644 index 0000000000000000000000000000000000000000..7b15232cff5598f12dbd38bea3dfebe3721d3bbe --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_emoji_objects.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + <path + android:fillColor="#000000" + android:pathData="M5,16L3,5L8.5,12L12,5L15.5,12L21,5L19,16H5M19,19A1,1 0 0,1 18,20H6A1,1 0 0,1 5,19V18H19V19Z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/ic_emoji_recent.xml b/mailbox-android/src/main/res/drawable/ic_emoji_recent.xml new file mode 100644 index 0000000000000000000000000000000000000000..fc0081fc7b722e22997aea2b8f60117b085691ea --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_emoji_recent.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#000000" + android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_emoji_smiley_people.xml b/mailbox-android/src/main/res/drawable/ic_emoji_smiley_people.xml new file mode 100644 index 0000000000000000000000000000000000000000..8af14098045c2fb9c31e54aa34a0bc7603d839f7 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_emoji_smiley_people.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#000000" + android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_emoji_symbols.xml b/mailbox-android/src/main/res/drawable/ic_emoji_symbols.xml new file mode 100644 index 0000000000000000000000000000000000000000..524912968a581c263199fed9d65ae5835e47ab9d --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_emoji_symbols.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#000000" + android:pathData="M12,7.77L18.39,18H5.61L12,7.77M12,4L2,20h20L12,4z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_emoji_toggle.xml b/mailbox-android/src/main/res/drawable/ic_emoji_toggle.xml new file mode 100644 index 0000000000000000000000000000000000000000..32324f57b52089fffde0d36ecafdc7956b64dda4 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_emoji_toggle.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_emoji_travel_places.xml b/mailbox-android/src/main/res/drawable/ic_emoji_travel_places.xml new file mode 100644 index 0000000000000000000000000000000000000000..c52b6076fcbaa22f01c8108ee72035e59197ff64 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_emoji_travel_places.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#000000" + android:pathData="M18.92,6.01C18.72,5.42 18.16,5 17.5,5h-11c-0.66,0 -1.21,0.42 -1.42,1.01L3,12v8c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v-1h12v1c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v-8l-2.08,-5.99zM6.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,13 6.5,13s1.5,0.67 1.5,1.5S7.33,16 6.5,16zM17.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM5,11l1.5,-4.5h11L19,11L5,11z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_empty_state_blog.xml b/mailbox-android/src/main/res/drawable/ic_empty_state_blog.xml new file mode 100644 index 0000000000000000000000000000000000000000..a93f3eb1a5c1f43cee26ee01b172bb43c5f4cdfc --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_empty_state_blog.xml @@ -0,0 +1,21 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="100dp" + android:height="96dp" + android:viewportHeight="156" + android:viewportWidth="162"> + <path + android:fillColor="#ffffff" + android:pathData="M140.87,53.647H91.565V64.235H140.87V53.647Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M140.869,99.529V88.941H115.512L126.077,99.529H140.869Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M140.869,71.294H97.904L108.469,81.882H140.869V71.294Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M147.912,14.823H41.556L84.521,57.882V28.941H147.912V120.706H147.208L157.773,131.294C160.59,128.47 161.999,124.941 161.999,120.706V28.941C161.999,21.176 155.66,14.823 147.912,14.823Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M129.6,120.706L84.522,75.529L23.948,14.823L9.157,0L0,9.176L10.565,19.765C8.452,21.882 7.043,25.412 7.043,28.941V120.706C7.043,128.471 13.383,134.824 21.13,134.824H125.374L146.504,156L155.661,146.824L143.687,134.824L129.6,120.706ZM84.522,120.706V93.882L111.287,120.706H84.522Z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_empty_state_contact_list.xml b/mailbox-android/src/main/res/drawable/ic_empty_state_contact_list.xml new file mode 100644 index 0000000000000000000000000000000000000000..560b137c50b901c4f25e992cfc5b4a6fcca41e82 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_empty_state_contact_list.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="100dp" + android:height="100dp" + android:viewportHeight="164" + android:viewportWidth="164"> + <path + android:fillColor="#ffffff" + android:pathData="M27.334,0L27.334,13.666L136.668,13.666L136.668,0L27.334,0zM27.334,27.334C19.817,27.334 13.666,33.483 13.666,41L13.666,123C13.666,130.517 19.817,136.668 27.334,136.668L136.668,136.668C144.184,136.668 150.332,130.517 150.332,123L150.332,41C150.332,33.483 144.184,27.334 136.668,27.334L27.334,27.334zM82.15,44.758C89.592,44.758 95.348,46.477 99.42,49.914C103.525,53.351 105.576,58.239 105.576,64.58C105.576,67.35 105.027,69.869 103.926,72.139C102.825,74.408 101.055,76.728 98.619,79.098L92.863,84.453C91.228,86.022 90.093,87.64 89.459,89.309C88.825,90.944 88.475,93.03 88.408,95.566L74.092,95.566C74.092,90.694 74.641,86.856 75.742,84.053C76.843,81.216 78.63,78.762 81.1,76.693C83.569,74.624 85.437,72.739 86.705,71.037C88.006,69.302 88.658,67.401 88.658,65.332C88.658,60.293 86.489,57.771 82.15,57.771C80.148,57.771 78.53,58.506 77.295,59.975C76.06,61.443 75.409,63.429 75.342,65.932L58.424,65.932C58.49,59.257 60.592,54.068 64.73,50.363C68.869,46.626 74.675,44.758 82.15,44.758zM81.398,102.324C84.068,102.324 86.288,103.125 88.057,104.727C89.859,106.295 90.76,108.314 90.76,110.783C90.76,113.253 89.859,115.289 88.057,116.891C86.288,118.459 84.068,119.242 81.398,119.242C78.729,119.242 76.493,118.459 74.691,116.891C72.923,115.289 72.039,113.253 72.039,110.783C72.039,108.314 72.923,106.295 74.691,104.727C76.493,103.125 78.729,102.324 81.398,102.324zM27.334,150.332L27.334,164L136.668,164L136.668,150.332L27.334,150.332z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_empty_state_forum_list.xml b/mailbox-android/src/main/res/drawable/ic_empty_state_forum_list.xml new file mode 100644 index 0000000000000000000000000000000000000000..132ec634ef1196df14e17f5d8268c86e6d33e82c --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_empty_state_forum_list.xml @@ -0,0 +1,15 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="100dp" + android:height="100dp" + android:viewportHeight="148" + android:viewportWidth="148"> + <path + android:fillColor="#ffffff" + android:pathData="M107.266,74.679C111.34,74.679 114.055,71.964 114.055,67.89V6.789C114.055,2.716 111.34,0 107.266,0H24.44L99.119,74.679H107.266Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M141.211,27.156H127.633V88.257H112.697L148,123.56V33.945C148,29.872 144.606,27.156 141.211,27.156Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M8.826,1.357L0,10.183L12.22,22.403V101.835L39.376,74.679H64.495L78.074,88.257H39.376V101.835C39.376,105.908 42.092,108.624 46.165,108.624H98.44L137.817,148L146.642,139.174L8.826,1.357Z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_empty_state_group_list.xml b/mailbox-android/src/main/res/drawable/ic_empty_state_group_list.xml new file mode 100644 index 0000000000000000000000000000000000000000..21f892221d752ea8ef9b6a4feebea93eeab2724d --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_empty_state_group_list.xml @@ -0,0 +1,18 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="100dp" + android:height="81dp" + android:viewportHeight="140" + android:viewportWidth="172"> + <path + android:fillColor="#ffffff" + android:pathData="M125.091,103.444L71.927,50.556L38.309,17.111L21.109,0L10.946,10.111L31.273,30.333C31.273,31.889 31.273,32.667 31.273,34.222C31.273,47.444 41.437,57.556 54.727,57.556C56.291,57.556 57.073,57.556 58.637,56.778L78.182,76.222C69.582,74.667 60.982,73.111 54.727,73.111C36.745,73.111 0,82.444 0,100.333V119.778H109.455V107.333L142.291,140L152.455,129.889L142.291,119.778L125.091,103.444Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M117.273,57.555C130.227,57.555 140.728,47.108 140.728,34.222C140.728,21.335 130.227,10.888 117.273,10.888C104.319,10.888 93.818,21.335 93.818,34.222C93.818,47.108 104.319,57.555 117.273,57.555Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M78.182,34.222C78.182,20.999 68.018,10.888 54.727,10.888C53.945,10.888 53.164,10.888 52.382,10.888L78.182,36.555C78.182,35.777 78.182,34.999 78.182,34.222Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M117.272,73.11C116.49,73.11 115.709,73.11 114.927,73.11L161.836,119.777H172V100.333C172,82.444 135.254,73.11 117.272,73.11Z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_forums_black_24dp.xml b/mailbox-android/src/main/res/drawable/ic_forums_black_24dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..5bb4d8ebce0599d382b7d9af54d6dd64754d3ced --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_forums_black_24dp.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M21,6h-2v9L6,15v2c0,0.55 0.45,1 1,1h11l4,4L22,7c0,-0.55 -0.45,-1 -1,-1zM17,12L17,3c0,-0.55 -0.45,-1 -1,-1L3,2c-0.55,0 -1,0.45 -1,1v14l4,-4h10c0.55,0 1,-0.45 1,-1z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_fullscreen_black_48dp.xml b/mailbox-android/src/main/res/drawable/ic_fullscreen_black_48dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..29b26803eb0d29731863f9c99917b0bee8eeba65 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_fullscreen_black_48dp.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M7,14L5,14v5h5v-2L7,17v-3zM5,10h2L7,7h3L10,5L5,5v5zM17,17h-3v2h5v-5h-2v3zM14,5v2h3v3h2L19,5h-5z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_fullscreen_exit_black_48dp.xml b/mailbox-android/src/main/res/drawable/ic_fullscreen_exit_black_48dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..5b62d104c1dba38e6b6b60aba19014442437b9ed --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_fullscreen_exit_black_48dp.xml @@ -0,0 +1,4 @@ +<vector android:height="48dp" android:viewportHeight="24.0" + android:viewportWidth="24.0" android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FF000000" android:pathData="M5,16h3v3h2v-5L5,14v2zM8,8L5,8v2h5L10,5L8,5v3zM14,19h2v-3h3v-2h-5v5zM16,8L16,5h-2v5h5L19,8h-3z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_group.xml b/mailbox-android/src/main/res/drawable/ic_group.xml new file mode 100644 index 0000000000000000000000000000000000000000..b7516903236a0186d3a43bd38acd33777464a4ce --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_group.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_group_white.xml b/mailbox-android/src/main/res/drawable/ic_group_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..f6e32475bd91839f3d140ff1afc791f660edaacb --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_group_white.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_help_outline_white.xml b/mailbox-android/src/main/res/drawable/ic_help_outline_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..b39381493b87b03f58002ab4e17ab9c258bfeb24 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_help_outline_white.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_info_white.xml b/mailbox-android/src/main/res/drawable/ic_info_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c4d881ba07a28b17decfc68fcb644a73013ffd3 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_info_white.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_keyboard.xml b/mailbox-android/src/main/res/drawable/ic_keyboard.xml new file mode 100644 index 0000000000000000000000000000000000000000..dfcb91016bddc552adb0055f1cb98add832ffa91 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_keyboard.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M20,5L4,5c-1.1,0 -1.99,0.9 -1.99,2L2,17c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,7c0,-1.1 -0.9,-2 -2,-2zM11,8h2v2h-2L11,8zM11,11h2v2h-2v-2zM8,8h2v2L8,10L8,8zM8,11h2v2L8,13v-2zM7,13L5,13v-2h2v2zM7,10L5,10L5,8h2v2zM16,17L8,17v-2h8v2zM16,13h-2v-2h2v2zM16,10h-2L14,8h2v2zM19,13h-2v-2h2v2zM19,10h-2L17,8h2v2z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_more_vert_accent.xml b/mailbox-android/src/main/res/drawable/ic_more_vert_accent.xml new file mode 100644 index 0000000000000000000000000000000000000000..13b8c957f9eb1a70c9d2c1b1dba7bc4c13e99e31 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_more_vert_accent.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF2D3E50" + android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_our_identity.xml b/mailbox-android/src/main/res/drawable/ic_our_identity.xml new file mode 100644 index 0000000000000000000000000000000000000000..f8e38d95b4b82e992c4c16177e8aff536c442b12 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_our_identity.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="16dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M12,5.9c1.16,0 2.1,0.94 2.1,2.1s-0.94,2.1 -2.1,2.1S9.9,9.16 9.9,8s0.94,-2.1 2.1,-2.1m0,9c2.97,0 6.1,1.46 6.1,2.1v1.1L5.9,18.1L5.9,17c0,-0.64 3.13,-2.1 6.1,-2.1M12,4C9.79,4 8,5.79 8,8s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,13c-2.67,0 -8,1.34 -8,4v3h16v-3c0,-2.66 -5.33,-4 -8,-4z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_repeat.xml b/mailbox-android/src/main/res/drawable/ic_repeat.xml new file mode 100644 index 0000000000000000000000000000000000000000..a7771172a07213c956911c78c12eeaffc039ddc6 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_repeat.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_rss_feed.xml b/mailbox-android/src/main/res/drawable/ic_rss_feed.xml new file mode 100644 index 0000000000000000000000000000000000000000..167b7d7b976c976cc09053e3a130164f85a8acec --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_rss_feed.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="30dp" + android:height="30dp" + android:viewportHeight="30" + android:viewportWidth="30"> + + <path + android:fillColor="#ffa500" + android:pathData="M0,0 L30,0 L30,30 L0,30 L0,0 Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M8.9322,18.0339 C10.6078,18.0339,11.9661,19.3922,11.9661,21.0678 +C11.9661,22.7434,10.6078,24.1017,8.9322,24.1017 +C7.25663,24.1017,5.8983,22.7434,5.8983,21.0678 +C5.8983,19.3922,7.25663,18.0339,8.9322,18.0339 Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M5.8983,15 A9.1016949,9.1016949,0,0,1,15,24.1017 L18.0339,24.1017 +A12.135593,12.135593,0,0,0,5.8983,11.9661 Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M5.8983,8.9322 A15.169492,15.169492,0,0,1,21.0678,24.1017 L24.1017,24.1017 +A18.20339,18.20339,0,0,0,5.8983,5.8983 Z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/ic_settings_black_24dp.xml b/mailbox-android/src/main/res/drawable/ic_settings_black_24dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..11f1920e25810891c58c7636ea558e36315cfdaa --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_settings_black_24dp.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_signout.xml b/mailbox-android/src/main/res/drawable/ic_signout.xml new file mode 100644 index 0000000000000000000000000000000000000000..2dd789085a157058356d72ca8701da0aaaaaeb57 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_signout.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M17,17.25V14H10V10H17V6.75L22.25,12L17,17.25M13,2A2,2 0 0,1 15,4V8H13V4H4V20H13V16H15V20A2,2 0 0,1 13,22H4A2,2 0 0,1 2,20V4A2,2 0 0,1 4,2H13Z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/ic_visibility.xml b/mailbox-android/src/main/res/drawable/ic_visibility.xml new file mode 100644 index 0000000000000000000000000000000000000000..80395495695264e60033525f74f14628efd8b362 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_visibility.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_visibility_off.xml b/mailbox-android/src/main/res/drawable/ic_visibility_off.xml new file mode 100644 index 0000000000000000000000000000000000000000..681832c9a38403081e2f513b6f1d5068abd28927 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_visibility_off.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/ic_visibility_white.xml b/mailbox-android/src/main/res/drawable/ic_visibility_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..c64e5d7a12af86504a13eb2ca511a2bf37870381 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/ic_visibility_white.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/introduction_white.xml b/mailbox-android/src/main/res/drawable/introduction_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..ac4328d1210e12e8446ff705716d5364a3532887 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/introduction_white.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M21,8V7l-3,2 -3,-2v1l3,2 3,-2zm1,-5H2C0.9,3 0,3.9 0,5v14c0,1.1 0.9,2 2,2h20c1.1,0 1.99,-0.9 1.99,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM8,6c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zm6,12H2v-1c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1v1zm8,-6h-8V6h8v6z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/level_indicator_circle.xml b/mailbox-android/src/main/res/drawable/level_indicator_circle.xml new file mode 100644 index 0000000000000000000000000000000000000000..4b486911196b8d561ba9eee8fdf2538818f85037 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/level_indicator_circle.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + + <solid android:color="@color/window_background"/> + + <stroke + android:width="2dp" + android:color="@color/thread_indicator"/> +</shape> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/list_item_thread_background.xml b/mailbox-android/src/main/res/drawable/list_item_thread_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..4d71497abdf9488bb45749d683a4f712f3f55876 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/list_item_thread_background.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector + xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:drawable="@color/thread_item_background" + android:state_activated="false"/> + + <item + android:drawable="@color/thread_item_highlight" + android:state_activated="true"/> + +</selector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/message_delivered.xml b/mailbox-android/src/main/res/drawable/message_delivered.xml new file mode 100644 index 0000000000000000000000000000000000000000..88535626864df7f3c7d0363e126009f441b1bb48 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/message_delivered.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="16dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M18,7l-1.41,-1.41 -6.34,6.34 1.41,1.41L18,7zm4.24,-1.41L11.66,16.17 7.48,12l-1.41,1.41L11.66,19l12,-12 -1.42,-1.41zM0.41,13.41L6,19l1.41,-1.41L1.83,12 0.41,13.41z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/message_delivered_white.xml b/mailbox-android/src/main/res/drawable/message_delivered_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..720dab1f7101da2f5d3d04724491c6829680eadb --- /dev/null +++ b/mailbox-android/src/main/res/drawable/message_delivered_white.xml @@ -0,0 +1,5 @@ +<vector android:height="16dp" + android:viewportHeight="24.0" android:viewportWidth="24.0" + android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FFFFFFFF" android:pathData="M18,7l-1.41,-1.41 -6.34,6.34 1.41,1.41L18,7zm4.24,-1.41L11.66,16.17 7.48,12l-1.41,1.41L11.66,19l12,-12 -1.42,-1.41zM0.41,13.41L6,19l1.41,-1.41L1.83,12 0.41,13.41z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/message_sent.xml b/mailbox-android/src/main/res/drawable/message_sent.xml new file mode 100644 index 0000000000000000000000000000000000000000..a205b178da5f71ddb6c7f3b19c001f7d74636841 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/message_sent.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="16dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/message_sent_white.xml b/mailbox-android/src/main/res/drawable/message_sent_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..59e6d6d1dde7e9662152b1ae9dc6b3b7ac6bef80 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/message_sent_white.xml @@ -0,0 +1,5 @@ +<vector android:height="16dp" + android:viewportHeight="24.0" android:viewportWidth="24.0" + android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FFFFFFFF" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/message_stored.xml b/mailbox-android/src/main/res/drawable/message_stored.xml new file mode 100644 index 0000000000000000000000000000000000000000..f1a1a31b0876b4a4b0e07c0f27372c29d72cef8c --- /dev/null +++ b/mailbox-android/src/main/res/drawable/message_stored.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="16dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/message_stored_white.xml b/mailbox-android/src/main/res/drawable/message_stored_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..71ee22feaa013232c6218686372d94c418ebcace --- /dev/null +++ b/mailbox-android/src/main/res/drawable/message_stored_white.xml @@ -0,0 +1,5 @@ +<vector android:height="16dp" + android:viewportHeight="24.0" android:viewportWidth="24.0" + android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillAlpha=".9" android:fillColor="#FFFFFF" android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/msg_in.xml b/mailbox-android/src/main/res/drawable/msg_in.xml new file mode 100644 index 0000000000000000000000000000000000000000..14b8d7d838a9e4874d90e8c1044bbf9e85c027f6 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/msg_in.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners + android:bottomLeftRadius="@dimen/message_bubble_radius_big" + android:bottomRightRadius="@dimen/message_bubble_radius_big" + android:topLeftRadius="@dimen/message_bubble_radius_small" + android:topRightRadius="@dimen/message_bubble_radius_big"/> + <padding + android:bottom="@dimen/message_bubble_padding_bottom" + android:left="@dimen/message_bubble_padding_sides" + android:right="@dimen/message_bubble_padding_sides" + android:top="@dimen/message_bubble_padding_top"/> + <solid + android:color="@color/msg_in"/> + <stroke + android:width="@dimen/message_bubble_stroke" + android:color="@color/msg_stroke"/> +</shape> diff --git a/mailbox-android/src/main/res/drawable/msg_in_top.xml b/mailbox-android/src/main/res/drawable/msg_in_top.xml new file mode 100644 index 0000000000000000000000000000000000000000..236c82b75c519984e7b603a88a3a2f24c426cd1f --- /dev/null +++ b/mailbox-android/src/main/res/drawable/msg_in_top.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners + android:bottomLeftRadius="0dp" + android:bottomRightRadius="0dp" + android:topLeftRadius="@dimen/message_bubble_radius_small" + android:topRightRadius="@dimen/message_bubble_radius_big"/> + <padding + android:bottom="@dimen/message_bubble_padding_top" + android:left="@dimen/message_bubble_padding_sides" + android:right="@dimen/message_bubble_padding_sides" + android:top="@dimen/message_bubble_padding_top"/> + <solid + android:color="@color/msg_in"/> + <stroke + android:width="@dimen/message_bubble_stroke" + android:color="@color/msg_stroke"/> +</shape> diff --git a/mailbox-android/src/main/res/drawable/msg_out.xml b/mailbox-android/src/main/res/drawable/msg_out.xml new file mode 100644 index 0000000000000000000000000000000000000000..35fa220ad0e634a95edec78dc7fcff4d1d34956c --- /dev/null +++ b/mailbox-android/src/main/res/drawable/msg_out.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners + android:bottomLeftRadius="@dimen/message_bubble_radius_big" + android:bottomRightRadius="@dimen/message_bubble_radius_big" + android:topLeftRadius="@dimen/message_bubble_radius_big" + android:topRightRadius="@dimen/message_bubble_radius_small"/> + <padding + android:bottom="@dimen/message_bubble_padding_bottom" + android:left="@dimen/message_bubble_padding_sides" + android:right="@dimen/message_bubble_padding_sides" + android:top="@dimen/message_bubble_padding_top"/> + <solid + android:color="@color/msg_out"/> + <stroke + android:width="@dimen/message_bubble_stroke" + android:color="@color/msg_stroke_dark"/> +</shape> diff --git a/mailbox-android/src/main/res/drawable/msg_out_top.xml b/mailbox-android/src/main/res/drawable/msg_out_top.xml new file mode 100644 index 0000000000000000000000000000000000000000..fe6299634a962879d879ed3c7a8bbf3060b9b9ce --- /dev/null +++ b/mailbox-android/src/main/res/drawable/msg_out_top.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners + android:bottomLeftRadius="0dp" + android:bottomRightRadius="0dp" + android:topLeftRadius="@dimen/message_bubble_radius_big" + android:topRightRadius="@dimen/message_bubble_radius_small"/> + <padding + android:bottom="@dimen/message_bubble_padding_top" + android:left="@dimen/message_bubble_padding_sides" + android:right="@dimen/message_bubble_padding_sides" + android:top="@dimen/message_bubble_padding_top"/> + <solid + android:color="@color/msg_out"/> + <stroke + android:width="@dimen/message_bubble_stroke" + android:color="@color/msg_stroke_dark"/> +</shape> diff --git a/mailbox-android/src/main/res/drawable/navigation_drawer_header.xml b/mailbox-android/src/main/res/drawable/navigation_drawer_header.xml new file mode 100644 index 0000000000000000000000000000000000000000..e8bf91962288fb51d884f32c8a46e6d5a0e044dd --- /dev/null +++ b/mailbox-android/src/main/res/drawable/navigation_drawer_header.xml @@ -0,0 +1,15 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="146dp" + android:height="50dp" + android:viewportHeight="50" + android:viewportWidth="146"> + <path + android:fillColor="#ffffff" + android:pathData="m65.098,30.699v19.301h9.068c4.226,0 6.475,-2.124 6.496,-5.479 0,-2.145 -1.018,-3.78 -3.014,-4.672v-0.041c1.508,-0.934 2.166,-2.103 2.166,-3.908 0,-2.739 -1.848,-5.201 -5.861,-5.201h-8.855zM83.848,30.699v19.301h2.271v-7.729l-0.232,-0.234h4.586c2.548,0 4.013,0.914 4.947,2.889l2.4,5.074h2.547l-2.93,-6.031c-0.637,-1.359 -1.614,-2.208 -2.527,-2.59v-0.043c2.123,-0.552 3.865,-2.42 3.865,-4.947 0,-3.801 -2.952,-5.689 -6.477,-5.689h-8.451zM102.725,30.699v19.301h2.273v-19.301zM116.145,30.699 L107.65,50h2.484l2.039,-4.65 -0.127,-0.234h10.574l-0.127,0.234 2.039,4.65h2.484l-8.473,-19.301zM129.48,30.699v19.301h2.271v-7.729l-0.234,-0.234h4.588c2.548,0 4.013,0.914 4.947,2.889l2.398,5.074L146,50l-2.93,-6.031c-0.637,-1.359 -1.614,-2.208 -2.527,-2.59v-0.043c2.123,-0.552 3.865,-2.42 3.865,-4.947 0,-3.801 -2.952,-5.689 -6.477,-5.689h-8.451zM67.158,32.844h6.561c2.463,0 3.76,0.997 3.76,3.035 0,1.72 -0.999,3.102 -3.76,3.102h-6.561l0.234,-0.234v-5.67zM85.887,32.844h6.434c2.378,0 4.141,0.975 4.162,3.523 0,2.038 -1.634,3.504 -4.416,3.504h-6.18l0.232,-0.232v-6.563zM131.539,32.844h6.434c2.357,0 4.141,0.975 4.141,3.523 0,2.038 -1.613,3.504 -4.395,3.504h-6.18l0.234,-0.232v-6.563zM117.334,33.055h0.043l0.572,1.934 3.398,7.75 0.232,0.232h-8.471l0.232,-0.232 3.398,-7.75 0.594,-1.934zM67.137,41.125h7.008c2.845,0 4.162,1.315 4.162,3.375 0,2.145 -1.189,3.334 -4.141,3.334h-7.029l0.234,-0.234v-6.242z"/> + <path + android:fillColor="#87c214" + android:pathData="m13.809,0c-2.064,0 -3.766,1.702 -3.766,3.766L10.042,8.553h9.277L19.319,3.766C19.319,1.702 17.638,0 15.574,0ZM34.447,0c-2.064,0 -3.766,1.702 -3.766,3.766L30.681,29.191h9.277L39.958,3.766C39.958,1.702 38.276,0 36.213,0ZM10.042,20.809v25.426c0,2.064 1.681,3.766 3.766,3.766h1.766c2.064,0 3.766,-1.702 3.766,-3.766L19.341,20.809ZM30.681,41.447v4.787c0,2.064 1.702,3.766 3.766,3.766h1.766c2.064,0 3.766,-1.702 3.766,-3.766v-4.787z"/> + <path + android:fillColor="#95d220" + android:pathData="M3.766,10.042C1.702,10.042 0,11.723 0,13.809v1.766c0,2.064 1.681,3.766 3.766,3.766L29.191,19.341v-9.298zM41.447,10.042v9.298h4.787c2.064,0 3.766,-1.681 3.766,-3.766v-1.766c0,-2.085 -1.702,-3.766 -3.766,-3.766zM3.766,30.681C1.702,30.681 0,32.362 0,34.447v1.766c0,2.064 1.681,3.766 3.766,3.766h4.787v-9.298zM20.809,30.681v9.298h25.426c2.064,0 3.766,-1.702 3.766,-3.766L50,34.447c0,-2.085 -1.702,-3.766 -3.766,-3.766z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/navigation_item_background.xml b/mailbox-android/src/main/res/drawable/navigation_item_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..4067c8829e7d8a32944e63d3cc9aeb2c5cdbf03a --- /dev/null +++ b/mailbox-android/src/main/res/drawable/navigation_item_background.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@color/item_background_highlight" android:state_checked="true"/> + <item android:drawable="@android:color/transparent" android:state_checked="false"/> +</selector> diff --git a/mailbox-android/src/main/res/drawable/notice_in.xml b/mailbox-android/src/main/res/drawable/notice_in.xml new file mode 100644 index 0000000000000000000000000000000000000000..fbfaa069b2ac9e8dded768af6393f868e4061dda --- /dev/null +++ b/mailbox-android/src/main/res/drawable/notice_in.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners + android:bottomLeftRadius="@dimen/message_bubble_radius_big" + android:bottomRightRadius="@dimen/message_bubble_radius_big" + android:topLeftRadius="@dimen/message_bubble_radius_small" + android:topRightRadius="@dimen/message_bubble_radius_big"/> + <padding + android:bottom="@dimen/message_bubble_padding_bottom" + android:left="@dimen/message_bubble_padding_sides" + android:right="@dimen/message_bubble_padding_sides" + android:top="@dimen/message_bubble_padding_top"/> + <solid + android:color="@color/notice_in"/> + <stroke + android:width="@dimen/message_bubble_stroke" + android:color="@color/msg_stroke"/> +</shape> diff --git a/mailbox-android/src/main/res/drawable/notice_in_bottom.xml b/mailbox-android/src/main/res/drawable/notice_in_bottom.xml new file mode 100644 index 0000000000000000000000000000000000000000..5f6b29663f9daaa7808ffc9f48f1eef7c58c41d3 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/notice_in_bottom.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners + android:bottomLeftRadius="@dimen/message_bubble_radius_big" + android:bottomRightRadius="@dimen/message_bubble_radius_big" + android:topLeftRadius="0dp" + android:topRightRadius="0dp"/> + <padding + android:bottom="@dimen/message_bubble_padding_bottom" + android:left="@dimen/message_bubble_padding_sides" + android:right="@dimen/message_bubble_padding_sides" + android:top="@dimen/message_bubble_padding_bottom"/> + <solid + android:color="@color/notice_in"/> + <stroke + android:width="@dimen/message_bubble_stroke" + android:color="@color/msg_stroke"/> +</shape> diff --git a/mailbox-android/src/main/res/drawable/notice_out.xml b/mailbox-android/src/main/res/drawable/notice_out.xml new file mode 100644 index 0000000000000000000000000000000000000000..8734935cfc595d1f398321a285ed1b68a365d1c6 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/notice_out.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners + android:bottomLeftRadius="@dimen/message_bubble_radius_big" + android:bottomRightRadius="@dimen/message_bubble_radius_big" + android:topLeftRadius="@dimen/message_bubble_radius_big" + android:topRightRadius="@dimen/message_bubble_radius_small"/> + <padding + android:bottom="@dimen/message_bubble_padding_bottom" + android:left="@dimen/message_bubble_padding_sides" + android:right="@dimen/message_bubble_padding_sides" + android:top="@dimen/message_bubble_padding_top"/> + <solid + android:color="@color/notice_out"/> + <stroke + android:width="@dimen/message_bubble_stroke" + android:color="@color/msg_stroke_dark"/> +</shape> diff --git a/mailbox-android/src/main/res/drawable/notice_out_bottom.xml b/mailbox-android/src/main/res/drawable/notice_out_bottom.xml new file mode 100644 index 0000000000000000000000000000000000000000..6479a753ecc6d31e3f770405e509eb9f8cc5c07b --- /dev/null +++ b/mailbox-android/src/main/res/drawable/notice_out_bottom.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners + android:bottomLeftRadius="@dimen/message_bubble_radius_big" + android:bottomRightRadius="@dimen/message_bubble_radius_big" + android:topLeftRadius="0dp" + android:topRightRadius="0dp"/> + <padding + android:bottom="@dimen/message_bubble_padding_bottom" + android:left="@dimen/message_bubble_padding_sides" + android:right="@dimen/message_bubble_padding_sides" + android:top="@dimen/message_bubble_padding_bottom"/> + <solid + android:color="@color/notice_out"/> + <stroke + android:width="@dimen/message_bubble_stroke" + android:color="@color/msg_stroke_dark"/> +</shape> diff --git a/mailbox-android/src/main/res/drawable/notification_blog.xml b/mailbox-android/src/main/res/drawable/notification_blog.xml new file mode 100644 index 0000000000000000000000000000000000000000..d5218f632940886038a1de4cf218d0634d054e88 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/notification_blog.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M13,12h7v1.5h-7zM13,9.5h7L20,11h-7zM13,14.5h7L20,16h-7zM21,4L3,4c-1.1,0 -2,0.9 -2,2v13c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,6c0,-1.1 -0.9,-2 -2,-2zM21,19h-9L12,6h9v13z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/notification_forum.xml b/mailbox-android/src/main/res/drawable/notification_forum.xml new file mode 100644 index 0000000000000000000000000000000000000000..5bd071e1d601d69783a719b0289cc30665b4aee9 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/notification_forum.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M21,6h-2v9L6,15v2c0,0.55 0.45,1 1,1h11l4,4L22,7c0,-0.55 -0.45,-1 -1,-1zM17,12L17,3c0,-0.55 -0.45,-1 -1,-1L3,2c-0.55,0 -1,0.45 -1,1v14l4,-4h10c0.55,0 1,-0.45 1,-1z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/notification_introduction.xml b/mailbox-android/src/main/res/drawable/notification_introduction.xml new file mode 100644 index 0000000000000000000000000000000000000000..48c8339f02f2a2b0ace16a40fe25807dc188f89e --- /dev/null +++ b/mailbox-android/src/main/res/drawable/notification_introduction.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M20,0L4,0v2h16L20,0zM4,24h16v-2L4,22v2zM20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM12,6.75c1.24,0 2.25,1.01 2.25,2.25s-1.01,2.25 -2.25,2.25S9.75,10.24 9.75,9 10.76,6.75 12,6.75zM17,17L7,17v-1.5c0,-1.67 3.33,-2.5 5,-2.5s5,0.83 5,2.5L17,17z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/notification_ongoing.xml b/mailbox-android/src/main/res/drawable/notification_ongoing.xml new file mode 100644 index 0000000000000000000000000000000000000000..56ca2a343839c45b6a39f8094606719f0870fd0a --- /dev/null +++ b/mailbox-android/src/main/res/drawable/notification_ongoing.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="329.40625" + android:viewportWidth="329.40625"> + <path + android:fillColor="#ffffff" + android:pathData="M164.7,0C73.7,0 0,73.7 0,164.7c0,91 73.7,164.7 164.7,164.7 91,0 164.7,-73.8 164.7,-164.7 0,-91 -73.8,-164.7 -164.7,-164.7zM111.7,46.6 L120,46.6c9.7,0 17.7,8 17.7,17.7l0,22.5 -43.7,0 0,-22.5c0,-9.7 8,-17.7 17.7,-17.7zM208.7,46.6 L217,46.6c9.8,0 17.7,8 17.7,17.7l0,119.5 -43.7,0 0,-119.5c0,-9.7 8,-17.7 17.7,-17.7zM64.5,93.8l119.5,0 0,43.7 -119.5,0c-9.8,0 -17.7,-8 -17.7,-17.7l0,-8.3c0,-9.8 8,-17.7 17.7,-17.7zM241.7,93.8 L264.2,93.8c9.7,0 17.6,8 17.7,17.7l0,8.3c0,9.8 -8,17.7 -17.7,17.7l-22.5,0 0,-43.7zM94,144.5l43.7,0 0,119.5c0,9.7 -8,17.7 -17.7,17.7l-8.3,0c-9.8,0 -17.7,-8 -17.7,-17.7l0,-119.5zM64.5,190.8 L87,190.8 87,234.5 64.5,234.5c-9.8,0 -17.7,-8 -17.7,-17.7l0,-8.3c0,-9.8 8,-17.7 17.7,-17.7zM144.7,190.8 L264.2,190.8c9.7,0 17.6,8 17.7,17.7l0,8.3c0,9.7 -8,17.7 -17.7,17.7l-119.5,0 0,-43.7zM191,241.5 L234.7,241.5 234.7,264c0,9.7 -8,17.7 -17.7,17.7l-8.3,0c-9.7,0 -17.7,-8 -17.7,-17.7l0,-22.5z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/notification_private_group.xml b/mailbox-android/src/main/res/drawable/notification_private_group.xml new file mode 100644 index 0000000000000000000000000000000000000000..55cbde9eeed748f9685ba6738ad3df16f158cfc5 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/notification_private_group.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/notification_private_message.xml b/mailbox-android/src/main/res/drawable/notification_private_message.xml new file mode 100644 index 0000000000000000000000000000000000000000..b42ea09e2211e8f48e8e950c8918509095b0c260 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/notification_private_message.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/qr_code_error.xml b/mailbox-android/src/main/res/drawable/qr_code_error.xml new file mode 100644 index 0000000000000000000000000000000000000000..f866e63890ef95254d81bf74201fe37cca225cd8 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/qr_code_error.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="409.2dp" + android:height="161.7dp" + android:viewportHeight="161.7" + android:viewportWidth="409.2"> + <path + android:fillColor="#FF000000" + android:pathData="M369.8,157.4l-4.3,-4.3l-7.1,-2.4c-3.9,-1.3 -8.7,-3 -10.7,-3.7l-3.7,-1.3l3.5,-0.2c8.2,-0.4 13,-4 14.3,-10.9c0.8,-4.1 1.1,-17.3 0.8,-33c-0.2,-8.1 -0.2,-15.4 0,-16.3c0.1,-0.9 0.5,-2.4 0.9,-3.4c1.2,-3.5 0.3,-11.9 -1.9,-17.6c-0.3,-0.9 -1.9,-4.2 -3.5,-7.4c-4.2,-8.2 -4.5,-8.9 -4.9,-10.5c-0.5,-1.8 -0.2,-5.4 0.5,-6.8c0.7,-1.3 2.2,-2.9 3.2,-3.5c1.3,-0.7 2.6,0.1 4.7,2.9c3.4,4.5 14,19.4 15.7,22.2c3.7,6 6,11.2 8,18.8c0.7,2.5 1.9,7 2.7,10.1c0.8,3.1 2.7,10.2 4.1,15.8l2.6,10.2l4.6,5.2c2.6,2.9 5.8,6.5 7.2,8c1.4,1.6 2.5,3 2.5,3.2c0,0.3 -34.5,29.3 -34.9,29.3C374.2,161.7 372.2,159.7 369.8,157.4zM275.9,141c-1.3,-0.6 -2.2,-1.4 -2.9,-2.3c-2.1,-2.7 -2,2.4 -1.9,-68.5l0.1,-64l0.7,-1.2c1,-1.9 2,-2.9 3.7,-3.9l1.6,-0.9l37.8,-0.1c42.5,-0.1 39.4,-0.2 42.1,2.2c0.9,0.8 1.8,2 2.2,2.9c0.7,1.6 0.7,1.6 0.8,14.2l0.1,12.6l-1.8,-0.1c-1.4,-0.1 -2.1,0 -3.2,0.5c-2,1 -3.9,2.9 -5.1,5.1l-1,2l0,-12.8l0,-12.8h-33.6h-33.6v51.3v51.3h33.6h33.6l0.1,-34.4c0.1,-33 0.1,-34.4 0.6,-32.9c0.3,0.8 1.8,4 3.4,7c5.5,10.6 5.4,9.9 5.4,47.2c0,27.6 -0.1,30 -1.7,33.1c-1.1,2.2 -2.7,3.7 -5.1,4.7l-1.7,0.7L314,141.8l-36.2,0.1L275.9,141L275.9,141zM318.3,135.9c2.9,-1.3 4.5,-3.7 4.4,-6.6c0,-4.1 -3.1,-7.2 -7.1,-7.2c-2.1,0 -3.6,0.6 -5.2,2.2c-2.2,2.2 -2.8,5.4 -1.3,8.3c0.7,1.4 2.5,3 4,3.5C314.6,136.6 317,136.6 318.3,135.9z"/> + <path + android:fillColor="#FF000000" + android:pathData="M39.4,157.4l4.3,-4.3l7.1,-2.4c3.9,-1.3 8.7,-3 10.7,-3.7l3.7,-1.3l-3.5,-0.2c-8.2,-0.4 -13,-4 -14.3,-10.9c-0.8,-4.1 -1.1,-17.3 -0.8,-33c0.2,-8.1 0.2,-15.4 0,-16.3c-0.1,-0.9 -0.5,-2.4 -0.9,-3.4c-1.2,-3.5 -0.3,-11.9 1.9,-17.6c0.3,-0.9 1.9,-4.2 3.5,-7.4c4.2,-8.2 4.5,-8.9 4.9,-10.5c0.5,-1.8 0.2,-5.4 -0.5,-6.8c-0.7,-1.3 -2.2,-2.9 -3.2,-3.5c-1.3,-0.7 -2.6,0.1 -4.7,2.9c-3.4,4.5 -14,19.4 -15.7,22.2c-3.7,6 -6,11.2 -8,18.8c-0.7,2.5 -1.9,7 -2.7,10.1c-0.8,3.1 -2.7,10.2 -4.1,15.8l-2.6,10.2l-4.6,5.2c-2.6,2.9 -5.8,6.5 -7.2,8s-2.5,3 -2.5,3.2c0,0.3 34.5,29.3 34.9,29.3C35,161.7 37.1,159.7 39.4,157.4zM133.3,141c1.3,-0.6 2.2,-1.4 2.9,-2.3c2.1,-2.7 2,2.4 1.9,-68.5l-0.1,-64l-0.7,-1.2c-1,-1.9 -2,-2.9 -3.7,-3.9l-1.6,-0.9l-37.8,-0.1c-42.5,-0.1 -39.4,-0.2 -42.1,2.2c-0.9,0.8 -1.8,2 -2.2,2.9c-0.7,1.6 -0.7,1.6 -0.8,14.2L49,32l1.8,-0.1c1.4,-0.1 2.1,0 3.2,0.5c2,1 3.9,2.9 5.1,5.1l1,2l0,-12.8l0,-12.8h33.6h33.6v51.3v51.3L93.8,116.5L60.2,116.5l-0.1,-34.4c-0.1,-33 -0.1,-34.4 -0.6,-32.9c-0.3,0.8 -1.8,4 -3.4,7c-5.5,10.6 -5.4,9.9 -5.4,47.2c0,27.6 0.1,30 1.7,33.1c1.1,2.2 2.7,3.7 5.1,4.7l1.7,0.7l36.2,0.1l36.2,0.1L133.3,141L133.3,141zM90.9,135.9c-2.9,-1.3 -4.5,-3.7 -4.4,-6.6c0,-4.1 3.1,-7.2 7.1,-7.2c2.1,0 3.6,0.6 5.2,2.2c2.2,2.2 2.8,5.4 1.3,8.3c-0.7,1.4 -2.5,3 -4,3.5C94.6,136.6 92.3,136.6 90.9,135.9z"/> + <path + android:fillColor="#FF000000" + android:pathData="M80.5,63h2.3v2.3h2.3v2.3L73.6,67.6v-2.3h2.3v-4.6h4.6L80.5,63L80.5,63zM110.5,83.8h2.3v-2.3h-2.3L110.5,83.8zM82.8,63h2.3v-2.3h-2.3L82.8,63zM115.1,83.8h2.3v-2.3h-2.3L115.1,83.8zM87.4,86.1L92,86.1L92,83.8h-4.6L87.4,86.1zM108.2,86.1L108.2,83.8h-2.3v2.3L108.2,86.1zM99,86.1h2.3v-4.6L99,81.5L99,86.1zM80.5,56.1v2.3h6.9v-2.3L80.5,56.1zM78.2,58.4v-2.3h-4.6v4.6h2.3v-2.3L78.2,58.4zM85.1,53.8L69,53.8v-16.1h16.1L85.1,53.8zM82.8,40L71.3,40v11.5h11.5L82.8,40zM73.6,81.5h6.9v-6.9h-6.9L73.6,81.5zM96.6,79.1v2.3L99,81.4v-2.3L96.6,79.1zM80.5,42.3h-6.9v6.9h6.9L80.5,42.3zM117.4,37.7L117.4,53.8L101.3,53.8v-16.1L117.4,37.7zM115.1,40L103.6,40v11.5h11.5L115.1,40zM69,69.9h16.1v16.1L69,86L69,69.9zM71.3,83.8h11.5v-11.5L71.3,72.3L71.3,83.8zM71.3,56.1L69,56.1v11.5h2.3L71.3,56.1zM101.3,67.6v2.3h2.3v-2.3L101.3,67.6zM94.3,76.9v-2.3L92,74.6v2.3h-4.6v4.6L92,81.5v2.3h2.3v-4.6h2.3v-2.3L94.3,76.9zM87.4,46.9L92,46.9v-2.3h-4.6L87.4,46.9zM105.9,65.3h4.6v2.3h2.3v-6.9h-2.3v-4.6h-2.3v6.9h-6.9v2.3h2.3v2.3h2.3L105.9,65.3zM108.2,72.2h-2.3v-2.3h-2.3v4.6h-6.9v2.3h4.6v4.6h2.3v2.3h2.3v-4.6h9.2v-2.3h-6.9L108.2,72.2zM108.2,72.2h2.3v-4.6h-2.3L108.2,72.2zM89.7,72.2v-2.3L92,69.9v-2.3h2.3v-2.3h2.3v-4.6h6.9v-4.6h-2.3v2.3L99,58.4v-9.2h-2.3v-4.6L99,44.6v-6.9h-2.3v4.6h-2.3v-4.6h-6.9v4.6h2.3v-2.3L92,40v4.6h2.3v6.9h2.3v2.3h-2.3v4.6L92,58.4L92,53.8h-2.3v-2.3h-2.3v4.6h2.3v2.3h-2.3v6.9h2.3v-4.6L92,60.7v4.6h-2.3v2.3h-2.3v6.9L92,74.5v-2.3L89.7,72.2zM115.1,74.5v-2.3h-4.6v2.3L115.1,74.5zM112.8,42.3h-6.9v6.9h6.9L112.8,42.3zM94.3,72.2L99,72.2v-2.3h-2.3v-2.3h-2.3L94.4,72.2zM99,67.6v-2.3h-2.3v2.3L99,67.6zM112.8,58.4h4.6v-2.3h-4.6L112.8,58.4zM115.1,76.9h2.3v-2.3h-2.3L115.1,76.9zM115.1,63h2.3v-2.3h-2.3L115.1,63zM94.3,51.5L92,51.5v2.3h2.3L94.3,51.5zM94.3,51.5"/> + <path + android:fillColor="#FF000000" + android:pathData="M303.5,63h2.3v2.3h2.3v2.3h-11.5v-2.3h2.3v-4.6h4.6L303.5,63L303.5,63zM333.5,83.8h2.3v-2.3h-2.3L333.5,83.8zM305.8,63h2.3v-2.3h-2.3L305.8,63zM338.1,83.8h2.3v-2.3h-2.3L338.1,83.8zM310.4,86.1h4.6L315,83.8h-4.6L310.4,86.1zM331.2,86.1L331.2,83.8h-2.3v2.3L331.2,86.1zM322,86.1h2.3v-4.6L322,81.5L322,86.1zM303.5,56.1v2.3h6.9v-2.3L303.5,56.1zM301.2,58.4v-2.3h-4.6v4.6h2.3v-2.3L301.2,58.4zM308.1,53.8L292,53.8v-16.1h16.1L308.1,53.8zM305.8,40h-11.5v11.5h11.5L305.8,40zM296.6,81.5h6.9v-6.9h-6.9L296.6,81.5zM319.6,79.1v2.3h2.3v-2.3L319.6,79.1zM303.5,42.3h-6.9v6.9h6.9L303.5,42.3zM340.4,37.7L340.4,53.8h-16.1v-16.1L340.4,37.7zM338.1,40h-11.5v11.5h11.5L338.1,40zM292,69.9h16.1v16.1L292,86L292,69.9zM294.3,83.8h11.5v-11.5h-11.5L294.3,83.8zM294.3,56.1L292,56.1v11.5h2.3L294.3,56.1zM324.3,67.6v2.3h2.3v-2.3L324.3,67.6zM317.3,76.9v-2.3L315,74.6v2.3h-4.6v4.6h4.6v2.3h2.3v-4.6h2.3v-2.3L317.3,76.9zM310.4,46.9h4.6v-2.3h-4.6L310.4,46.9zM328.9,65.3h4.6v2.3h2.3v-6.9h-2.3v-4.6h-2.3v6.9h-6.9v2.3h2.3v2.3h2.3L328.9,65.3zM331.2,72.2h-2.3v-2.3h-2.3v4.6h-6.9v2.3h4.6v4.6h2.3v2.3h2.3v-4.6h9.2v-2.3h-6.9L331.2,72.2zM331.2,72.2h2.3v-4.6h-2.3L331.2,72.2zM312.7,72.2v-2.3h2.3v-2.3h2.3v-2.3h2.3v-4.6h6.9v-4.6h-2.3v2.3L322,58.4v-9.2h-2.3v-4.6h2.3v-6.9h-2.3v4.6h-2.3v-4.6h-6.9v4.6h2.3v-2.3h2.3v4.6h2.3v6.9h2.3v2.3h-2.3v4.6L315,58.4L315,53.8h-2.3v-2.3h-2.3v4.6h2.3v2.3h-2.3v6.9h2.3v-4.6h2.3v4.6h-2.3v2.3h-2.3v6.9h4.6v-2.3L312.7,72.2zM338.1,74.5v-2.3h-4.6v2.3L338.1,74.5zM335.8,42.3h-6.9v6.9h6.9L335.8,42.3zM317.3,72.2h4.6v-2.3h-2.3v-2.3h-2.3L317.3,72.2zM322,67.6v-2.3h-2.3v2.3L322,67.6zM335.8,58.4h4.6v-2.3h-4.6L335.8,58.4zM338.1,76.9h2.3v-2.3h-2.3L338.1,76.9zM338.1,63h2.3v-2.3h-2.3L338.1,63zM317.3,51.5L315,51.5v2.3h2.3L317.3,51.5zM317.3,51.5"/> + <path + android:fillColor="#000000" + android:pathData="M 207.61295,88.782357 h -6.42588 v -12.85177 h 6.42588 m 0,25.703533 h -6.42588 v -6.425883 h 6.42588 m -38.5553,16.064713 h 70.68472 L 204.40001,50.227047 Z" + android:strokeWidth="3.21294165"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/qr_code_explanation.xml b/mailbox-android/src/main/res/drawable/qr_code_explanation.xml new file mode 100644 index 0000000000000000000000000000000000000000..157025c222f4979db4f70804cf72b8e199a4e17c --- /dev/null +++ b/mailbox-android/src/main/res/drawable/qr_code_explanation.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="400dp" + android:height="100dp" + android:viewportHeight="49.5" + android:viewportWidth="194.8"> + <path + android:fillColor="#000000" + android:pathData="M30.1 16.5l-9 0 0 -5c0 -2.4 -2 -4.4 -4.4 -4.4L4.4 7.1C2 7.1 0 9.1 0 11.5l0 24.2c0 2.4 2 4.4 4.4 4.4l9 0 0 5c0 2.4 2 4.4 4.4 4.4l12.2 0c2.4 0 4.4 -2 4.4 -4.4l0 -24.2c0.1 -2.4 -1.9 -4.4 -4.3 -4.4zm-27.4 16.1l0 -20.9 15.8 0 0 20.9 -15.8 0zm10.7 4.6l-5.8 0 0 -1.5 5.8 0 0 1.5zm13.5 9.4l-5.8 0 0 -1.5 5.8 0 0 1.5zm5 -4.6l-15.8 0 0 -1.9 0.5 0c2.4 0 4.4 -2 4.4 -4.4l0 -14.6 10.8 0 0 20.9z"/> + <path + android:fillColor="#000000" + android:pathData="M101.2 16.5l-8.3 0 0 -4.4c0 -1.4 -1.2 -2.6 -2.6 -2.6l-3.9 0 -2.1 -2.5 -6.9 0 -2.2 2.5 -3.8 0c-1.4 0 -2.6 1.2 -2.6 2.6l0 13.3c0 1.4 1.2 2.6 2.6 2.6l13.1 0 0 17.2c0 2.4 2 4.4 4.4 4.4l12.2 0c2.4 0 4.4 -2 4.4 -4.4l0 -24.3c0.2 -2.4 -1.8 -4.4 -4.3 -4.4zm-26.4 2.4c0 -3.3 2.7 -6 6 -6 3.3 0 6 2.7 6 6 0 3.3 -2.7 6 -6 6 -3.3 0 -6 -2.7 -6 -6zm23.2 27.7l-5.8 0 0 -1.5 5.8 0 0 1.5zm5 -4.6l-15.8 0 0 -14.1 3.1 0c1.4 0 2.6 -1.2 2.6 -2.6l0 -4.2 10.1 0 0 20.9z"/> + <path + android:fillColor="#000000" + android:pathData="M84.600003 18.9a3.8 3.8 0 0 1 -3.8 3.8 3.8 3.8 0 0 1 -3.8 -3.8 3.8 3.8 0 0 1 3.8 -3.8 3.8 3.8 0 0 1 3.8 3.8z"/> + <path + android:fillColor="#000000" + android:pathData="M175.3 16.5l-9.8 0 0 -5.7c0 -1.4 -1.2 -2.6 -2.6 -2.6l-19.3 0c-1.4 0 -2.6 1.2 -2.6 2.6l0 14.4c0 1.4 1.2 2.6 2.6 2.6l15.1 0 0 17.3c0 2.4 2 4.4 4.4 4.4l12.2 0c2.4 0 4.4 -2 4.4 -4.4l0 -24.2c0.1 -2.4 -1.9 -4.4 -4.4 -4.4zm-12.4 -5.9l-9.6 6 -9.6 -6 19.2 0zm-19.4 14.8l0 -12.3 9.8 6.1 9.8 -6.1 0 12.3 -19.6 0zm28.6 21.2l-5.8 0 0 -1.5 5.8 0 0 1.5zm5 -4.6l-15.8 0 0 -14.2 1.6 0c1.4 0 2.6 -1.2 2.6 -2.6l0 -4.1 11.6 0 0 20.9z"/> + <path + android:fillColor="#ff0000" + android:pathData="M101.4 17.8l2 2 7.4 -7.3 7.3 7.3 2.1 -2 -7.4 -7.4 7.4 -7.3 -2.1 -2.1 -7.3 7.4 -7.4 -7.4 -2 2.1 7.3 7.3z"/> + <path + android:fillColor="#ff0000" + android:pathData="M176 17.8l2.1 2 7.3 -7.3 7.4 7.3 2 -2 -7.3 -7.4 7.3 -7.3 -2 -2.1 -7.4 7.4 -7.3 -7.4 -2.1 2.1 7.3 7.3z"/> + <path + android:fillColor="#08b124" + android:pathData="M35.8 18.8l0 0L52.5 2.1 50.5 0 35.6 14.8 28.5 7.7l-2.1 2.1 9.2 9.1z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/qr_code_intro.xml b/mailbox-android/src/main/res/drawable/qr_code_intro.xml new file mode 100644 index 0000000000000000000000000000000000000000..6b09db32dd279901f6b64b19a03ecff6bf58beb6 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/qr_code_intro.xml @@ -0,0 +1,24 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="409dp" + android:height="162dp" + android:viewportHeight="161.7" + android:viewportWidth="409.2"> + <path + android:fillColor="#FF000000" + android:pathData="M369.8,157.4l-4.3,-4.3l-7.1,-2.4c-3.9,-1.3 -8.7,-3 -10.7,-3.7l-3.7,-1.3l3.5,-0.2c8.2,-0.4 13,-4 14.3,-10.9c0.8,-4.1 1.1,-17.3 0.8,-33c-0.2,-8.1 -0.2,-15.4 0,-16.3c0.1,-0.9 0.5,-2.4 0.9,-3.4c1.2,-3.5 0.3,-11.9 -1.9,-17.6c-0.3,-0.9 -1.9,-4.2 -3.5,-7.4c-4.2,-8.2 -4.5,-8.9 -4.9,-10.5c-0.5,-1.8 -0.2,-5.4 0.5,-6.8c0.7,-1.3 2.2,-2.9 3.2,-3.5c1.3,-0.7 2.6,0.1 4.7,2.9c3.4,4.5 14,19.4 15.7,22.2c3.7,6 6,11.2 8,18.8c0.7,2.5 1.9,7 2.7,10.1c0.8,3.1 2.7,10.2 4.1,15.8l2.6,10.2l4.6,5.2c2.6,2.9 5.8,6.5 7.2,8c1.4,1.6 2.5,3 2.5,3.2c0,0.3 -34.5,29.3 -34.9,29.3C374.2,161.7 372.2,159.7 369.8,157.4zM275.9,141c-1.3,-0.6 -2.2,-1.4 -2.9,-2.3c-2.1,-2.7 -2,2.4 -1.9,-68.5l0.1,-64l0.7,-1.2c1,-1.9 2,-2.9 3.7,-3.9l1.6,-0.9l37.8,-0.1c42.5,-0.1 39.4,-0.2 42.1,2.2c0.9,0.8 1.8,2 2.2,2.9c0.7,1.6 0.7,1.6 0.8,14.2l0.1,12.6l-1.8,-0.1c-1.4,-0.1 -2.1,0 -3.2,0.5c-2,1 -3.9,2.9 -5.1,5.1l-1,2l0,-12.8l0,-12.8h-33.6h-33.6v51.3v51.3h33.6h33.6l0.1,-34.4c0.1,-33 0.1,-34.4 0.6,-32.9c0.3,0.8 1.8,4 3.4,7c5.5,10.6 5.4,9.9 5.4,47.2c0,27.6 -0.1,30 -1.7,33.1c-1.1,2.2 -2.7,3.7 -5.1,4.7l-1.7,0.7L314,141.8l-36.2,0.1L275.9,141L275.9,141zM318.3,135.9c2.9,-1.3 4.5,-3.7 4.4,-6.6c0,-4.1 -3.1,-7.2 -7.1,-7.2c-2.1,0 -3.6,0.6 -5.2,2.2c-2.2,2.2 -2.8,5.4 -1.3,8.3c0.7,1.4 2.5,3 4,3.5C314.6,136.6 317,136.6 318.3,135.9z"/> + <path + android:fillColor="#FF000000" + android:pathData="M39.4,157.4l4.3,-4.3l7.1,-2.4c3.9,-1.3 8.7,-3 10.7,-3.7l3.7,-1.3l-3.5,-0.2c-8.2,-0.4 -13,-4 -14.3,-10.9c-0.8,-4.1 -1.1,-17.3 -0.8,-33c0.2,-8.1 0.2,-15.4 0,-16.3c-0.1,-0.9 -0.5,-2.4 -0.9,-3.4c-1.2,-3.5 -0.3,-11.9 1.9,-17.6c0.3,-0.9 1.9,-4.2 3.5,-7.4c4.2,-8.2 4.5,-8.9 4.9,-10.5c0.5,-1.8 0.2,-5.4 -0.5,-6.8c-0.7,-1.3 -2.2,-2.9 -3.2,-3.5c-1.3,-0.7 -2.6,0.1 -4.7,2.9c-3.4,4.5 -14,19.4 -15.7,22.2c-3.7,6 -6,11.2 -8,18.8c-0.7,2.5 -1.9,7 -2.7,10.1c-0.8,3.1 -2.7,10.2 -4.1,15.8l-2.6,10.2l-4.6,5.2c-2.6,2.9 -5.8,6.5 -7.2,8s-2.5,3 -2.5,3.2c0,0.3 34.5,29.3 34.9,29.3C35,161.7 37.1,159.7 39.4,157.4zM133.3,141c1.3,-0.6 2.2,-1.4 2.9,-2.3c2.1,-2.7 2,2.4 1.9,-68.5l-0.1,-64l-0.7,-1.2c-1,-1.9 -2,-2.9 -3.7,-3.9l-1.6,-0.9l-37.8,-0.1c-42.5,-0.1 -39.4,-0.2 -42.1,2.2c-0.9,0.8 -1.8,2 -2.2,2.9c-0.7,1.6 -0.7,1.6 -0.8,14.2L49,32l1.8,-0.1c1.4,-0.1 2.1,0 3.2,0.5c2,1 3.9,2.9 5.1,5.1l1,2l0,-12.8l0,-12.8h33.6h33.6v51.3v51.3L93.8,116.5L60.2,116.5l-0.1,-34.4c-0.1,-33 -0.1,-34.4 -0.6,-32.9c-0.3,0.8 -1.8,4 -3.4,7c-5.5,10.6 -5.4,9.9 -5.4,47.2c0,27.6 0.1,30 1.7,33.1c1.1,2.2 2.7,3.7 5.1,4.7l1.7,0.7l36.2,0.1l36.2,0.1L133.3,141L133.3,141zM90.9,135.9c-2.9,-1.3 -4.5,-3.7 -4.4,-6.6c0,-4.1 3.1,-7.2 7.1,-7.2c2.1,0 3.6,0.6 5.2,2.2c2.2,2.2 2.8,5.4 1.3,8.3c-0.7,1.4 -2.5,3 -4,3.5C94.6,136.6 92.3,136.6 90.9,135.9z"/> + <path + android:fillColor="#FF000000" + android:pathData="M80.5,63h2.3v2.3h2.3v2.3L73.6,67.6v-2.3h2.3v-4.6h4.6L80.5,63L80.5,63zM110.5,83.8h2.3v-2.3h-2.3L110.5,83.8zM82.8,63h2.3v-2.3h-2.3L82.8,63zM115.1,83.8h2.3v-2.3h-2.3L115.1,83.8zM87.4,86.1L92,86.1L92,83.8h-4.6L87.4,86.1zM108.2,86.1L108.2,83.8h-2.3v2.3L108.2,86.1zM99,86.1h2.3v-4.6L99,81.5L99,86.1zM80.5,56.1v2.3h6.9v-2.3L80.5,56.1zM78.2,58.4v-2.3h-4.6v4.6h2.3v-2.3L78.2,58.4zM85.1,53.8L69,53.8v-16.1h16.1L85.1,53.8zM82.8,40L71.3,40v11.5h11.5L82.8,40zM73.6,81.5h6.9v-6.9h-6.9L73.6,81.5zM96.6,79.1v2.3L99,81.4v-2.3L96.6,79.1zM80.5,42.3h-6.9v6.9h6.9L80.5,42.3zM117.4,37.7L117.4,53.8L101.3,53.8v-16.1L117.4,37.7zM115.1,40L103.6,40v11.5h11.5L115.1,40zM69,69.9h16.1v16.1L69,86L69,69.9zM71.3,83.8h11.5v-11.5L71.3,72.3L71.3,83.8zM71.3,56.1L69,56.1v11.5h2.3L71.3,56.1zM101.3,67.6v2.3h2.3v-2.3L101.3,67.6zM94.3,76.9v-2.3L92,74.6v2.3h-4.6v4.6L92,81.5v2.3h2.3v-4.6h2.3v-2.3L94.3,76.9zM87.4,46.9L92,46.9v-2.3h-4.6L87.4,46.9zM105.9,65.3h4.6v2.3h2.3v-6.9h-2.3v-4.6h-2.3v6.9h-6.9v2.3h2.3v2.3h2.3L105.9,65.3zM108.2,72.2h-2.3v-2.3h-2.3v4.6h-6.9v2.3h4.6v4.6h2.3v2.3h2.3v-4.6h9.2v-2.3h-6.9L108.2,72.2zM108.2,72.2h2.3v-4.6h-2.3L108.2,72.2zM89.7,72.2v-2.3L92,69.9v-2.3h2.3v-2.3h2.3v-4.6h6.9v-4.6h-2.3v2.3L99,58.4v-9.2h-2.3v-4.6L99,44.6v-6.9h-2.3v4.6h-2.3v-4.6h-6.9v4.6h2.3v-2.3L92,40v4.6h2.3v6.9h2.3v2.3h-2.3v4.6L92,58.4L92,53.8h-2.3v-2.3h-2.3v4.6h2.3v2.3h-2.3v6.9h2.3v-4.6L92,60.7v4.6h-2.3v2.3h-2.3v6.9L92,74.5v-2.3L89.7,72.2zM115.1,74.5v-2.3h-4.6v2.3L115.1,74.5zM112.8,42.3h-6.9v6.9h6.9L112.8,42.3zM94.3,72.2L99,72.2v-2.3h-2.3v-2.3h-2.3L94.4,72.2zM99,67.6v-2.3h-2.3v2.3L99,67.6zM112.8,58.4h4.6v-2.3h-4.6L112.8,58.4zM115.1,76.9h2.3v-2.3h-2.3L115.1,76.9zM115.1,63h2.3v-2.3h-2.3L115.1,63zM94.3,51.5L92,51.5v2.3h2.3L94.3,51.5zM94.3,51.5"/> + <path + android:fillColor="#FF000000" + android:pathData="M303.5,63h2.3v2.3h2.3v2.3h-11.5v-2.3h2.3v-4.6h4.6L303.5,63L303.5,63zM333.5,83.8h2.3v-2.3h-2.3L333.5,83.8zM305.8,63h2.3v-2.3h-2.3L305.8,63zM338.1,83.8h2.3v-2.3h-2.3L338.1,83.8zM310.4,86.1h4.6L315,83.8h-4.6L310.4,86.1zM331.2,86.1L331.2,83.8h-2.3v2.3L331.2,86.1zM322,86.1h2.3v-4.6L322,81.5L322,86.1zM303.5,56.1v2.3h6.9v-2.3L303.5,56.1zM301.2,58.4v-2.3h-4.6v4.6h2.3v-2.3L301.2,58.4zM308.1,53.8L292,53.8v-16.1h16.1L308.1,53.8zM305.8,40h-11.5v11.5h11.5L305.8,40zM296.6,81.5h6.9v-6.9h-6.9L296.6,81.5zM319.6,79.1v2.3h2.3v-2.3L319.6,79.1zM303.5,42.3h-6.9v6.9h6.9L303.5,42.3zM340.4,37.7L340.4,53.8h-16.1v-16.1L340.4,37.7zM338.1,40h-11.5v11.5h11.5L338.1,40zM292,69.9h16.1v16.1L292,86L292,69.9zM294.3,83.8h11.5v-11.5h-11.5L294.3,83.8zM294.3,56.1L292,56.1v11.5h2.3L294.3,56.1zM324.3,67.6v2.3h2.3v-2.3L324.3,67.6zM317.3,76.9v-2.3L315,74.6v2.3h-4.6v4.6h4.6v2.3h2.3v-4.6h2.3v-2.3L317.3,76.9zM310.4,46.9h4.6v-2.3h-4.6L310.4,46.9zM328.9,65.3h4.6v2.3h2.3v-6.9h-2.3v-4.6h-2.3v6.9h-6.9v2.3h2.3v2.3h2.3L328.9,65.3zM331.2,72.2h-2.3v-2.3h-2.3v4.6h-6.9v2.3h4.6v4.6h2.3v2.3h2.3v-4.6h9.2v-2.3h-6.9L331.2,72.2zM331.2,72.2h2.3v-4.6h-2.3L331.2,72.2zM312.7,72.2v-2.3h2.3v-2.3h2.3v-2.3h2.3v-4.6h6.9v-4.6h-2.3v2.3L322,58.4v-9.2h-2.3v-4.6h2.3v-6.9h-2.3v4.6h-2.3v-4.6h-6.9v4.6h2.3v-2.3h2.3v4.6h2.3v6.9h2.3v2.3h-2.3v4.6L315,58.4L315,53.8h-2.3v-2.3h-2.3v4.6h2.3v2.3h-2.3v6.9h2.3v-4.6h2.3v4.6h-2.3v2.3h-2.3v6.9h4.6v-2.3L312.7,72.2zM338.1,74.5v-2.3h-4.6v2.3L338.1,74.5zM335.8,42.3h-6.9v6.9h6.9L335.8,42.3zM317.3,72.2h4.6v-2.3h-2.3v-2.3h-2.3L317.3,72.2zM322,67.6v-2.3h-2.3v2.3L322,67.6zM335.8,58.4h4.6v-2.3h-4.6L335.8,58.4zM338.1,76.9h2.3v-2.3h-2.3L338.1,76.9zM338.1,63h2.3v-2.3h-2.3L338.1,63zM317.3,51.5L315,51.5v2.3h2.3L317.3,51.5zM317.3,51.5"/> + <path + android:fillColor="#FF000000" + android:pathData="M179.6,48.9l-20.6,18l20.6,16.7v-5.2L199,78.4v-24.3h-19.3L179.7,48.9z"/> + <path + android:fillColor="#FF000000" + android:pathData="M229.4,83.7l20.6,-18l-20.6,-16.7v5.2L210,54.2v24.3h19.3L229.3,83.7z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/social_send_now_white.xml b/mailbox-android/src/main/res/drawable/social_send_now_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..43662f48b70e19b8963903ddfa5566568e10a2e0 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/social_send_now_white.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/social_share_white.xml b/mailbox-android/src/main/res/drawable/social_share_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..a7bbe28605e06d56c0f84d04c906a9195ab20d5f --- /dev/null +++ b/mailbox-android/src/main/res/drawable/social_share_white.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/splash_screen.xml b/mailbox-android/src/main/res/drawable/splash_screen.xml new file mode 100644 index 0000000000000000000000000000000000000000..a8c8a1c36e2ff25c12ec56ec3ca999affdc35205 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/splash_screen.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="235dp" + android:height="310dp" + android:viewportHeight="310" + android:viewportWidth="235"> + + <path + android:fillColor="#87c214" + android:pathData="M47.2,47.2 L90.9,47.2 L90.9,90.9 L47.2,90.9 L47.2,47.2 Z"/> + <path + android:fillColor="#87c214" + android:pathData="M64.9004,0 C55.2004,0,47.1992,7.99922,47.1992,17.6992 L47.1992,40.1992 +L90.8008,40.1992 L90.8008,17.6992 +C90.8008,7.99922,82.8992,0,73.1992,0 L64.9004,0 Z M161.9,0 +C152.2,0,144.199,7.99922,144.199,17.6992 L144.199,137.199 L187.801,137.199 +L187.801,17.6992 C187.801,7.99922,179.899,0,170.199,0 L161.9,0 Z +M47.1992,97.8008 L47.1992,217.301 C47.1992,227.001,55.1004,235,64.9004,235 +L73.1992,235 C82.8992,235,90.9004,227.001,90.9004,217.301 L90.9004,97.8008 +L47.1992,97.8008 Z M144.199,194.801 L144.199,217.301 +C144.199,227.001,152.2,235,161.9,235 L170.199,235 +C179.899,235,187.9,227.001,187.9,217.301 L187.9,194.801 L144.199,194.801 Z"/> + <path + android:fillColor="#87c214" + android:pathData="M144.2,144.2 L187.9,144.2 L187.9,187.9 L144.2,187.9 L144.2,144.2 Z"/> + <path + android:fillColor="#95d220" + android:pathData="M17.6992,47.1992 C7.99922,47.1992,0,55.1004,0,64.9004 L0,73.1992 +C0,82.8992,7.89922,90.9004,17.6992,90.9004 L137.199,90.9004 L137.199,47.1992 +L17.6992,47.1992 Z M194.801,47.1992 L194.801,90.9004 L217.301,90.9004 +C227.001,90.9004,235,82.9992,235,73.1992 L235,64.9004 +C235,55.1004,227.001,47.1992,217.301,47.1992 L194.801,47.1992 Z M17.6992,144.199 +C7.99922,144.199,0,152.1,0,161.9 L0,170.199 +C0,179.899,7.89922,187.9,17.6992,187.9 L40.1992,187.9 L40.1992,144.199 +L17.6992,144.199 Z M97.8008,144.199 L97.8008,187.9 L217.301,187.9 +C227.001,187.9,235,179.899,235,170.199 L235,161.9 +C235,152.1,227.001,144.199,217.301,144.199 L97.8008,144.199 Z"/> + <path + android:fillColor="#000000" + android:pathData="M0,253.9 L0,310 L26.2656,310 C38.6498,310,45.1426,303.8,45.1426,294.1 +C45.1426,287.8,42.2457,283.1,36.4531,280.5 L36.4531,280.4 +C40.8475,277.7,42.7461,274.3,42.7461,269 C42.7461,261,37.2532,253.9,25.668,253.9 +L0,253.9 Z M54.5313,253.9 L54.5313,310 L61.1211,310 L61.1211,287.5 +L60.4238,286.801 L73.7051,286.801 +C81.0956,286.801,85.2917,289.399,87.9883,295.199 L94.9785,310 L102.369,310 +L94.0801,292.5 C92.2824,288.6,89.3857,286.1,86.7891,285 L86.7891,284.9 +C92.8813,283.3,97.9746,277.8,97.9746,270.5 +C97.9746,259.4,89.3865,253.9,79.0996,253.9 L54.5313,253.9 Z M109.26,253.9 +L109.26,310 L115.852,310 L115.852,253.9 L109.26,253.9 Z M148.012,253.9 +L123.342,310 L130.533,310 L136.525,296.5 L136.227,295.801 L166.887,295.801 +L166.588,296.5 L172.58,310 L179.771,310 L155.002,253.9 L148.012,253.9 Z +M187.16,253.9 L187.16,310 L193.752,310 L193.752,287.5 L193.053,286.801 +L206.336,286.801 C213.727,286.801,217.923,289.399,220.619,295.199 L227.609,310 +L235,310 L226.711,292.5 C224.913,288.6,222.017,286.1,219.42,285 L219.42,284.9 +C225.512,283.3,230.605,277.8,230.605,270.5 +C230.605,259.4,222.017,253.9,211.73,253.9 L187.16,253.9 Z M5.89258,260.1 +L24.9688,260.1 C32.1596,260.1,35.9531,263,35.9531,269 +C35.9531,274,32.9585,278,24.9688,278 L5.89258,278 L6.5918,277.301 +L6.5918,260.801 L5.89258,260.1 Z M60.4238,260.1 L79.0996,260.1 +C85.8909,260.1,91.0837,262.9,91.1836,270.4 +C91.1836,276.4,86.4901,280.6,78.4004,280.6 L60.4238,280.6 L61.1211,279.9 +L61.1211,260.801 L60.4238,260.1 Z M192.953,260.1 L211.629,260.1 +C218.52,260.1,223.715,262.9,223.715,270.4 +C223.715,276.4,219.021,280.6,210.932,280.6 L192.953,280.6 L193.652,279.9 +L193.652,260.801 L192.953,260.1 Z M151.605,260.801 L151.707,260.801 +L153.404,266.4 L163.291,288.9 L163.99,289.6 L139.322,289.6 L140.021,288.9 +L149.908,266.4 L151.605,260.801 Z M5.89258,284.199 L26.2656,284.199 +C34.555,284.199,38.3516,288,38.3516,294.1 +C38.3516,300.3,34.8547,303.801,26.2656,303.801 L5.89258,303.801 L6.5918,303.1 +L6.5918,284.9 L5.89258,284.199 Z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/startup_lock.xml b/mailbox-android/src/main/res/drawable/startup_lock.xml new file mode 100644 index 0000000000000000000000000000000000000000..181a64cc9162141b4bfe208b94a70bf94d4b31da --- /dev/null +++ b/mailbox-android/src/main/res/drawable/startup_lock.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="64dp" + android:height="64dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/startup_migration.xml b/mailbox-android/src/main/res/drawable/startup_migration.xml new file mode 100644 index 0000000000000000000000000000000000000000..a5021ef0dad493614ddb3e068540d5cf992d6e77 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/startup_migration.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="64dp" + android:height="64dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M21,10.12h-6.78l2.74,-2.82c-2.73,-2.7 -7.15,-2.8 -9.88,-0.1 -2.73,2.71 -2.73,7.08 0,9.79 2.73,2.71 7.15,2.71 9.88,0C18.32,15.65 19,14.08 19,12.1h2c0,1.98 -0.88,4.55 -2.64,6.29 -3.51,3.48 -9.21,3.48 -12.72,0 -3.5,-3.47 -3.53,-9.11 -0.02,-12.58 3.51,-3.47 9.14,-3.47 12.65,0L21,3v7.12zM12.5,8v4.25l3.5,2.08 -0.72,1.21L11,13V8h1.5z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/transport_bt.xml b/mailbox-android/src/main/res/drawable/transport_bt.xml new file mode 100644 index 0000000000000000000000000000000000000000..2a8774c8c4e451bbb6275780db63f9a5a5d90c52 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/transport_bt.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41V22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59V5.83zm1.88,10.46L13,18.17v-3.76l1.88,1.88z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/transport_lan.xml b/mailbox-android/src/main/res/drawable/transport_lan.xml new file mode 100644 index 0000000000000000000000000000000000000000..60844d4d4d4a8ff174c83cdda09c5cfe8830d4ab --- /dev/null +++ b/mailbox-android/src/main/res/drawable/transport_lan.xml @@ -0,0 +1,13 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillAlpha=".3" + android:fillColor="#FF000000" + android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"/> + <path + android:fillColor="#FF000000" + android:pathData="M3.53,10.95l8.46,10.54 0.01,0.01 0.01,-0.01 8.46,-10.54C20.04,10.62 16.81,8 12,8c-4.81,0 -8.04,2.62 -8.47,2.95z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/transport_tor.xml b/mailbox-android/src/main/res/drawable/transport_tor.xml new file mode 100644 index 0000000000000000000000000000000000000000..ce8f0060f3b96f547645c15790a68b530736d70f --- /dev/null +++ b/mailbox-android/src/main/res/drawable/transport_tor.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zm6.93,6h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56 1.84,0.63 3.37,1.91 4.33,3.56zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82c0.43,-1.43 1.08,-2.76 1.91,-3.96zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2 0,0.68 0.06,1.34 0.14,2H4.26zm0.82,2h2.95c0.32,1.25 0.78,2.45 1.38,3.56 -1.84,-0.63 -3.37,-1.9 -4.33,-3.56zm2.95,-8H5.08c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8zM12,19.96c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96h3.82c-0.43,1.43 -1.08,2.76 -1.91,3.96zM14.34,14H9.66c-0.09,-0.66 -0.16,-1.32 -0.16,-2 0,-0.68 0.07,-1.35 0.16,-2h4.68c0.09,0.65 0.16,1.32 0.16,2 0,0.68 -0.07,1.34 -0.16,2zm0.25,5.56c0.6,-1.11 1.06,-2.31 1.38,-3.56h2.95c-0.96,1.65 -2.49,2.93 -4.33,3.56zM16.36,14c0.08,-0.66 0.14,-1.32 0.14,-2 0,-0.68 -0.06,-1.34 -0.14,-2h3.38c0.16,0.64 0.26,1.31 0.26,2s-0.1,1.36 -0.26,2h-3.38z"/> +</vector> diff --git a/mailbox-android/src/main/res/drawable/trust_indicator_anonymous.xml b/mailbox-android/src/main/res/drawable/trust_indicator_anonymous.xml new file mode 100644 index 0000000000000000000000000000000000000000..82214b8d4fccc90ac9c85f520467d160cebdf546 --- /dev/null +++ b/mailbox-android/src/main/res/drawable/trust_indicator_anonymous.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="31dp" + android:height="12dp" + android:viewportHeight="20" + android:viewportWidth="49"> + <path + android:fillColor="#b7b7b7" + android:pathData="M15.5002,13.8797 L15.5002,11.8208 L12.9502,11.8208 L12.9502,8.38194 +L15.5002,8.38194 L15.5002,6.32312 L12.9502,6.32312 L12.9502,2.49959 +L10.5752,2.49959 L10.5752,6.32312 L7.42514,6.32312 L7.42514,2.49959 +L5.05014,2.49959 L5.05014,6.32312 L2.50016,6.32312 L2.50016,8.38194 +L5.05014,8.38194 L5.05014,11.8208 L2.50016,11.8208 L2.50016,13.8797 +L5.05014,13.8797 L5.05014,17.4996 L7.42514,17.4996 L7.42514,13.8797 +L10.5752,13.8797 L10.5752,17.4996 L12.9502,17.4996 L12.9502,13.8797 +L15.5002,13.8797 Z M10.5752,11.8208 L7.42514,11.8208 L7.42514,8.38194 +L10.5752,8.38194 L10.5752,11.8208 Z"/> + <path + android:fillColor="#b7b7b7" + android:pathData="M31.0002,13.8797 L31.0002,11.8208 L28.4502,11.8208 L28.4502,8.38194 +L31.0002,8.38194 L31.0002,6.32312 L28.4502,6.32312 L28.4502,2.49959 +L26.0752,2.49959 L26.0752,6.32312 L22.9251,6.32312 L22.9251,2.49959 +L20.5501,2.49959 L20.5501,6.32312 L18.0002,6.32312 L18.0002,8.38194 +L20.5501,8.38194 L20.5501,11.8208 L18.0002,11.8208 L18.0002,13.8797 +L20.5501,13.8797 L20.5501,17.4996 L22.9251,17.4996 L22.9251,13.8797 +L26.0752,13.8797 L26.0752,17.4996 L28.4502,17.4996 L28.4502,13.8797 +L31.0002,13.8797 Z M26.0752,11.8208 L22.9251,11.8208 L22.9251,8.38194 +L26.0752,8.38194 L26.0752,11.8208 Z"/> + <path + android:fillColor="#b7b7b7" + android:pathData="M46.5002,13.8797 L46.5002,11.8208 L43.9502,11.8208 L43.9502,8.38194 +L46.5002,8.38194 L46.5002,6.32312 L43.9502,6.32312 L43.9502,2.49959 +L41.5752,2.49959 L41.5752,6.32312 L38.4251,6.32312 L38.4251,2.49959 +L36.0501,2.49959 L36.0501,6.32312 L33.5002,6.32312 L33.5002,8.38194 +L36.0501,8.38194 L36.0501,11.8208 L33.5002,11.8208 L33.5002,13.8797 +L36.0501,13.8797 L36.0501,17.4996 L38.4251,17.4996 L38.4251,13.8797 +L41.5752,13.8797 L41.5752,17.4996 L43.9502,17.4996 L43.9502,13.8797 +L46.5002,13.8797 Z M41.5752,11.8208 L38.4251,11.8208 L38.4251,8.38194 +L41.5752,8.38194 L41.5752,11.8208 Z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/trust_indicator_unknown.xml b/mailbox-android/src/main/res/drawable/trust_indicator_unknown.xml new file mode 100644 index 0000000000000000000000000000000000000000..63e6ab7afaedca0935498be5f0847429846b665f --- /dev/null +++ b/mailbox-android/src/main/res/drawable/trust_indicator_unknown.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="31dp" + android:height="12dp" + android:viewportHeight="20" + android:viewportWidth="49"> + <path + android:fillColor="#c34032" + android:pathData="M15.5002,13.8797 L15.5002,11.8208 L12.9502,11.8208 L12.9502,8.38194 +L15.5002,8.38194 L15.5002,6.32312 L12.9502,6.32312 L12.9502,2.49959 +L10.5752,2.49959 L10.5752,6.32312 L7.42514,6.32312 L7.42514,2.49959 +L5.05014,2.49959 L5.05014,6.32312 L2.50016,6.32312 L2.50016,8.38194 +L5.05014,8.38194 L5.05014,11.8208 L2.50016,11.8208 L2.50016,13.8797 +L5.05014,13.8797 L5.05014,17.4996 L7.42514,17.4996 L7.42514,13.8797 +L10.5752,13.8797 L10.5752,17.4996 L12.9502,17.4996 L12.9502,13.8797 +L15.5002,13.8797 Z M10.5752,11.8208 L7.42514,11.8208 L7.42514,8.38194 +L10.5752,8.38194 L10.5752,11.8208 Z"/> + <path + android:fillColor="#b7b7b7" + android:pathData="M31.0002,13.8797 L31.0002,11.8208 L28.4502,11.8208 L28.4502,8.38194 +L31.0002,8.38194 L31.0002,6.32312 L28.4502,6.32312 L28.4502,2.49959 +L26.0752,2.49959 L26.0752,6.32312 L22.9251,6.32312 L22.9251,2.49959 +L20.5501,2.49959 L20.5501,6.32312 L18.0002,6.32312 L18.0002,8.38194 +L20.5501,8.38194 L20.5501,11.8208 L18.0002,11.8208 L18.0002,13.8797 +L20.5501,13.8797 L20.5501,17.4996 L22.9251,17.4996 L22.9251,13.8797 +L26.0752,13.8797 L26.0752,17.4996 L28.4502,17.4996 L28.4502,13.8797 +L31.0002,13.8797 Z M26.0752,11.8208 L22.9251,11.8208 L22.9251,8.38194 +L26.0752,8.38194 L26.0752,11.8208 Z"/> + <path + android:fillColor="#b7b7b7" + android:pathData="M46.5002,13.8797 L46.5002,11.8208 L43.9502,11.8208 L43.9502,8.38194 +L46.5002,8.38194 L46.5002,6.32312 L43.9502,6.32312 L43.9502,2.49959 +L41.5752,2.49959 L41.5752,6.32312 L38.4251,6.32312 L38.4251,2.49959 +L36.0501,2.49959 L36.0501,6.32312 L33.5002,6.32312 L33.5002,8.38194 +L36.0501,8.38194 L36.0501,11.8208 L33.5002,11.8208 L33.5002,13.8797 +L36.0501,13.8797 L36.0501,17.4996 L38.4251,17.4996 L38.4251,13.8797 +L41.5752,13.8797 L41.5752,17.4996 L43.9502,17.4996 L43.9502,13.8797 +L46.5002,13.8797 Z M41.5752,11.8208 L38.4251,11.8208 L38.4251,8.38194 +L41.5752,8.38194 L41.5752,11.8208 Z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/trust_indicator_unverified.xml b/mailbox-android/src/main/res/drawable/trust_indicator_unverified.xml new file mode 100644 index 0000000000000000000000000000000000000000..97af93df956bd198b07ba367c960741a7cf7becc --- /dev/null +++ b/mailbox-android/src/main/res/drawable/trust_indicator_unverified.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="31dp" + android:height="12dp" + android:viewportHeight="20" + android:viewportWidth="49"> + <path + android:fillColor="#fcd53a" + android:pathData="M15.5002,13.8797 L15.5002,11.8208 L12.9502,11.8208 L12.9502,8.38194 +L15.5002,8.38194 L15.5002,6.32312 L12.9502,6.32312 L12.9502,2.49959 +L10.5752,2.49959 L10.5752,6.32312 L7.42514,6.32312 L7.42514,2.49959 +L5.05014,2.49959 L5.05014,6.32312 L2.50016,6.32312 L2.50016,8.38194 +L5.05014,8.38194 L5.05014,11.8208 L2.50016,11.8208 L2.50016,13.8797 +L5.05014,13.8797 L5.05014,17.4996 L7.42514,17.4996 L7.42514,13.8797 +L10.5752,13.8797 L10.5752,17.4996 L12.9502,17.4996 L12.9502,13.8797 +L15.5002,13.8797 Z M10.5752,11.8208 L7.42514,11.8208 L7.42514,8.38194 +L10.5752,8.38194 L10.5752,11.8208 Z"/> + <path + android:fillColor="#fcd53a" + android:pathData="M31.0002,13.8797 L31.0002,11.8208 L28.4502,11.8208 L28.4502,8.38194 +L31.0002,8.38194 L31.0002,6.32312 L28.4502,6.32312 L28.4502,2.49959 +L26.0752,2.49959 L26.0752,6.32312 L22.9251,6.32312 L22.9251,2.49959 +L20.5501,2.49959 L20.5501,6.32312 L18.0002,6.32312 L18.0002,8.38194 +L20.5501,8.38194 L20.5501,11.8208 L18.0002,11.8208 L18.0002,13.8797 +L20.5501,13.8797 L20.5501,17.4996 L22.9251,17.4996 L22.9251,13.8797 +L26.0752,13.8797 L26.0752,17.4996 L28.4502,17.4996 L28.4502,13.8797 +L31.0002,13.8797 Z M26.0752,11.8208 L22.9251,11.8208 L22.9251,8.38194 +L26.0752,8.38194 L26.0752,11.8208 Z"/> + <path + android:fillColor="#b7b7b7" + android:pathData="M46.5002,13.8797 L46.5002,11.8208 L43.9502,11.8208 L43.9502,8.38194 +L46.5002,8.38194 L46.5002,6.32312 L43.9502,6.32312 L43.9502,2.49959 +L41.5752,2.49959 L41.5752,6.32312 L38.4251,6.32312 L38.4251,2.49959 +L36.0501,2.49959 L36.0501,6.32312 L33.5002,6.32312 L33.5002,8.38194 +L36.0501,8.38194 L36.0501,11.8208 L33.5002,11.8208 L33.5002,13.8797 +L36.0501,13.8797 L36.0501,17.4996 L38.4251,17.4996 L38.4251,13.8797 +L41.5752,13.8797 L41.5752,17.4996 L43.9502,17.4996 L43.9502,13.8797 +L46.5002,13.8797 Z M41.5752,11.8208 L38.4251,11.8208 L38.4251,8.38194 +L41.5752,8.38194 L41.5752,11.8208 Z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/drawable/trust_indicator_verified.xml b/mailbox-android/src/main/res/drawable/trust_indicator_verified.xml new file mode 100644 index 0000000000000000000000000000000000000000..5b37c223ad2a2cba22690643cf43d0ea90eb81cc --- /dev/null +++ b/mailbox-android/src/main/res/drawable/trust_indicator_verified.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="31dp" + android:height="12dp" + android:viewportHeight="20" + android:viewportWidth="49"> + <path + android:fillColor="#7fac49" + android:pathData="M15.5002,13.8797 L15.5002,11.8208 L12.9502,11.8208 L12.9502,8.38194 +L15.5002,8.38194 L15.5002,6.32312 L12.9502,6.32312 L12.9502,2.49959 +L10.5752,2.49959 L10.5752,6.32312 L7.42514,6.32312 L7.42514,2.49959 +L5.05014,2.49959 L5.05014,6.32312 L2.50016,6.32312 L2.50016,8.38194 +L5.05014,8.38194 L5.05014,11.8208 L2.50016,11.8208 L2.50016,13.8797 +L5.05014,13.8797 L5.05014,17.4996 L7.42514,17.4996 L7.42514,13.8797 +L10.5752,13.8797 L10.5752,17.4996 L12.9502,17.4996 L12.9502,13.8797 +L15.5002,13.8797 Z M10.5752,11.8208 L7.42514,11.8208 L7.42514,8.38194 +L10.5752,8.38194 L10.5752,11.8208 Z"/> + <path + android:fillColor="#7fac49" + android:pathData="M31.0002,13.8797 L31.0002,11.8208 L28.4502,11.8208 L28.4502,8.38194 +L31.0002,8.38194 L31.0002,6.32312 L28.4502,6.32312 L28.4502,2.49959 +L26.0752,2.49959 L26.0752,6.32312 L22.9251,6.32312 L22.9251,2.49959 +L20.5501,2.49959 L20.5501,6.32312 L18.0002,6.32312 L18.0002,8.38194 +L20.5501,8.38194 L20.5501,11.8208 L18.0002,11.8208 L18.0002,13.8797 +L20.5501,13.8797 L20.5501,17.4996 L22.9251,17.4996 L22.9251,13.8797 +L26.0752,13.8797 L26.0752,17.4996 L28.4502,17.4996 L28.4502,13.8797 +L31.0002,13.8797 Z M26.0752,11.8208 L22.9251,11.8208 L22.9251,8.38194 +L26.0752,8.38194 L26.0752,11.8208 Z"/> + <path + android:fillColor="#7fac49" + android:pathData="M46.5002,13.8797 L46.5002,11.8208 L43.9502,11.8208 L43.9502,8.38194 +L46.5002,8.38194 L46.5002,6.32312 L43.9502,6.32312 L43.9502,2.49959 +L41.5752,2.49959 L41.5752,6.32312 L38.4251,6.32312 L38.4251,2.49959 +L36.0501,2.49959 L36.0501,6.32312 L33.5002,6.32312 L33.5002,8.38194 +L36.0501,8.38194 L36.0501,11.8208 L33.5002,11.8208 L33.5002,13.8797 +L36.0501,13.8797 L36.0501,17.4996 L38.4251,17.4996 L38.4251,13.8797 +L41.5752,13.8797 L41.5752,17.4996 L43.9502,17.4996 L43.9502,13.8797 +L46.5002,13.8797 Z M41.5752,11.8208 L38.4251,11.8208 L38.4251,8.38194 +L41.5752,8.38194 L41.5752,11.8208 Z"/> +</vector> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout-land/fragment_keyagreement_id.xml b/mailbox-android/src/main/res/layout-land/fragment_keyagreement_id.xml new file mode 100644 index 0000000000000000000000000000000000000000..f25b2c5543f7362d07bbbc3e665b7bbe7ca5991f --- /dev/null +++ b/mailbox-android/src/main/res/layout-land/fragment_keyagreement_id.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + android:id="@+id/scrollView" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <android.support.constraint.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="@dimen/margin_large"> + + <ImageView + android:id="@+id/diagram" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:adjustViewBounds="true" + android:padding="@dimen/margin_medium" + android:scaleType="fitCenter" + android:src="@drawable/qr_code_intro" + android:tint="@color/color_primary" + app:layout_constraintBottom_toBottomOf="@id/explanationText" + app:layout_constraintEnd_toStartOf="@id/explanationText" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"/> + + <ImageView + android:id="@+id/explanationImage" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:adjustViewBounds="true" + android:paddingLeft="@dimen/margin_large" + android:paddingRight="@dimen/margin_large" + android:paddingTop="@dimen/margin_large" + android:scaleType="fitCenter" + android:src="@drawable/qr_code_explanation" + app:layout_constraintBottom_toTopOf="@id/explanationText" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/diagram" + app:layout_constraintTop_toTopOf="parent" + tools:ignore="ContentDescription"/> + + <TextView + android:id="@+id/explanationText" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:padding="@dimen/margin_large" + android:text="@string/face_to_face" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/diagram" + app:layout_constraintTop_toBottomOf="@id/explanationImage"/> + + <View + android:id="@+id/explanationBorder" + android:layout_width="0dp" + android:layout_height="0dp" + android:background="@drawable/border_explanation" + app:layout_constraintBottom_toBottomOf="@id/explanationText" + app:layout_constraintEnd_toEndOf="@id/explanationImage" + app:layout_constraintStart_toStartOf="@id/explanationImage" + app:layout_constraintTop_toTopOf="@id/explanationImage"/> + + <android.support.constraint.Barrier + android:id="@+id/barrier" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:barrierDirection="bottom" + app:constraint_referenced_ids="diagram,explanationBorder"/> + + <Button + android:id="@+id/continueButton" + style="@style/BriarButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginTop="@dimen/margin_medium" + android:text="@string/continue_button" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/barrier"/> + + </android.support.constraint.ConstraintLayout> + +</ScrollView> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_change_password.xml b/mailbox-android/src/main/res/layout/activity_change_password.xml new file mode 100644 index 0000000000000000000000000000000000000000..436d5728053e4f0d2d85a86d5a99738e41763a51 --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_change_password.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".android.login.ChangePasswordActivity"> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingBottom="@dimen/margin_activity_vertical" + android:paddingEnd="@dimen/margin_activity_horizontal" + android:paddingLeft="@dimen/margin_activity_horizontal" + android:paddingRight="@dimen/margin_activity_horizontal" + android:paddingStart="@dimen/margin_activity_horizontal" + android:paddingTop="@dimen/margin_activity_vertical"> + + <android.support.design.widget.TextInputLayout + android:id="@+id/current_password_entry_wrapper" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + app:errorEnabled="true" + app:hintEnabled="false" + app:passwordToggleEnabled="true"> + + <EditText + android:id="@+id/current_password_entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/current_password" + android:inputType="textPassword" + android:maxLines="1"/> + </android.support.design.widget.TextInputLayout> + + <android.support.design.widget.TextInputLayout + android:id="@+id/new_password_entry_wrapper" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/current_password_entry_wrapper" + android:layout_centerHorizontal="true" + app:errorEnabled="true" + app:hintEnabled="false" + app:passwordToggleEnabled="true"> + + <EditText + android:id="@+id/new_password_entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/choose_new_password" + android:inputType="textPassword" + android:maxLines="1"/> + </android.support.design.widget.TextInputLayout> + + <android.support.design.widget.TextInputLayout + android:id="@+id/new_password_confirm_wrapper" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/new_password_entry_wrapper" + android:layout_centerHorizontal="true" + app:errorEnabled="true" + app:hintEnabled="false" + app:passwordToggleEnabled="true"> + + <EditText + android:id="@+id/new_password_confirm" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/confirm_new_password" + android:imeOptions="actionDone" + android:inputType="textPassword" + android:maxLines="1"/> + </android.support.design.widget.TextInputLayout> + + <org.briarproject.mailbox.android.login.StrengthMeter + android:id="@+id/strength_meter" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/new_password_confirm_wrapper" + android:layout_centerHorizontal="true" + android:visibility="invisible"/> + + <Button + android:id="@+id/change_password" + style="@style/BriarButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/strength_meter" + android:layout_centerHorizontal="true" + android:layout_marginTop="@dimen/margin_medium" + android:enabled="false" + android:text="@string/change_password" + tools:enabled="true"/> + + <ProgressBar + android:id="@+id/progress_wheel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignTop="@id/change_password" + android:layout_centerHorizontal="true" + android:visibility="invisible"/> + + </RelativeLayout> + +</ScrollView> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_conversation.xml b/mailbox-android/src/main/res/layout/activity_conversation.xml new file mode 100644 index 0000000000000000000000000000000000000000..c12c7ad26ed573cc41aed91988268ad72a18b8fa --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_conversation.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + 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:orientation="vertical" + tools:context=".android.contact.ConversationActivity"> + + <android.support.design.widget.AppBarLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <android.support.v7.widget.Toolbar + android:id="@+id/toolbar" + style="@style/BriarToolbar" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="match_parent"> + + <include layout="@layout/contact_avatar_status"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/contactName" + style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse" + android:textColor="@color/action_bar_text" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_marginLeft="@dimen/margin_medium" + android:layout_marginStart="@dimen/margin_medium" + android:gravity="center" + tools:text="Contact Name"/> + + </LinearLayout> + + </android.support.v7.widget.Toolbar> + + </android.support.design.widget.AppBarLayout> + + <org.briarproject.mailbox.android.view.BriarRecyclerView + android:id="@+id/conversationView" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"/> + + <org.briarproject.mailbox.android.view.TextInputView + android:id="@+id/text_input_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:hint="@string/message_hint"/> + +</LinearLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_create_forum.xml b/mailbox-android/src/main/res/layout/activity_create_forum.xml new file mode 100644 index 0000000000000000000000000000000000000000..e759e25c465544164cd82215efc0920933810585 --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_create_forum.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + 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:orientation="vertical" + android:padding="@dimen/margin_large"> + + <android.support.design.widget.TextInputLayout + android:id="@+id/createForumNameLayout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:errorEnabled="true" + app:hintEnabled="false"> + + <EditText + android:id="@+id/createForumNameEntry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/choose_forum_hint" + android:inputType="text|textCapSentences" + android:maxLines="1"/> + + </android.support.design.widget.TextInputLayout> + + <Button + android:id="@+id/createForumButton" + style="@style/BriarButton" + android:enabled="false" + android:text="@string/create_forum_button" + tools:enabled="true"/> + + <ProgressBar + android:id="@+id/createForumProgressBar" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:indeterminate="true" + android:visibility="gone" + tools:visibility="visible"/> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/activity_dev_report.xml b/mailbox-android/src/main/res/layout/activity_dev_report.xml new file mode 100644 index 0000000000000000000000000000000000000000..ab17da50e4e0f63f7b8f7fd46a77fcbc5f011cf9 --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_dev_report.xml @@ -0,0 +1,186 @@ +<?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:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:id="@+id/report_form" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:visibility="visible" + tools:context=".android.reporting.DevReportActivity"> + + <include layout="@layout/toolbar"/> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginEnd="@dimen/margin_large" + android:layout_marginLeft="@dimen/margin_large" + android:layout_marginRight="@dimen/margin_large" + android:layout_marginStart="@dimen/margin_large"> + + <android.support.design.widget.TextInputLayout + android:id="@+id/user_comment_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/user_comment" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="textMultiLine|textCapSentences" + tools:hint="@string/describe_crash"/> + + </android.support.design.widget.TextInputLayout> + + <android.support.design.widget.TextInputLayout + android:id="@+id/user_email_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/user_comment_layout" + android:layout_marginTop="@dimen/margin_small"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/user_email" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/optional_contact_email" + android:inputType="textEmailAddress" + android:maxLines="1"/> + + </android.support.design.widget.TextInputLayout> + + <CheckBox + android:id="@+id/include_debug_report" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_below="@+id/user_email_layout" + android:layout_marginTop="@dimen/margin_small" + android:layout_toLeftOf="@+id/chevron" + android:checked="false" + android:text="@string/include_debug_report_crash"/> + + <Button + android:id="@+id/chevron" + style="@style/BriarButtonFlat.Positive" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentRight="true" + android:layout_alignTop="@+id/include_debug_report" + android:text="@string/show"/> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/include_debug_report" + android:layout_marginTop="@dimen/margin_small"> + + <LinearLayout + android:id="@+id/report_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:orientation="vertical" + android:paddingBottom="@dimen/listitem_height_one_line_avatar" + android:paddingEnd="@dimen/margin_large" + android:paddingLeft="@dimen/margin_large" + android:paddingRight="@dimen/margin_large" + android:paddingStart="@dimen/margin_large" + android:paddingTop="@dimen/margin_small" + android:visibility="gone"/> + + </ScrollView> + + <ProgressBar + android:id="@+id/progress_wheel" + style="?android:attr/progressBarStyleLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:layout_below="@+id/include_debug_report" + android:layout_centerHorizontal="true" + android:indeterminate="true" + android:visibility="gone"/> + + </RelativeLayout> + </LinearLayout> + + <RelativeLayout + android:id="@+id/request_report" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clickable="true" + android:gravity="center" + android:padding="@dimen/margin_large" + android:visibility="invisible"> + + <TextView + android:id="@+id/crashed" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_large" + android:gravity="center" + android:text="@string/briar_crashed" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_large"/> + + <TextView + android:id="@+id/fault" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/crashed" + android:layout_marginTop="@dimen/margin_large" + android:gravity="center" + android:text="@string/not_your_fault" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_large"/> + + <TextView + android:id="@+id/pleaseSend" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/fault" + android:layout_marginTop="@dimen/margin_large" + android:gravity="center" + android:text="@string/please_send_report" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_large"/> + + <TextView + android:id="@+id/encrypted" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/pleaseSend" + android:layout_marginBottom="@dimen/margin_large" + android:layout_marginTop="@dimen/margin_large" + android:gravity="center" + android:text="@string/report_is_encrypted" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_large"/> + + <Button + android:id="@+id/declineButton" + style="@style/BriarButtonFlat.Negative" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_below="@+id/encrypted" + android:text="@string/close"/> + + <Button + android:id="@+id/acceptButton" + style="@style/BriarButtonFlat.Positive" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentRight="true" + android:layout_below="@+id/encrypted" + android:text="@string/send_report"/> + + </RelativeLayout> + +</FrameLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_expired.xml b/mailbox-android/src/main/res/layout/activity_expired.xml new file mode 100644 index 0000000000000000000000000000000000000000..fc99a4112d2224573f4c614c242861900df1972e --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_expired.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_large" + android:orientation="vertical"> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_medium" + android:gravity="center" + android:text="@string/expiry_date_reached" + android:textSize="@dimen/text_size_large"/> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_medium" + android:gravity="center" + android:text="@string/download_briar" + android:textSize="@dimen/text_size_large"/> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_medium" + android:gravity="center" + android:text="@string/create_new_account" + android:textSize="@dimen/text_size_large"/> + + <Button + android:id="@+id/download_briar_button" + style="@style/BriarButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_medium" + android:text="@string/download_briar_button"/> + </LinearLayout> +</ScrollView> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_fragment_container.xml b/mailbox-android/src/main/res/layout/activity_fragment_container.xml new file mode 100644 index 0000000000000000000000000000000000000000..e6c20760fb5078de5def86eec38402fc2db9042a --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_fragment_container.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + android:id="@+id/fragmentContainer" + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"/> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_fragment_container_toolbar.xml b/mailbox-android/src/main/res/layout/activity_fragment_container_toolbar.xml new file mode 100644 index 0000000000000000000000000000000000000000..442bc6de79f4ecb49910578601cdd48d7b8f6192 --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_fragment_container_toolbar.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + tools:context=".android.keyagreement.KeyAgreementActivity"> + + <include layout="@layout/toolbar"/> + + <FrameLayout + android:id="@+id/fragmentContainer" + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/activity_nav_drawer.xml b/mailbox-android/src/main/res/layout/activity_nav_drawer.xml new file mode 100644 index 0000000000000000000000000000000000000000..ec6f40fc0db6c37a7593435430803071305a2d9f --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_nav_drawer.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.v4.widget.DrawerLayout + android:id="@+id/drawer_layout" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".android.navdrawer.NavDrawerActivity"> + + <!-- The first child(root) is the content view --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <include layout="@layout/toolbar"/> + + <RelativeLayout + android:id="@+id/expiryWarning" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@color/briar_warning_background" + android:orientation="horizontal" + android:padding="@dimen/margin_medium" + android:visibility="gone" + tools:visibility="visible"> + + <TextView + android:id="@+id/expiryWarningText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@+id/expiryWarningClose" + android:text="@plurals/expiry_warning" + android:textColor="@color/briar_text_primary_inverse" + android:textSize="@dimen/text_size_small"/> + + <ImageView + android:id="@+id/expiryWarningClose" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_alignParentRight="true" + android:layout_centerInParent="true" + android:contentDescription="@string/close" + android:scaleType="center" + android:src="@drawable/ic_close" + android:tint="@color/briar_text_tertiary_inverse"/> + + </RelativeLayout> + + <FrameLayout + android:id="@+id/fragmentContainer" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + + </LinearLayout> + + <!-- The second child is the menu --> + <include + layout="@layout/navigation_menu" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="start"/> + +</android.support.v4.widget.DrawerLayout> diff --git a/mailbox-android/src/main/res/layout/activity_open_database.xml b/mailbox-android/src/main/res/layout/activity_open_database.xml new file mode 100644 index 0000000000000000000000000000000000000000..3efce6d655b760c077fa0cad05ab462dcba2511f --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_open_database.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.constraint.ConstraintLayout + 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"> + + <ImageView + android:id="@+id/imageView" + android:layout_width="128dp" + android:layout_height="128dp" + android:scaleType="center" + android:src="@drawable/startup_lock" + android:tint="@color/briar_accent" + app:layout_constraintBottom_toTopOf="@+id/textView" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.5" + app:layout_constraintVertical_chainStyle="packed" + tools:ignore="ContentDescription"/> + + <ProgressBar + android:id="@+id/progressBar" + style="?android:attr/progressBarStyleLarge" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintBottom_toBottomOf="@+id/imageView" + app:layout_constraintEnd_toEndOf="@+id/imageView" + app:layout_constraintStart_toStartOf="@+id/imageView" + app:layout_constraintTop_toTopOf="@+id/imageView"/> + + <TextView + android:id="@+id/textView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:paddingLeft="@dimen/margin_large" + android:paddingRight="@dimen/margin_large" + android:text="@string/startup_open_database" + android:textSize="@dimen/text_size_large" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/imageView"/> + +</android.support.constraint.ConstraintLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_panic_preferences.xml b/mailbox-android/src/main/res/layout/activity_panic_preferences.xml new file mode 100644 index 0000000000000000000000000000000000000000..4ce4df484ee890edb38a2dca622b218b7cbd2d23 --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_panic_preferences.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <fragment + android:id="@+id/fragment" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:name="org.briarproject.mailbox.android.panic.PanicPreferencesFragment"/> +</FrameLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_password.xml b/mailbox-android/src/main/res/layout/activity_password.xml new file mode 100644 index 0000000000000000000000000000000000000000..78f3242d7aae757d78859f8a3fa00e55e3dc942a --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_password.xml @@ -0,0 +1,70 @@ +<?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" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingBottom="@dimen/margin_activity_vertical" + android:paddingEnd="@dimen/margin_activity_horizontal" + android:paddingLeft="@dimen/margin_activity_horizontal" + android:paddingRight="@dimen/margin_activity_horizontal" + android:paddingStart="@dimen/margin_activity_horizontal" + android:paddingTop="@dimen/margin_activity_vertical"> + + <android.support.design.widget.TextInputLayout + android:id="@+id/password_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + app:errorEnabled="true" + app:hintEnabled="false" + app:passwordToggleEnabled="true"> + + <EditText + android:id="@+id/edit_password" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/enter_password" + android:imeOptions="actionDone" + android:inputType="textPassword" + android:maxLines="1"/> + </android.support.design.widget.TextInputLayout> + + <Button + android:id="@+id/btn_sign_in" + style="@style/BriarButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/password_layout" + android:layout_marginTop="@dimen/margin_medium" + android:onClick="onSignInClick" + android:text="@string/sign_in_button"/> + + <ProgressBar + android:id="@+id/progress_wheel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignTop="@id/btn_sign_in" + android:layout_centerHorizontal="true" + android:visibility="invisible"/> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/btn_sign_in" + android:layout_centerHorizontal="true" + android:layout_marginTop="@dimen/margin_large" + android:clickable="true" + android:focusable="true" + android:onClick="onForgottenPasswordClick" + android:text="@string/forgotten_password" + android:textColor="?android:attr/textColorLink"/> + + </RelativeLayout> + +</ScrollView> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_reveal_contacts.xml b/mailbox-android/src/main/res/layout/activity_reveal_contacts.xml new file mode 100644 index 0000000000000000000000000000000000000000..4faa8c869c89743ae710fa5cbd35fb182e07175c --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_reveal_contacts.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + tools:context=".android.privategroup.reveal.RevealContactsActivity"> + + <FrameLayout + android:id="@+id/fragmentContainer" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"/> + + <Button + android:id="@+id/revealButton" + style="@style/BriarButton" + android:layout_marginEnd="@dimen/margin_small" + android:layout_marginLeft="@dimen/margin_small" + android:layout_marginRight="@dimen/margin_small" + android:layout_marginStart="@dimen/margin_small" + android:text="@string/groups_reveal_contacts"/> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/activity_rss_feed_import.xml b/mailbox-android/src/main/res/layout/activity_rss_feed_import.xml new file mode 100644 index 0000000000000000000000000000000000000000..2c814dc4ce509545bfb1d6b6932f8fa6013d3b93 --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_rss_feed_import.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + 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:orientation="vertical" + android:padding="@dimen/margin_small" + tools:context=".android.blog.RssFeedImportActivity"> + + <android.support.v7.widget.CardView + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:elevation="@dimen/cardview_default_elevation" + app:cardBackgroundColor="@color/card_background" + app:cardCornerRadius="0dp" + app:cardUseCompatPadding="false"> + + <EditText + android:id="@+id/urlInput" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@android:color/transparent" + android:gravity="top" + android:hint="@string/blogs_rss_feeds_import_hint" + android:inputType="textUri" + android:padding="@dimen/margin_medium" + android:textColor="?android:attr/textColorPrimary"/> + + </android.support.v7.widget.CardView> + + <Button + android:id="@+id/importButton" + style="@style/BriarButton" + android:enabled="false" + android:text="@string/blogs_rss_feeds_import_button"/> + + <ProgressBar + android:id="@+id/progressBar" + style="?android:attr/progressBarStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:visibility="gone"/> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/activity_rss_feed_manage.xml b/mailbox-android/src/main/res/layout/activity_rss_feed_manage.xml new file mode 100644 index 0000000000000000000000000000000000000000..e5ce9aaa088287e85767c7a0bcb2512c8503553e --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_rss_feed_manage.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<org.briarproject.mailbox.android.view.BriarRecyclerView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/feedList" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:scrollToEnd="false" + app:emptyText="@string/blogs_rss_feeds_manage_empty_state" + tools:listitem="@layout/list_item_rss_feed"/> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_settings.xml b/mailbox-android/src/main/res/layout/activity_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..e695e801c0f0fe2761d2b02850df056fc922a517 --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_settings.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <fragment + android:id="@+id/fragment" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:name="org.briarproject.mailbox.android.settings.SettingsFragment"/> +</FrameLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_sharing_status.xml b/mailbox-android/src/main/res/layout/activity_sharing_status.xml new file mode 100644 index 0000000000000000000000000000000000000000..904e935535baa901a6850276c4e8424bba5c38be --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_sharing_status.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.constraint.ConstraintLayout + android:id="@+id/linearLayout" + 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.support.v7.widget.AppCompatImageView + android:id="@+id/infoView" + android:layout_width="wrap_content" + android:layout_height="0dp" + android:layout_marginLeft="8dp" + android:layout_marginStart="8dp" + android:elevation="@dimen/margin_tiny" + android:src="@drawable/ic_info_white" + app:layout_constraintBottom_toTopOf="@+id/divider" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:tint="?attr/colorControlNormal"/> + + <TextView + android:id="@+id/info" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:elevation="@dimen/margin_tiny" + android:padding="@dimen/margin_medium" + android:textColor="?android:textColorSecondary" + android:textSize="@dimen/text_size_tiny" + app:layout_constraintBottom_toTopOf="@+id/divider" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/infoView" + app:layout_constraintTop_toTopOf="parent" + tools:text="@string/sharing_status_forum"/> + + <View + android:id="@+id/divider" + style="@style/Divider.Horizontal" + android:elevation="@dimen/margin_tiny" + app:layout_constraintBottom_toTopOf="@+id/list" + app:layout_constraintStart_toStartOf="@+id/info" + app:layout_constraintTop_toBottomOf="@+id/info"/> + + <org.briarproject.mailbox.android.view.BriarRecyclerView + android:id="@+id/list" + 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_toBottomOf="@+id/divider" + app:scrollToEnd="false" + tools:listitem="@layout/list_item_contact_small"/> + +</android.support.constraint.ConstraintLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_test_data.xml b/mailbox-android/src/main/res/layout/activity_test_data.xml new file mode 100644 index 0000000000000000000000000000000000000000..33a659c86b18586114ab1de15189301fdf8462ea --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_test_data.xml @@ -0,0 +1,178 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.constraint.ConstraintLayout + 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"> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="0dp" + android:padding="8dp" + tools:ignore="HardcodedText"> + + <android.support.constraint.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="wrap_content"> + + <TextView + android:id="@+id/textViewContacts" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_medium" + android:text="Number of contacts" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"/> + + <SeekBar + android:id="@+id/seekBarContacts" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:max="49" + android:progress="20" + app:layout_constraintEnd_toStartOf="@+id/textViewContactsSb" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textViewContacts"/> + + <TextView + android:id="@+id/textViewContactsSb" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ems="2" + android:text="20" + app:layout_constraintBottom_toBottomOf="@+id/seekBarContacts" + app:layout_constraintEnd_toEndOf="parent"/> + + + <TextView + android:id="@+id/textViewMessages" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_medium" + android:text="Number of messages per contact" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/seekBarContacts"/> + + <SeekBar + android:id="@+id/seekBarMessages" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:max="50" + android:paddingTop="5dp" + android:progress="15" + app:layout_constraintEnd_toStartOf="@+id/textViewMessagesSb" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textViewMessages"/> + + <TextView + android:id="@+id/textViewMessagesSb" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ems="2" + android:text="20" + app:layout_constraintBottom_toBottomOf="@+id/seekBarMessages" + app:layout_constraintEnd_toEndOf="parent"/> + + <TextView + android:id="@+id/textViewBlogPosts" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_medium" + android:text="Number of blog posts" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/seekBarMessages"/> + + <SeekBar + android:id="@+id/seekBarBlogPosts" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:max="50" + android:paddingTop="5dp" + android:progress="30" + app:layout_constraintEnd_toStartOf="@+id/TextViewBlogPostsSb" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textViewBlogPosts"/> + + <TextView + android:id="@+id/TextViewBlogPostsSb" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ems="2" + android:text="20" + app:layout_constraintBottom_toBottomOf="@+id/seekBarBlogPosts" + app:layout_constraintEnd_toEndOf="parent"/> + + <TextView + android:id="@+id/textViewForums" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_medium" + android:text="Number of forums" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/seekBarBlogPosts"/> + + <SeekBar + android:id="@+id/seekBarForums" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:max="10" + android:paddingTop="5dp" + android:progress="3" + app:layout_constraintEnd_toStartOf="@+id/TextViewForumsSb" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textViewForums"/> + + <TextView + android:id="@+id/TextViewForumsSb" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ems="2" + android:text="20" + app:layout_constraintBottom_toBottomOf="@+id/seekBarForums" + app:layout_constraintEnd_toEndOf="parent"/> + + <TextView + android:id="@+id/textViewForumMessages" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_medium" + android:text="Number of forum messages" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/seekBarForums"/> + + <SeekBar + android:id="@+id/seekBarForumMessages" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:max="50" + android:paddingTop="5dp" + android:progress="30" + app:layout_constraintEnd_toStartOf="@+id/TextViewForumMessagesSb" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textViewForumMessages"/> + + <TextView + android:id="@+id/TextViewForumMessagesSb" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ems="2" + android:text="20" + app:layout_constraintBottom_toBottomOf="@+id/seekBarForumMessages" + app:layout_constraintEnd_toEndOf="parent"/> + + <Button + android:id="@+id/buttonCreateTestData" + style="@style/BriarButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:text="Create test data" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/seekBarForumMessages"/> + </android.support.constraint.ConstraintLayout> + </ScrollView> +</android.support.constraint.ConstraintLayout> diff --git a/mailbox-android/src/main/res/layout/activity_threaded_conversation.xml b/mailbox-android/src/main/res/layout/activity_threaded_conversation.xml new file mode 100644 index 0000000000000000000000000000000000000000..9df74041592ebb66e21330da8283692c9240b325 --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_threaded_conversation.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + 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:orientation="vertical" + tools:context=".android.forum.ForumActivity"> + + <include layout="@layout/toolbar"/> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + + <org.briarproject.mailbox.android.view.BriarRecyclerView + android:id="@+id/list" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:emptyText="@string/no_forum_posts" + app:scrollToEnd="false"/> + + <org.briarproject.mailbox.android.view.UnreadMessageButton + android:id="@+id/upButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="top|right" + app:direction="up"/> + + <org.briarproject.mailbox.android.view.UnreadMessageButton + android:id="@+id/downButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom|right" + app:direction="down"/> + + </FrameLayout> + + <org.briarproject.mailbox.android.view.TextInputView + android:id="@+id/text_input_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:hint="@string/forum_new_message_hint"/> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/activity_unlock.xml b/mailbox-android/src/main/res/layout/activity_unlock.xml new file mode 100644 index 0000000000000000000000000000000000000000..48413a19820d5251e01c1418ffd54fb48aedcb09 --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_unlock.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.constraint.ConstraintLayout + 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:orientation="vertical" + tools:context=".android.login.UnlockActivity"> + + <android.support.v7.widget.AppCompatImageView + android:id="@+id/image" + android:layout_width="150dp" + android:layout_height="150dp" + android:layout_margin="@dimen/margin_large" + android:src="@drawable/splash_screen" + app:layout_constraintBottom_toTopOf="@+id/is_locked" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_chainStyle="spread" + app:tint="?attr/colorControlNormal"/> + + <TextView + android:id="@+id/is_locked" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_large" + android:gravity="center" + android:text="@string/lock_is_locked" + android:textSize="@dimen/text_size_xlarge" + app:layout_constraintBottom_toTopOf="@+id/unlock" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/image" + app:layout_constraintVertical_chainStyle="spread"/> + + <Button + android:id="@+id/unlock" + style="@style/BriarButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_large" + android:text="@string/lock_unlock" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent"/> + +</android.support.constraint.ConstraintLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/activity_write_blog_post.xml b/mailbox-android/src/main/res/layout/activity_write_blog_post.xml new file mode 100644 index 0000000000000000000000000000000000000000..a6e130fc1f13f3d6750b6d17f95cf879cc85aa12 --- /dev/null +++ b/mailbox-android/src/main/res/layout/activity_write_blog_post.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + 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" + tools:context=".android.blog.WriteBlogPostActivity"> + + <org.briarproject.mailbox.android.view.LargeTextInputView + android:id="@+id/bodyInput" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="bottom" + app:buttonText="@string/blogs_publish_blog_post" + app:hint="@string/blogs_write_blog_post_body_hint" + app:fillHeight="true"/> + + <ProgressBar + android:id="@+id/progressBar" + style="?android:attr/progressBarStyleLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:visibility="invisible"/> + +</FrameLayout> diff --git a/mailbox-android/src/main/res/layout/author_view.xml b/mailbox-android/src/main/res/layout/author_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..0edf0b9975f04f27bcb41266c10873d77fc30202 --- /dev/null +++ b/mailbox-android/src/main/res/layout/author_view.xml @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + tools:showIn="@layout/list_item_blog_post"> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/avatar" + style="@style/BriarAvatar" + android:layout_width="@dimen/blogs_avatar_normal_size" + android:layout_height="@dimen/blogs_avatar_normal_size" + android:layout_alignTop="@+id/authorName" + android:layout_marginRight="@dimen/margin_medium" + tools:src="@mipmap/ic_launcher_round"/> + + <ImageView + android:id="@+id/avatarIcon" + android:layout_width="@dimen/blogs_avatar_icon_size" + android:layout_height="@dimen/blogs_avatar_icon_size" + android:layout_alignBottom="@+id/avatar" + android:layout_alignRight="@+id/avatar" + android:background="@drawable/bubble_white" + android:padding="2dp" + android:scaleType="fitCenter" + android:src="@drawable/ic_repeat" + android:visibility="invisible" + tools:ignore="ContentDescription"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/authorName" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toEndOf="@+id/avatar" + android:layout_toRightOf="@+id/avatar" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_small" + tools:text="Author Name"/> + + <org.briarproject.mailbox.android.view.TrustIndicatorView + android:id="@+id/trustIndicator" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/authorName" + android:layout_alignTop="@+id/authorName" + android:layout_marginLeft="@dimen/margin_small" + android:layout_toRightOf="@id/authorName" + android:scaleType="center" + tools:src="@drawable/trust_indicator_verified"/> + + <TextView + android:id="@+id/dateView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/authorName" + android:layout_toEndOf="@+id/avatar" + android:layout_toRightOf="@+id/avatar" + android:gravity="bottom" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_tiny" + tools:text="yesterday"/> + +</merge> diff --git a/mailbox-android/src/main/res/layout/briar_recycler_view.xml b/mailbox-android/src/main/res/layout/briar_recycler_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..b0f9b1b19cf48bad83e0c9bfb8a1d91d180d047d --- /dev/null +++ b/mailbox-android/src/main/res/layout/briar_recycler_view.xml @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.constraint.ConstraintLayout + android:id="@+id/relativeLayout" + 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.support.v7.widget.RecyclerView + android:id="@+id/recyclerView" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scrollbars="vertical" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:listitem="@layout/list_item_contact" + tools:visibility="visible"/> + + <ProgressBar + android:id="@+id/progressBar" + style="?android:attr/progressBarStyleLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:visibility="invisible"/> + + <android.support.constraint.Group + android:id="@+id/emptyState" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:constraint_referenced_ids="emptyImage, emptyText, emptyAction" + tools:visibility="invisible"/> + + <android.support.v7.widget.AppCompatImageView + android:id="@+id/emptyImage" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="16dp" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + app:layout_constraintBottom_toTopOf="@+id/emptyText" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_chainStyle="packed" + app:tint="?attr/colorControlNormal" + tools:src="@drawable/ic_empty_state_group_list"/> + + <TextView + android:id="@+id/emptyText" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:gravity="center" + android:padding="@dimen/margin_large" + android:text="@string/no_data" + android:textSize="@dimen/text_size_large" + app:layout_constraintBottom_toTopOf="@+id/emptyAction" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/emptyImage" + tools:text="@string/no_contacts"/> + + <TextView + android:id="@+id/emptyAction" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:gravity="center" + android:paddingBottom="@dimen/margin_large" + android:paddingLeft="@dimen/margin_large" + android:paddingRight="@dimen/margin_large" + android:textSize="@dimen/text_size_small" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/emptyText" + tools:text="@string/no_contacts_action"/> + +</android.support.constraint.ConstraintLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/checkbox.xml b/mailbox-android/src/main/res/layout/checkbox.xml new file mode 100644 index 0000000000000000000000000000000000000000..eb3dfe6a44b0f61eaff19e08dbb4970d7592d24e --- /dev/null +++ b/mailbox-android/src/main/res/layout/checkbox.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <CheckBox + android:id="@+id/checkbox" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/margin_activity_horizontal" + android:layout_marginTop="@dimen/margin_activity_vertical" + android:checked="false" + android:text="@string/don_t_ask_again"/> + +</FrameLayout> diff --git a/mailbox-android/src/main/res/layout/contact_avatar_status.xml b/mailbox-android/src/main/res/layout/contact_avatar_status.xml new file mode 100644 index 0000000000000000000000000000000000000000..0d47e786e6451d0231a944b4e81da7827fb220c2 --- /dev/null +++ b/mailbox-android/src/main/res/layout/contact_avatar_status.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + 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="32dp" + android:layout_height="32dp" + tools:showIn="@layout/activity_conversation"> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/contactAvatar" + style="@style/BriarAvatar" + android:layout_width="30dp" + android:layout_height="30dp" + app:civ_border_color="@color/action_bar_text" + tools:src="@mipmap/ic_launcher_round"/> + + <ImageView + android:id="@+id/contactStatus" + android:layout_width="15dp" + android:layout_height="15dp" + android:layout_gravity="bottom|right" + android:scaleType="fitCenter" + tools:ignore="ContentDescription" + tools:src="@drawable/contact_online"/> + +</FrameLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/dialog_screen_filter.xml b/mailbox-android/src/main/res/layout/dialog_screen_filter.xml new file mode 100644 index 0000000000000000000000000000000000000000..b883d16e71408101e42e4f0e890932ca29bc8493 --- /dev/null +++ b/mailbox-android/src/main/res/layout/dialog_screen_filter.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:padding="@dimen/margin_large"> + + <ScrollView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1"> + + <TextView + android:id="@+id/screen_filter_message" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + + </ScrollView> + + <CheckBox + android:id="@+id/screen_filter_checkbox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:layout_marginTop="@dimen/margin_large" + android:text="@string/screen_filter_allow"/> + +</LinearLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/emoji_drawer.xml b/mailbox-android/src/main/res/layout/emoji_drawer.xml new file mode 100644 index 0000000000000000000000000000000000000000..28f2cfa4923123f73029ca0e7f344b6baa64accb --- /dev/null +++ b/mailbox-android/src/main/res/layout/emoji_drawer.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <View + style="@style/Divider.Horizontal"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="40dp" + android:orientation="horizontal"> + + <com.astuetz.PagerSlidingTabStrip + android:id="@+id/tabs" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + app:pstsIndicatorColor="@color/color_primary" + app:pstsIndicatorHeight="@dimen/emoji_drawer_indicator_height" + app:pstsShouldExpand="true" + app:pstsTabPaddingLeftRight="@dimen/emoji_drawer_left_right_padding"/> + + <View + android:layout_width="@dimen/margin_separator" + android:layout_height="match_parent" + android:layout_marginBottom="10dp" + android:layout_marginTop="10dp" + android:background="@color/divider"/> + + <org.thoughtcrime.securesms.components.RepeatableImageKey + android:id="@+id/backspace" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:background="?attr/selectableItemBackground" + android:paddingLeft="@dimen/margin_medium" + android:paddingRight="@dimen/margin_medium" + android:src="@drawable/ic_backspace" + app:tint="?attr/colorControlNormal"/> + + </LinearLayout> + + <View + style="@style/Divider.Horizontal"/> + + <android.support.v4.view.ViewPager + android:id="@+id/emoji_pager" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="visible"/> + +</merge> diff --git a/mailbox-android/src/main/res/layout/emoji_grid_layout.xml b/mailbox-android/src/main/res/layout/emoji_grid_layout.xml new file mode 100644 index 0000000000000000000000000000000000000000..c1486e2dcb94a9f7ff14ce5dc7bc4504528372da --- /dev/null +++ b/mailbox-android/src/main/res/layout/emoji_grid_layout.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <GridView + android:id="@+id/emoji" + android:layout_width="fill_parent" + android:layout_height="match_parent" + android:columnWidth="@dimen/emoji_drawer_size" + android:gravity="center" + android:horizontalSpacing="0dp" + android:numColumns="auto_fit" + android:stretchMode="columnWidth" + android:verticalSpacing="0dp" + android:visibility="visible"/> + +</FrameLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/fragment_blog.xml b/mailbox-android/src/main/res/layout/fragment_blog.xml new file mode 100644 index 0000000000000000000000000000000000000000..711dfb25eb78390d24661ac425b01b32f421a237 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_blog.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<org.briarproject.mailbox.android.view.BriarRecyclerView + android:id="@+id/postList" + 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" + app:scrollToEnd="false" + tools:context=".android.blog.BlogActivity"/> diff --git a/mailbox-android/src/main/res/layout/fragment_blog_post.xml b/mailbox-android/src/main/res/layout/fragment_blog_post.xml new file mode 100644 index 0000000000000000000000000000000000000000..3fdce0b1c5a634db1ee967423f13ee85ae620299 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_blog_post.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:descendantFocusability="beforeDescendants" + android:focusable="true" + android:focusableInTouchMode="true"> + <!-- Above focusability attributes prevent automatic scroll-down, + because body text is selectable --> + + <include + android:id="@+id/postLayout" + style="@style/BriarCard" + layout="@layout/list_item_blog_post" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <ProgressBar + android:id="@+id/progressBar" + style="?android:attr/progressBarStyleLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center"/> + + </FrameLayout> + +</ScrollView> diff --git a/mailbox-android/src/main/res/layout/fragment_create_group.xml b/mailbox-android/src/main/res/layout/fragment_create_group.xml new file mode 100644 index 0000000000000000000000000000000000000000..3fc495e9ba20f4c0e7a6cfbdb03d4fdbefa1c421 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_create_group.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + 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:orientation="vertical" + android:padding="@dimen/margin_large"> + + <android.support.design.widget.TextInputLayout + android:id="@+id/nameLayout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:errorEnabled="true" + app:hintEnabled="false"> + + <EditText + android:id="@+id/name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/groups_create_group_hint" + android:inputType="text|textCapSentences" + android:maxLines="1"/> + + </android.support.design.widget.TextInputLayout> + + <Button + android:id="@+id/button" + style="@style/BriarButton" + android:enabled="false" + android:text="@string/groups_create_group_button" + tools:enabled="true"/> + + <ProgressBar + android:id="@+id/progressBar" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:indeterminate="true" + android:visibility="gone" + tools:visibility="visible"/> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/fragment_error.xml b/mailbox-android/src/main/res/layout/fragment_error.xml new file mode 100644 index 0000000000000000000000000000000000000000..b705051ccdd57d7d9b980ae534b3b99efc20023b --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_error.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.constraint.ConstraintLayout + 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.support.v7.widget.AppCompatImageView + android:id="@+id/errorIcon" + android:layout_width="128dp" + android:layout_height="128dp" + android:layout_marginEnd="8dp" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" + android:src="@drawable/alerts_and_states_error" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:tint="?attr/colorControlNormal" + tools:ignore="ContentDescription"/> + + <TextView + android:id="@+id/errorTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" + android:text="@string/sorry" + android:textSize="@dimen/text_size_xlarge" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/errorIcon"/> + + <TextView + android:id="@+id/errorMessage" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginEnd="16dp" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:layout_marginStart="16dp" + android:layout_marginTop="8dp" + android:textSize="@dimen/text_size_medium" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/errorTitle" + tools:text="@string/qr_code_unsupported"/> + +</android.support.constraint.ConstraintLayout> diff --git a/mailbox-android/src/main/res/layout/fragment_error_contact_exchange.xml b/mailbox-android/src/main/res/layout/fragment_error_contact_exchange.xml new file mode 100644 index 0000000000000000000000000000000000000000..48a563ca1a054f14a4fae7579375d47b82593399 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_error_contact_exchange.xml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fillViewport="true"> + + <android.support.constraint.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:id="@+id/errorTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:text="@string/connection_error_title" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_large" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"/> + + <android.support.v7.widget.AppCompatImageView + android:id="@+id/errorIcon" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:layout_marginTop="16dp" + android:scaleType="fitCenter" + android:src="@drawable/qr_code_error" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/errorTitle" + app:tint="?attr/colorControlNormal" + tools:ignore="ContentDescription"/> + + <TextView + android:id="@+id/errorMessage" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginEnd="16dp" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:layout_marginStart="16dp" + android:layout_marginTop="8dp" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_medium" + app:layout_constraintBottom_toTopOf="@+id/sendFeedback" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/errorIcon" + app:layout_constraintVertical_bias="0" + app:layout_constraintVertical_chainStyle="packed" + tools:text="@string/connection_error_explanation"/> + + <TextView + android:id="@+id/sendFeedback" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginEnd="16dp" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:layout_marginStart="16dp" + android:layout_marginTop="8dp" + android:text="@string/connection_error_feedback" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_medium" + app:layout_constraintBottom_toTopOf="@+id/tryAgainButton" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/errorMessage"/> + + <Button + android:id="@+id/tryAgainButton" + style="@style/BriarButtonFlat.Positive" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginBottom="8dp" + android:layout_marginEnd="8dp" + android:layout_marginRight="8dp" + android:text="@string/try_again_button" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_weight="1" + app:layout_constraintStart_toEndOf="@+id/cancelButton"/> + + <Button + android:id="@+id/cancelButton" + style="@style/BriarButtonFlat.Negative" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginBottom="8dp" + android:layout_marginEnd="8dp" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_marginStart="8dp" + android:text="@string/cancel" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@+id/tryAgainButton" + app:layout_constraintHorizontal_chainStyle="spread" + app:layout_constraintHorizontal_weight="1" + app:layout_constraintStart_toStartOf="parent"/> + + </android.support.constraint.ConstraintLayout> +</ScrollView> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/fragment_forum_list.xml b/mailbox-android/src/main/res/layout/fragment_forum_list.xml new file mode 100644 index 0000000000000000000000000000000000000000..7554c59659424a87ea9f055c9e9ed9dc9adaa1a1 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_forum_list.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<org.briarproject.mailbox.android.view.BriarRecyclerView + android:id="@+id/forumList" + 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" + app:emptyAction="@string/no_forums_action" + app:emptyImage="@drawable/ic_empty_state_forum_list" + app:emptyText="@string/no_forums" + app:layout_behavior="org.briarproject.briar.android.view.BriarRecyclerViewBehavior"/> diff --git a/mailbox-android/src/main/res/layout/fragment_keyagreement_id.xml b/mailbox-android/src/main/res/layout/fragment_keyagreement_id.xml new file mode 100644 index 0000000000000000000000000000000000000000..4098878273008197d49f69e1bc32d407690d1c30 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_keyagreement_id.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + android:id="@+id/scrollView" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <android.support.constraint.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="@dimen/margin_large"> + + <ImageView + android:id="@+id/diagram" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:adjustViewBounds="true" + android:paddingBottom="@dimen/margin_large" + android:scaleType="fitCenter" + android:src="@drawable/qr_code_intro" + android:tint="@color/color_primary" + app:layout_constraintBottom_toTopOf="@id/explanationImage" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"/> + + <ImageView + android:id="@+id/explanationImage" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:adjustViewBounds="true" + android:paddingLeft="@dimen/margin_large" + android:paddingRight="@dimen/margin_large" + android:paddingTop="@dimen/margin_large" + android:scaleType="fitCenter" + android:src="@drawable/qr_code_explanation" + app:layout_constraintBottom_toTopOf="@id/explanationText" + app:layout_constraintEnd_toEndOf="@id/diagram" + app:layout_constraintStart_toStartOf="@id/diagram" + app:layout_constraintTop_toBottomOf="@id/diagram" + tools:ignore="ContentDescription"/> + + <TextView + android:id="@+id/explanationText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="@dimen/margin_large" + android:text="@string/face_to_face" + app:layout_constrainedWidth="true" + app:layout_constraintEnd_toEndOf="@id/explanationImage" + app:layout_constraintStart_toStartOf="@id/explanationImage" + app:layout_constraintTop_toBottomOf="@id/explanationImage"/> + + <View + android:id="@+id/explanationBorder" + android:layout_width="0dp" + android:layout_height="0dp" + android:background="@drawable/border_explanation" + app:layout_constraintBottom_toBottomOf="@id/explanationText" + app:layout_constraintEnd_toEndOf="@id/explanationImage" + app:layout_constraintStart_toStartOf="@id/explanationImage" + app:layout_constraintTop_toTopOf="@id/explanationImage"/> + + <Button + android:id="@+id/continueButton" + style="@style/BriarButton" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_medium" + android:text="@string/continue_button" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@id/explanationImage" + app:layout_constraintStart_toStartOf="@id/explanationImage" + app:layout_constraintTop_toBottomOf="@id/explanationText"/> + + </android.support.constraint.ConstraintLayout> + +</ScrollView> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/fragment_keyagreement_qr.xml b/mailbox-android/src/main/res/layout/fragment_keyagreement_qr.xml new file mode 100644 index 0000000000000000000000000000000000000000..cc53978b5ec509d17d7d1e68afb2943267a43d33 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_keyagreement_qr.xml @@ -0,0 +1,52 @@ +<?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:layout_width="match_parent" + android:layout_height="match_parent"> + + <org.briarproject.mailbox.android.keyagreement.CameraView + android:id="@+id/camera_view" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + + <LinearLayout + android:id="@+id/camera_overlay" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:baselineAligned="false" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/status_container" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:gravity="center" + android:orientation="vertical" + android:padding="@dimen/margin_medium" + android:visibility="invisible" + tools:visibility="visible"> + + <ProgressBar + style="?android:attr/progressBarStyleLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <TextView + android:id="@+id/connect_status" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:paddingTop="@dimen/margin_large" + tools:text="Connection failed"/> + </LinearLayout> + + <org.briarproject.mailbox.android.view.QrCodeView + android:id="@+id/qr_code_view" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:background="@android:color/white"/> + </LinearLayout> +</FrameLayout> diff --git a/mailbox-android/src/main/res/layout/fragment_link_dialog.xml b/mailbox-android/src/main/res/layout/fragment_link_dialog.xml new file mode 100644 index 0000000000000000000000000000000000000000..328185e424e33fcf135927cc423dee680e48ef7b --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_link_dialog.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="@dimen/margin_large"> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/link_warning_title" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_large" + android:textStyle="bold"/> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_large" + android:text="@string/link_warning_intro" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_medium"/> + + <TextView + android:id="@+id/urlView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_large" + android:textIsSelectable="true" + android:typeface="monospace" + tools:text="http://very.bad.site.com"/> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_large" + android:text="@string/link_warning_text" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_medium"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <Button + android:id="@+id/cancelButton" + style="@style/BriarButtonFlat.Positive" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0.5" + android:text="@string/cancel"/> + + <Button + android:id="@+id/openButton" + style="@style/BriarButtonFlat.Negative" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0.5" + android:text="@string/link_warning_open_link"/> + + </LinearLayout> + +</LinearLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/fragment_message.xml b/mailbox-android/src/main/res/layout/fragment_message.xml new file mode 100644 index 0000000000000000000000000000000000000000..bd1ae0c94a3be233bc2bd9802f0afad5d0703733 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_message.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<org.briarproject.mailbox.android.view.LargeTextInputView + android:id="@+id/messageView" + 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" + app:buttonText="@string/forum_share_button" + app:fillHeight="true" + app:hint="@string/forum_share_message"/> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/fragment_overview.xml b/mailbox-android/src/main/res/layout/fragment_overview.xml new file mode 100644 index 0000000000000000000000000000000000000000..082da4c8b71946a029db6c64820cfc2dbec3a76b --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_overview.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.constraint.ConstraintLayout + 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" + tools:context="org.briarproject.mailbox.navdrawer.NavDrawerActivity"> + + <TextView + android:id="@+id/ownerText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:text="Paired with:" + android:textColor="@color/briar_text_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"/> + + <TextView + android:id="@+id/ownerName" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:text="@string/mailbox_unpaired" + android:textColor="@color/briar_text_primary" + app:layout_constraintStart_toEndOf="@id/ownerText" + app:layout_constraintTop_toTopOf="parent"/> + + <ImageView + android:id="@+id/ownerStatus" + android:layout_width="15dp" + android:layout_height="15dp" + android:layout_margin="8dp" + android:scaleType="fitCenter" + app:layout_constraintBottom_toBottomOf="@+id/ownerName" + app:layout_constraintStart_toEndOf="@id/ownerName" + app:layout_constraintTop_toTopOf="@id/ownerName" + tools:ignore="ContentDescription" + tools:src="@drawable/contact_offline"/> + + <Switch + android:id="@+id/btToggle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:text="@string/transport_bt" + app:layout_constraintTop_toBottomOf="@id/ownerText"/> + + <Switch + android:id="@+id/wifiToggle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:text="@string/transport_lan" + app:layout_constraintTop_toBottomOf="@id/btToggle"/> + + <Switch + android:id="@+id/torToggle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:text="@string/transport_tor" + app:layout_constraintTop_toBottomOf="@id/wifiToggle"/> + +</android.support.constraint.ConstraintLayout> diff --git a/mailbox-android/src/main/res/layout/fragment_reblog.xml b/mailbox-android/src/main/res/layout/fragment_reblog.xml new file mode 100644 index 0000000000000000000000000000000000000000..c7d2da8360ff15e93baaf7264adc08736e420449 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_reblog.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + 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" + android:orientation="vertical"> + + <ScrollView + android:id="@+id/scrollView" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <include + android:id="@+id/postLayout" + layout="@layout/list_item_blog_post" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_small"/> + + <ProgressBar + android:id="@+id/progressBar" + style="?android:attr/progressBarStyleLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerInParent="true"/> + + </RelativeLayout> + + </ScrollView> + + <org.briarproject.mailbox.android.view.LargeTextInputView + android:id="@+id/inputText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="bottom" + app:buttonText="@string/blogs_reblog_button" + app:hint="@string/blogs_reblog_comment_hint" + app:maxLines="5"/> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/fragment_setup_author_name.xml b/mailbox-android/src/main/res/layout/fragment_setup_author_name.xml new file mode 100644 index 0000000000000000000000000000000000000000..51f81a40a53c4b84372064a7debcce5b67174d74 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_setup_author_name.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fillViewport="true"> + + <android.support.constraint.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="@dimen/margin_activity_vertical" + android:paddingEnd="@dimen/margin_activity_horizontal" + android:paddingLeft="@dimen/margin_activity_horizontal" + android:paddingRight="@dimen/margin_activity_horizontal" + android:paddingStart="@dimen/margin_activity_horizontal" + android:paddingTop="@dimen/margin_activity_vertical"> + + <android.support.design.widget.TextInputLayout + android:id="@+id/nickname_entry_wrapper" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_medium" + app:errorEnabled="true" + app:hintEnabled="false" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/nickname_entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/choose_nickname" + android:imeOptions="actionNext" + android:inputType="text|textCapWords" + android:maxLines="1"/> + + <requestFocus/> + </android.support.design.widget.TextInputLayout> + + <Button + android:id="@+id/next" + style="@style/BriarButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_activity_horizontal" + android:enabled="false" + android:text="@string/setup_next" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@+id/nickname_entry_wrapper" + app:layout_constraintVertical_bias="1.0" + tools:enabled="true"/> + + </android.support.constraint.ConstraintLayout> + +</ScrollView> diff --git a/mailbox-android/src/main/res/layout/fragment_setup_doze.xml b/mailbox-android/src/main/res/layout/fragment_setup_doze.xml new file mode 100644 index 0000000000000000000000000000000000000000..19f1a02af4b69dd883e74a0b9c4fd79cc508bc9a --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_setup_doze.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fillViewport="true"> + + <android.support.constraint.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="@dimen/margin_activity_vertical" + android:paddingEnd="@dimen/margin_activity_horizontal" + android:paddingLeft="@dimen/margin_activity_horizontal" + android:paddingRight="@dimen/margin_activity_horizontal" + android:paddingStart="@dimen/margin_activity_horizontal" + android:paddingTop="@dimen/margin_activity_vertical"> + + <org.briarproject.mailbox.android.login.DozeView + android:id="@+id/dozeView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"/> + + <org.briarproject.mailbox.android.login.HuaweiView + android:id="@+id/huaweiView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@+id/dozeView"/> + + <Button + android:id="@+id/next" + style="@style/BriarButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:enabled="false" + android:text="@string/create_account_button" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@+id/huaweiView" + app:layout_constraintVertical_bias="1.0" + tools:enabled="true"/> + + <ProgressBar + android:id="@+id/progress" + style="?android:attr/progressBarStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:visibility="invisible" + app:layout_constraintBottom_toBottomOf="@+id/next" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="@+id/next"/> + + </android.support.constraint.ConstraintLayout> + +</ScrollView> diff --git a/mailbox-android/src/main/res/layout/fragment_setup_password.xml b/mailbox-android/src/main/res/layout/fragment_setup_password.xml new file mode 100644 index 0000000000000000000000000000000000000000..51d78098b52f08b426c78186f46185b2d0014099 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_setup_password.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fillViewport="true"> + + <android.support.constraint.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="@dimen/margin_activity_vertical" + android:paddingEnd="@dimen/margin_activity_horizontal" + android:paddingLeft="@dimen/margin_activity_horizontal" + android:paddingRight="@dimen/margin_activity_horizontal" + android:paddingStart="@dimen/margin_activity_horizontal" + android:paddingTop="@dimen/margin_activity_vertical"> + + <android.support.design.widget.TextInputLayout + android:id="@+id/password_entry_wrapper" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + app:errorEnabled="true" + app:hintEnabled="false" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:passwordToggleEnabled="true"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/password_entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/choose_password" + android:imeOptions="actionNext" + android:inputType="textPassword" + android:maxLines="1"> + + <requestFocus/> + </android.support.design.widget.TextInputEditText> + + </android.support.design.widget.TextInputLayout> + + <org.briarproject.mailbox.android.login.StrengthMeter + android:id="@+id/strength_meter" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:visibility="invisible" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@+id/password_entry_wrapper" + tools:visibility="visible"/> + + <android.support.design.widget.TextInputLayout + android:id="@+id/password_confirm_wrapper" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + app:errorEnabled="true" + app:hintEnabled="false" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@+id/strength_meter" + app:passwordToggleEnabled="true"> + + <android.support.design.widget.TextInputEditText + android:id="@+id/password_confirm" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/confirm_password" + android:inputType="textPassword" + android:maxLines="1"/> + </android.support.design.widget.TextInputLayout> + + <Button + android:id="@+id/next" + style="@style/BriarButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:enabled="false" + android:text="@string/setup_next" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@+id/password_confirm_wrapper" + app:layout_constraintVertical_bias="1.0" + tools:enabled="true"/> + + <ProgressBar + android:id="@+id/progress" + style="?android:attr/progressBarStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:visibility="invisible" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@+id/password_confirm_wrapper" + app:layout_constraintVertical_bias="1.0"/> + + </android.support.constraint.ConstraintLayout> + +</ScrollView> diff --git a/mailbox-android/src/main/res/layout/fragment_sign_out.xml b/mailbox-android/src/main/res/layout/fragment_sign_out.xml new file mode 100644 index 0000000000000000000000000000000000000000..73fd8f4e535d5dbef40998790205cd2659703a30 --- /dev/null +++ b/mailbox-android/src/main/res/layout/fragment_sign_out.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.constraint.ConstraintLayout + 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"> + + <ImageView + android:id="@+id/imageView" + android:layout_width="128dp" + android:layout_height="128dp" + android:scaleType="center" + android:src="@drawable/startup_lock" + android:tint="@color/briar_primary" + app:layout_constraintBottom_toTopOf="@+id/textView" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.5" + app:layout_constraintVertical_chainStyle="packed" + tools:ignore="ContentDescription"/> + + <ProgressBar + android:id="@+id/progressBar" + style="?android:attr/progressBarStyleLarge" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintBottom_toBottomOf="@+id/imageView" + app:layout_constraintEnd_toEndOf="@+id/imageView" + app:layout_constraintStart_toStartOf="@+id/imageView" + app:layout_constraintTop_toTopOf="@+id/imageView"/> + + <TextView + android:id="@+id/textView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:text="@string/progress_title_logout" + android:textSize="@dimen/text_size_large" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/imageView"/> + +</android.support.constraint.ConstraintLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/introduction_message.xml b/mailbox-android/src/main/res/layout/introduction_message.xml new file mode 100644 index 0000000000000000000000000000000000000000..d955aa6a5e15c5704f07d7b5d4fed4e853826e3c --- /dev/null +++ b/mailbox-android/src/main/res/layout/introduction_message.xml @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_activity_horizontal" + android:gravity="center" + android:orientation="horizontal"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="top|center_horizontal" + android:orientation="vertical"> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/avatarContact1" + style="@style/BriarAvatar" + android:layout_width="@dimen/listitem_picture_size" + android:layout_height="@dimen/listitem_picture_size" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + tools:src="@mipmap/ic_launcher_round"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/nameContact1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_small" + android:gravity="center" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_small" + tools:text="Contact 1"/> + + </LinearLayout> + + <android.support.v7.widget.AppCompatImageView + android:id="@+id/introductionIcon" + android:layout_width="@dimen/listitem_picture_size" + android:layout_height="@dimen/listitem_picture_size" + android:src="@drawable/ic_contact_introduction" + app:tint="?attr/colorControlNormal" + tools:ignore="ContentDescription"/> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="top|center_horizontal" + android:orientation="vertical"> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/avatarContact2" + style="@style/BriarAvatar" + android:layout_width="@dimen/listitem_picture_size" + android:layout_height="@dimen/listitem_picture_size" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + tools:src="@mipmap/ic_launcher_round"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/nameContact2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_small" + android:gravity="center" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_small" + tools:text="Contact 2"/> + + </LinearLayout> + + </LinearLayout> + + <ProgressBar + android:id="@+id/progressBar" + style="?android:attr/progressBarStyleLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + tools:visibility="gone"/> + + <TextView + android:id="@+id/introductionNotPossibleView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_activity_horizontal" + android:text="@string/introduction_not_possible" + android:textSize="@dimen/text_size_large" + android:visibility="gone" + tools:visibility="visible"/> + + <org.briarproject.mailbox.android.view.LargeTextInputView + android:id="@+id/introductionMessageView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="gone" + app:buttonText="@string/introduction_button" + app:hint="@string/introduction_message_hint" + app:maxLines="5" + tools:visibility="visible"/> + + </LinearLayout> +</ScrollView> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/list.xml b/mailbox-android/src/main/res/layout/list.xml new file mode 100644 index 0000000000000000000000000000000000000000..72672f02d65a74b13d4d117d81197610511a81bf --- /dev/null +++ b/mailbox-android/src/main/res/layout/list.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<org.briarproject.mailbox.android.view.BriarRecyclerView + android:id="@+id/list" + 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" + app:scrollToEnd="false"/> diff --git a/mailbox-android/src/main/res/layout/list_item_blog_comment.xml b/mailbox-android/src/main/res/layout/list_item_blog_comment.xml new file mode 100644 index 0000000000000000000000000000000000000000..e2f3204af72204bf19b7395e9c82bd7d25119f51 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_blog_comment.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:showIn="@layout/list_item_blog_post"> + + <View + android:id="@+id/inputDivider" + style="@style/Divider.Horizontal"/> + + <org.briarproject.mailbox.android.view.AuthorView + android:id="@+id/authorView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:padding="@dimen/listitem_vertical_margin" + app:persona="commenter"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/bodyView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/authorView" + android:paddingBottom="@dimen/listitem_vertical_margin" + android:paddingLeft="@dimen/listitem_vertical_margin" + android:paddingRight="@dimen/listitem_vertical_margin" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="This is a comment that appears below a blog post. Usually, it is expected to be rather short. Not much longer than this one."/> + +</RelativeLayout> diff --git a/mailbox-android/src/main/res/layout/list_item_blog_post.xml b/mailbox-android/src/main/res/layout/list_item_blog_post.xml new file mode 100644 index 0000000000000000000000000000000000000000..a41e9366754de1ffb4a4ecdd62a81d7d8d9d07a0 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_blog_post.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.v7.widget.CardView + android:id="@+id/postLayout" + style="@style/BriarCard" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:foreground="?attr/selectableItemBackground"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="@dimen/listitem_vertical_margin"> + + <org.briarproject.mailbox.android.view.AuthorView + android:id="@+id/rebloggerView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:layout_marginBottom="@dimen/listitem_horizontal_margin" + android:layout_toLeftOf="@+id/commentView" + app:persona="reblogger"/> + + <org.briarproject.mailbox.android.view.AuthorView + android:id="@+id/authorView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_below="@+id/rebloggerView" + android:layout_marginBottom="@dimen/listitem_vertical_margin" + android:layout_toLeftOf="@+id/commentView"/> + + <android.support.v7.widget.AppCompatImageButton + android:id="@+id/commentView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentRight="true" + android:layout_alignParentTop="true" + android:background="?attr/selectableItemBackground" + android:contentDescription="@string/blogs_reblog_comment_hint" + android:padding="@dimen/margin_small" + android:src="@drawable/ic_repeat" + app:tint="?attr/colorControlNormal"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/bodyView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/authorView" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_medium" + tools:text="This is a body text that shows the content of a blog post.\n\nThis one is not short, but it is also not too long."/> + + </RelativeLayout> + + <LinearLayout + android:id="@+id/commentContainer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <include + layout="@layout/list_item_blog_comment" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + + </LinearLayout> + + </LinearLayout> + +</android.support.v7.widget.CardView> diff --git a/mailbox-android/src/main/res/layout/list_item_contact.xml b/mailbox-android/src/main/res/layout/list_item_contact.xml new file mode 100644 index 0000000000000000000000000000000000000000..bac38bf1869ce80e16b20a8e0db892a74e030630 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_contact.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground" + android:clickable="true" + android:focusable="true" + android:orientation="vertical"> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="@dimen/listitem_horizontal_margin" + android:paddingTop="@dimen/listitem_horizontal_margin"> + + <FrameLayout + android:id="@+id/avatarFrameView" + android:layout_width="@dimen/listitem_picture_frame_size" + android:layout_height="@dimen/listitem_picture_frame_size" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin"> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/avatarView" + style="@style/BriarAvatar" + android:layout_width="@dimen/listitem_picture_size" + android:layout_height="@dimen/listitem_picture_size" + android:layout_gravity="bottom|left" + tools:src="@mipmap/ic_launcher_round"/> + + <TextView + android:id="@+id/unreadCountView" + android:layout_width="wrap_content" + android:layout_height="@dimen/unread_bubble_size" + android:layout_gravity="right|top" + android:background="@drawable/bubble" + android:gravity="center" + android:minWidth="@dimen/unread_bubble_size" + android:textColor="@color/briar_text_primary_inverse" + android:textSize="@dimen/unread_bubble_text_size" + android:textStyle="bold" + tools:text="123"/> + + </FrameLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + android:layout_toEndOf="@+id/avatarFrameView" + android:layout_toLeftOf="@+id/bulbView" + android:layout_toRightOf="@+id/avatarFrameView" + android:orientation="vertical"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/nameView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:maxLines="2" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_medium" + tools:text="This is a name of a contact"/> + + <TextView + android:id="@+id/dateView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="Dec 24"/> + + </LinearLayout> + + <ImageView + android:id="@+id/bulbView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_centerVertical="true" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + tools:src="@drawable/contact_connected"/> + + </RelativeLayout> + + <View style="@style/Divider.ContactList"/> + +</LinearLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/list_item_contact_small.xml b/mailbox-android/src/main/res/layout/list_item_contact_small.xml new file mode 100644 index 0000000000000000000000000000000000000000..01bfc431aa659737eef3dfc18e1bd1e78f065e87 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_contact_small.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingBottom="@dimen/margin_medium" + android:paddingTop="@dimen/margin_medium"> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/avatarView" + style="@style/BriarAvatar" + android:layout_width="@dimen/listitem_picture_size_small" + android:layout_height="@dimen/listitem_picture_size_small" + android:layout_gravity="center_vertical" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + tools:src="@mipmap/ic_launcher_round"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/nameView" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginLeft="@dimen/margin_medium" + android:layout_marginStart="@dimen/margin_medium" + android:layout_weight="1" + android:maxLines="2" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_medium" + tools:text="This is a name of a contact"/> + + <ImageView + android:id="@+id/bulbView" + android:layout_width="@dimen/listitem_horizontal_margin" + android:layout_height="@dimen/listitem_horizontal_margin" + android:layout_gravity="center_vertical" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + tools:src="@drawable/contact_connected"/> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/list_item_conversation_msg_in.xml b/mailbox-android/src/main/res/layout/list_item_conversation_msg_in.xml new file mode 100644 index 0000000000000000000000000000000000000000..d2c83738cde78227ce0197994a3ddd0b76d3a313 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_conversation_msg_in.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + android:id="@+id/layout" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/message_bubble_margin" + android:layout_marginLeft="@dimen/message_bubble_margin_tail" + android:layout_marginRight="@dimen/message_bubble_margin_non_tail" + android:layout_marginTop="@dimen/message_bubble_margin" + android:background="@drawable/msg_in" + android:elevation="@dimen/message_bubble_elevation" + android:orientation="vertical"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/text" + style="@style/TextMessage" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="?android:attr/textColorPrimary" + tools:text="Short message"/> + + <TextView + android:id="@+id/time" + style="@style/TextMessage.Timestamp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right|end" + android:layout_marginTop="@dimen/message_bubble_timestamp_margin" + tools:text="Dec 24, 13:37"/> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/list_item_conversation_msg_out.xml b/mailbox-android/src/main/res/layout/list_item_conversation_msg_out.xml new file mode 100644 index 0000000000000000000000000000000000000000..58f9ad862d42678558ae07ef5443fd27820c2343 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_conversation_msg_out.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <RelativeLayout + android:id="@+id/layout" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right|end" + android:layout_marginBottom="@dimen/message_bubble_margin" + android:layout_marginLeft="@dimen/message_bubble_margin_non_tail" + android:layout_marginRight="@dimen/message_bubble_margin_tail" + android:layout_marginTop="@dimen/message_bubble_margin" + android:background="@drawable/msg_out" + android:elevation="@dimen/message_bubble_elevation"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/text" + style="@style/TextMessage" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="@color/briar_text_primary_inverse" + tools:text="This is a long long long message that spans over several lines.\n\nIt ends here."/> + + <TextView + android:id="@+id/time" + style="@style/TextMessage.Timestamp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_below="@+id/text" + android:layout_marginTop="@dimen/message_bubble_timestamp_margin" + android:textColor="@color/private_message_date_inverse" + tools:text="Dec 24, 13:37"/> + + <ImageView + android:id="@+id/status" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/time" + android:layout_marginLeft="@dimen/margin_medium" + android:layout_toEndOf="@+id/time" + android:layout_toRightOf="@+id/time" + tools:ignore="ContentDescription" + tools:src="@drawable/message_delivered_white"/> + + </RelativeLayout> + +</LinearLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/list_item_conversation_notice_in.xml b/mailbox-android/src/main/res/layout/list_item_conversation_notice_in.xml new file mode 100644 index 0000000000000000000000000000000000000000..c504e9704235eebfa2922cb0c84f73b7f35d45a5 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_conversation_notice_in.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/message_bubble_margin" + android:orientation="vertical"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/msgText" + style="@style/TextMessage" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="left|start" + android:layout_marginLeft="@dimen/message_bubble_margin_tail" + android:layout_marginRight="@dimen/message_bubble_margin_non_tail" + android:background="@drawable/msg_in_top" + android:elevation="@dimen/message_bubble_elevation" + tools:text="Short message"/> + + <RelativeLayout + android:id="@+id/layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/message_bubble_margin" + android:layout_marginLeft="@dimen/message_bubble_margin_tail" + android:layout_marginRight="@dimen/message_bubble_margin_non_tail" + android:background="@drawable/notice_in_bottom" + android:elevation="@dimen/message_bubble_elevation"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/text" + style="@style/TextMessage.Notice" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minWidth="80dp" + tools:text="@string/forum_invitation_received"/> + + <TextView + android:id="@+id/time" + style="@style/TextMessage.Timestamp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignEnd="@+id/text" + android:layout_alignRight="@+id/text" + android:layout_below="@+id/text" + android:layout_marginTop="@dimen/message_bubble_timestamp_margin" + tools:text="Dec 24, 13:37"/> + + </RelativeLayout> + +</LinearLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/list_item_conversation_notice_out.xml b/mailbox-android/src/main/res/layout/list_item_conversation_notice_out.xml new file mode 100644 index 0000000000000000000000000000000000000000..50e369a77ca209196b75ff67520b4cef7e083ff9 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_conversation_notice_out.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/message_bubble_margin" + android:orientation="vertical"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/msgText" + style="@style/TextMessage" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/message_bubble_margin_non_tail" + android:layout_marginRight="@dimen/message_bubble_margin_tail" + android:background="@drawable/msg_out_top" + android:elevation="@dimen/message_bubble_elevation" + android:textColor="@color/briar_text_primary_inverse" + tools:text="This is a long long long message that spans over several lines.\n\nIt ends here."/> + + <RelativeLayout + android:id="@+id/layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/message_bubble_margin" + android:layout_marginLeft="@dimen/message_bubble_margin_non_tail" + android:layout_marginRight="@dimen/message_bubble_margin_tail" + android:background="@drawable/notice_out_bottom" + android:elevation="@dimen/message_bubble_elevation"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/text" + style="@style/TextMessage.Notice" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textColor="@color/private_message_date_inverse" + tools:text="@string/introduction_request_received"/> + + <TextView + android:id="@+id/time" + style="@style/TextMessage.Timestamp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_below="@+id/text" + android:layout_marginTop="@dimen/message_bubble_timestamp_margin" + android:textColor="@color/private_message_date_inverse" + tools:text="Dec 24, 13:37"/> + + <android.support.v7.widget.AppCompatImageView + android:id="@+id/status" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/time" + android:layout_marginLeft="@dimen/margin_medium" + android:layout_toEndOf="@+id/time" + android:layout_toRightOf="@+id/time" + app:tint="@color/private_message_date_inverse" + tools:ignore="ContentDescription" + tools:src="@drawable/message_delivered"/> + + </RelativeLayout> + +</LinearLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/list_item_conversation_request.xml b/mailbox-android/src/main/res/layout/list_item_conversation_request.xml new file mode 100644 index 0000000000000000000000000000000000000000..16c1f8649d9124536fb0a3d545eaaef83c282580 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_conversation_request.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/message_bubble_margin" + android:orientation="vertical"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/msgText" + style="@style/TextMessage" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/message_bubble_margin_tail" + android:layout_marginRight="@dimen/message_bubble_margin_non_tail" + android:background="@drawable/msg_in_top" + android:elevation="@dimen/message_bubble_elevation" + android:textColor="?android:attr/textColorPrimary" + tools:text="Short message"/> + + <RelativeLayout + android:id="@+id/layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/message_bubble_margin" + android:layout_marginLeft="@dimen/message_bubble_margin_tail" + android:layout_marginRight="@dimen/message_bubble_margin_non_tail" + android:background="@drawable/notice_in_bottom" + android:elevation="@dimen/message_bubble_elevation"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/text" + style="@style/TextMessage.Notice" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:text="@string/introduction_request_received"/> + + <TextView + android:id="@+id/time" + style="@style/TextMessage.Timestamp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignEnd="@+id/text" + android:layout_alignRight="@+id/text" + android:layout_below="@+id/acceptButton" + android:layout_marginTop="@dimen/message_bubble_timestamp_margin" + tools:text="Dec 24, 13:37"/> + + <Button + android:id="@+id/acceptButton" + style="@style/BriarButtonFlat.Positive" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignEnd="@+id/text" + android:layout_alignRight="@+id/text" + android:layout_below="@+id/text" + android:layout_marginBottom="-10dp" + android:text="@string/accept"/> + + <Button + android:id="@+id/declineButton" + style="@style/BriarButtonFlat.Negative" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/acceptButton" + android:layout_alignTop="@+id/acceptButton" + android:layout_toLeftOf="@+id/acceptButton" + android:layout_toStartOf="@+id/acceptButton" + android:text="@string/decline"/> + + </RelativeLayout> + +</LinearLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/list_item_crash.xml b/mailbox-android/src/main/res/layout/list_item_crash.xml new file mode 100644 index 0000000000000000000000000000000000000000..63439eddb09a90a94a222471f0d0c1cf1c008481 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_crash.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <CheckBox + android:id="@+id/include_in_report" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_marginBottom="@dimen/margin_small" + android:gravity="bottom" + android:textSize="@dimen/text_size_large" + android:textColor="?android:attr/textColorPrimary" + tools:text="Crash log entry title"/> + </LinearLayout> + + <TextView + android:id="@+id/content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/margin_medium" + android:textColor="?android:attr/textColorSecondary" + tools:text="Crash log entry value"/> + +</LinearLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/list_item_forum.xml b/mailbox-android/src/main/res/layout/list_item_forum.xml new file mode 100644 index 0000000000000000000000000000000000000000..308eb2defaea95ff5ddcd308e384dcf356b7e9e8 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_forum.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground" + android:paddingLeft="@dimen/listitem_horizontal_margin" + android:paddingStart="@dimen/listitem_horizontal_margin" + tools:ignore="RtlSymmetry"> + + <org.briarproject.mailbox.android.view.TextAvatarView + android:id="@+id/avatarView" + android:layout_width="@dimen/listitem_picture_frame_size" + android:layout_height="@dimen/listitem_picture_frame_size" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:layout_marginTop="@dimen/listitem_horizontal_margin"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/forumNameView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_marginTop="@dimen/listitem_horizontal_margin" + android:layout_toEndOf="@+id/avatarView" + android:layout_toRightOf="@+id/avatarView" + android:maxLines="2" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_medium" + tools:text="This is a name of a forum"/> + + <TextView + android:id="@+id/postCountView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/forumNameView" + android:layout_toEndOf="@+id/avatarView" + android:layout_toRightOf="@+id/avatarView" + android:paddingBottom="@dimen/listitem_horizontal_margin" + android:paddingTop="@dimen/margin_medium" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="1337 posts"/> + + <TextView + android:id="@+id/dateView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_below="@+id/forumNameView" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:paddingBottom="@dimen/listitem_horizontal_margin" + android:paddingTop="@dimen/margin_medium" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="Dec 24"/> + + <View + style="@style/Divider.ThreadItem" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_below="@+id/postCountView"/> + +</RelativeLayout> + diff --git a/mailbox-android/src/main/res/layout/list_item_group.xml b/mailbox-android/src/main/res/layout/list_item_group.xml new file mode 100644 index 0000000000000000000000000000000000000000..fd0828391db7ea635efdc7355aaf6a05f9922a2b --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_group.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground" + android:paddingLeft="@dimen/listitem_horizontal_margin" + android:paddingStart="@dimen/listitem_horizontal_margin" + tools:ignore="RtlSymmetry"> + + <org.briarproject.mailbox.android.view.TextAvatarView + android:id="@+id/avatarView" + android:layout_width="@dimen/listitem_picture_frame_size" + android:layout_height="@dimen/listitem_picture_frame_size" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:layout_marginTop="@dimen/listitem_horizontal_margin"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/nameView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_marginTop="@dimen/listitem_horizontal_margin" + android:layout_toEndOf="@+id/avatarView" + android:layout_toRightOf="@+id/avatarView" + android:maxLines="2" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_medium" + tools:text="This is a name of a Private Group"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/creatorView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/nameView" + android:layout_marginBottom="@dimen/margin_small" + android:layout_toEndOf="@+id/avatarView" + android:layout_toRightOf="@+id/avatarView" + android:paddingTop="@dimen/margin_small" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="Created by Santa Claus"/> + + <TextView + android:id="@+id/messageCountView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/creatorView" + android:layout_marginBottom="@dimen/margin_small" + android:layout_toEndOf="@+id/avatarView" + android:layout_toRightOf="@+id/avatarView" + android:paddingTop="@dimen/margin_small" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="1337 messages" + tools:visibility="visible"/> + + <TextView + android:id="@+id/dateView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_below="@+id/creatorView" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:paddingTop="@dimen/margin_small" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="3 weeks ago, 12:00" + tools:visibility="visible"/> + + <TextView + android:id="@+id/statusView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/messageCountView" + android:layout_toEndOf="@+id/avatarView" + android:layout_toLeftOf="@+id/removeButton" + android:layout_toRightOf="@+id/avatarView" + android:paddingTop="@dimen/margin_small" + android:textColor="?android:attr/textColorTertiary" + tools:text="@string/groups_group_is_empty"/> + + <Button + android:id="@+id/removeButton" + style="@style/BriarButtonFlat.Negative" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/divider" + android:layout_alignParentRight="true" + android:text="@string/groups_remove" + tools:visibility="gone"/> + + <View + android:id="@+id/divider" + style="@style/Divider.ThreadItem" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_below="@+id/statusView" + android:layout_marginTop="@dimen/listitem_horizontal_margin"/> + +</RelativeLayout> + diff --git a/mailbox-android/src/main/res/layout/list_item_group_join_notice.xml b/mailbox-android/src/main/res/layout/list_item_group_join_notice.xml new file mode 100644 index 0000000000000000000000000000000000000000..302033e943361f0d2b977f800111617e2c01940e --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_group_join_notice.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout + android:id="@+id/layout" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:baselineAligned="false" + android:orientation="vertical"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_medium" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_medium" + android:textStyle="italic" + tools:text="@string/groups_member_joined"/> + + <org.briarproject.mailbox.android.view.AuthorView + android:id="@+id/author" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignLeft="@+id/text" + android:layout_alignStart="@+id/text" + android:layout_below="@+id/text" + app:persona="commenter"/> + + <View + style="@style/Divider.ThreadItem" + android:layout_below="@+id/author" + android:layout_marginTop="@dimen/margin_medium"/> + +</RelativeLayout> diff --git a/mailbox-android/src/main/res/layout/list_item_group_member.xml b/mailbox-android/src/main/res/layout/list_item_group_member.xml new file mode 100644 index 0000000000000000000000000000000000000000..4e2b17ce993ceaf37e2f8b94a5c0313dfd6dc1cf --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_group_member.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + android:paddingTop="@dimen/margin_medium"> + + <org.briarproject.mailbox.android.view.AuthorView + android:id="@+id/authorView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentStart="true" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:layout_marginBottom="@dimen/margin_small" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:layout_toStartOf="@+id/bulbView" + android:layout_toLeftOf="@+id/bulbView" + app:persona="list"/> + + <ImageView + android:id="@+id/bulbView" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_alignBottom="@+id/authorView" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_alignTop="@+id/authorView" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + tools:src="@drawable/contact_connected"/> + + <TextView + android:id="@+id/creatorView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/authorView" + android:layout_marginBottom="@dimen/margin_small" + android:layout_marginLeft="@dimen/listitem_group_member_indentation" + android:layout_marginStart="@dimen/listitem_group_member_indentation" + android:text="@string/groups_member_created_you" + android:textColor="?android:attr/textColorSecondary" + tools:visibility="visible"/> + + <View + android:id="@+id/divider" + style="@style/Divider.ContactList" + android:layout_below="@+id/creatorView" + android:layout_marginStart="@dimen/listitem_group_member_indentation" + android:layout_marginLeft="@dimen/listitem_group_member_indentation" + android:layout_marginTop="@dimen/margin_medium"/> + +</RelativeLayout> diff --git a/mailbox-android/src/main/res/layout/list_item_invitations.xml b/mailbox-android/src/main/res/layout/list_item_invitations.xml new file mode 100644 index 0000000000000000000000000000000000000000..368b4c418b20db01cd5da8f87adc15c0e2335912 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_invitations.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + android:background="?attr/selectableItemBackground" + android:paddingTop="@dimen/listitem_horizontal_margin"> + + <org.briarproject.mailbox.android.view.TextAvatarView + android:id="@+id/avatarView" + android:layout_width="@dimen/listitem_picture_frame_size" + android:layout_height="@dimen/listitem_picture_frame_size" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_marginRight="@dimen/listitem_horizontal_margin"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/forumNameView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:layout_toEndOf="@+id/avatarView" + android:layout_toRightOf="@+id/avatarView" + android:maxLines="2" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_medium" + tools:text="This is a name of a forum that is available"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/sharedByView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/forumNameView" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:layout_toEndOf="@+id/avatarView" + android:layout_toRightOf="@+id/avatarView" + android:paddingTop="@dimen/margin_medium" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="Shared by Megalox"/> + + <TextView + android:id="@+id/forumSubscribedView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/sharedByView" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:paddingTop="@dimen/margin_medium" + android:text="@string/forum_invitation_exists" + android:textColor="?android:attr/textColorTertiary" + android:textSize="@dimen/text_size_small" + tools:visibility="visible"/> + + <Button + android:id="@+id/acceptButton" + style="@style/BriarButtonFlat.Positive" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_below="@+id/forumSubscribedView" + android:layout_marginTop="-8dp" + android:text="@string/accept"/> + + <Button + android:id="@+id/declineButton" + style="@style/BriarButtonFlat.Negative" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/forumSubscribedView" + android:layout_marginTop="-8dp" + android:layout_toLeftOf="@+id/acceptButton" + android:layout_toStartOf="@+id/acceptButton" + android:text="@string/decline"/> + + <View + style="@style/Divider.ThreadItem" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_below="@+id/acceptButton"/> + +</RelativeLayout> + diff --git a/mailbox-android/src/main/res/layout/list_item_revealable_contact.xml b/mailbox-android/src/main/res/layout/list_item_revealable_contact.xml new file mode 100644 index 0000000000000000000000000000000000000000..3b43ad49e50d6a42adbccdea79fec2ed827f38be --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_revealable_contact.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground" + android:orientation="vertical" + android:padding="@dimen/listitem_horizontal_margin"> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/avatarView" + style="@style/BriarAvatar" + android:layout_width="@dimen/listitem_selectable_picture_size" + android:layout_height="@dimen/listitem_selectable_picture_size" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + tools:src="@mipmap/ic_launcher_round"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/nameView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toRightOf="@+id/avatarView" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_large" + tools:text="Revealable Contact"/> + + <android.support.v7.widget.AppCompatImageView + android:id="@+id/visibilityView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/nameView" + android:layout_marginRight="@dimen/margin_small" + android:layout_toRightOf="@+id/avatarView" + android:src="@drawable/ic_visibility" + app:tint="?attr/colorControlNormal" + tools:ignore="ContentDescription"/> + + <TextView + android:id="@+id/infoView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/nameView" + android:layout_toLeftOf="@+id/checkBox" + android:layout_toRightOf="@+id/visibilityView" + android:gravity="center_vertical" + android:text="@string/groups_reveal_visible" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:visibility="visible"/> + + <CheckBox + android:id="@+id/checkBox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_centerVertical="true" + android:clickable="false"/> + + </RelativeLayout> + + <View style="@style/Divider.ContactList"/> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/list_item_rss_feed.xml b/mailbox-android/src/main/res/layout/list_item_rss_feed.xml new file mode 100644 index 0000000000000000000000000000000000000000..3bc3d3aea96333cfbcc0869f2a519d06186ffc99 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_rss_feed.xml @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + android:layout_marginTop="@dimen/listitem_horizontal_margin" + android:background="?attr/selectableItemBackground"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/titleView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:maxLines="2" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_medium" + tools:text="This is a name of a RSS Feed"/> + + <android.support.v7.widget.AppCompatImageButton + android:id="@+id/deleteButton" + android:layout_width="@dimen/button_size" + android:layout_height="@dimen/button_size" + android:layout_alignParentRight="true" + android:layout_alignParentTop="true" + android:background="?attr/selectableItemBackground" + android:contentDescription="@string/delete" + android:src="@drawable/action_delete_black" + app:tint="?attr/colorControlNormal"/> + + <TextView + android:id="@+id/author" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/titleView" + android:layout_marginRight="@dimen/margin_small" + android:paddingTop="@dimen/margin_tiny" + android:text="@string/blogs_rss_feeds_manage_author" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/authorView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/author" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:layout_toRightOf="@+id/author" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="Bruce Schneier"/> + + <TextView + android:id="@+id/imported" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/author" + android:layout_marginRight="@dimen/margin_small" + android:paddingTop="@dimen/margin_tiny" + android:text="@string/blogs_rss_feeds_manage_imported" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small"/> + + <TextView + android:id="@+id/importedView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/imported" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:layout_toRightOf="@+id/imported" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="July 4"/> + + <TextView + android:id="@+id/updated" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/imported" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/margin_small" + android:paddingTop="@dimen/margin_tiny" + android:text="@string/blogs_rss_feeds_manage_updated" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small"/> + + <TextView + android:id="@+id/updatedView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/updated" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:layout_toRightOf="@+id/updated" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="5 min. ago"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/descriptionView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/updated" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:paddingTop="@dimen/margin_medium" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small" + tools:text="This is a description of the RSS feed. It can be several lines long, but it can also not exist at all if it is not present in the feed itself."/> + + <View + style="@style/Divider.ThreadItem" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_below="@+id/descriptionView" + android:layout_marginTop="@dimen/listitem_horizontal_margin"/> + +</RelativeLayout> + diff --git a/mailbox-android/src/main/res/layout/list_item_selectable_contact.xml b/mailbox-android/src/main/res/layout/list_item_selectable_contact.xml new file mode 100644 index 0000000000000000000000000000000000000000..df31c253d1dc2da5ac1f3359782a33a59dbfedeb --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_selectable_contact.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground" + android:padding="@dimen/listitem_horizontal_margin"> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/avatarView" + style="@style/BriarAvatar" + android:layout_width="@dimen/listitem_selectable_picture_size" + android:layout_height="@dimen/listitem_selectable_picture_size" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + tools:src="@mipmap/ic_launcher_round"/> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + android:layout_toEndOf="@+id/avatarView" + android:layout_toLeftOf="@+id/checkBox" + android:layout_toRightOf="@+id/avatarView" + android:orientation="vertical"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/nameView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_large" + tools:text="This is a name of a contact with a long name"/> + + <TextView + android:id="@+id/infoView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:maxLines="2" + android:text="@string/forum_invitation_already_sharing" + android:textColor="?android:attr/textColorTertiary" + android:textSize="@dimen/text_size_small" + tools:visibility="visible"/> + + </LinearLayout> + + <CheckBox + android:id="@+id/checkBox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_centerVertical="true" + android:clickable="false"/> + + </RelativeLayout> + + <View style="@style/Divider.ContactList"/> + +</LinearLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/list_item_thread.xml b/mailbox-android/src/main/res/layout/list_item_thread.xml new file mode 100644 index 0000000000000000000000000000000000000000..ffd2fbc2ca3b4381b28d12c612f097de9c504e50 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_thread.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + android:id="@+id/layout" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:baselineAligned="false" + android:background="@drawable/list_item_thread_background" + android:orientation="horizontal"> + + <RelativeLayout + android:layout_width="wrap_content" + android:layout_height="match_parent"> + + <View + android:id="@+id/nested_line_1" + style="@style/DiscussionLevelIndicator" + android:layout_width="@dimen/forum_nested_line_width" + android:layout_height="match_parent" + android:visibility="gone" + tools:visibility="visible"/> + + <View + android:id="@+id/nested_line_2" + style="@style/DiscussionLevelIndicator" + android:layout_width="@dimen/forum_nested_line_width" + android:layout_height="match_parent" + android:layout_toRightOf="@id/nested_line_1" + android:visibility="gone"/> + + <View + android:id="@+id/nested_line_3" + style="@style/DiscussionLevelIndicator" + android:layout_width="@dimen/forum_nested_line_width" + android:layout_height="match_parent" + android:layout_toRightOf="@id/nested_line_2" + android:visibility="gone"/> + + <View + android:id="@+id/nested_line_4" + style="@style/DiscussionLevelIndicator" + android:layout_width="@dimen/forum_nested_line_width" + android:layout_height="match_parent" + android:layout_toRightOf="@id/nested_line_3" + android:visibility="gone"/> + + <View + android:id="@+id/nested_line_5" + style="@style/DiscussionLevelIndicator" + android:layout_width="@dimen/forum_nested_line_width" + android:layout_height="match_parent" + android:layout_toRightOf="@id/nested_line_4" + android:visibility="gone"/> + + <TextView + android:id="@+id/nested_line_text" + android:layout_width="@dimen/forum_nested_indicator" + android:layout_height="@dimen/forum_nested_indicator" + android:layout_centerInParent="true" + android:background="@drawable/level_indicator_circle" + android:gravity="center" + android:textSize="@dimen/text_size_small" + android:visibility="gone"/> + + </RelativeLayout> + + <RelativeLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1"> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="@dimen/margin_medium" + android:textColor="?android:attr/textColorPrimary" + android:textIsSelectable="true" + android:textSize="@dimen/text_size_medium" + tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."/> + + <org.briarproject.mailbox.android.view.AuthorView + android:id="@+id/author" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignLeft="@id/text" + android:layout_below="@id/text" + android:layout_marginLeft="@dimen/margin_medium" + android:layout_toLeftOf="@+id/btn_reply" + app:persona="commenter"/> + + <TextView + android:id="@+id/btn_reply" + style="@style/BriarButtonFlat.Positive.Tiny" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/author" + android:layout_alignParentRight="true" + android:layout_below="@+id/text" + android:layout_marginRight="@dimen/margin_medium" + android:text="@string/btn_reply" + android:textSize="@dimen/text_size_tiny"/> + + <View + style="@style/Divider.ThreadItem" + android:layout_alignLeft="@id/text" + android:layout_below="@+id/author" + android:layout_marginTop="@dimen/margin_medium"/> + + </RelativeLayout> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/list_item_transport.xml b/mailbox-android/src/main/res/layout/list_item_transport.xml new file mode 100644 index 0000000000000000000000000000000000000000..ab796704971fbd47d86f7163cb3a8e5ff81549b3 --- /dev/null +++ b/mailbox-android/src/main/res/layout/list_item_transport.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="@dimen/margin_small" + android:gravity="center_horizontal"> + + <ImageView + android:id="@+id/imageView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="@dimen/margin_small" + tools:src="@drawable/transport_tor"/> + + <TextView + android:id="@+id/textView" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:padding="@dimen/margin_small" + android:textColor="?android:attr/textColorSecondary" + tools:text="@string/transport_tor"/> + +</LinearLayout> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/navigation_header.xml b/mailbox-android/src/main/res/layout/navigation_header.xml new file mode 100644 index 0000000000000000000000000000000000000000..a54b9b6a0f63042b5e0268d7e179cd73c79215ef --- /dev/null +++ b/mailbox-android/src/main/res/layout/navigation_header.xml @@ -0,0 +1,19 @@ +<?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:layout_width="match_parent" + android:layout_height="85dp" + android:background="@color/briar_primary" + tools:showIn="@layout/navigation_menu"> + + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:layout_marginBottom="@dimen/margin_medium" + android:layout_marginLeft="@dimen/margin_medium" + android:contentDescription="@string/app_name" + android:src="@drawable/navigation_drawer_header"/> + +</FrameLayout> diff --git a/mailbox-android/src/main/res/layout/navigation_menu.xml b/mailbox-android/src/main/res/layout/navigation_menu.xml new file mode 100644 index 0000000000000000000000000000000000000000..8a21629148ca1ae486b7a1c01b9e4edecc5866e9 --- /dev/null +++ b/mailbox-android/src/main/res/layout/navigation_menu.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:background="@color/window_background" + android:fillViewport="true" + android:orientation="vertical"> + + <android.support.constraint.ConstraintLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <android.support.design.widget.NavigationView + android:id="@+id/navigation" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@color/window_background" + app:elevation="0dp" + app:headerLayout="@layout/navigation_header" + app:itemBackground="@drawable/navigation_item_background" + app:itemIconTint="?attr/colorControlNormal" + app:itemTextColor="?android:textColorPrimary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:menu="@menu/navigation_drawer"/> + + <View + android:id="@+id/divider1" + style="@style/Divider.Horizontal" + android:layout_width="0dp" + app:layout_constraintEnd_toEndOf="@+id/navigation" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/navigation"/> + + <View + android:id="@+id/spacer" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintBottom_toTopOf="@+id/transports" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/divider1" + app:layout_constraintVertical_weight="1"/> + + <include + android:id="@+id/transports" + layout="@layout/transports_list" + android:layout_width="0dp" + android:layout_height="wrap_content" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@+id/navigation" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/spacer" + tools:layout_height="75dp"/> + + </android.support.constraint.ConstraintLayout> + +</ScrollView> diff --git a/mailbox-android/src/main/res/layout/power_view.xml b/mailbox-android/src/main/res/layout/power_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..2a288c217b088ebb7524d1f5e6bb1adc07ecf27b --- /dev/null +++ b/mailbox-android/src/main/res/layout/power_view.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:parentTag="android.support.constraint.ConstraintLayout"> + + <TextView + android:id="@+id/textView" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:paddingLeft="@dimen/margin_large" + android:paddingRight="@dimen/margin_large" + android:textSize="@dimen/text_size_medium" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="@string/setup_huawei_text"/> + + <android.support.v7.widget.AppCompatImageView + android:id="@+id/checkImage" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_margin="8dp" + android:src="@drawable/ic_check_white" + android:visibility="invisible" + app:layout_constraintBottom_toBottomOf="@+id/button" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@+id/button" + app:tint="?attr/colorControlNormal" + tools:ignore="ContentDescription"/> + + <Button + android:id="@+id/button" + style="@style/BriarButton" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="8dp" + app:layout_constraintEnd_toStartOf="@+id/helpButton" + app:layout_constraintStart_toEndOf="@+id/checkImage" + app:layout_constraintTop_toBottomOf="@+id/textView" + tools:text="@string/setup_huawei_button"/> + + <ImageButton + android:id="@+id/helpButton" + style="@style/BriarButtonFlat.Positive" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_margin="8dp" + android:contentDescription="@string/help" + android:src="@drawable/ic_help_outline_white" + android:tint="@color/briar_button_text_positive" + app:layout_constraintBottom_toBottomOf="@+id/button" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="@+id/button"/> + +</merge> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/preference_switch_compat.xml b/mailbox-android/src/main/res/layout/preference_switch_compat.xml new file mode 100644 index 0000000000000000000000000000000000000000..de1f7c770a32f49951ff6b3bdd3d44e191585fd7 --- /dev/null +++ b/mailbox-android/src/main/res/layout/preference_switch_compat.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Needed for SwitchPreference on Android 4 (API < 21)--> +<android.support.v7.widget.SwitchCompat + android:id="@android:id/switch_widget" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@null" + android:clickable="false" + android:focusable="false" + android:focusableInTouchMode="false" + tools:targetApi="n"/> diff --git a/mailbox-android/src/main/res/layout/preferences_category.xml b/mailbox-android/src/main/res/layout/preferences_category.xml new file mode 100644 index 0000000000000000000000000000000000000000..c323d8dca6b6047db12354ed06cf1b071a2c99d8 --- /dev/null +++ b/mailbox-android/src/main/res/layout/preferences_category.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<TextView + android:id="@android:id/title" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@color/preference_category_background" + android:padding="16dp" + android:textColor="@color/briar_accent" + android:textSize="14sp" + android:textStyle="bold" + tools:text="This is a category"/> \ No newline at end of file diff --git a/mailbox-android/src/main/res/layout/qr_code_view.xml b/mailbox-android/src/main/res/layout/qr_code_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..9062428d0e6b3456b06b1e91a8e952cd3963e44d --- /dev/null +++ b/mailbox-android/src/main/res/layout/qr_code_view.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge + 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" + tools:showIn="@layout/fragment_keyagreement_qr"> + + <ProgressBar + style="?android:attr/progressBarStyleLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center"/> + + <android.support.constraint.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ImageView + android:id="@+id/qr_code" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:contentDescription="@string/qr_code" + android:scaleType="fitCenter"/> + + <ImageView + android:id="@+id/fullscreen_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="@dimen/margin_small" + android:alpha="0.54" + android:background="?selectableItemBackground" + android:contentDescription="@string/show_qr_code_fullscreen" + android:src="@drawable/ic_fullscreen_black_48dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintRight_toRightOf="parent"/> + + </android.support.constraint.ConstraintLayout> +</merge> diff --git a/mailbox-android/src/main/res/layout/splash.xml b/mailbox-android/src/main/res/layout/splash.xml new file mode 100644 index 0000000000000000000000000000000000000000..bab1dc6fb5bbce2da76fbe48bdf4d70c18d6cd91 --- /dev/null +++ b/mailbox-android/src/main/res/layout/splash.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ImageView + android:src="@drawable/splash_screen" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_margin="@dimen/margin_xxlarge" + android:contentDescription="@string/app_name"/> + +</FrameLayout> diff --git a/mailbox-android/src/main/res/layout/text_avatar_view.xml b/mailbox-android/src/main/res/layout/text_avatar_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..215bc510c398fee143a05bb1951f1c48c4f3c119 --- /dev/null +++ b/mailbox-android/src/main/res/layout/text_avatar_view.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + tools:showIn="@layout/list_item_forum"> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/avatarBackground" + style="@style/BriarAvatar" + android:layout_width="@dimen/avatar_forum_size" + android:layout_height="@dimen/avatar_forum_size" + android:layout_gravity="bottom|left" + android:src="@color/briar_button_text_positive"/> + + <android.support.v7.widget.AppCompatTextView + android:id="@+id/textAvatarView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginRight="@dimen/listitem_picture_frame_offset_horizontal" + android:layout_marginTop="@dimen/listitem_picture_frame_offset_vertical" + android:maxLength="1" + android:shadowColor="@color/forum_avatar_shadow" + android:shadowDx="0" + android:shadowDy="1.5" + android:shadowRadius="1.5" + android:textColor="@color/briar_text_primary_inverse" + android:textSize="@dimen/avatar_text_size" + tools:text="T"/> + + <TextView + android:id="@+id/unreadCountView" + android:layout_width="wrap_content" + android:layout_height="@dimen/unread_bubble_size" + android:layout_gravity="right|top" + android:background="@drawable/bubble" + android:gravity="center" + android:minWidth="@dimen/unread_bubble_size" + android:textColor="@color/briar_text_primary_inverse" + android:textSize="@dimen/unread_bubble_text_size" + android:textStyle="bold" + tools:text="12"/> + +</merge> diff --git a/mailbox-android/src/main/res/layout/text_input_view.xml b/mailbox-android/src/main/res/layout/text_input_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..28cef379221ea44a6c7f0e976f8e27a236356df2 --- /dev/null +++ b/mailbox-android/src/main/res/layout/text_input_view.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:showIn="@layout/activity_conversation"> + + <View + style="@style/Divider.Horizontal" + android:layout_alignParentTop="true"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@color/card_background"> + + <org.thoughtcrime.securesms.components.emoji.EmojiToggle + android:id="@+id/emoji_toggle" + android:layout_width="@dimen/text_input_height" + android:layout_height="@dimen/text_input_height" + android:layout_gravity="bottom" + android:background="?attr/selectableItemBackground" + android:padding="@dimen/margin_small" + android:scaleType="center" + app:tint="?attr/colorControlNormal"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiEditText + android:id="@+id/input_text" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:background="@android:color/transparent" + android:inputType="textMultiLine|textCapSentences" + android:maxLines="4" + android:minHeight="@dimen/text_input_height" + android:paddingLeft="2dp" + android:textColor="?android:attr/textColorPrimary" + tools:ignore="RtlSymmetry"/> + + <android.support.v7.widget.AppCompatImageButton + android:id="@+id/btn_send" + android:layout_width="@dimen/text_input_height" + android:layout_height="@dimen/text_input_height" + android:layout_gravity="bottom" + android:background="?attr/selectableItemBackground" + android:clickable="true" + android:contentDescription="@string/send" + android:enabled="false" + android:focusable="true" + android:padding="4dp" + android:scaleType="center" + android:src="@drawable/social_send_now_white" + app:tint="@color/briar_accent"/> + + </LinearLayout> + + <org.thoughtcrime.securesms.components.emoji.EmojiDrawer + android:id="@+id/emoji_drawer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/input_text" + android:visibility="gone"/> + +</merge> diff --git a/mailbox-android/src/main/res/layout/text_input_view_large.xml b/mailbox-android/src/main/res/layout/text_input_view_large.xml new file mode 100644 index 0000000000000000000000000000000000000000..a4a9d7b0247ea8e3f6802979bf77a927b3d69c47 --- /dev/null +++ b/mailbox-android/src/main/res/layout/text_input_view_large.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:showIn="@layout/fragment_reblog"> + + <android.support.v7.widget.CardView + android:id="@+id/input_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/margin_medium" + android:layout_marginLeft="@dimen/margin_medium" + android:layout_marginRight="@dimen/margin_medium" + android:layout_marginStart="@dimen/margin_medium" + android:layout_marginTop="@dimen/margin_medium" + android:elevation="@dimen/cardview_default_elevation" + android:minHeight="@dimen/text_input_height" + app:cardBackgroundColor="@color/card_background" + app:cardCornerRadius="0dp" + app:cardUseCompatPadding="false"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal"> + + <org.thoughtcrime.securesms.components.emoji.EmojiToggle + android:id="@+id/emoji_toggle" + android:layout_width="@dimen/text_input_height" + android:layout_height="@dimen/text_input_height" + android:layout_gravity="bottom" + android:background="?attr/selectableItemBackground" + android:padding="@dimen/margin_small" + android:scaleType="center" + app:tint="?attr/colorControlNormal"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiEditText + android:id="@+id/input_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@android:color/transparent" + android:gravity="bottom" + android:inputType="textMultiLine|textLongMessage|textCapSentences|textAutoCorrect" + android:minHeight="@dimen/text_input_height" + android:paddingBottom="10dp" + android:paddingEnd="@dimen/margin_small" + android:paddingRight="@dimen/margin_small" + android:paddingTop="@dimen/margin_small" + android:textColor="?android:attr/textColorPrimary" + tools:ignore="RtlSymmetry"/> + + </LinearLayout> + + </android.support.v7.widget.CardView> + + <Button + android:id="@+id/btn_send" + style="@style/BriarButton" + android:layout_marginEnd="@dimen/margin_small" + android:layout_marginLeft="@dimen/margin_small" + android:layout_marginRight="@dimen/margin_small" + android:layout_marginStart="@dimen/margin_small"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiDrawer + android:id="@+id/emoji_drawer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="gone"/> + +</merge> diff --git a/mailbox-android/src/main/res/layout/toolbar.xml b/mailbox-android/src/main/res/layout/toolbar.xml new file mode 100644 index 0000000000000000000000000000000000000000..9a17ba10dd162b140bba9db8fbe1b307e621e47b --- /dev/null +++ b/mailbox-android/src/main/res/layout/toolbar.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.design.widget.AppBarLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <android.support.v7.widget.Toolbar + android:id="@+id/toolbar" + style="@style/BriarToolbar" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + +</android.support.design.widget.AppBarLayout> diff --git a/mailbox-android/src/main/res/layout/transports_list.xml b/mailbox-android/src/main/res/layout/transports_list.xml new file mode 100644 index 0000000000000000000000000000000000000000..17fd52a59077a7da759aac88fac18e1b2024adab --- /dev/null +++ b/mailbox-android/src/main/res/layout/transports_list.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + tools:showIn="@layout/navigation_menu"> + + <View style="@style/Divider.Horizontal"/> + + <GridView + android:id="@+id/transportsView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:listSelector="@android:color/transparent" + android:numColumns="3" + tools:listitem="@layout/list_item_transport"/> + +</LinearLayout> diff --git a/mailbox-android/src/main/res/layout/unread_message_button.xml b/mailbox-android/src/main/res/layout/unread_message_button.xml new file mode 100644 index 0000000000000000000000000000000000000000..9c00eca8e6ce0f655fa268e0758ac7ff54c31723 --- /dev/null +++ b/mailbox-android/src/main/res/layout/unread_message_button.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge + 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" + tools:showIn="@layout/activity_threaded_conversation"> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/fab" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:fabSize="mini" + app:useCompatPadding="true"/> + + <TextView + android:id="@+id/unreadCountView" + android:layout_width="wrap_content" + android:layout_height="@dimen/unread_bubble_size" + android:layout_gravity="right|top" + android:layout_marginRight="5dp" + android:layout_marginTop="10dp" + android:background="@drawable/bubble" + android:elevation="7dp" + android:gravity="center" + android:minWidth="@dimen/unread_bubble_size" + android:textColor="@color/briar_text_primary_inverse" + android:textSize="@dimen/unread_bubble_text_size" + android:textStyle="bold" + tools:text="12"/> + +</merge> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/blogs_blog_actions.xml b/mailbox-android/src/main/res/menu/blogs_blog_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..c422489b3854c5cf6a62388bfd1a55227f3cb4f1 --- /dev/null +++ b/mailbox-android/src/main/res/menu/blogs_blog_actions.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + 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"> + + <item + android:id="@+id/action_write_blog_post" + android:icon="@drawable/forum_item_create_white" + android:title="@string/blogs_write_blog_post" + android:visible="false" + app:showAsAction="ifRoom" + tools:visible="true"/> + + <item + android:id="@+id/action_blog_share" + android:icon="@drawable/social_share_white" + android:title="@string/blogs_sharing_share" + app:showAsAction="ifRoom"/> + + <item + android:id="@+id/action_blog_sharing_status" + android:title="@string/sharing_status" + app:showAsAction="never"/> + + <item + android:id="@+id/action_blog_delete" + android:icon="@drawable/action_delete_white" + android:title="@string/blogs_remove_blog" + android:enabled="false" + app:showAsAction="never"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/blogs_feed_actions.xml b/mailbox-android/src/main/res/menu/blogs_feed_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..22cf36961f6ccd40bc17eb4cc353c148951c7893 --- /dev/null +++ b/mailbox-android/src/main/res/menu/blogs_feed_actions.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_write_blog_post" + android:icon="@drawable/forum_item_create_white" + android:title="@string/blogs_write_blog_post" + app:showAsAction="always"/> + + <item + android:id="@+id/action_rss_feeds_import" + android:title="@string/blogs_rss_feeds_import" + app:showAsAction="never"/> + + <item + android:id="@+id/action_rss_feeds_manage" + android:title="@string/blogs_rss_feeds_manage" + app:showAsAction="never"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/contact_list_actions.xml b/mailbox-android/src/main/res/menu/contact_list_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..c5d0dc76ab40cd91b89391236e33f809d04f09a2 --- /dev/null +++ b/mailbox-android/src/main/res/menu/contact_list_actions.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_add_contact" + android:icon="@drawable/ic_add_white" + android:title="@string/add_contact_title" + app:showAsAction="ifRoom"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/contact_selection_actions.xml b/mailbox-android/src/main/res/menu/contact_selection_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..fbef25059b583515e0a331941059f8a5893c9f3d --- /dev/null +++ b/mailbox-android/src/main/res/menu/contact_selection_actions.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_contacts_selected" + android:icon="@drawable/ic_check_white" + android:title="@string/contacts_selected" + app:showAsAction="always"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/conversation_actions.xml b/mailbox-android/src/main/res/menu/conversation_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..594446eb2ed90f3de7eda078d33c8a3e50c51429 --- /dev/null +++ b/mailbox-android/src/main/res/menu/conversation_actions.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_introduction" + android:icon="@drawable/introduction_white" + android:title="@string/introduction_menu_item" + android:enabled="false" + app:showAsAction="never"/> + + <item + android:id="@+id/action_social_remove_person" + android:icon="@drawable/action_delete_white" + android:title="@string/delete_contact" + app:showAsAction="never"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/dev_report_actions.xml b/mailbox-android/src/main/res/menu/dev_report_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..0567cb5d69e956c9309c6274fe93fb8ffd822d38 --- /dev/null +++ b/mailbox-android/src/main/res/menu/dev_report_actions.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_send_report" + android:icon="@drawable/social_send_now_white" + android:title="@string/send_report" + app:showAsAction="always"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/forum_actions.xml b/mailbox-android/src/main/res/menu/forum_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..349f70582997f4fe43a697b0af7f620fbfcf5f50 --- /dev/null +++ b/mailbox-android/src/main/res/menu/forum_actions.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_forum_share" + android:icon="@drawable/social_share_white" + android:title="@string/forum_share_button" + app:showAsAction="ifRoom"/> + + <item + android:id="@+id/action_forum_sharing_status" + android:title="@string/sharing_status" + app:showAsAction="never"/> + + <item + android:id="@+id/action_forum_delete" + android:icon="@drawable/action_delete_white" + android:title="@string/forum_leave" + app:showAsAction="never"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/forum_list_actions.xml b/mailbox-android/src/main/res/menu/forum_list_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..ddc26364ec5e04e757a2ede7ba482ac268e36497 --- /dev/null +++ b/mailbox-android/src/main/res/menu/forum_list_actions.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_create_forum" + android:icon="@drawable/ic_add_white" + android:title="@string/create_forum_button" + app:showAsAction="ifRoom"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/group_actions.xml b/mailbox-android/src/main/res/menu/group_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..eac18cd62195fb493ff53a32f76bf1718f9bbfa4 --- /dev/null +++ b/mailbox-android/src/main/res/menu/group_actions.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_group_invite" + android:icon="@drawable/social_share_white" + android:title="@string/groups_invite_members" + app:showAsAction="ifRoom"/> + + <item + android:id="@+id/action_group_member_list" + android:icon="@drawable/ic_group_white" + android:title="@string/groups_member_list" + app:showAsAction="ifRoom"/> + + <item + android:id="@+id/action_group_reveal" + android:icon="@drawable/ic_visibility_white" + android:title="@string/groups_reveal_contacts" + app:showAsAction="never"/> + + <item + android:id="@+id/action_group_leave" + android:icon="@drawable/action_delete_white" + android:title="@string/groups_leave" + app:showAsAction="never"/> + + <item + android:id="@+id/action_group_dissolve" + android:icon="@drawable/action_delete_white" + android:title="@string/groups_dissolve" + app:showAsAction="never"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/group_reveal_actions.xml b/mailbox-android/src/main/res/menu/group_reveal_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..8612c943633ad0057c3ac7d3493f0f7bb260f174 --- /dev/null +++ b/mailbox-android/src/main/res/menu/group_reveal_actions.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_group_reveal_onboarding" + android:icon="@drawable/ic_info_white" + android:title="@string/show_onboarding" + app:showAsAction="always"/> + +</menu> diff --git a/mailbox-android/src/main/res/menu/groups_list_actions.xml b/mailbox-android/src/main/res/menu/groups_list_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..16eeba4625ce8a78907e35818f693ef191560154 --- /dev/null +++ b/mailbox-android/src/main/res/menu/groups_list_actions.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_add_group" + android:icon="@drawable/ic_add_white" + android:title="@string/groups_create_group_title" + app:showAsAction="ifRoom"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/help_action.xml b/mailbox-android/src/main/res/menu/help_action.xml new file mode 100644 index 0000000000000000000000000000000000000000..a0e4c3d2c8a3a82923caa7a5ba2cdd723605c3d4 --- /dev/null +++ b/mailbox-android/src/main/res/menu/help_action.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_help" + android:icon="@drawable/ic_info_white" + android:title="@string/more_info" + app:showAsAction="always"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/navigation_drawer.xml b/mailbox-android/src/main/res/menu/navigation_drawer.xml new file mode 100644 index 0000000000000000000000000000000000000000..cc628b7db75f5d67aaa3d3933334fdfe35230d45 --- /dev/null +++ b/mailbox-android/src/main/res/menu/navigation_drawer.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android"> + + <group android:checkableBehavior="single"> + <item + android:id="@+id/nav_btn_overview" + android:title="@string/overview"/> + <item + android:id="@+id/nav_btn_settings" + android:icon="@drawable/ic_settings_black_24dp" + android:title="@string/settings_button"/> + <item + android:id="@+id/nav_btn_lock" + android:icon="@drawable/startup_lock" + android:title="@string/lock_button" + android:visible="false"/> + <item + android:id="@+id/nav_btn_signout" + android:icon="@drawable/ic_signout" + android:title="@string/sign_out_button"/> + </group> + +</menu> diff --git a/mailbox-android/src/main/res/menu/overview_actions.xml b/mailbox-android/src/main/res/menu/overview_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..c5d0dc76ab40cd91b89391236e33f809d04f09a2 --- /dev/null +++ b/mailbox-android/src/main/res/menu/overview_actions.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_add_contact" + android:icon="@drawable/ic_add_white" + android:title="@string/add_contact_title" + app:showAsAction="ifRoom"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/menu/rss_feed_manage_actions.xml b/mailbox-android/src/main/res/menu/rss_feed_manage_actions.xml new file mode 100644 index 0000000000000000000000000000000000000000..c51bb7051bd1b5523cce4e8df38f6758af1ea9ab --- /dev/null +++ b/mailbox-android/src/main/res/menu/rss_feed_manage_actions.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/action_rss_feeds_import" + android:icon="@drawable/ic_add_white" + android:title="@string/blogs_rss_feeds_import" + app:showAsAction="always"/> + +</menu> \ No newline at end of file diff --git a/mailbox-android/src/main/res/mipmap-hdpi/ic_launcher_round.png b/mailbox-android/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..2a1df44f1f3d87ffdb578f3a750301fde865715d Binary files /dev/null and b/mailbox-android/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/mailbox-android/src/main/res/mipmap-mdpi/ic_launcher_round.png b/mailbox-android/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..a0c366016e1d532a0725f6a403509cd03da5e5df Binary files /dev/null and b/mailbox-android/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/mailbox-android/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/mailbox-android/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..50071b876f47b1c86493b07120e5891161db7bf9 Binary files /dev/null and b/mailbox-android/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/mailbox-android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/mailbox-android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..1ef39ff9e2633073e3676a17f84f9394a331aeed Binary files /dev/null and b/mailbox-android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/mailbox-android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/mailbox-android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..4cad5b99332a00880d4241be371f926429198b24 Binary files /dev/null and b/mailbox-android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/mailbox-android/src/main/res/values-ast/strings.xml b/mailbox-android/src/main/res/values-ast/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..3054b07aaa82f168855591dc0f3f4032b84b6bcb --- /dev/null +++ b/mailbox-android/src/main/res/values-ast/strings.xml @@ -0,0 +1,147 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Afáyate\'n Briar</string> + <string name="setup_name_explanation">El to alcuñu apaecerá cabo cualquier contenÃu que publiques.Nun puede cambiase después de crear la cuenta.</string> + <string name="setup_next">Siguiente</string> + <string name="setup_password_intro">Escueye una contraseña</string> + <string name="setup_doze_title">Conexones de fondu</string> + <string name="setup_doze_button">Permitir conexones</string> + <string name="choose_nickname">Escueyi un alcuñu</string> + <string name="choose_password">Escueyi una contraseña</string> + <string name="confirm_password">Confirma la contraseña</string> + <string name="name_too_long">El nome ye enforma llargu</string> + <string name="password_too_weak">La contraseña ye enforma feble</string> + <string name="passwords_do_not_match">Les contraseñes nun casen</string> + <string name="create_account_button">Crear cuenta</string> + <string name="more_info">Más información</string> + <string name="don_t_ask_again">Nun volver a entrugar</string> + <string name="setup_huawei_button">Protexer Briar</string> + <string name="warning_dozed">%s nun pudo executase\'n segundu planu</string> + <!--Login--> + <string name="try_again">Contraseña enquivocada, tenta otra vuelta</string> + <string name="sign_in_button">Aniciar sesión</string> + <string name="forgotten_password">Escaecà la contraseña</string> + <string name="dialog_title_lost_password">Contraseña perdida</string> + <string name="dialog_message_lost_password">La cuenta de Briar guárdase cifrada nel preséu, non na nube, de manera que nun podemos reaniciala.. ¿Quies desaniciar la cuenta y principiar de cero?\n\nAtención: Les tos identidaes, contautos y mensaxes perderánse de mou permanente.</string> + <string name="startup_failed_notification_title">Briar nun pudo arrancar</string> + <string name="startup_failed_activity_title">Fallu nel arranque de Briar</string> + <string name="expiry_date_reached">Esti software caducó.\n¡Gracies por probalu!</string> + <string name="download_briar">Pa siguir usando Briar, descarga la versión 1.0.</string> + <string name="create_new_account">Tendrás de crear una cuenta nueva, pero puedes usar el mesmu alcuñu.</string> + <string name="download_briar_button">Descargar Briar 1.0</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Abrir el caxón de navegación</string> + <string name="nav_drawer_close_description">Zarrar el caxón de navegación</string> + <string name="contact_list_button">Contactos</string> + <string name="groups_button">Grupos privaos</string> + <string name="forums_button">Foros</string> + <string name="blogs_button">Blogs</string> + <string name="settings_button">Preferencies</string> + <string name="sign_out_button">Colar</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="ongoing_notification_title">Sesión aniciada</string> + <string name="ongoing_notification_text">Toca p\'abrir Briar.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Mensaxes priváu nuevu.</item> + <item quantity="other">%d mensaxes privaos nuevos.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Mensaxe de grupu nuevu.</item> + <item quantity="other">%d mensaxes de grupu nuevos.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Mensaxe de foru nuevu.</item> + <item quantity="other">%d mensaxes de foru nuevos.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Una publicación del blog nueva.</item> + <item quantity="other">%d publicaciones del blog nueves.</item> + </plurals> + <!--Misc--> + <string name="now">agora</string> + <string name="show">Amosar</string> + <string name="hide">Anubrir</string> + <string name="ok">Aceutar</string> + <string name="cancel">Encaboxar</string> + <string name="got_it">EntendÃlo</string> + <string name="delete">Desaniciar</string> + <string name="accept">Aceutar</string> + <string name="decline">Refugar</string> + <string name="options">Opciones</string> + <string name="online">En llinia</string> + <string name="offline">Sin conexón</string> + <string name="send">Unviar</string> + <string name="allow">Permitir</string> + <string name="open">Abrir</string> + <string name="no_data">Sin datos</string> + <string name="ellipsis">…</string> + <string name="fix">Iguar</string> + <string name="help">Ayuda</string> + <!--Contacts and Private Conversations--> + <!--Adding Contacts--> + <!--Introductions--> + <!--Private Groups--> + <plurals name="messages"> + <item quantity="one">%d mensaxe</item> + <item quantity="other">%d mensaxes</item> + </plurals> + <string name="groups_remove">Desaniciar</string> + <string name="groups_create_group_title">Crear Grupu priváu</string> + <string name="groups_create_group_button">Crear Grupu</string> + <string name="groups_create_group_invitation_button">Unviar Invitación</string> + <string name="groups_member_list">Llista de miembros</string> + <string name="groups_invite_members">Invitar a miembros</string> + <string name="groups_member_created_you">Creasti\'\'l grupu</string> + <string name="groups_member_created">%s creó\'\'l grupu</string> + <string name="groups_dissolve_button">Disolver</string> + <string name="groups_dissolved_dialog_title">Disolvióse\'\'l grupu</string> + <!--Private Group Invitations--> + <string name="groups_invitations_invitation_sent">Invitasti a %1$s a xunise al grupu \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s invitóte a xunite al grupu \"%2$s\".</string> + <!--Private Groups Revealing Contacts--> + <!--Forums--> + <string name="create_forum_title">Crear foru</string> + <string name="choose_forum_hint">Escueyi un nome pal foru</string> + <string name="create_forum_button">Crear foru</string> + <string name="forum_created_toast">Creóse\'l foru</string> + <string name="no_forum_posts">Nun hai mensaxes qu\'amosar</string> + <!--Forum Sharing--> + <string name="nobody">Naide</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Nun hai mensaxes qu\'amosar</string> + <string name="read_more">lleer más</string> + <string name="blogs_publish_blog_post">Publicar</string> + <string name="blogs_remove_blog_ok">Desaniciar</string> + <!--Blog Sharing--> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Importar canal RSS</string> + <string name="blogs_rss_feeds_import_button">Importar</string> + <string name="blogs_rss_feeds_manage_author">Autor:</string> + <string name="blogs_rss_remove_feed_ok">Desaniciar</string> + <!--Settings Display--> + <!--Settings Network--> + <string name="network_settings_title">Redes</string> + <string name="tor_network_setting">Coneutar vÃa Tor</string> + <string name="tor_network_setting_never">Nunca</string> + <string name="tor_network_setting_wifi">Sólo al usar Wi-Fi</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Seguridá</string> + <string name="panic_setting">Configuración del Botón d\'espantu</string> + <string name="panic_setting_title">Botón d\'espantu</string> + <string name="panic_setting_signout_title">Colar</string> + <string name="uninstall_setting_title">Desinstalar Briar</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Avisos</string> + <string name="notify_private_messages_setting_title">Mensaxes privaos</string> + <!--Settings Feedback--> + <!--Link Warning--> + <!--Crash Reporter--> + <!--Sign Out--> + <!--Screen Filters & Tapjacking--> + <!--Permission Requests--> +</resources> diff --git a/mailbox-android/src/main/res/values-bg/strings.xml b/mailbox-android/src/main/res/values-bg/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..339f00f2bcd8cbcb34ed8b32f0ebca02f2af47a1 --- /dev/null +++ b/mailbox-android/src/main/res/values-bg/strings.xml @@ -0,0 +1,326 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Добре дошли в Briar</string> + <string name="setup_next">Следващ</string> + <string name="choose_nickname">Изберете име</string> + <string name="choose_password">Изберете парола</string> + <string name="confirm_password">Потвърдете парола</string> + <string name="name_too_long">Името е твърде дълго</string> + <string name="password_too_weak">Паролата е твърде Ñлаба</string> + <string name="passwords_do_not_match">Паролите не Ñъвпадат</string> + <string name="create_account_button">Създаване на профил</string> + <!--Login--> + <string name="enter_password">Парола</string> + <string name="try_again">Грешна парола, опитайте пак</string> + <string name="sign_in_button">Вход</string> + <string name="forgotten_password">Забравена парола</string> + <string name="dialog_title_lost_password">Забравена парола</string> + <string name="dialog_message_lost_password">Briar профилът Ñе ÑъхранÑва криптиран във вашето уÑтройÑтво, не в облака, така че не можем да зададем нова парола. ИÑкате ли да изтриете профила Ñи и да започнете отначало?\n\nВнимание: ВашиÑÑ‚ профил, контакти и ÑÑŠÐ¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ‰Ðµ бъдат изтрити завинаги.</string> + <string name="startup_failed_notification_title">Briar не можа да Ñтартира</string> + <string name="startup_failed_activity_title">ÐеуÑпешно Ñтартиране</string> + <string name="startup_failed_service_error">Briar не уÑÐ¿Ñ Ð´Ð° Ñтартира задължителен плъгин. Обикновено преинÑталирането на Briar решава този проблем. МолÑ, имайте предвид, че ще изгубите профила Ñи и вÑички данни, аÑоциирани Ñ Ð½ÐµÐ³Ð¾, тъй като Briar не ÑъхранÑва данните ви в централни Ñървъри.</string> + <string name="expiry_date_reached">Софтуерът е невалиден.\nБлагодарим ви за теÑтването!</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Отвори навигационно чекмедже</string> + <string name="nav_drawer_close_description">Затвори навигационно чекмедже</string> + <string name="contact_list_button">Контакти</string> + <string name="groups_button">ЧаÑтни групи</string> + <string name="forums_button">Форуми</string> + <string name="blogs_button">Блогове</string> + <string name="settings_button">ÐаÑтройки</string> + <string name="sign_out_button">ОтпиÑване</string> + <!--Transports--> + <string name="transport_tor">Интернет</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="ongoing_notification_title">ВпиÑан Ñте в Briar</string> + <string name="ongoing_notification_text">ДокоÑнете, за да отворите Briar.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Ðово лично Ñъобщение.</item> + <item quantity="other">%d нови лични ÑъобщениÑ.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Ðово групово Ñъобщение.</item> + <item quantity="other">%d нови групови ÑъобщениÑ.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Ðова форумна публикациÑ.</item> + <item quantity="other">%d нови форумни публикации.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Ðова блог публикациÑ.</item> + <item quantity="other">%d нови блог публикации.</item> + </plurals> + <!--Misc--> + <string name="now">Ñега</string> + <string name="show">Покажи</string> + <string name="hide">Скрий</string> + <string name="ok">ОК</string> + <string name="cancel">Отказ</string> + <string name="got_it">Разбрах</string> + <string name="delete">Изтрий</string> + <string name="accept">Приеми</string> + <string name="decline">Откажи</string> + <string name="options">Опции</string> + <string name="online">Онлайн</string> + <string name="offline">Офлайн</string> + <string name="send">Изпрати</string> + <string name="allow">Позволи</string> + <string name="open">Отвори</string> + <string name="no_data">ÐÑма данни</string> + <string name="ellipsis">...</string> + <string name="text_too_long">ВъведениÑÑ‚ текÑÑ‚ е твърде дълъг</string> + <string name="show_onboarding">Показване на помощен диалог</string> + <string name="help">Помощ</string> + <!--Contacts and Private Conversations--> + <string name="date_no_private_messages">ÐÑма ÑъобщениÑ.</string> + <string name="message_hint">Ðапиши Ñъобщение</string> + <string name="delete_contact">Изтрий контакт</string> + <string name="dialog_title_delete_contact">Потвърди изтриването на контакт</string> + <string name="dialog_message_delete_contact">Сигурни ли Ñте, че иÑкате да изтриете този контакт и вÑички ÑъобщениÑ, обменени Ñ Ñ‚Ð¾Ð·Ð¸ контакт?</string> + <string name="contact_deleted_toast">Контактът е изтрит</string> + <!--Adding Contacts--> + <string name="add_contact_title">ДобавÑне на контакт</string> + <string name="face_to_face">ТрÑбва да Ñе Ñрещнете лично Ñ Ñ‡Ð¾Ð²ÐµÐºÐ°, когото иÑкате да добавите в Контакти.\n\nПо този начин никой не може да Ñе предÑтави за Ð²Ð°Ñ Ð¸Ð»Ð¸ да чете ÑъобщениÑта ви в бъдеще.</string> + <string name="continue_button">Ðапред</string> + <string name="connection_failed">ÐеуÑпешна връзка</string> + <string name="try_again_button">Опитай пак</string> + <string name="waiting_for_contact_to_scan">Изчакване контактът да Ñканира и да Ñе Ñвърже\u2026</string> + <string name="exchanging_contact_details">Обмен на данни за контакт\u2026</string> + <string name="contact_added_toast">Добавен конктакт: %s</string> + <string name="contact_already_exists">Контактът %s вече ÑъщеÑтвува</string> + <string name="contact_exchange_failed">ÐеуÑпех при обмен на контакти</string> + <string name="qr_code_invalid">QR кодът е невалиден</string> + <string name="connecting_to_device">Свързване Ñ ÑƒÑтройÑтво\u2026</string> + <string name="authenticating_with_device">УдоÑтоверÑване Ñ ÑƒÑтройÑтво\u2026</string> + <string name="connection_aborted_remote">Връзката е прекъÑната от контакта ви! Това може да значи, че нÑкой Ñе опитва да попречи на Ñвързването</string> + <!--Introductions--> + <string name="introduction_onboarding_title">ПредÑтавете контактите Ñи</string> + <string name="introduction_onboarding_text">Можете да предÑтавите контактите Ñи един на друг, за да не им Ñе налага да Ñе Ñрещат лично, когато Ñе Ñвързват чрез Briar.</string> + <string name="introduction_menu_item">ПредÑтави</string> + <string name="introduction_activity_title">Избери контакт</string> + <string name="introduction_message_title">ПредÑтави контакти</string> + <string name="introduction_message_hint">Добавете Ñъобщение (незадължително)</string> + <string name="introduction_button">ПредÑтави</string> + <string name="introduction_sent">ПредÑтавÑнето ви е изпратено.</string> + <string name="introduction_error">Възникна грешка при предÑтавÑнето.</string> + <string name="introduction_response_error">Грешка при отговор на предÑтавÑнето</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_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_response_accepted_sent">Приехте предÑтавÑнето на %1$s.</string> + <string name="introduction_response_declined_sent">Отказахте предÑтавÑнето на %1$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_by_introducee">%1$s казва, че %2$s отказва предÑтавÑнето.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Добавен нов контакт.</item> + <item quantity="other">%d добавени нови контакти.</item> + </plurals> + <!--Private Groups--> + <string name="groups_created_by">Създаден от %s</string> + <plurals name="messages"> + <item quantity="one">%d Ñъобщение</item> + <item quantity="other">%d ÑъобщениÑ</item> + </plurals> + <string name="groups_group_is_empty">Групата е празна</string> + <string name="groups_group_is_dissolved">Групата Ñе е разпаднала</string> + <string name="groups_remove">Премахни</string> + <string name="groups_create_group_title">Създаване на група</string> + <string name="groups_create_group_button">Създай група</string> + <string name="groups_create_group_invitation_button">Изпрати покана</string> + <string name="groups_create_group_hint">Изберете име за групата</string> + <string name="groups_invitation_sent">Поканата в група е изпратена</string> + <string name="groups_message_sent">Съобщението е изпратено</string> + <string name="groups_member_list">СпиÑък Ñ ÑƒÑ‡Ð°Ñтници</string> + <string name="groups_invite_members">Поканете учаÑтници</string> + <string name="groups_member_created_you">Вие Ñъздадохте групата</string> + <string name="groups_member_created">%s Ñъздаде групата</string> + <string name="groups_member_joined_you">Включихте Ñе в групата</string> + <string name="groups_member_joined">%s Ñе включи в групата</string> + <string name="groups_leave">ÐапуÑни групата</string> + <string name="groups_leave_dialog_title">Потвърждение на напуÑкането</string> + <string name="groups_leave_dialog_message">Сигурни ли Ñте, че иÑкате да напуÑнете тази група?</string> + <string name="groups_dissolve">Затвори групата</string> + <string name="groups_dissolve_dialog_title">Потвърди затварÑнето на групата</string> + <string name="groups_dissolve_dialog_message">Сигурни ли Ñте, че иÑкате да затворите групата?\n\nÐ’Ñички други учаÑтници нÑма да могат да продължат разговора и може да не получат най-новите ÑъобщениÑ. </string> + <string name="groups_dissolve_button">Затвори</string> + <string name="groups_dissolved_dialog_title">Групата е затворена</string> + <string name="groups_dissolved_dialog_message">Групата е затворена от ÑъздателÑ.\n\nÐе можете да пишете нови ÑÑŠÐ¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð² Ð³Ñ€ÑƒÐ¿Ð¾Ð²Ð¸Ñ Ñ‡Ð°Ñ‚ и може да не получите най-новите ÑъобщениÑ. </string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Покани в група</string> + <string name="groups_invitations_invitation_sent">Поканихте %1$s в групата \"%2$s\"</string> + <string name="groups_invitations_invitation_received">%1$s ви покани в групата \"%2$s\".</string> + <string name="groups_invitations_joined">Включихте Ñе в групата</string> + <string name="groups_invitations_declined">Отказана покана в група</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d отворена покана в група</item> + <item quantity="other">%d отворени покани в група</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Приехте поканата в група на %s.</string> + <string name="groups_invitations_response_declined_sent">Отказахте поканата в група на %s.</string> + <string name="groups_invitations_response_accepted_received">%s прие поканата в група.</string> + <string name="groups_invitations_response_declined_received">%s отказа поканата в група. </string> + <string name="sharing_status_groups">Само ÑъздателÑÑ‚ може да покани нови учаÑтници в групата. По-долу Ñа изброени Ñегашните учаÑтници в групата.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Разкрий контакти</string> + <string name="groups_reveal_dialog_message">Може да изберете да разкриете контактите на вÑички Ñегашни и бъдещи учаÑтници в тази група.\n\nРазкриването на контактите прави връзката Ñ Ð³Ñ€ÑƒÐ¿Ð°Ñ‚Ð° по-бърза и Ñигурна, тъй като можете да общувате Ñ Ñ€Ð°Ð·ÐºÑ€Ð¸Ñ‚Ð¸ контакти, дори когато ÑъздателÑÑ‚ на групата е офлайн.</string> + <string name="groups_reveal_visible">Връзка Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð° Ñе вижда от групата</string> + <string name="groups_reveal_visible_revealed_by_us">Връзка Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð° Ñе вижда от групата (разкрита от ваÑ)</string> + <string name="groups_reveal_visible_revealed_by_contact">Връзка Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð° Ñе вижда от групата (разкрита от %s)</string> + <string name="groups_reveal_invisible">Връзка Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð° не Ñе вижда от групата</string> + <!--Forums--> + <string name="create_forum_title">Създаване на форум</string> + <string name="choose_forum_hint">Изберете име за форума</string> + <string name="create_forum_button">Създай форум</string> + <string name="forum_created_toast">Форумът е Ñъздаден</string> + <string name="no_posts">ÐÑма публикации</string> + <plurals name="posts"> + <item quantity="one">%d публикациÑ</item> + <item quantity="other">%d публикации</item> + </plurals> + <string name="forum_message_reply_hint">Ðов отговор</string> + <string name="btn_reply">Отговори</string> + <string name="forum_leave">ÐапуÑни форума</string> + <string name="dialog_title_leave_forum">Потвърдете напуÑкането на форума</string> + <string name="dialog_button_leave">ÐапуÑни</string> + <!--Forum Sharing--> + <string name="forum_share_button">Сподели форум</string> + <string name="contacts_selected">Избрани контакти</string> + <string name="activity_share_toolbar_header">Избиране на контакти</string> + <string name="forum_shared_snackbar">Форумът е Ñподелен Ñ Ð¸Ð·Ð±Ñ€Ð°Ð½Ð¸Ñ‚Ðµ контакти</string> + <string name="forum_share_message">Добавете Ñъобщение (незадължително)</string> + <string name="forum_share_error">Възникна грешка при ÑподелÑнето на този форум.</string> + <string name="forum_invitation_received">%1$s Ñподели форума \"%2$s\" Ñ Ð²Ð°Ñ.</string> + <string name="forum_invitation_sent">Споделихте форума \"%1$s\" Ñ %2$s.</string> + <string name="forum_invitations_title">Покани във форум</string> + <string name="shared_by_format">Споделен от %s</string> + <string name="forum_invitation_already_sharing">Вече е Ñподелен</string> + <string name="forum_invitation_response_accepted_sent">Приехте поканата за форум на %s.</string> + <string name="forum_invitation_response_declined_sent">Отказахте поканата във форум от %s.</string> + <string name="forum_invitation_response_accepted_received">%s прие поканата във форум.</string> + <string name="forum_invitation_response_declined_received">%s отказа поканата във форум.</string> + <string name="sharing_status">Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð½Ð° ÑподелÑнето</string> + <string name="sharing_status_forum">Ð’Ñеки учаÑтник във форума може да го Ñподели Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð¸Ñ‚Ðµ Ñи. СподелÑте този форум ÑÑŠÑ Ñледните контакти. Възможно е да има и други, които не можете да видите.</string> + <string name="shared_with">Споделен Ñ %1$d (%2$d онлайн)</string> + <plurals name="forums_shared"> + <item quantity="one">%d форум, Ñподелен от контакти</item> + <item quantity="other">%d форума, Ñподелени от контакти</item> + </plurals> + <string name="nobody">Ðикого</string> + <!--Blogs--> + <string name="read_more">прочети още</string> + <string name="blogs_write_blog_post">Ðова блог публикациÑ</string> + <string name="blogs_publish_blog_post">Публикуване</string> + <string name="blogs_blog_post_created">Блог публикациÑта е Ñъздадена</string> + <string name="blogs_blog_post_received">Ðова блог публикациÑ</string> + <string name="blogs_blog_post_scroll_to">Отвори</string> + <string name="blogs_remove_blog">Премахване на блог</string> + <string name="blogs_remove_blog_ok">Премахване</string> + <string name="blogs_reblog_comment_hint">Добавете Ñъобщение (незадължително)</string> + <string name="blogs_reblog_button">Реблог</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">СподелÑне на блог</string> + <string name="blogs_sharing_error">Възникна грешка при ÑподелÑнето на този блог.</string> + <string name="blogs_sharing_button">Сподели блог</string> + <string name="blogs_sharing_snackbar">Блогът е Ñподелен Ñ Ð¸Ð·Ð±Ñ€Ð°Ð½Ð¸Ñ‚Ðµ контакти</string> + <string name="blogs_sharing_response_accepted_sent">Приехте поканата в блог от %s.</string> + <string name="blogs_sharing_response_declined_sent">Отказахте поканата в блог от %s.</string> + <string name="blogs_sharing_response_accepted_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_sent">Споделихте блога \"%1$s\" Ñ %2$s.</string> + <string name="blogs_sharing_invitations_title">Блог покани</string> + <string name="sharing_status_blog">Ð’Ñеки абонат на бÐ»Ð¾Ð³Ð° може да го Ñподели Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð¸Ñ‚Ðµ Ñи. СподелÑте този блог ÑÑŠÑ Ñледните контакти. Възможно е да има и други, които не можете да видите.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">ВнаÑÑне на RSS емиÑиÑ</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_error">Възникна грешка при внаÑÑнето на емиÑиÑ.</string> + <string name="blogs_rss_feeds_manage">Управление на RSS емиÑии</string> + <string name="blogs_rss_feeds_manage_imported">ВнеÑена:</string> + <string name="blogs_rss_feeds_manage_author">Ðвтор:</string> + <string name="blogs_rss_feeds_manage_updated">ПоÑледно актуализиране:</string> + <string name="blogs_rss_remove_feed">Премахване на емиÑиÑ</string> + <string name="blogs_rss_remove_feed_ok">Премахване</string> + <string name="blogs_rss_feeds_manage_delete_error">ЕмиÑиÑта не можа да бъде изтрита!</string> + <string name="blogs_rss_feeds_manage_error">Възникна проблем при зареждането на емиÑиите ви. МолÑ, опитайте пак по-къÑно.</string> + <!--Settings Display--> + <!--Settings Network--> + <string name="network_settings_title">Мрежа</string> + <string name="bluetooth_setting">Свързване чрез Bluetooth</string> + <string name="bluetooth_setting_enabled">Когато контактите Ñа наблизо</string> + <string name="bluetooth_setting_disabled">Само при добавÑне на контакти</string> + <string name="tor_network_setting">Свързване чрез Tor</string> + <string name="tor_network_setting_never">Ðикога</string> + <string name="tor_network_setting_wifi">Само при активна Wi-Fi връзка</string> + <string name="tor_network_setting_always">През Wi-Fi или мобилни данни</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">СигурноÑÑ‚</string> + <string name="change_password">ПромÑна на парола</string> + <string name="password_changed">Паролата е променена.</string> + <string name="panic_setting">ÐаÑтройка на паник бутон</string> + <string name="panic_setting_title">Паник бутон</string> + <string name="panic_setting_hint">ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð½Ð° приложение за паник бутон</string> + <string name="panic_app_setting_title">Приложение за паник бутон</string> + <string name="unknown_app">непознато приложение</string> + <string name="panic_app_setting_summary">ÐÑма зададено приложение</string> + <string name="panic_app_setting_none">ÐÑма</string> + <string name="dialog_title_connect_panic_app">Потвърждение на паник приложение</string> + <string name="dialog_message_connect_panic_app">Сигурни ли Ñте, че иÑкате да позволите на %1$s да задейÑтва унищожителни дейÑÑ‚Ð²Ð¸Ñ Ð½Ð° паник бутон?</string> + <string name="panic_setting_signout_title">ОтпиÑване</string> + <string name="panic_setting_signout_summary">ОтпиÑване от Briar, ако паник бутонът е натиÑнат</string> + <string name="purge_setting_title">Изтриване на профил</string> + <string name="purge_setting_summary">Изтриване на Briar профила, ако паник бутонът е натиÑнат. Внимание: Изтрива завинаги Ð²Ð°ÑˆÐ¸Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð», контакти и ÑъобщениÑ</string> + <string name="uninstall_setting_title">ДеинÑталиране на Briar</string> + <string name="uninstall_setting_summary">ИзиÑква ръчно потвърждение в паник Ñлучай</string> + <!--Settings Notifications--> + <string name="notification_settings_title">ИзвеÑтиÑ</string> + <string name="notify_private_messages_setting_title">Лични ÑъобщениÑ</string> + <string name="notify_private_messages_setting_summary">Показвай извеÑÑ‚Ð¸Ñ Ð·Ð° лични ÑъобщениÑ</string> + <string name="notify_group_messages_setting_title">Групови ÑъобщениÑ</string> + <string name="notify_group_messages_setting_summary">Показвай извеÑÑ‚Ð¸Ñ Ð·Ð° групови ÑъобщениÑ</string> + <string name="notify_forum_posts_setting_title">Форумни публикации</string> + <string name="notify_forum_posts_setting_summary">Показвай извеÑÑ‚Ð¸Ñ Ð·Ð° форумни публикации</string> + <string name="notify_blog_posts_setting_title">Блог публикации</string> + <string name="notify_blog_posts_setting_summary">Показвай извеÑÑ‚Ð¸Ñ Ð·Ð° блог публикации</string> + <string name="notify_vibration_setting">ВибрациÑ</string> + <string name="notify_lock_screen_setting_title">Заключен екран</string> + <string name="notify_lock_screen_setting_summary">Показвай извеÑÑ‚Ð¸Ñ Ð·Ð° на заключен екран</string> + <string name="notify_sound_setting">Звук</string> + <string name="notify_sound_setting_default">ÐœÐµÐ»Ð¾Ð´Ð¸Ñ Ð¿Ð¾ подразбиране</string> + <string name="notify_sound_setting_disabled">Ðикакви</string> + <string name="choose_ringtone_title">Изберете рингтон</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Отзиви</string> + <string name="send_feedback">Изпращане на отзиви</string> + <!--Link Warning--> + <string name="link_warning_title">Предупреждение за линк</string> + <string name="link_warning_intro">Линкът ще Ñе отвори във външно приложение.</string> + <string name="link_warning_text">Линкът може да Ñе използва, за да ви идентифицира. ПомиÑлете дали имате доверие на човека, който ви изпраща линка, и обмиÑлете дали да не го отворите Ñ Orfox.</string> + <string name="link_warning_open_link">Отвори линк</string> + <!--Crash Reporter--> + <string name="crash_report_title">Доклад на Ñрив</string> + <string name="briar_crashed">Извинете, Briar Ñе Ñрина.</string> + <string name="not_your_fault">Ðе е по ваша вина.</string> + <string name="please_send_report">МолÑ, помогнете да изградим по-добър Briar, като ни изпратите доклад.</string> + <string name="report_is_encrypted">Гарантираме, че докладът е криптиран и изпратен безопаÑно.</string> + <string name="feedback_title">Отзиви</string> + <string name="describe_crash">Опишете Ñтаналото (незадължително)</string> + <string name="enter_feedback">Въведете отзив</string> + <string name="optional_contact_email">Имейл адреÑÑŠÑ‚ ви (незадължително)</string> + <string name="include_debug_report_crash">Добави анонимни данни за Ñрива</string> + <string name="include_debug_report_feedback">Добави анонимни данни за това уÑтройÑтвo</string> + <string name="could_not_load_report_data">Данните за доклада не можаха да заредÑÑ‚.</string> + <string name="send_report">Изпращане на доклад</string> + <string name="close">ЗатварÑне</string> + <string name="dev_report_saved">Докладът е запазен. Ще бъде изпратен при Ñледващото влизане в Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">ОтпиÑване от Briar...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Открит е овърлей на екрана</string> + <!--Permission Requests--> +</resources> diff --git a/mailbox-android/src/main/res/values-br/strings.xml b/mailbox-android/src/main/res/values-br/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..25de4a52efaaf04a1f0121954f7c5a6b63a3aeef --- /dev/null +++ b/mailbox-android/src/main/res/values-br/strings.xml @@ -0,0 +1,177 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Degemer mat war Briar</string> + <string name="setup_next">De-heul</string> + <string name="setup_password_intro">Dibabit ur ger-tremen</string> + <string name="setup_doze_title">Kevreadennoù drek-leur</string> + <string name="setup_doze_button">Aotren ar c\'hevreadennoù</string> + <string name="choose_nickname">Dibabit ho lezanv</string> + <string name="choose_password">Dibabit ho ker-tremen</string> + <string name="confirm_password">Kadarnait ho ker-tremen</string> + <string name="name_too_long">Re hir eo an anv</string> + <string name="password_too_weak">Re wan eo ar ger-kuzh</string> + <string name="passwords_do_not_match">Ne glot ket ar gerioù-tremen</string> + <string name="create_account_button">Krouiñ ur gont</string> + <string name="more_info">Muioc\'h a ditouroù</string> + <string name="don_t_ask_again">Arabat goulenn ganin ken</string> + <string name="setup_huawei_button">Gwareziñ Briar</string> + <!--Login--> + <string name="enter_password">Ger-tremen</string> + <string name="try_again">Ger-tremen fall, klaskit adarre</string> + <string name="sign_in_button">Kevreañ</string> + <string name="forgotten_password">Ankoueet em eus ma ger-tremen</string> + <string name="dialog_title_lost_password">Kollet em eus ma ger-tremen</string> + <string name="startup_failed_notification_title">N\'hall ket loc\'hañ Briar</string> + <!--Navigation Drawer--> + <string name="contact_list_button">Darempredoù</string> + <string name="groups_button">Strolladoù prevez</string> + <string name="forums_button">Foromoù</string> + <string name="blogs_button">Blogoù</string> + <string name="settings_button">Arventennoù</string> + <string name="sign_out_button">Digevreañ</string> + <!--Transports--> + <string name="transport_tor">Kenrouedad</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="ongoing_notification_title">Marilhet e-barzh Briar</string> + <string name="ongoing_notification_text">Touchit da zigeriñ Briar.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Kemennadenn prevez nevez</item> + <item quantity="two">%d a gemennadennoù prevez nevez. </item> + <item quantity="few">%d a gemennadennoù prevez nevez. </item> + <item quantity="many">%d a gemennadennoù prevez nevez. </item> + <item quantity="other">%d a gemennadennoù prevez nevez. </item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Kemennadenn strollad nevez.</item> + <item quantity="two">%d a gemennadennoù strollad nevez.</item> + <item quantity="few">%d a gemennadennoù strollad nevez.</item> + <item quantity="many">%d a gemennadennoù strollad nevez.</item> + <item quantity="other">%d a gemennadennoù strollad nevez.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Postadenn forom nevez.</item> + <item quantity="two">%da bostadennoù forom nevez.</item> + <item quantity="few">%da bostadennoù forom nevez.</item> + <item quantity="many">%da bostadennoù forom nevez.</item> + <item quantity="other">%da bostadennoù forom nevez.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Postadenn blog nevez.</item> + <item quantity="two">%d a bostadennoù blog nevez.</item> + <item quantity="few">%d a bostadennoù blog nevez.</item> + <item quantity="many">%d a bostadennoù blog nevez.</item> + <item quantity="other">%d a bostadennoù blog nevez.</item> + </plurals> + <!--Misc--> + <string name="now">bremañ</string> + <string name="show">Diskouez</string> + <string name="hide">Kuzhaat</string> + <string name="ok">MAT EO</string> + <string name="cancel">Nullañ</string> + <string name="got_it">Deuet eo ganin</string> + <string name="delete">Dilemel</string> + <string name="accept">Asantiñ</string> + <string name="decline">Nac\'hañ</string> + <string name="options">Dibarzhioù</string> + <string name="online">Enlinenn</string> + <string name="offline">Ezlinenn</string> + <string name="send">Kas</string> + <string name="allow">Aotren</string> + <string name="open">Digeriñ</string> + <string name="no_data">Roadenn ebet</string> + <string name="ellipsis">…</string> + <string name="text_too_long">An destenn ebarzhet a zo re hir</string> + <string name="show_onboarding">Diskouez an diviz skoazell</string> + <string name="help">Skoazell</string> + <!--Contacts and Private Conversations--> + <string name="date_no_private_messages">Kemennadenn ebet.</string> + <string name="message_hint">Doare kemennadenn</string> + <string name="delete_contact">Dilemel an darempred</string> + <string name="dialog_title_delete_contact">Kadarnat dilemel darempred</string> + <string name="contact_deleted_toast">Darempred dilemet</string> + <!--Adding Contacts--> + <string name="add_contact_title">Ouzhpennañ un darempred</string> + <string name="continue_button">Kenderc\'hel</string> + <string name="connection_failed">Kevereadenn c\'hwitet</string> + <string name="try_again_button">Klask adarre</string> + <string name="contact_added_toast">Darempred ouzhpennet: %s</string> + <string name="contact_already_exists">An darempred %s a zo anezhañ endeo</string> + <string name="camera_error">Fazi Kamera</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Degas e-barzh ho tarempredoù</string> + <string name="introduction_menu_item">Sevel un digoradur</string> + <string name="introduction_activity_title">Diuziñ darempred</string> + <string name="introduction_message_title">Degas e-barzh darempredoù</string> + <string name="introduction_message_hint">Ouzhpennañ ur gemennadenn (diret)</string> + <string name="introduction_button">Sevel un digoradur</string> + <string name="introduction_sent">Kaset eo bet ho tigoradur.</string> + <string name="introduction_error">Ur fazi a zo c\'hoarvezet en ur ober an digoradur.</string> + <string name="introduction_response_error">Fazi en ur respont d\'an digoradur</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Darempred nevez ouzhpennet.</item> + <item quantity="two">%d a zarempredoù nevez ouzhpennet.</item> + <item quantity="few">%d a zarempredoù nevez ouzhpennet.</item> + <item quantity="many">%d a zarempredoù nevez ouzhpennet.</item> + <item quantity="other">%d a zarempredoù nevez ouzhpennet.</item> + </plurals> + <!--Private Groups--> + <string name="groups_created_by">Graet gant %s</string> + <plurals name="messages"> + <item quantity="one">%d kemennadenn</item> + <item quantity="two">%d a gemennadennoù</item> + <item quantity="few">%d a gemennadennoù</item> + <item quantity="many">%d a gemennadennoù</item> + <item quantity="other">%d a gemennadennoù</item> + </plurals> + <string name="groups_group_is_empty">Leun eo ar strollad-mañ</string> + <string name="groups_group_is_dissolved">Divodet eo bet ar strollad-mañ</string> + <string name="groups_remove">Dilemel</string> + <string name="groups_create_group_title">Krouiñ ur strollad prevez</string> + <string name="groups_create_group_button">Krouiñ ur strollad</string> + <string name="groups_create_group_invitation_button">Kas pedadennoù</string> + <string name="groups_create_group_hint">Dibabit un anv evit ho strollad prevez</string> + <string name="groups_invitation_sent">Pedadenn ar strollad a zo bet kaset</string> + <string name="groups_message_sent">Kemennadenn kaset</string> + <string name="groups_member_list">Listenn an izili</string> + <string name="groups_invite_members">Pediñ izili</string> + <string name="groups_member_created_you">Krouet ho peus ar strollad</string> + <string name="groups_member_created">%s en deus krouet ar strollad</string> + <string name="groups_member_joined_you">Emezelet ho peus er strollad</string> + <string name="groups_member_joined">%s a zo deuet e-barzh ar strollad</string> + <string name="groups_leave">Kuitaat ar strollad</string> + <string name="groups_leave_dialog_title">Kadarnaat e kuitait ar strollad</string> + <string name="groups_leave_dialog_message">C\'hoant ho peus da guitaat ar strollad-mañ?</string> + <string name="groups_dissolve">Divodañ ar strollad</string> + <string name="groups_dissolve_dialog_title">Kadarnaat e tivodit ar strollad</string> + <string name="groups_dissolve_button">Divodañ</string> + <!--Private Group Invitations--> + <!--Private Groups Revealing Contacts--> + <!--Forums--> + <!--Forum Sharing--> + <string name="forum_share_message">Ouzhpennañ ur gemennadenn (diret)</string> + <!--Blogs--> + <string name="blogs_remove_blog_ok">Dilemel</string> + <!--Blog Sharing--> + <!--RSS Feeds--> + <string name="blogs_rss_remove_feed_ok">Dilemel</string> + <!--Settings Display--> + <!--Settings Network--> + <!--Settings Security and Panic--> + <string name="security_settings_title">Surentezh</string> + <string name="change_password">Cheñch ar ger-tremen</string> + <string name="confirm_new_password">Kadarnaat ar ger-tremen nevez</string> + <string name="panic_app_setting_none">Hini ebet</string> + <string name="panic_setting_signout_title">Digevreañ</string> + <!--Settings Notifications--> + <string name="notify_sound_setting_disabled">Hini ebet</string> + <!--Settings Feedback--> + <!--Link Warning--> + <!--Crash Reporter--> + <string name="close">Serriñ</string> + <!--Sign Out--> + <!--Screen Filters & Tapjacking--> + <!--Permission Requests--> +</resources> diff --git a/mailbox-android/src/main/res/values-ca/strings.xml b/mailbox-android/src/main/res/values-ca/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..ba13119f2fc81481a6bb707106e0a2d8911954c9 --- /dev/null +++ b/mailbox-android/src/main/res/values-ca/strings.xml @@ -0,0 +1,413 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Benvingut a Briar</string> + <string name="setup_name_explanation">El vostre sobrenom etiquetarà tot el que publiqueu. Després de crear el compte ja no podreu canviar el sobrenom.</string> + <string name="setup_next">Següent</string> + <string name="setup_password_intro">Establiu una contrasenya</string> + <string name="setup_password_explanation">El compte de Briar s\'emmagatzema xifrat en el vostre dispositiu, no en el núvol. Si oblideu la contrasenya o desinstal·leu Briar no podreu recuperar el vostre compte ni les dades associades.\n\nTrieu una contrasenya llarga que sigui difÃcil d\'endevinar, com ara quatre paraules aleatòries o deu lletres, números i sÃmbols aleatoris.</string> + <string name="setup_doze_title">Connexions en segon pla</string> + <string name="setup_doze_intro">Per rebre missatges Briar necessita estar connectat en segon pla.</string> + <string name="setup_doze_explanation">Per rebre missatges Briar necessita estar connectat en segon pla. Desactiveu les optimitzacions de la bateria per permetre que Briar resti sempre connectat.</string> + <string name="setup_doze_button">Permet connexions</string> + <string name="choose_nickname">Trieu el sobrenom</string> + <string name="choose_password">Trieu la contrasenya</string> + <string name="confirm_password">Confirmeu la contrasenya</string> + <string name="name_too_long">El nom és massa llarg</string> + <string name="password_too_weak">La contrasenya és massa feble</string> + <string name="passwords_do_not_match">Les contrasenyes no coincideixen</string> + <string name="create_account_button">Crea el compte</string> + <string name="more_info">Més informació</string> + <string name="don_t_ask_again">No tornis a preguntar-ho</string> + <string name="setup_huawei_text">Feu un toc sobre el botó següent i assegureu-vos de que Briar consta com a protegit a la pantalla «Aplicacions protegides».</string> + <string name="setup_huawei_button">Protegeix Briar</string> + <string name="setup_huawei_help">Si no afegiu Briar a la llista d\'aplicacions protegides, s\'evitarà que Briar s\'executi en segon pla.</string> + <string name="warning_dozed">%s no s\'ha pogut executar en segon pla</string> + <!--Login--> + <string name="enter_password">Contrasenya</string> + <string name="try_again">La contrasenya és incorrecta, torneu a escriure-la</string> + <string name="sign_in_button">Inicia la sessió</string> + <string name="forgotten_password">No recordo la contrasenya</string> + <string name="dialog_title_lost_password">Contrasenya perduda</string> + <string name="dialog_message_lost_password">El vostre compte de Briar s\'emmagatzema només en el vostre dispositiu i xifrat. La contrasenya, doncs, no es pot restablir. Voleu esborrar el compte i crear-ne un de nou?\n\nAtenció! Si esborreu el compte la vostra identitat, els contactes i els missatges antics es perdran per sempre.</string> + <string name="startup_failed_notification_title">Briar no s\'ha pogut iniciar</string> + <string name="startup_failed_notification_text">Feu un toc per obtenir més informació.</string> + <string name="startup_failed_activity_title">Error iniciant Briar</string> + <string name="startup_failed_db_error">Per alguna raó, la base de dades de Briar s\'ha corromput i no es pot adobar. El vostre compte, les dades i els contactes s\'han perdut. Malauradament, heu de reinstal·lar Briar o bé crear un nou compte triant l\'opció «No recordo la contrasenya» quan se us demani la contrasenya.</string> + <string name="startup_failed_data_too_old_error">El vostre compte fou creat amb una versió antiga de Briar i no es pot obrir amb la versió actual. O bé reinstal·leu la versió antiga o bé creeu un nou compte triant l\'opció «No recordo la contrasenya» quan se us demani la contrasenya.</string> + <string name="startup_failed_data_too_new_error">Aquesta versió de Briar és massa antiga. Actualitzeu Briar a la darrera versió i torneu a provar-ho.</string> + <string name="startup_failed_service_error">Briar no ha pogut engegar un connector imprescindible. La reinstal·lació de Briar acostuma a resoldre aquest problema. Tingueu en compte que si reinstal·leu, perdreu el vostre compte i les dades associades doncs Briar no usa servidors centrals per desar-les.</string> + <plurals name="expiry_warning"> + <item quantity="one">Aquesta és una versió de prova de Briar. El vostre compte expira en %d dia i no es pot renovar.</item> + <item quantity="other">Aquesta és una versió de prova de Briar. El vostre compte caducarà en %d dies i no es podrà renovar.</item> + </plurals> + <string name="expiry_update">S\'ha allargat la data de caducitat d\'aquesta versió de test de Briar. Ara el vostre compte caducarà d\'aquà a %d dies.</string> + <string name="expiry_date_reached">Aquesta versió de Briar ha caducat.\nGrà cies per haver-lo provat!</string> + <string name="download_briar">Per continuar fent servir Briar, descarregueu-vos la versió 1.0.</string> + <string name="create_new_account">Haureu de crear un compte nou, però podeu utilitzar el mateix sobrenom.</string> + <string name="download_briar_button">Descarrega Briar 1.0</string> + <string name="startup_open_database">S\'està desxifrant la base de dades...</string> + <string name="startup_migrate_database">S\'està actualitzant la base de dades...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Obre el calaix de navegació</string> + <string name="nav_drawer_close_description">Tanca el calaix de navegació</string> + <string name="contact_list_button">Contactes</string> + <string name="groups_button">Grups privats</string> + <string name="forums_button">Fòrums</string> + <string name="blogs_button">Blogs</string> + <string name="settings_button">Configuració</string> + <string name="sign_out_button">Tanca la sessió </string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="reminder_notification_title">Heu sortit de Briar</string> + <string name="reminder_notification_text">Toqueu per tornar a iniciar sessió.</string> + <string name="reminder_notification_channel_title">Recordatori d\'inici de sessió de Briar</string> + <string name="reminder_notification_dismiss">Descarta</string> + <string name="ongoing_notification_title">Sessió iniciada</string> + <string name="ongoing_notification_text">Toca per a obrir Briar.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Missatge privat nou.</item> + <item quantity="other">%d missatges privats nous.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Missatge de grup nou.</item> + <item quantity="other">%d missatges de grup nous</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one"> Un nou missatge del fòrum.</item> + <item quantity="other">%d apunts nous al fòrum.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Una nova publicacions al bloc.</item> + <item quantity="other">%d apunts nous al blog.</item> + </plurals> + <!--Misc--> + <string name="now">Ara</string> + <string name="show">Mostra</string> + <string name="hide">Oculta</string> + <string name="ok">D\'acord</string> + <string name="cancel">Cancel·la</string> + <string name="got_it">D\'acord</string> + <string name="delete">Suprimeix</string> + <string name="accept">Accepta</string> + <string name="decline">Refusa</string> + <string name="options">Opcions</string> + <string name="online">En lÃnia</string> + <string name="offline">Fora de lÃnia</string> + <string name="send">Envia</string> + <string name="allow">Permet</string> + <string name="open">Obre</string> + <string name="no_data">Sense dades</string> + <string name="ellipsis">...</string> + <string name="text_too_long">El text és massa llarg</string> + <string name="show_onboarding">Mostra el dià leg d\'ajuda.</string> + <string name="fix">Corregeix</string> + <string name="help">Ajuda</string> + <string name="sorry">Ens sap greu</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">No hi ha cap contacte\n\nFeu un toc sobre la icona + per afegir un nou contacte</string> + <string name="date_no_private_messages">Sense missatges.</string> + <string name="no_private_messages">No hi ha cap missatge</string> + <string name="message_hint">Escriviu un missatge</string> + <string name="delete_contact">Suprimeix aquest contacte</string> + <string name="dialog_title_delete_contact">Confirmeu la supressió del contacte</string> + <string name="dialog_message_delete_contact">Segur que voleu suprimir aquest contacte i tots els missatges que us heu intercanviat?</string> + <string name="contact_deleted_toast">S\'ha suprimit el contacte</string> + <!--Adding Contacts--> + <string name="add_contact_title">Afegiu un contacte</string> + <string name="face_to_face">Heu de coincidir en el mateix lloc amb la persona que voleu afegir com a contacte.\n\nD\'aquesta manera evitareu que algú suplanti les vostres identitats o pugui llegir els vostres missatges en el futur.</string> + <string name="continue_button">Continua</string> + <string name="connection_failed">La connexió ha fallat</string> + <string name="try_again_button">Torna-ho a provar</string> + <string name="waiting_for_contact_to_scan">Esperant que el vostre contacte escanegi i es connecti\u2026</string> + <string name="exchanging_contact_details">Intercanviant els detalls del contacte\u2026</string> + <string name="contact_added_toast">S\'ha afegit el contacte %s</string> + <string name="contact_already_exists">El contacte %s ja existia</string> + <string name="contact_exchange_failed">L\'intercanvi de contactes ha fallat</string> + <string name="qr_code_invalid">El codi QR és invà lid</string> + <string name="qr_code_unsupported">El codi QR que intenteu escanejar pertany a una versió antiga de %s que ja no és compatible.\n\nAssegureu-vos que tothom està executant la darrera versió i torneu a provar-ho.</string> + <string name="camera_error">Error de la cà mera</string> + <string name="connecting_to_device">Connectant-se al dispositiu\u2026</string> + <string name="authenticating_with_device">Autenticant-se amb el dispositiu\u2026</string> + <string name="connection_aborted_local">S\'ha avortat la connexió! Podria ser que algú estigués provant d\'interferir la vostra connexió</string> + <string name="connection_aborted_remote">El vostre contacte ha avortat la connexió! Podria ser que algú estigués provant d\'interferir la vostra connexió</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Presenteu als vostres contactes</string> + <string name="introduction_onboarding_text">Podeu presentar als vostres contactes entre si, de manera que no necessitin trobar-se en persona per a relacionar-se a través de Briar.</string> + <string name="introduction_menu_item">Presenta-li un altre contacte</string> + <string name="introduction_activity_title">Trieu un contacte</string> + <string name="introduction_not_possible">Ja teniu una presentació en marxa entre aquests contactes. Si us plau, primer deixeu que aquesta presentació acabi. Si vós o els contactes presentats sovint esteu desconnectats, la presentació pot trigar temps.</string> + <string name="introduction_message_title">Presentació de contactes</string> + <string name="introduction_message_hint">Afegiu una nota (opcional)</string> + <string name="introduction_button">Presenta\'ls</string> + <string name="introduction_sent">S\'ha enviat la vostra presentació.</string> + <string name="introduction_error">Hi ha hagut un error en presentar els contactes.</string> + <string name="introduction_response_error">Error en respondre a la presentació</string> + <string name="introduction_request_sent">Heu demanat fer les presentacions per a que %1$s i %2$s es coneguin.</string> + <string name="introduction_request_received">%1$s us vol presentar a %2$s. Voleu afegir a%2$s a la vostra llista de contactes?</string> + <string name="introduction_request_exists_received">%1$s us vol presentar a %2$s, però ja teniu a %2$s a la llista de contactes. Atès que segurament %1$s no ho sabia, encara el podeu contestar:</string> + <string name="introduction_request_answered_received">%1$s us vol presentar a %2$s.</string> + <string name="introduction_response_accepted_sent">Heu acceptat conèixer a %1$s.</string> + <string name="introduction_response_accepted_sent_info">Quan %1$s també hagi acceptat la presentació, s\'afegirà als vostres contactes. Això pot trigar un temps.</string> + <string name="introduction_response_declined_sent">Heu refusat conèixer a %1$s.</string> + <string name="introduction_response_accepted_received">%1$s ha acceptat conèixer a %2$s.</string> + <string name="introduction_response_declined_received">%1$s ha refusat conèixer a %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s diu que %2$s ha refusat conèixer-lo.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">S\'ha afegit un nou contacte.</item> + <item quantity="other">S\'han afegit %d nous contactes.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">No hi ha cap grup\n\nFeu un toc sobre la icona + per crear un nou grup, o demaneu als vostres contactes que comparteixin els seus grups amb vós.</string> + <string name="groups_created_by">Creat per %s</string> + <plurals name="messages"> + <item quantity="one">1%d missatge</item> + <item quantity="other">%d missatges</item> + </plurals> + <string name="groups_group_is_empty">Aquest grup està buit.</string> + <string name="groups_group_is_dissolved">Aquest grup s\'ha dissolt.</string> + <string name="groups_remove">Suprimeix</string> + <string name="groups_create_group_title">Creeu un grup privat</string> + <string name="groups_create_group_button">Crea el grup</string> + <string name="groups_create_group_invitation_button">Envia una invitació</string> + <string name="groups_create_group_hint">Trieu un nom per al vostre grup privat</string> + <string name="groups_invitation_sent">S\'ha enviat la invitació del grup</string> + <string name="groups_message_sent">Missatge enviat</string> + <string name="groups_member_list">Llista de membres</string> + <string name="groups_invite_members">Convida a nous membres</string> + <string name="groups_member_created_you">Heu creat el grup</string> + <string name="groups_member_created">%s ha creat el grup</string> + <string name="groups_member_joined_you">Us heu afegit al grup</string> + <string name="groups_member_joined">%s s\'ha afegit al grup</string> + <string name="groups_leave">Abandona el grup</string> + <string name="groups_leave_dialog_title">Confirmeu que abandoneu el grup</string> + <string name="groups_leave_dialog_message">Segur que voleu abandonar aquest grup?</string> + <string name="groups_dissolve">Dissol el grup</string> + <string name="groups_dissolve_dialog_title">Confirmeu la dissolució del grup</string> + <string name="groups_dissolve_dialog_message">Esteu segur que voleu dissoldre aquest grup?\n\nSi el dissoleu cap altre membre podrà continuar la conversa i alguns membres pot ser que no rebin els darrers missatges.</string> + <string name="groups_dissolve_button">Dissol</string> + <string name="groups_dissolved_dialog_title">S\'ha dissolt el grup</string> + <string name="groups_dissolved_dialog_message">El creador del grup l\'ha dissolt.\n\nJa no hi podeu escriure més. És possible que no hagueu rebut algun dels darrers missatges que s\'hi havien escrit.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Convideu a formar part del grup</string> + <string name="groups_invitations_invitation_sent">Heu convidat a %1$s a afegir-se al grup «%2$s».</string> + <string name="groups_invitations_invitation_received">%1$s us ha convidat a afegir-vos al grup «%2$s».</string> + <string name="groups_invitations_joined">Us heu afegit al grup</string> + <string name="groups_invitations_declined">Ha refusat afegir-se al grup</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d invitació a un grup obert</item> + <item quantity="other">%d invitacions a grups oberts</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Heu acceptat afegir-vos al grup per invitació de %s.</string> + <string name="groups_invitations_response_declined_sent">Heu refusat afegir-vos al grup per invitació de %s.</string> + <string name="groups_invitations_response_accepted_received">%s ha decidit afegir-se al grup.</string> + <string name="groups_invitations_response_declined_received">%s ha refusat afegir-se al grup.</string> + <string name="sharing_status_groups">Només el creador del grup pot convidar a nous membres. Tot seguit hi ha la llista dels membres del grup.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Revela els contactes</string> + <string name="groups_reveal_dialog_message">Podeu triar si voleu que es mostrin els contactes a tots els membres actuals i futurs d\'aquest grup.\n\nLa revelació dels contactes fa que la vostra connexió al grup sigui més rà pida i més fiable, ja que podeu comunicar-vos amb els contactes revelats, fins i tot quan el creador del grup està fora de lÃnia.</string> + <string name="groups_reveal_visible">La relació de contactes és visible pel grup</string> + <string name="groups_reveal_visible_revealed_by_us">La relació de contactes és visible pel grup (revelada per vós)</string> + <string name="groups_reveal_visible_revealed_by_contact">La relació de contactes és visible pel grup (revelada per %s)</string> + <string name="groups_reveal_invisible">La relació de contactes no és visible pel grup</string> + <!--Forums--> + <string name="no_forums">No hi ha cap fòrum\n\nFeu un toc sobre la icona + per crear un nou fòrum, o demaneu als vostres contactes que comparteixin els seus fòrums amb vós.</string> + <string name="create_forum_title">Creeu un fòrum</string> + <string name="choose_forum_hint">Trieu un nom per al fòrum</string> + <string name="create_forum_button">Crea el fòrum</string> + <string name="forum_created_toast">S\'ha creat el fòrum</string> + <string name="no_forum_posts">No hi ha cap apunt per mostrar</string> + <string name="no_posts">No hi ha cap apunt</string> + <plurals name="posts"> + <item quantity="one">%d publicacio</item> + <item quantity="other">%d apunts</item> + </plurals> + <string name="forum_new_entry_posted">S\'ha publicat l\'apunt al fòrum</string> + <string name="forum_new_message_hint">Apunt nou</string> + <string name="forum_message_reply_hint">Resposta nova</string> + <string name="btn_reply">Respon</string> + <string name="forum_leave">Abandona el fòrum</string> + <string name="dialog_title_leave_forum">Confirmeu l\'abandonament del Forum</string> + <string name="dialog_message_leave_forum">Segur que voleu abandonar aquest fòrum?\n\nEls contactes amb els que heu compartit aquest fòrum poden deixar de rebre les actualitzacions</string> + <string name="dialog_button_leave">Abandona</string> + <string name="forum_left_toast">Heu abandonat el fòrum</string> + <!--Forum Sharing--> + <string name="forum_share_button">Comparteix el fòrum</string> + <string name="contacts_selected">Contactes seleccionats</string> + <string name="activity_share_toolbar_header">Trieu els contactes</string> + <string name="no_contacts_selector">No hi ha cap contacte\n\nSi us plau, reintenteu-ho després d\'haver afegit algun contacte</string> + <string name="forum_shared_snackbar">Fòrum compartit amb els contactes seleccionats</string> + <string name="forum_share_message">Afegiu una nota (opcional)</string> + <string name="forum_share_error">S\'ha produït un error en compartir aquest fòrum.</string> + <string name="forum_invitation_received">%1$s vol compartir el fòrum «%2$s» amb vós.</string> + <string name="forum_invitation_sent">Heu convidat a%2$s a compartit el fòrum «%1$s».</string> + <string name="forum_invitations_title">Convideu a participar al fòrum</string> + <string name="forum_invitation_exists">Ja heu acceptat una invitació a aquest fòrum.\n\nAcceptar més invitacions farà que la vostra connexió amb el fòrum sigui més rà pida i fiable.</string> + <string name="forum_joined_toast">Us heu afegit al fòrum</string> + <string name="forum_declined_toast">Heu refusat la invitació</string> + <string name="shared_by_format">Compartit per %s</string> + <string name="forum_invitation_already_sharing">Ja l\'esteu compartint</string> + <string name="forum_invitation_response_accepted_sent">Heu acceptat la invitació al fòrum enviada per %s.</string> + <string name="forum_invitation_response_declined_sent">Heu refusat la invitació al fòrum enviada per %s.</string> + <string name="forum_invitation_response_accepted_received">%s ha acceptat la invitació al fòrum.</string> + <string name="forum_invitation_response_declined_received">%s ha rebutjat la invitació al fòrum.</string> + <string name="sharing_status">Estat de la compartició</string> + <string name="sharing_status_forum">Qualsevol membre d\'un fòrum pot compartir-lo amb els seus contactes. Esteu compartint aquest fòrum amb els següents contactes. Poden haver-hi membres del fòrum que no pugueu veure.</string> + <string name="shared_with">Compartit amb %1$d (%2$d en lÃnia)</string> + <plurals name="forums_shared"> + <item quantity="one">%d fòrum compartit per contactes</item> + <item quantity="other">%d fòrums compartits per contactes</item> + </plurals> + <string name="nobody">Ningú</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">No hi ha cap apunt per mostrar</string> + <string name="read_more">llegeix-ne més</string> + <string name="blogs_write_blog_post">Escriviu un apunt al blog</string> + <string name="blogs_write_blog_post_body_hint">Escriviu el vostre apunt al blog</string> + <string name="blogs_publish_blog_post">Publica</string> + <string name="blogs_blog_post_created">S\'ha publicat l\'apunt al blog</string> + <string name="blogs_blog_post_received">S\'ha rebut un nou apunt al blog</string> + <string name="blogs_blog_post_scroll_to">Desplaça</string> + <string name="blogs_feed_empty_state">No hi ha cap apunt\n\nEls apunts dels vostres contactes i dels blogs als que esteu subscrit es mostraran aquÃ\n\nFeu un toc sobre la icona del bolÃgraf per escriure un nou apunt</string> + <string name="blogs_remove_blog">Suprimeix el blog</string> + <string name="blogs_remove_blog_dialog_message">Segur que voleu suprimir aquest blog?\n\nEls apunts publicats s\'esborraran del vostre dispositiu però no del d\'altres persones.\n\nEls contactes amb els que hagueu compartit aquest blog poden deixar de rebre les actualitzacions.</string> + <string name="blogs_remove_blog_ok">Suprimeix</string> + <string name="blogs_blog_removed">S\'ha suprimit el blog</string> + <string name="blogs_reblog_comment_hint">Afegiu una nota (opcional)</string> + <string name="blogs_reblog_button">Rebloga</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Compartiu el blog</string> + <string name="blogs_sharing_error">S\'ha produït un error en compartir aquest blog.</string> + <string name="blogs_sharing_button">Compartiu el blog</string> + <string name="blogs_sharing_snackbar">S\'ha compartit el blog amb els contactes seleccionats</string> + <string name="blogs_sharing_response_accepted_sent">Heu acceptat la invitació al blog de %s.</string> + <string name="blogs_sharing_response_declined_sent">Heu refusat la invitació al blog de %s.</string> + <string name="blogs_sharing_response_accepted_received">%s ha acceptat la invitació al blog.</string> + <string name="blogs_sharing_response_declined_received">%s ha refusat la invitació al blog.</string> + <string name="blogs_sharing_invitation_received">%1$s ha compartit el blog «%2$s» amb vós.</string> + <string name="blogs_sharing_invitation_sent">Heu compartit el blog «%1$s» amb %2$s.</string> + <string name="blogs_sharing_invitations_title">Convideu veure el blog</string> + <string name="blogs_sharing_joined_toast">Us heu subscrit al blog</string> + <string name="blogs_sharing_declined_toast">Heu refusat la invitació</string> + <string name="sharing_status_blog">Qualsevol membre subscrit a un blog el pot compartir amb els seus contactes. Esteu compartint aquest blog amb els següents contactes. Poden haver-hi altres membres subscrits que no veieu.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Subscriure\'s al canal de notÃcies RSS</string> + <string name="blogs_rss_feeds_import_button">Subscriu-me</string> + <string name="blogs_rss_feeds_import_hint">Escriviu l\'URL del canal de notÃcies RSS</string> + <string name="blogs_rss_feeds_import_error">Ens sap greu! S\'ha produït un error en subscriure-us al vostre canal de notÃcies.</string> + <string name="blogs_rss_feeds_manage">Gestiona els canals de notÃcies RSS</string> + <string name="blogs_rss_feeds_manage_imported">Importat:</string> + <string name="blogs_rss_feeds_manage_author">Autor:</string> + <string name="blogs_rss_feeds_manage_updated">Darrera actualització:</string> + <string name="blogs_rss_remove_feed">Suprimeix la subscripció al canal de notÃcies</string> + <string name="blogs_rss_remove_feed_dialog_message">Segur que voleu suprimir la subscripció a aquest canal de notÃcies?\n\nLes notÃcies d\'aquest canal s\'eliminaran del vostre dispositiu però no del d\'altres persones.\n\nEls contactes amb els que hagueu compartit aquest canal poden deixar de rebre les actualitzacions.</string> + <string name="blogs_rss_remove_feed_ok">Suprimeix la subscripció</string> + <string name="blogs_rss_feeds_manage_delete_error">La subscripció al canal de notÃcies no s\'ha pogut suprimir.</string> + <string name="blogs_rss_feeds_manage_empty_state">No hi ha cap notÃcia per mostrar\n\nFeu un toc sobre la icona + per subscriure-us a un canal de notÃcies</string> + <string name="blogs_rss_feeds_manage_error">S\'ha produït un problema en actualitzar els vostres canals de notÃcies. Torneu-ho a provar més endavant.</string> + <!--Settings Display--> + <string name="pref_language_title">Llengua i regió</string> + <string name="pref_language_changed">L\'efecte d\'aquest canvi només l\'apreciareu després de reiniciar Briar. Si us plau, tanqueu la sessió i reinicieu Briar.</string> + <string name="pref_language_default">Valor per defecte del sistema</string> + <string name="display_settings_title">Visualització</string> + <string name="pref_theme_title">Tema</string> + <string name="pref_theme_light">Clar</string> + <string name="pref_theme_dark">Fosc</string> + <string name="pref_theme_auto">Automà tic (segons l\'hora)</string> + <string name="pref_theme_system">Valor per defecte del sistema</string> + <!--Settings Network--> + <string name="network_settings_title">Xarxes</string> + <string name="bluetooth_setting">Connecta via bluetooth</string> + <string name="bluetooth_setting_enabled">Sempre que hi hagi contactes propers</string> + <string name="bluetooth_setting_disabled">Només quan s\'afegeixen contactes</string> + <string name="tor_network_setting">Connecta via Tor</string> + <string name="tor_network_setting_never">Mai</string> + <string name="tor_network_setting_wifi">Només quan s\'utilitzi WiFi</string> + <string name="tor_network_setting_always">Quan s\'utilitzi WiFi o les dades mòbils</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Seguretat</string> + <string name="change_password">Canvia la contrasenya</string> + <string name="current_password">Contrassenya actual</string> + <string name="choose_new_password">Contrassenya nova</string> + <string name="confirm_new_password">Confirmació de la contrassenya nova</string> + <string name="password_changed">Heu canviat la contrasenya.</string> + <string name="panic_setting">Configuració del botó del pà nic</string> + <string name="panic_setting_title">Botó de pà nic</string> + <string name="panic_setting_hint">Configureu com reaccionarà Briar quan feu servir el botó de pà nic</string> + <string name="panic_app_setting_title">Aplicació de botó de pà nic</string> + <string name="unknown_app">una aplicació desconeguda</string> + <string name="panic_app_setting_summary">No s\'ha definit cap aplicació</string> + <string name="panic_app_setting_none">Cap</string> + <string name="dialog_title_connect_panic_app">Confirmeu l\'aplicació de pà nic</string> + <string name="dialog_message_connect_panic_app">Segur que voleu permetre que %1$s desencadeni accions destructives a conseqüència del botó de pà nic?</string> + <string name="panic_setting_signout_title">Tanca la sessió</string> + <string name="panic_setting_signout_summary">Tanca la sessió de Briar si es prem un botó de pà nic</string> + <string name="purge_setting_title">Esborreu el compte</string> + <string name="purge_setting_summary">Suprimeix el compte de Briar si es prem el botó de pà nic. Atenció: En aquest cas, s\'eliminarien permanentment les vostres identitats, contactes i missatges</string> + <string name="uninstall_setting_title">Desinstal·leu Briar</string> + <string name="uninstall_setting_summary">Això requeria la confirmació manual malgrat ser en una situació de pà nic</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Notificacions</string> + <string name="notify_sign_in_title">Recordeu-me que iniciï sessió</string> + <string name="notify_sign_in_summary">Mostra un recordatori quan s\'inicia el telèfon o s\'ha actualitzat l\'aplicació</string> + <string name="notify_private_messages_setting_title">Missatges privats</string> + <string name="notify_private_messages_setting_summary">Mostra avisos pels missatges privats</string> + <string name="notify_private_messages_setting_summary_26">Configura els avisos pels missatges privats</string> + <string name="notify_group_messages_setting_title">Missatges dels grups</string> + <string name="notify_group_messages_setting_summary">Mostra avisos pels missatges dels grups</string> + <string name="notify_group_messages_setting_summary_26">Configura els avisos pels missatges dels grups</string> + <string name="notify_forum_posts_setting_title">Apunts del fòrum</string> + <string name="notify_forum_posts_setting_summary">Mostra avisos pels apunts del fòrum</string> + <string name="notify_forum_posts_setting_summary_26">Configura els avisos pels apunts dels fòrums</string> + <string name="notify_blog_posts_setting_title">Apunts als blogs</string> + <string name="notify_blog_posts_setting_summary">Mostra avisos pels apunts als blogs</string> + <string name="notify_blog_posts_setting_summary_26">Configura els avisos pels apunts als blogs</string> + <string name="notify_vibration_setting">Vibra</string> + <string name="notify_lock_screen_setting_title">Bloca la pantalla</string> + <string name="notify_lock_screen_setting_summary">Mostra les notificacions a la pantalla de bloqueig</string> + <string name="notify_sound_setting">So</string> + <string name="notify_sound_setting_default">So d\'avÃs predeterminat</string> + <string name="notify_sound_setting_disabled">Cap</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> + <!--Settings Feedback--> + <string name="feedback_settings_title">Comentaris</string> + <string name="send_feedback">Envieu comentaris</string> + <!--Link Warning--> + <string name="link_warning_title">AvÃs d\'enllaç</string> + <string name="link_warning_intro">L\'enllaç s\'obrirà amb una aplicació externa.</string> + <string name="link_warning_text">Això podria usar-se per a identificar-vos. Penseu si us en refieu prou de la persona que us ha enviat l\'enllaç. Avalueu si us convindria obrir-lo amb un navegador que faciliti l\'anonimat com Orfox.</string> + <string name="link_warning_open_link">Obre l\'enllaç</string> + <!--Crash Reporter--> + <string name="crash_report_title">Informe de fallida de Briar</string> + <string name="briar_crashed">Ens sap greu, Briar s\'ha tancat inesperadament.</string> + <string name="not_your_fault">Això no és culpa vostra.</string> + <string name="please_send_report">Ajudi\'ns a construir un Briar millor enviant-nos un informe de fallida.</string> + <string name="report_is_encrypted">Us garantim que l\'informe es xifra i s\'envia de manera segura.</string> + <string name="feedback_title">Comentaris</string> + <string name="describe_crash">Descriviu el que hi ha succeït (opcional)</string> + <string name="enter_feedback">Escriviu els vostres comentaris</string> + <string name="optional_contact_email">La vostra adreça de correu (opcional)</string> + <string name="include_debug_report_crash">Inclou dades anònimes sobre la fallida</string> + <string name="include_debug_report_feedback">Inclou dades anònimes sobre el dispositiu</string> + <string name="could_not_load_report_data">No s\'han pogut carregar les dades de l\'informe.</string> + <string name="send_report">Envia l\'informe</string> + <string name="close">Tanca</string> + <string name="dev_report_saved">S\'ha desat l\'informe. Se us enviarà la propera vegada que inicieu sessió a Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">S\'està tancant la sessió de Briar...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">S\'ha detectat superposició de la pantalla</string> + <string name="screen_filter_body">Una altra aplicació es troba damunt de Briar. Per protegir la vostra seguretat, Briar no respondrà a les pulsacions quan una altra aplicació s\'hi hagi sobreposat.\n\nLes següents aplicacions poden estar sobreposades a Briar:\n\n%1$s</string> + <string name="screen_filter_allow">Permet que aquestes aplicacions se sobreposin a Briar</string> + <!--Permission Requests--> + <string name="permission_camera_title">PermÃs de la cà mera</string> + <string name="permission_camera_request_body">Per escanejar el codi QR, Briar necessita accedir a la cà mera.</string> + <string name="permission_camera_denied_body">Heu denegat l\'accés a la cà mera però per afegir contactes cal utilitzar la cà mera.\n\nRecomanem que permeteu l\'accés a la cà mera.</string> + <string name="permission_camera_denied_toast">No s\'ha concedit el permÃs per accedir a la cà mera</string> + <string name="qr_code">Codi QR</string> + <string name="show_qr_code_fullscreen">Mostra el codi QR a pantalla completa</string> +</resources> diff --git a/mailbox-android/src/main/res/values-cs/strings.xml b/mailbox-android/src/main/res/values-cs/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..16bcaf2a76f8b5036f5c523b5764a7e1f32a453b --- /dev/null +++ b/mailbox-android/src/main/res/values-cs/strings.xml @@ -0,0 +1,413 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">VÃtejte v Briar</string> + <string name="setup_name_explanation">VaÅ¡e uživatelské jméno bude zobrazeno u jakéhokoli obsahu, který zveÅ™ejnÃte. Následná zmÄ›na již nebude možná.</string> + <string name="setup_next">DalÅ¡Ã</string> + <string name="setup_password_intro">Zvolte heslo</string> + <string name="setup_password_explanation">Váš Briar úÄet je Å¡ifrován a uložen ve vaÅ¡em zaÅ™ÃzenÃ, nikoli v cloudu. Pokud zapomenete své heslo nebo odinstalujete Briar, obnovit Váš úÄet již nebude možné.\n\nZvolte si dlouhé heslo, které je těžké uhádnout, napÅ™Ãklad ÄtyÅ™i náhodné fráze nebo deset náhodných pÃsmen, ÄÃsel a symbolů.</string> + <string name="setup_doze_title">PÅ™ipojenà na pozadÃ</string> + <string name="setup_doze_intro">Pro pÅ™Ãjem zpráv je nutné, aby byl Briar stále spuÅ¡tÄ›n na pozadÃ.</string> + <string name="setup_doze_explanation">Pro pÅ™Ãjem zpráv je nutné, aby byl Briar spuÅ¡tÄ›n na pozadÃ. ProsÃm, vypnÄ›te optimalizaci baterie, jedinÄ› tak bude Briar stále pÅ™ipojen.</string> + <string name="setup_doze_button">Povolit pÅ™ipojenÃ</string> + <string name="choose_nickname">Zvolte si uživatelské jméno</string> + <string name="choose_password">Zvolte si heslo</string> + <string name="confirm_password">PotvrÄte své heslo</string> + <string name="name_too_long">Jméno je pÅ™ÃliÅ¡ dlouhé</string> + <string name="password_too_weak">Heslo je pÅ™ÃliÅ¡ slabé</string> + <string name="passwords_do_not_match">Zadaná hesla se neshodujÃ</string> + <string name="create_account_button">VytvoÅ™it úÄet</string> + <string name="more_info">Dalšà informace</string> + <string name="don_t_ask_again">Znovu se již neptat</string> + <string name="setup_huawei_text">KliknÄ›te na nÞe uvedené tlaÄÃtko a ujistÄ›te se, že byl Briar zaÅ™azen mezi \"ChránÄ›né aplikace\".</string> + <string name="setup_huawei_button">Chránit Briar</string> + <string name="setup_huawei_help">Pokud nebyl Briar pÅ™idán mezi chránÄ›né aplikace, nebude ho možné spustit na pozadÃ.</string> + <string name="warning_dozed">%s nebylo možné spustit na pozadÃ</string> + <!--Login--> + <string name="enter_password">Heslo</string> + <string name="try_again">Zadali jste Å¡patné heslo, zkuste to znovu</string> + <string name="sign_in_button">PÅ™ihlásit se</string> + <string name="forgotten_password">Nepamatuji si své heslo</string> + <string name="dialog_title_lost_password">Ztracené heslo</string> + <string name="dialog_message_lost_password">Váš Briar úÄet je Å¡ifrován a uložen ve vaÅ¡em zaÅ™ÃzenÃ, nikoli v cloudu, z tohoto důvodu nenà možné obnovit VaÅ¡e heslo. Chcete odstranit svůj úÄet a zaÄÃt znovu?\n\nUpozornÄ›nÃ: VaÅ¡e identita, kontakty a zprávy budou permanentnÄ› ztraceny.</string> + <string name="startup_failed_notification_title">Briar nemohl být spuÅ¡tÄ›n</string> + <string name="startup_failed_notification_text">KliknÄ›te pro vÃce informacÃ</string> + <string name="startup_failed_activity_title">SpuÅ¡tÄ›nà Briar selhalo.</string> + <string name="startup_failed_db_error">Z nÄ›jakého důvodu je vaÅ¡e databáze Briar poÅ¡kozena. Váš úÄet, vaÅ¡e data a vÅ¡echny vaÅ¡e kontakty budou ztraceny. Bohužel musÃte pÅ™einstalovat Briar nebo nastavit nový úÄet výbÄ›rem položky \'ZapomnÄ›l jsem heslo\' v řádku zadat heslo.</string> + <string name="startup_failed_data_too_old_error">Váš úÄet byl vytvoÅ™en se starou verzà aplikace a nemůže být otevÅ™en v této verzi. MusÃte pÅ™einstalovat starou verzi nebo nastavit nový úÄet vybránÃm \'ZapomnÄ›l jsem své heslo v nabÃdce hesla.</string> + <string name="startup_failed_data_too_new_error">Tato verze aplikace je zastaralá. ProsÃm aktualizujte na nejvyššà verzi a zkuste to znovu.</string> + <string name="startup_failed_service_error">Briar nemohl spustit vyžadovaný plugin. Tento problém vyÅ™ešà pÅ™einstalovánà Briar. MÄ›jte prosÃm na vÄ›domÃ, že pÅ™einstalovánÃm ztratÃte veÅ¡kerá data pro váš úÄet, protože Briar nepoužÃvá centralizované ukládánà vaÅ¡ich dat na serverech.</string> + <plurals name="expiry_warning"> + <item quantity="one">Toto je testovacà verze Briar. Váš úÄet a jeho platnost vypršà po %d dnech a nenà možné ho obnovit.</item> + <item quantity="few">Toto je testovacà verze Briar. Váš úÄet a jeho platnost vypršà po %d dnech a nenà možné ho obnovit.</item> + <item quantity="many">Toto je testovacà verze Briar. Váš úÄet a jeho platnost vypršà po %d dnech a nenà možné ho obnovit.</item> + <item quantity="other">Toto je testovacà verze Briar. Váš úÄet a jeho platnost vypršà po %d dnech a nenà možné ho obnovit.</item> + </plurals> + <string name="expiry_update">Datum expirace pro testovánà bylo prodlouženo. Váš úÄet nynà bude expirovat po %d dnech.</string> + <string name="expiry_date_reached">Platnost tohoto software vyprÅ¡ela.\nDÄ›kujeme za jeho otestovánÃ!</string> + <string name="download_briar">Pro pokraÄovánà použÃvánà Briar, stáhnÄ›te si prosÃm verzi 1.0.</string> + <string name="create_new_account">Budete potÅ™ebovat vytvoÅ™it nový úÄet, ale můžete použÃt stejné uživatelské jméno.</string> + <string name="download_briar_button">Stáhnout Briar 1.0</string> + <string name="startup_open_database">DeÅ¡ifrovánà databáze...</string> + <string name="startup_migrate_database">Aktualizovánà databáze...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">OtevÅ™Ãt navigaÄnà liÅ¡tu</string> + <string name="nav_drawer_close_description">ZavÅ™Ãt navigaÄnà liÅ¡tu</string> + <string name="contact_list_button">Kontakty</string> + <string name="groups_button">Soukromá skupina</string> + <string name="forums_button">Fóra</string> + <string name="blogs_button">Blogy</string> + <string name="settings_button">NastavenÃ</string> + <string name="sign_out_button">Odhlásit se</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="ongoing_notification_title">PÅ™ihlásit se do Briar</string> + <string name="ongoing_notification_text">KliknutÃm otevÅ™Ãt Briar</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Nová soukromá zpráva</item> + <item quantity="few">%d nových soukromých zpráv.</item> + <item quantity="many">%d nových soukromých zpráv.</item> + <item quantity="other">%d nových soukromých zpráv.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Nová zpráva ve skupinÄ›.</item> + <item quantity="few">%d nových zpráv ve skupinÄ›. </item> + <item quantity="many">%d nových zpráv ve skupinÄ›.</item> + <item quantity="other">%d nových zpráv ve skupinÄ›.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Nový pÅ™ÃspÄ›vek ve fóru.</item> + <item quantity="few">%dnových pÅ™ÃspÄ›vků ve fóru. </item> + <item quantity="many">%d nových pÅ™ÃspÄ›vků ve fóru.</item> + <item quantity="other">%d nových pÅ™ÃspÄ›vků ve fóru.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Nový pÅ™ÃspÄ›vek v blogu.</item> + <item quantity="few">%dnových pÅ™ÃspÄ›vků v blogu. </item> + <item quantity="many">%d nových pÅ™ÃspÄ›vků v blogu.</item> + <item quantity="other">%d nových pÅ™ÃspÄ›vků v blogu.</item> + </plurals> + <!--Misc--> + <string name="now">nynÃ</string> + <string name="show">Ukázat</string> + <string name="hide">Skrýt</string> + <string name="ok">Ok</string> + <string name="cancel">ZruÅ¡it</string> + <string name="got_it">Chápu</string> + <string name="delete">Odstranit</string> + <string name="accept">PÅ™ijmout</string> + <string name="decline">OdmÃtnout</string> + <string name="options">Možnosti</string> + <string name="online">Online</string> + <string name="offline">Offline</string> + <string name="send">Odeslat</string> + <string name="allow">Povolit</string> + <string name="open">OtevÅ™Ãt</string> + <string name="no_data">Žádná data</string> + <string name="ellipsis">...</string> + <string name="text_too_long">Zadaný text je pÅ™ÃliÅ¡ dlouhý</string> + <string name="show_onboarding">Zobrazit dialog pro pomoc</string> + <string name="fix">Opravit</string> + <string name="help">Pomoc</string> + <string name="sorry">Promiňte</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Žádné kontakty k zobrazenÃ\n\nKliknÄ›te na ikonu + kde můžete pÅ™idat kontakt</string> + <string name="date_no_private_messages">Žádné zprávy</string> + <string name="no_private_messages">Žádné zprávy k zobrazenÃ</string> + <string name="message_hint">Psát zprávu</string> + <string name="delete_contact">Odstranit kontakt</string> + <string name="dialog_title_delete_contact">Potvrdit odstranÄ›nà kontaktu</string> + <string name="dialog_message_delete_contact">Jste si jisti, že chcete odstranit kontakt a vÅ¡echny souvisejÃcà zprávy s tÃmto kontaktem?</string> + <string name="contact_deleted_toast">Kontakt odstranÄ›n</string> + <!--Adding Contacts--> + <string name="add_contact_title">PÅ™idat kontakt</string> + <string name="face_to_face">MusÃte se osobnÄ› setkat s osobou, kterou si chcete pÅ™idat jako kontakt.\n\nToto v budoucnu zabránà komukoli, aby se za vás vydával nebo Äetl VaÅ¡e zprávy.</string> + <string name="continue_button">PokraÄovat</string> + <string name="connection_failed">Chyba spojenÃ</string> + <string name="try_again_button">Zkusit znovu</string> + <string name="waiting_for_contact_to_scan">ÄŒekánà na scan kontaktu a spojenÃ\u2026</string> + <string name="exchanging_contact_details">VýmÄ›na detailů kontaktu\u2026</string> + <string name="contact_added_toast">Kontakt byl pÅ™idán: %s</string> + <string name="contact_already_exists">Kontakt %s již existuje</string> + <string name="contact_exchange_failed">Chyba výmÄ›ny kontaktu</string> + <string name="qr_code_invalid">QR kód je neplatný</string> + <string name="qr_code_unsupported">QR kód, který se pokouÅ¡Ãte skenovat, patřà k staršà verzi %s, která již nenà podporována.\n\nJe potÅ™ebné, aby oba kontakty použÃvali nejnovÄ›jšà verzi a následnÄ› to zkuste znovu.</string> + <string name="camera_error">Vyskytla se chyba fotoaparátu</string> + <string name="connecting_to_device">PÅ™ipojovánà k zaÅ™ÃzenÃ\u2026</string> + <string name="authenticating_with_device">Ověřovánà se zaÅ™ÃzenÃm\u2026</string> + <string name="connection_aborted_local">Spojenà bylo pÅ™eruÅ¡eno! To může znamenat, že se nÄ›kdo pokoušà zasáhnout do vaÅ¡eho spojenÃ.</string> + <string name="connection_aborted_remote">PÅ™ipojenà bylo pÅ™eruÅ¡eno vaÅ¡Ãm kontaktem! To může znamenat, že se nÄ›kdo pokoušà zasahovat do vaÅ¡eho pÅ™ipojenÃ</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Uvést vaÅ¡e kontakty</string> + <string name="introduction_onboarding_text">Můžete si navzájem pÅ™edstavit své kontakty, takže se následnÄ› nemusejà setkat osobnÄ›, aby se pÅ™ipojili k Briar.</string> + <string name="introduction_menu_item">VytvoÅ™it pozvánÃ</string> + <string name="introduction_activity_title">Vybrat kontakt</string> + <string name="introduction_message_title">Pozvat kontakty</string> + <string name="introduction_message_hint">PÅ™idat zprávu (volitelné)</string> + <string name="introduction_button">VytvoÅ™it pozvánÃ</string> + <string name="introduction_sent">VaÅ¡e pozvánà bylo odesláno.</string> + <string name="introduction_error">Vyskytla se chyba pÅ™i tvorbÄ› pozvánÃ.</string> + <string name="introduction_response_error">Chyba pÅ™i odpovÄ›di na pozvánÃ.</string> + <string name="introduction_request_sent">Požádali jste o pozvánà %1$s do %2$s.</string> + <string name="introduction_request_received">%1$s vás požádal o uvedenà do %2$s. Chcete pÅ™idat %2$s mezi vaÅ¡e kontakty?</string> + <string name="introduction_request_exists_received">%1$s vás požádal o pÅ™edstavenà s %2$s, ale %2$s je již ve vaÅ¡ich kontaktech. PravdÄ›podobnÄ› to %1$s nevÃ, ale stále můžete odpovÄ›dÄ›t:</string> + <string name="introduction_request_answered_received">%1$s vás žádá o pozvánà do %2$s.</string> + <string name="introduction_response_accepted_sent">PÅ™ijali jste pozvánà do %1$s.</string> + <string name="introduction_response_declined_sent">OdmÃtli jste pÅ™edstavenà do %1$s.</string> + <string name="introduction_response_accepted_received">%1$s pÅ™ijal pozvánà do %2$s.</string> + <string name="introduction_response_declined_received">%1$s odmÃtl pozvánà do %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s Å™ekl, že %2$s odmÃtl pozvánÃ.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Nový kontakt byl pÅ™idán.</item> + <item quantity="few">Bylo pÅ™idáno %d nových kontaktů.</item> + <item quantity="many">%d nových kontaktů bylo pÅ™idáno.</item> + <item quantity="other">%d nových kontaktů bylo pÅ™idáno.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">Žádné skupiny k zobrazenÃ\n\nKliknÄ›te na ikonu + kde můžete vytvoÅ™it skupinu, nebo požádejte své kontakty o sdÃlenà skupin s vámi</string> + <string name="groups_created_by">VytvoÅ™eno %s</string> + <plurals name="messages"> + <item quantity="one">%d zpráva</item> + <item quantity="few">%d zpráv</item> + <item quantity="many">%d zpráv</item> + <item quantity="other">%d zpráv</item> + </plurals> + <string name="groups_group_is_empty">Tato skupina je prázdná</string> + <string name="groups_group_is_dissolved">Tato skupina byla rozpuÅ¡tÄ›na</string> + <string name="groups_remove">Odstranit</string> + <string name="groups_create_group_title">VytvoÅ™it soukromou skupinu</string> + <string name="groups_create_group_button">VytvoÅ™it skupinu</string> + <string name="groups_create_group_invitation_button">Poslat pozvánku</string> + <string name="groups_create_group_hint">Vyberte jméno pro vaÅ¡i soukromou skupinu</string> + <string name="groups_invitation_sent">Skupinová pozvánka byla odeslána</string> + <string name="groups_message_sent">Zpráva odeslána</string> + <string name="groups_member_list">Seznam Älenů</string> + <string name="groups_invite_members">Pozvat Äleny</string> + <string name="groups_member_created_you">VytvoÅ™ili jste skupinu</string> + <string name="groups_member_created">%s vytvoÅ™il skupinu</string> + <string name="groups_member_joined_you">Vstoupili jste do skupiny</string> + <string name="groups_member_joined">%s se pÅ™ipojil ke skupinÄ›</string> + <string name="groups_leave">Opustit skupinu</string> + <string name="groups_leave_dialog_title">Potvrdit opuÅ¡tÄ›nà skupiny</string> + <string name="groups_leave_dialog_message">Jste si jisti, že chcete opustit tuto skupinu?</string> + <string name="groups_dissolve">Rozpustit skupinu</string> + <string name="groups_dissolve_dialog_title">Potvrzenà rozpuÅ¡tÄ›nà skupiny</string> + <string name="groups_dissolve_dialog_message">Jste si jisti, že chcete tuto skupinu rozpustit?\n\nVÅ¡ichni Älenové nebudou moci pokraÄovat v konverzacÃch a taktéž nebudou schopni pÅ™ijÃmat zprávy.</string> + <string name="groups_dissolve_button">RozpuÅ¡tÄ›nÃ</string> + <string name="groups_dissolved_dialog_title">Skupina byla rozpuÅ¡tÄ›na</string> + <string name="groups_dissolved_dialog_message">Zakladatel tuto skupinu rozpustil.\n\nV této skupinÄ› již nemůžeÅ¡ psát zprávy a taktéž pÅ™ijÃmat pÅ™ÃspÄ›vky, které byly napsány.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Skupinové pozvánky</string> + <string name="groups_invitations_invitation_sent">Pozvali jste %1$s k pÅ™ipojenà ke skupinÄ› \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s vás pozval, abyste se pÅ™ipojili ke skupinÄ› \"%2$s\".</string> + <string name="groups_invitations_joined">PÅ™ipojenà ke skupinÄ›</string> + <string name="groups_invitations_declined">Pozvánà do skupiny bylo odmÃtnuto</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d otevÅ™ená skupinová pozvánka</item> + <item quantity="few">%d otevÅ™ených skupinových pozvánek</item> + <item quantity="many">%d otevÅ™ených skupinových pozvánek</item> + <item quantity="other">%d otevÅ™ených skupinových pozvánek</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">PÅ™ijali jste pozvánà do skupiny od %s.</string> + <string name="groups_invitations_response_declined_sent">OdmÃtli jste pozvánà do skupiny od %s.</string> + <string name="groups_invitations_response_accepted_received">%s pÅ™ijatých pozvánà ke skupinÄ›.</string> + <string name="groups_invitations_response_declined_received">%s odmÃtnutých pozvánà ke skupinÄ›.</string> + <string name="sharing_status_groups">Pouze zakladatel může pozvat nové Äleny do skupiny. NÞe jsou vÅ¡ichni souÄasnà Älenové skupiny.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Odkrýt kontakty</string> + <string name="groups_reveal_dialog_message">Můžete si vybrat, zda chcete své kontakty odhalit vÅ¡em souÄasným i budoucÃm Älenům této skupiny.\n\nPÅ™idánÃm kontaktů je vaÅ¡e pÅ™ipojenà ke skupinÄ› rychlejšà a spolehlivÄ›jÅ¡Ã, protože můžete komunikovat s odhalenými kontakty i když je tvůrce skupiny offline.</string> + <string name="groups_reveal_visible">Vztah s kontaktem je viditelný ve skupinÄ›</string> + <string name="groups_reveal_visible_revealed_by_us">Vztah s kontaktem je viditelný ve skupinÄ› (Tebou odkrytý)</string> + <string name="groups_reveal_visible_revealed_by_contact">Vztah s kontaktem je viditelný ve skupinÄ› (byl odkrytý %s)</string> + <string name="groups_reveal_invisible">Vztah s kontaktem nenà viditelný ve skupinÄ›</string> + <!--Forums--> + <string name="no_forums">Žádná fóra k zobrazenÃ\n\nKliknÄ›te na ikonu + pro vytvoÅ™enà fóra, nebo požádejte své kontakty pro sdÃlenà fóra s vámi</string> + <string name="create_forum_title">VytvoÅ™it fórum</string> + <string name="choose_forum_hint">Vybrat jméno pro vaÅ¡e fórum</string> + <string name="create_forum_button">VytvoÅ™it fórum</string> + <string name="forum_created_toast">Fórum vytvoÅ™eno</string> + <string name="no_forum_posts">Žádné pÅ™ÃspÄ›vky k zobrazenÃ</string> + <string name="no_posts">Žádné pÅ™ÃspÄ›vky</string> + <plurals name="posts"> + <item quantity="one">%d pÅ™ÃspÄ›vek</item> + <item quantity="few">%d pÅ™ÃspÄ›vků</item> + <item quantity="many">%d pÅ™ÃspÄ›vků</item> + <item quantity="other">%d pÅ™ÃspÄ›vků</item> + </plurals> + <string name="forum_message_reply_hint">Nová odpovÄ›Ä</string> + <string name="btn_reply">OdpovÄ›Ä</string> + <string name="forum_leave">Opustit fórum</string> + <string name="dialog_title_leave_forum">Potvrdit opuÅ¡tÄ›nà fóra</string> + <string name="dialog_message_leave_forum">Opravdu chcete opustit toto fórum?\n\nKaždý kontakt, se kterým jste sdÃleli toto fórum, může pÅ™estat pÅ™ijÃmat aktualizace.</string> + <string name="dialog_button_leave">Opustit</string> + <string name="forum_left_toast">Opustit fórum</string> + <!--Forum Sharing--> + <string name="forum_share_button">SdÃlet fórum</string> + <string name="contacts_selected">Zvolené kontakty</string> + <string name="activity_share_toolbar_header">Zvolit kontakty</string> + <string name="no_contacts_selector">Žádné kontakty k zobrazenà \n\nProsÃm, vraÅ¥te se zpÄ›t po pÅ™idánà kontaktu</string> + <string name="forum_shared_snackbar">Fórum sdÃleno s vybranými kontakty</string> + <string name="forum_share_message">PÅ™idat zprávu (volitelné)</string> + <string name="forum_share_error">PÅ™i sdÃlenà tohoto fóra nastala chyba.</string> + <string name="forum_invitation_received">%1$s sdÃlel fórum \"%2$s\" s vámi.</string> + <string name="forum_invitation_sent">SdÃleli jste fórum \"%1$s\" s %2$s.</string> + <string name="forum_invitations_title">Pozvánà do fóra</string> + <string name="forum_joined_toast">Vstup do fóra</string> + <string name="forum_declined_toast">Pozvánà zamÃtnuto</string> + <string name="shared_by_format">SdÃleno %s</string> + <string name="forum_invitation_already_sharing">Již sdÃlené</string> + <string name="forum_invitation_response_accepted_sent">PÅ™ijali jste pozvánà do fóra od %s.</string> + <string name="forum_invitation_response_declined_sent">OdmÃtli jste pozvánà do fóra od %s.</string> + <string name="forum_invitation_response_accepted_received">%s pÅ™ijatých pozvánà do fóra.</string> + <string name="forum_invitation_response_declined_received">%s odmÃtnutých pozvánà do fóra.</string> + <string name="sharing_status">SdÃlet status</string> + <string name="sharing_status_forum">Každý Älen fóra to může sdÃlet se svými kontakty. Vy sdÃlÃte toto fórum s následujÃcÃmi kontakty. Mohou existovat i dalšà Älenové, které nevidÃte.</string> + <string name="shared_with">SdÃleno s %1$d (%2$d online)</string> + <plurals name="forums_shared"> + <item quantity="one">%d fórum sdÃleno kontakty</item> + <item quantity="few">%d fór sdÃleno kontakty </item> + <item quantity="many">%d fór sdÃleno kontakty</item> + <item quantity="other">%d fór sdÃleno kontakty</item> + </plurals> + <string name="nobody">Nikdo</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Žádné pÅ™ÃspÄ›vky k zobrazenÃ</string> + <string name="read_more">ÄŒÃst dál</string> + <string name="blogs_write_blog_post">Napsat pÅ™ÃspÄ›vek do Blogu</string> + <string name="blogs_write_blog_post_body_hint">NapiÅ¡te svůj blog pÅ™ÃspÄ›vek</string> + <string name="blogs_publish_blog_post">Publikovat</string> + <string name="blogs_blog_post_created">PÅ™ÃspÄ›vek do blogu byl vytvoÅ™en</string> + <string name="blogs_blog_post_received">PÅ™ijatý nový pÅ™ÃspÄ›vek v blogu.</string> + <string name="blogs_blog_post_scroll_to">PÅ™ejÃt na</string> + <string name="blogs_remove_blog">Odstranit blog</string> + <string name="blogs_remove_blog_ok">Odstranit</string> + <string name="blogs_blog_removed">Blog odstranÄ›n</string> + <string name="blogs_reblog_comment_hint">PÅ™idat komentář (volitelné)</string> + <string name="blogs_reblog_button">Reblog</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">SdÃlet blog</string> + <string name="blogs_sharing_error">Vyskytla se chyba pÅ™i sdÃlenà tohoto blogu.</string> + <string name="blogs_sharing_button">SdÃlet blog</string> + <string name="blogs_sharing_snackbar">Blog sdÃlen s vybranými kontakty.</string> + <string name="blogs_sharing_response_accepted_sent">PÅ™ijali jste pozvánà do blogu od %s.</string> + <string name="blogs_sharing_response_declined_sent">OdmÃtli jste pozvánà do blogu od %s.</string> + <string name="blogs_sharing_response_accepted_received">%s schválených pozvánà do blogu.</string> + <string name="blogs_sharing_response_declined_received">%s odmÃtnutých pozvánà do blogu.</string> + <string name="blogs_sharing_invitation_received">%1$s sdÃlel blog \"%2$s\" s vámi.</string> + <string name="blogs_sharing_invitation_sent">SdÃleli jste blog \"%1$s\" s %2$s.</string> + <string name="blogs_sharing_invitations_title">Pozvánky do blogu</string> + <string name="blogs_sharing_joined_toast">PÅ™ihlásit se k blogu</string> + <string name="blogs_sharing_declined_toast">Pozvánà zamÃtnuto</string> + <string name="sharing_status_blog">Kdokoli, kdo odebÃrá blog ho může sdÃlet se svými kontakty. SdÃlÃte tento blog s následujÃcÃmi kontakty. Mohou existovat i jinà úÄastnÃci, které nevidÃte.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Import RSS kanálu</string> + <string name="blogs_rss_feeds_import_button">Import</string> + <string name="blogs_rss_feeds_import_hint">Zadejte URL adresu RSS kanálu</string> + <string name="blogs_rss_feeds_import_error">Omlouváme se! Vyskytla se chyba pÅ™i importu vaÅ¡eho kanálu.</string> + <string name="blogs_rss_feeds_manage">Správa RSS kanálů</string> + <string name="blogs_rss_feeds_manage_imported">Importováno:</string> + <string name="blogs_rss_feeds_manage_author">Autor:</string> + <string name="blogs_rss_feeds_manage_updated">Naposledy aktualizováno:</string> + <string name="blogs_rss_remove_feed">Odstranit kanál</string> + <string name="blogs_rss_remove_feed_ok">Odstranit</string> + <string name="blogs_rss_feeds_manage_delete_error">Kanál nemohl být odstranÄ›n !</string> + <string name="blogs_rss_feeds_manage_empty_state">Žádné RSS kanály k zobrazenÃ\n\nKliknÄ›te na ikonu + pro nahránà pÅ™ÃspÄ›vků</string> + <string name="blogs_rss_feeds_manage_error">Vyskytl se problém s naÄtenÃm vaÅ¡eho kanálu pÅ™ÃspÄ›vků. Zkuste to prosÃm pozdÄ›ji.</string> + <!--Settings Display--> + <string name="pref_language_title">Jazyk & region</string> + <string name="pref_language_changed">Toto nastavenà bude mÃt efekt když vykonáre restart svého Briar. ProsÃm odhlaste se a restartujte Briar.</string> + <string name="pref_language_default">Výchozà systému</string> + <string name="display_settings_title">Zobrazit</string> + <string name="pref_theme_title">Vzhled</string> + <string name="pref_theme_light">SvÄ›tlý</string> + <string name="pref_theme_dark">Temný</string> + <!--Settings Network--> + <string name="network_settings_title">SÃtÄ›</string> + <string name="bluetooth_setting">Spojenà pÅ™es Bluetooth</string> + <string name="bluetooth_setting_enabled">Vždy, když jsou kontakty v blÃzkosti</string> + <string name="bluetooth_setting_disabled">Jen když pÅ™idáte kontakty</string> + <string name="tor_network_setting">Spojenà pÅ™es Tor</string> + <string name="tor_network_setting_never">Nikdy</string> + <string name="tor_network_setting_wifi">Jen když použÃváte Wi-Fi</string> + <string name="tor_network_setting_always">Když použÃváte Wi-Fi nebo mobilnà data</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">ZabezpeÄenÃ</string> + <string name="change_password">ZmÄ›nit heslo</string> + <string name="password_changed">Heslo bylo zmÄ›nÄ›no.</string> + <string name="panic_setting">Nastavenà tlaÄÃtka Paniky</string> + <string name="panic_setting_title">TlaÄÃtko Paniky</string> + <string name="panic_setting_hint">Nastavte, jak bude Briar reagovat, když použijete aplikaci tlaÄÃtka paniky</string> + <string name="panic_app_setting_title">Aplikace Panik tlaÄÃtko</string> + <string name="unknown_app">neznámá aplikace</string> + <string name="panic_app_setting_summary">Žádná aplikace nebyla nastavena</string> + <string name="panic_app_setting_none">Žádný</string> + <string name="dialog_title_connect_panic_app">Potvrdit aplikaci Paniky</string> + <string name="dialog_message_connect_panic_app">Jste si jisti, že chcete povolit %1$s spustit akci zneÅ¡kodnÄ›nà pomocà tlaÄÃtka paniky?</string> + <string name="panic_setting_signout_title">Odhlásit se</string> + <string name="panic_setting_signout_summary">Odhlásit se z Briar, pokud je stisknuto tlaÄÃtko paniky</string> + <string name="purge_setting_title">Odstranit úÄet</string> + <string name="purge_setting_summary">Vymazat váš Briar úÄet pokud je stlaÄeno tlaÄÃtko paniky. UpozornÄ›nÃ: Toto trvale vymaže vaÅ¡i identitu, kontakty a zprávy</string> + <string name="uninstall_setting_title">Odinstalovat Briar</string> + <string name="uninstall_setting_summary">Toto vyžaduje manuálnà potvrzenà v události paniky</string> + <!--Settings Notifications--> + <string name="notification_settings_title">OznámenÃ</string> + <string name="notify_private_messages_setting_title">Soukromé zprávy</string> + <string name="notify_private_messages_setting_summary">Zobrazit upozornÄ›nà pro soukromé zprávy</string> + <string name="notify_private_messages_setting_summary_26">Nastavenà upozornÄ›nà pro soukromé zprávy</string> + <string name="notify_group_messages_setting_title">Skupinové zprávy</string> + <string name="notify_group_messages_setting_summary">Zobrazit upozornÄ›nà pro skupinové zprávy</string> + <string name="notify_group_messages_setting_summary_26">Nastavenà upozornÄ›nà pro skupinové zprávy</string> + <string name="notify_forum_posts_setting_title">PÅ™ÃspÄ›vky fóra</string> + <string name="notify_forum_posts_setting_summary">Zobrazit upozornÄ›nà pro pÅ™ÃspÄ›vky fóra</string> + <string name="notify_forum_posts_setting_summary_26">Nastavenà upozornÄ›nà pro pÅ™ÃspÄ›vky fóra</string> + <string name="notify_blog_posts_setting_title">PÅ™ÃspÄ›vky v blogu</string> + <string name="notify_blog_posts_setting_summary">Zobrazit upozornÄ›nà pro pÅ™ÃspÄ›vky v blogu</string> + <string name="notify_blog_posts_setting_summary_26">Nastavenà upozornÄ›nà pro pÅ™ÃspÄ›vky blogu</string> + <string name="notify_vibration_setting">Vibrovat</string> + <string name="notify_lock_screen_setting_title">ZamÄená obrazovka</string> + <string name="notify_lock_screen_setting_summary">Zobrazit oznámenà na zamÄené obrazovce</string> + <string name="notify_sound_setting">Zvuk</string> + <string name="notify_sound_setting_default">Výchozà vyzvánÄ›nÃ</string> + <string name="notify_sound_setting_disabled">Žádný</string> + <string name="choose_ringtone_title">Zvolit vyzvánÄ›cà tón</string> + <string name="cannot_load_ringtone">Nelze naÄÃst vyzvánÄ›cà tón</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">ZpÄ›tná vazba</string> + <string name="send_feedback">Poslat zpÄ›tnou vazbu</string> + <!--Link Warning--> + <string name="link_warning_title">Odkaz varovánÃ</string> + <string name="link_warning_intro">Chystáte se otevÅ™Ãt následujÃcà odkaz pomocà externà eplikace.</string> + <string name="link_warning_text">Toto může být užito pro vašà identifikaci. PÅ™emýšlejte o tom, zda důvěřujete osobÄ›, která vám poslala tento odkaz, a zvažte, zda ho otevÅ™ete s aplikacà Orfox.</string> + <string name="link_warning_open_link">OtevÅ™Ãt odkaz</string> + <!--Crash Reporter--> + <string name="crash_report_title">Hlášenà o pádu Briar</string> + <string name="briar_crashed">Promiňte, Briar se zhroutil.</string> + <string name="not_your_fault">Toto nenà vaÅ¡e chyba.</string> + <string name="please_send_report">VaÅ¡e pomoc je důležitá. DÃky nà můžeme postavit lepšà Briar tÃm, že nám poÅ¡lete zprávu o pádu aplikace.</string> + <string name="report_is_encrypted">Slibujeme, že hlášenà je zaÅ¡ifrováno a bezpeÄnÄ› odesláno.</string> + <string name="feedback_title">ZpÄ›tná vazba</string> + <string name="describe_crash">PopiÅ¡te, co se stalo (nepovinné)</string> + <string name="enter_feedback">Vložte svou zpÄ›tnou vazbu</string> + <string name="optional_contact_email">VaÅ¡e emailová adresa (nepovinné)</string> + <string name="include_debug_report_crash">Zahrnout anonymnà data o tomto selhánÃ</string> + <string name="include_debug_report_feedback">Zahrnout anonymnà data o tomto zaÅ™ÃzenÃ</string> + <string name="could_not_load_report_data">Data hlášenà nemohla být naÄtena.</string> + <string name="send_report">Odeslat hlášenÃ</string> + <string name="close">ZavÅ™Ãt</string> + <string name="dev_report_saved">Hlášenà uloženo. Odesláno bude pÅ™i pÅ™ÃÅ¡tÃm pÅ™ihlášenà do Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">Odhlásit se z Briar...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Bylo zjiÅ¡tÄ›no pÅ™ekrytà obrazovky</string> + <string name="screen_filter_allow">Povolit tÄ›mto aplikacÃm zůstat navrchu</string> + <!--Permission Requests--> + <string name="permission_camera_title">OprávnÄ›nà pro pÅ™Ãstup k fotoaparátu</string> + <string name="permission_camera_request_body">Pro scan QR kódu, Briar vyžaduje pÅ™Ãstup k fotoaparátu.</string> + <string name="permission_camera_denied_body">OdmÃtli jste udÄ›lit oprávnÄ›nà pÅ™Ãstupu k fotoaparátu, avÅ¡ak pro pÅ™idánà kontaktů je nutné použità fotoaparátu.\n\nZvažte prosÃm, opÄ›tovné udÄ›lenà pÅ™Ãstupu.</string> + <string name="permission_camera_denied_toast">OprávnÄ›nà pro pÅ™Ãstup k fotoaparátu nebylo udÄ›leno</string> + <string name="qr_code">QR kód</string> + <string name="show_qr_code_fullscreen">Zobrazit QR kód na celou obrazovku</string> +</resources> diff --git a/mailbox-android/src/main/res/values-de/strings.xml b/mailbox-android/src/main/res/values-de/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..df2052310a317898e81b58bf2d3c11e43872e3fa --- /dev/null +++ b/mailbox-android/src/main/res/values-de/strings.xml @@ -0,0 +1,401 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Willkommen bei Briar</string> + <string name="setup_name_explanation">Dein Benutzername wird neben deinem geposteten Inhalt angezeigt. Du kannst diesen nicht mehr ändern, nachdem du dein Konto erstellt hast.</string> + <string name="setup_next">Weiter</string> + <string name="setup_password_intro">Wähle ein Passwort</string> + <string name="setup_password_explanation">Dein Briar-Konto wird auf deinem Gerät verschlüsselt und nicht in der Cloud gespeichert. Wenn du dein Passwort vergisst oder Briar deinstallierst, gibt es keine Möglichkeit, dein Konto wiederherzustellen.\n\nWähle ein langes Passwort, das schwer zu erraten ist, z.B. vier zufällige Wörter oder zehn zufällige Buchstaben, Zahlen und Symbole.</string> + <string name="setup_doze_title">Hintergrundverbindungen</string> + <string name="setup_doze_intro">Um Nachrichten zu empfangen, muss Briar im Hintergrund verbunden bleiben.</string> + <string name="setup_doze_explanation">Um Nachrichten zu empfangen, muss Briar im Hintergrund verbunden bleiben. Bitte deaktiviere die Batterieoptimierungen, damit Briar in Verbindung bleiben kann.</string> + <string name="setup_doze_button">Erlaube Verbindungen</string> + <string name="choose_nickname">Wähle deinen Benutzernamen</string> + <string name="choose_password">Wähle dein Passwort</string> + <string name="confirm_password">Passwort bestätigen</string> + <string name="name_too_long">Name zu lang</string> + <string name="password_too_weak">Passwort zu schwach</string> + <string name="passwords_do_not_match">Passwörter stimmen nicht überein</string> + <string name="create_account_button">Konto anlegen</string> + <string name="more_info">Weitere Informationen</string> + <string name="don_t_ask_again">Frage nicht noch einmal</string> + <string name="setup_huawei_text">Bitte tippe auf die Schaltfläche unten und stelle sicher, dass Briar unter \"Geschützte Apps\" angezeigt wird.</string> + <string name="setup_huawei_button">Schütze Briar</string> + <string name="setup_huawei_help">Wenn Briar nicht zur Liste der geschützten Apps hinzugefügt wird, kann es nicht im Hintergrund ausgeführt werden.</string> + <string name="warning_dozed">%s konnte nicht im Hintergrund ausgeführt werden</string> + <!--Login--> + <string name="enter_password">Passwort</string> + <string name="try_again">Passwort falsch, bitte erneut versuchen</string> + <string name="sign_in_button">Anmelden</string> + <string name="forgotten_password">Ich habe mein Passwort vergessen</string> + <string name="dialog_title_lost_password">Passwort vergessen</string> + <string name="dialog_message_lost_password">Dein Briar-Konto ist auf deinem Gerät verschlüsselt und nicht in der Cloud gespeichert, deshalb kannst du dein Passwort nicht zurücksetzen. Willst du dein Konto löschen und neu beginnen?\n\nAchtung: Deine bestehenden Identitäten, Kontakte und Nachrichten gehen dann für immer verloren.</string> + <string name="startup_failed_notification_title">Briar konnte nicht gestartet werden</string> + <string name="startup_failed_notification_text">Für weitere Informationen, hier klicken.</string> + <string name="startup_failed_activity_title">Fehler beim Starten von Briar</string> + <string name="startup_failed_db_error">Aus irgendeinem Grund ist deine Briar-Datenbank irreparabel beschädigt. Dein Konto, deine Daten und alle deinen Kontakte sind verloren. Leider musst du Briar neu installieren oder ein neues Konto einrichten, indem du ,Ich habe mein Passwort vergessen\' auswählst, wenn du zur Eingabe deines Passworts aufgefordert wirst. </string> + <string name="startup_failed_data_too_old_error">Dein Konto wurde mit einer alten Version dieser App erstellt und kann mit dieser Version nicht geöffnet werden. Installiere entweder die alte Version oder richte ein neues Konto ein, indem du \"Ich habe mein Passwort vergessen\" auswählst, wenn du zur Eingabe deines Passworts aufgefordert wirst. </string> + <string name="startup_failed_data_too_new_error">Diese Version der App ist zu alt. Bitte führe eine Aktualisierung auf die neueste Version der App durch und versuch es dann noch mal.</string> + <string name="startup_failed_service_error">Briar konnte ein benötigtes Plugin nicht starten. Normalerweise kann das Problem durch eine Neuinstallation von Briar gelöst werden. Eine Neuinstallation führt jedoch zum Verlust deines Kontos und aller dazugehörigen Daten, da Briar deine Daten nicht auf zentralen Servern speichert.</string> + <plurals name="expiry_warning"> + <item quantity="one">Dies ist eine Testversion von Briar. Dein Konto läuft in %d Tag ab und kann nicht verlängert werden.</item> + <item quantity="other">Dies ist eine Testversion von Briar. Dein Konto läuft in %d Tagen ab und kann nicht verlängert werden.</item> + </plurals> + <string name="expiry_update">Das Ablaufdatum des Tests wurde verlängert. Dein Konto läuft nun in %d Tagen ab.</string> + <string name="expiry_date_reached">Diese Software ist abgelaufen.\nDanke dass du Briar getestet hast!</string> + <string name="download_briar">Lade bitte Version 1.0 herunter, um Briar weiterhin zu nutzen.</string> + <string name="create_new_account">Du wirst ein neues Konto erstellen müssen, wobei du jedoch wieder den selben Benutzernamen verwenden kannst.</string> + <string name="download_briar_button">Lade Briar 1.0 herunter</string> + <string name="startup_open_database">Datenbank wird entschlüsselt...</string> + <string name="startup_migrate_database">Datenbank wird aktualisiert...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Navigationsleiste öffnen</string> + <string name="nav_drawer_close_description">Navigationsleiste schliessen</string> + <string name="contact_list_button">Kontakte</string> + <string name="groups_button">Private Gruppen</string> + <string name="forums_button">Foren</string> + <string name="blogs_button">Blogs</string> + <string name="settings_button">Einstellungen</string> + <string name="sign_out_button">Abmelden</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">WLAN</string> + <!--Notifications--> + <string name="reminder_notification_title">Von Briar abgemeldet</string> + <string name="ongoing_notification_title">In Briar angemeldet</string> + <string name="ongoing_notification_text">Berühren, um Briar zu öffnen.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Neue private Nachricht.</item> + <item quantity="other">%d neue private Nachrichten.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Neue Gruppennachricht.</item> + <item quantity="other">%d neue Gruppennachrichten.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Neuer Forenbeitrag.</item> + <item quantity="other">%d neue Forenbeiträge.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Neuer Blogeintrag.</item> + <item quantity="other">%d neue Blogbeiträge.</item> + </plurals> + <!--Misc--> + <string name="now">jetzt</string> + <string name="show">Anzeigen</string> + <string name="hide">Ausblenden</string> + <string name="ok">OK</string> + <string name="cancel">Abbrechen</string> + <string name="got_it">Okay, verstanden.</string> + <string name="delete">Löschen</string> + <string name="accept">Annehmen</string> + <string name="decline">Ablehnen</string> + <string name="options">Optionen</string> + <string name="online">Online</string> + <string name="offline">Offline</string> + <string name="send">Senden</string> + <string name="allow">Erlauben</string> + <string name="open">Öffnen</string> + <string name="no_data">Keine Daten</string> + <string name="ellipsis">…</string> + <string name="text_too_long">Der eingegebene Text ist leider zu lang</string> + <string name="show_onboarding">Hilfe anzeigen</string> + <string name="fix">Behoben</string> + <string name="help">Hilfe</string> + <string name="sorry">Entschuldigung</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Du hast noch keine Kontakte\n\nTippe auf das +-Symbol um einen Kontakt hinzuzufügen</string> + <string name="date_no_private_messages">Keine Nachrichten.</string> + <string name="no_private_messages">Keine Nachrichten zum Anzeigen</string> + <string name="message_hint">Nachricht eingeben</string> + <string name="delete_contact">Kontakt löschen</string> + <string name="dialog_title_delete_contact">Löschen des Kontakts bestätigen</string> + <string name="dialog_message_delete_contact">Bist du sicher, dass du diesen Kontakt und alle dazugehörigen Nachrichten löschen möchtest?</string> + <string name="contact_deleted_toast">Kontakt gelöscht</string> + <!--Adding Contacts--> + <string name="add_contact_title">Kontakt hinzufügen</string> + <string name="face_to_face">Um einen neuen Kontakt hinzuzufügen, ist es notwendig, dass sich beide Kontakte an einem Ort treffen.\n\nDadurch wird betrügerische Identitätsvortäuschung und unautorisierter Kommunikationszugriff verhindert.</string> + <string name="continue_button">Weiter</string> + <string name="connection_failed">Verbindung fehlgeschlagen</string> + <string name="try_again_button">Noch einmal versuchen</string> + <string name="waiting_for_contact_to_scan">Warte auf Scan und Verbindung mit dem Kontakt\u2026</string> + <string name="exchanging_contact_details">Kontaktdetails werden ausgetauscht\u2026</string> + <string name="contact_added_toast">Kontakt hinzugefügt: %s</string> + <string name="contact_already_exists">Kontakt %s existiert bereits</string> + <string name="contact_exchange_failed">Kontaktaustausch fehlgeschlagen</string> + <string name="qr_code_invalid">Der QR-Code ist ungültig</string> + <string name="qr_code_unsupported">Der QR-Code, den du versuchst zu scannen, gehört zu einer alten Version von %s welche nicht mehr unterstützt wird.\n\nBitte versichert euch, dass bei euch beiden die neueste Version läuft und versucht es dann erneut.</string> + <string name="camera_error">Kamerafehler</string> + <string name="connecting_to_device">Verbinde mit Gerät\u2026</string> + <string name="authenticating_with_device">Authentifiziere Gerät\u2026</string> + <string name="connection_aborted_local">Verbindung abgebrochen! Dies könnte bedeuten, dass jemand versucht, deine Verbindung zu stören.</string> + <string name="connection_aborted_remote">Verbindung wurde durch deinen Kontakt abgebrochen! Möglicherweise stört jemand deine Verbindung.</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Mache deine Kontakte untereinander bekannt</string> + <string name="introduction_onboarding_text">Du kannst deine Kontakte untereinander bekannt machen. So können sie sich über Briar verbinden, ohne sich persönlich treffen zu müssen.</string> + <string name="introduction_menu_item">Kontaktempfehlung abgeben</string> + <string name="introduction_activity_title">Kontakt auswählen</string> + <string name="introduction_not_possible">Es wird bereits eine Kontaktempfehlung mit diesen Kontakten verarbeitet. Bitte warte, bis die Verarbeitung abgeschlossen ist. Falls du oder deine Kontakte selten online sind, kann es etwas dauern.</string> + <string name="introduction_message_title">Kontakte untereinander bekannt machen</string> + <string name="introduction_message_hint">Nachricht hinzufügen (optional)</string> + <string name="introduction_button">Kontaktempfehlung abgeben</string> + <string name="introduction_sent">Deine Kontaktempfehlung wurde verschickt.</string> + <string name="introduction_error">Es gab einen Fehler beim Versuch, die Kontaktempfehlung zu verschicken.</string> + <string name="introduction_response_error">Fehler bei Antwort auf Kontaktempfehlung</string> + <string name="introduction_request_sent">Du wolltest %1$s an %2$s als Kontakt empfehlen</string> + <string name="introduction_request_received">%1$s schlägt vor, dich als Kontakt an %2$s zu empfehlen. Möchtest du %2$s zu deiner Kontaktliste hinzufügen?</string> + <string name="introduction_request_exists_received">%1$s schlägt vor, dich als Kontakt an %2$s zu empfehlen. %2$s ist allerdings bereits in deiner Kontaktliste. Da %1$s das vielleicht nicht weiss, kannst du trotzdem antworten:</string> + <string name="introduction_request_answered_received">%1$s schlägt vor, dich als Kontakt an %2$s zu empfehlen. </string> + <string name="introduction_response_accepted_sent">Du hast die Kontaktempfehlung für %1$s angenommen.</string> + <string name="introduction_response_accepted_sent_info">Bevor %1$s zu deinen Kontakten hinzugefügt werden, müssen sie die Kontaktempfehlung ebenfalls akzeptieren. Dies kann eine Weile dauern.</string> + <string name="introduction_response_declined_sent">Du hast die Kontaktempfehlung von %1$s abgelehnt.</string> + <string name="introduction_response_accepted_received">%1$s hat die Kontaktempfehlung für %2$s angenommen.</string> + <string name="introduction_response_declined_received">%1$s hat deine Kontaktempfehlung von %2$s abgelehnt.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s meldet, dass %2$s die Kontaktempfehlung abgelehnt hat.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">neuer Kontakt hinzugefügt.</item> + <item quantity="other">%d neue Kontakte hinzugefügt.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">No groups to show\n\nTap the + icon to create a group, or ask your contacts to share groups with you</string> + <string name="groups_created_by">Erstellt durch %s</string> + <plurals name="messages"> + <item quantity="one">%d Nachrichten</item> + <item quantity="other">%d Nachrichten</item> + </plurals> + <string name="groups_group_is_empty">Diese Gruppe ist leer</string> + <string name="groups_group_is_dissolved">Diese Gruppe wurde aufgelöst</string> + <string name="groups_remove">Entfernen</string> + <string name="groups_create_group_title">Private Gruppe erstellen</string> + <string name="groups_create_group_button">Gruppe erstellen</string> + <string name="groups_create_group_invitation_button">Einladung schicken</string> + <string name="groups_create_group_hint">Wähle einen Namen für deine private Gruppe</string> + <string name="groups_invitation_sent">Gruppeneinladung versendet</string> + <string name="groups_message_sent">Nachricht gesendet</string> + <string name="groups_member_list">Mitgliederliste</string> + <string name="groups_invite_members">Mitglieder einladen</string> + <string name="groups_member_created_you">Du hast diese Gruppe erstellt</string> + <string name="groups_member_created">%s hat diese Gruppe erstellt</string> + <string name="groups_member_joined_you">Du bist der Gruppe beigetreten</string> + <string name="groups_member_joined">%s ist der Gruppe beigetreten</string> + <string name="groups_leave">Gruppe verlassen</string> + <string name="groups_leave_dialog_title">Verlassen der Gruppe bestätigen</string> + <string name="groups_leave_dialog_message">Bist du sicher, dass du die Gruppe verlassen willst?</string> + <string name="groups_dissolve">Gruppe auflösen</string> + <string name="groups_dissolve_dialog_title">Auflösung der Gruppe bestätigen</string> + <string name="groups_dissolve_dialog_message">Willst du wirklich diese Gruppe auflösen?\n\nAlle anderen Teilnehmer verlieren die Möglichkeit der Kommunikation ohne möglicherweise die neuesten Nachrichten erhalten zu haben.</string> + <string name="groups_dissolve_button">Auflösen</string> + <string name="groups_dissolved_dialog_title">Gruppe wurde aufgelöst</string> + <string name="groups_dissolved_dialog_message">Der Ersteller dieser Gruppe hat dieselbe aufgelöst.\n\nEs können keine weiteren Nachrichten mehr in dieser Gruppe geschrieben werden und möglicherweise wurden noch nicht alle Nachrichten empfangen.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Gruppeneinladungen</string> + <string name="groups_invitations_invitation_sent">%1$s wurde in die Gruppe \"%2$s\" eingeladen.</string> + <string name="groups_invitations_invitation_received">%1$s hat dich eingeladen der Gruppe \"%2$s\" beizutreten.</string> + <string name="groups_invitations_joined">Gruppe beigetreten</string> + <string name="groups_invitations_declined">Gruppeneinladung abgelehnt</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d offene Gruppeneinladung</item> + <item quantity="other">%d offene Gruppeneinladungen</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Gruppeneinladung von %s angenommen.</string> + <string name="groups_invitations_response_declined_sent">Gruppeneinladung von %s abgelehnt.</string> + <string name="groups_invitations_response_accepted_received">%s hat die Einladung zur Gruppe angenommen.</string> + <string name="groups_invitations_response_declined_received">%s hat die Einladung zur Gruppe abgelehnt.</string> + <string name="sharing_status_groups">Nur der Ersteller kann neue Mitglieder zu einer Gruppe einladen. Hier werden alle aktuellen Mitglieder dieser Gruppe angezeigt.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Kontakte teilen</string> + <string name="groups_reveal_dialog_message">Kontakte können mit allen derzeitigen und zukünftigen Mitgliedern dieser Gruppe geteilt werden.\n\nDas beschleunigt die Verbindung zu der Gruppe und macht sie zusätzlich zuverlässiger, da Kommunikation mit den Mitgliedern auch dann erfolgen kann, wenn der Ersteller der Gruppe offline ist.</string> + <string name="groups_reveal_visible">Verbindung zum Kontakt ist für die Gruppe sichtbar</string> + <string name="groups_reveal_visible_revealed_by_us">Verbindung zum Kontakt ist für diese Gruppe sichtbar (selbst offengelegt)</string> + <string name="groups_reveal_visible_revealed_by_contact">Verbindung zum Kontakt ist für diese Gruppe sichtbar (offengelegt durch %s)</string> + <string name="groups_reveal_invisible">Verbindung zum Kontakt ist für diese Gruppe nicht sichtbar</string> + <!--Forums--> + <string name="no_forums">Du bist in keinem Forum Mitglied.\n\nVerwende das + Symbol am oberen Rand um ein Forum zu erstellen oder frage bitte Deine Kontakte danach, Foren mit dir zu teilen</string> + <string name="create_forum_title">Forum erstellen</string> + <string name="choose_forum_hint">Wähle einen Namen für dein Forum</string> + <string name="create_forum_button">Forum erstellen</string> + <string name="forum_created_toast">Forum wurde erstellt</string> + <string name="no_forum_posts">Keine Beiträge zum Anzeigen</string> + <string name="no_posts">Keine Beiträge</string> + <plurals name="posts"> + <item quantity="one">%d Beitrag</item> + <item quantity="other">%d Beiträge</item> + </plurals> + <string name="forum_new_message_hint">Neuer Beitrag</string> + <string name="forum_message_reply_hint">Neue Antwort</string> + <string name="btn_reply">Antworten</string> + <string name="forum_leave">Forum verlassen</string> + <string name="dialog_title_leave_forum">Verlassen des Forums bestätigen</string> + <string name="dialog_message_leave_forum">Bist du sicher, dass du dieses Forum verlassen willst?\n\nKontakte, mit denen du dieses Forum geteilt hast, werden keine Updates mehr von diesem Forum bekommen.</string> + <string name="dialog_button_leave">Verlassen</string> + <string name="forum_left_toast">Forum wurde verlassen</string> + <!--Forum Sharing--> + <string name="forum_share_button">Forum teilen</string> + <string name="contacts_selected">Ausgewählte Kontakte</string> + <string name="activity_share_toolbar_header">Kontakte auswählen</string> + <string name="forum_shared_snackbar">Forum mit gewählten Kontakten geteilt</string> + <string name="forum_share_message">Nachricht hinzufügen (optional)</string> + <string name="forum_share_error">Es gab einen Fehler beim Versuch, dieses Forum zu teilen.</string> + <string name="forum_invitation_received">%1$s hat das Forum \"%2$s\" mit dir geteilt.</string> + <string name="forum_invitation_sent">Du hast das Forum \"%1$s\" mit %2$s geteilt.</string> + <string name="forum_invitations_title">Foreneinladungen</string> + <string name="forum_invitation_exists">Du hast bereits eine Einladung zu diesem Forum angenommen.\n\nMehrere Einladungen anzunehmen, wird deine Verbindung zu diesem Forum schneller und zuverlässiger machen.</string> + <string name="forum_joined_toast">Dem Forum beigetreten</string> + <string name="forum_declined_toast">Einladung abgelehnt</string> + <string name="shared_by_format">Geteilt durch %s</string> + <string name="forum_invitation_already_sharing">Bereits geteilt.</string> + <string name="forum_invitation_response_accepted_sent">Du hast die Forumseinladung von %s akzeptiert.</string> + <string name="forum_invitation_response_declined_sent">Du hast die Forumeinladung von %s abgelehnt.</string> + <string name="forum_invitation_response_accepted_received">%s hat die Forumeinladung akzeptiert.</string> + <string name="forum_invitation_response_declined_received">%s hat die Forumseinladung abgelehnt.</string> + <string name="sharing_status">Freigabestatus</string> + <string name="sharing_status_forum">Jedes Mitglied eines Forums kann dieses mit seinen Kontakten teilen. Du teilst dieses Forum mit den folgenden Kontakten. Möglicherweise gibt es Mitglieder die nicht sichtbar sind.</string> + <string name="shared_with">Geteilt mit %1$d (%2$d online)</string> + <plurals name="forums_shared"> + <item quantity="one">%d Forum von Kontaken geteilt</item> + <item quantity="other">%d Foren von Kontakten geteilt</item> + </plurals> + <string name="nobody">Niemand</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Keine Blogbeiträge zum Anzeigen</string> + <string name="read_more">weiterlesen</string> + <string name="blogs_write_blog_post">Blogbeitrag erstellen</string> + <string name="blogs_write_blog_post_body_hint">Gib deinen Blogbeitrag ein</string> + <string name="blogs_publish_blog_post">Veröffentlichen</string> + <string name="blogs_blog_post_created">Blogbeitrag erstellt</string> + <string name="blogs_blog_post_received">Neuen Blogbeitrag empfangen</string> + <string name="blogs_blog_post_scroll_to">Scrolle zu</string> + <string name="blogs_remove_blog">Blog entfernen</string> + <string name="blogs_remove_blog_ok">Aufheben</string> + <string name="blogs_blog_removed">Blog wurde entfernt</string> + <string name="blogs_reblog_comment_hint">Kommentar hinzufügen (optional)</string> + <string name="blogs_reblog_button">Rebloggen</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Blog teilen</string> + <string name="blogs_sharing_error">Es gab einen Fehler beim Versuch, diesen Blog zu teilen.</string> + <string name="blogs_sharing_button">Blog teilen</string> + <string name="blogs_sharing_snackbar">Blog wurde mit ausgewählten Kontakten geteilt</string> + <string name="blogs_sharing_response_accepted_sent">Du hast die Blogeinladung von %s akzeptiert.</string> + <string name="blogs_sharing_response_declined_sent">Du hast die Blogeinladung von %s abgelehnt.</string> + <string name="blogs_sharing_response_accepted_received">%s hat die Blogeinladung akzeptiert.</string> + <string name="blogs_sharing_response_declined_received">%s hat die Blogeinladung abgelehnt.</string> + <string name="blogs_sharing_invitation_received">%1$shat den Blog \"%2$s\" mit dir geteilt.</string> + <string name="blogs_sharing_invitation_sent">Du teilst den Blog \"%1$s\" mit %2$s.</string> + <string name="blogs_sharing_invitations_title">Blogeinladungen</string> + <string name="blogs_sharing_joined_toast">Blog abonniert</string> + <string name="blogs_sharing_declined_toast">Einladung abgelehnt</string> + <string name="sharing_status_blog">Jeder Abonnent eines Blogs kann diesen mit seinen Kontakten teilen. Du teilst diesen Blog mit den folgenden Kontakten. Möglicherweise gibt es Abonnenten die nicht sichtbar sind.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">RSS-Feed importieren</string> + <string name="blogs_rss_feeds_import_button">Importieren</string> + <string name="blogs_rss_feeds_import_hint">URL des RSS-Feeds eingeben</string> + <string name="blogs_rss_feeds_import_error">Es tut uns Leid! Es gab einen Fehler beim Importieren deines Feeds.</string> + <string name="blogs_rss_feeds_manage">RSS-Feeds verwalten</string> + <string name="blogs_rss_feeds_manage_imported">Importiert:</string> + <string name="blogs_rss_feeds_manage_author">Autor:</string> + <string name="blogs_rss_feeds_manage_updated">Letzte Aktualisierung:</string> + <string name="blogs_rss_remove_feed">Feed entfernen</string> + <string name="blogs_rss_remove_feed_dialog_message">Bist du sicher, dass Du diesen Feed löschen willst?\n\nDie Beiträge werden von Deinem Gerät gelöscht, jedoch nicht von Geräten anderer Leute.\n\nKontakte, mit denen Du diesen Feed geteilt hast, werden keine Updates mehr davon bekommen.</string> + <string name="blogs_rss_remove_feed_ok">Aufheben</string> + <string name="blogs_rss_feeds_manage_delete_error">Der Feed konnte nicht gelöscht werden!</string> + <string name="blogs_rss_feeds_manage_empty_state">Du hast noch keine RSS-Feeds\n\nTippe auf das +-Symbol um einen Feed zu importieren</string> + <string name="blogs_rss_feeds_manage_error">Es gab ein Problem beim Laden deiner Feeds. Bitte versuche es später erneut.</string> + <!--Settings Display--> + <string name="pref_language_title">Sprache & Region</string> + <string name="pref_language_changed">Diese Einstellung wird aktiv sobald Du Briar neu startest. Bitte melde dich ab und starte Briar neu.</string> + <string name="display_settings_title">Anzeigen</string> + <string name="pref_theme_title">Design</string> + <string name="pref_theme_light">Hell</string> + <string name="pref_theme_dark">Dunkel</string> + <!--Settings Network--> + <string name="network_settings_title">Netzwerke</string> + <string name="bluetooth_setting">Über Bluetooth verbinden</string> + <string name="bluetooth_setting_enabled">Sobald Kontakte in der Nähe sind</string> + <string name="bluetooth_setting_disabled">Nur beim Hinzufügen von Kontakten</string> + <string name="tor_network_setting">Über Tor verbinden</string> + <string name="tor_network_setting_never">Nie</string> + <string name="tor_network_setting_wifi">Nur WLAN</string> + <string name="tor_network_setting_always">WLAN oder mobile Datenverbindung</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Sicherheit</string> + <string name="change_password">Passwort ändern</string> + <string name="current_password">Aktuelles Passwort</string> + <string name="choose_new_password">Neues Passwort</string> + <string name="confirm_new_password">Neues Passwort bestätigen</string> + <string name="password_changed">Passwort wurde geändert.</string> + <string name="panic_setting">Panik-Button einrichten</string> + <string name="panic_setting_title">Panik-Button</string> + <string name="panic_setting_hint">Lege fest, wie Briar auf eine Panik-Button-App reagiert</string> + <string name="panic_app_setting_title">Panik-Button-App</string> + <string name="unknown_app">eine unbekannte App</string> + <string name="panic_app_setting_summary">Keine App eingerichtet</string> + <string name="panic_app_setting_none">Keine</string> + <string name="dialog_title_connect_panic_app">Bestätige Panik-App</string> + <string name="dialog_message_connect_panic_app">Bist du sicher, dass du %1$s erlauben willst, Panik-Button-Ereignisse auszulösen? Dies kann zum Löschen von Daten führen.</string> + <string name="panic_setting_signout_title">Abmelden</string> + <string name="panic_setting_signout_summary">Von Briar abmelden, wenn ein Panik-Button aktiviert wird</string> + <string name="purge_setting_title">Konto löschen</string> + <string name="purge_setting_summary">Briar-Konto löschen, wenn der Panik-Button gedrückt wird. Achtung: Es werden alle Identitäten, Kontakte und Nachrichten unwiderruflich gelöscht.</string> + <string name="uninstall_setting_title">Briar deinstallieren</string> + <string name="uninstall_setting_summary">Diese Aktion benötigt manuelle Bestätigung im Falle eines Panik-Ereignisses</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Benachrichtigungen</string> + <string name="notify_private_messages_setting_title">Private Nachrichten</string> + <string name="notify_private_messages_setting_summary">Zeige Benachrichtigungen für private Nachrichten</string> + <string name="notify_private_messages_setting_summary_26">Benachrichtigungen für private Nachrichten konfigurieren</string> + <string name="notify_group_messages_setting_title">Gruppennachrichten</string> + <string name="notify_group_messages_setting_summary">Benachrichtigungen für Gruppennachrichten anzeigen</string> + <string name="notify_group_messages_setting_summary_26">Benachrichtigungen für Gruppennachrichten konfigurieren</string> + <string name="notify_forum_posts_setting_title">Forenbeiträge</string> + <string name="notify_forum_posts_setting_summary">Benachrichtigungen für Forenbeiträge anzeigen</string> + <string name="notify_forum_posts_setting_summary_26">Benachrichtigungen für Forenbeiträge konfigurieren</string> + <string name="notify_blog_posts_setting_title">Blogbeiträge</string> + <string name="notify_blog_posts_setting_summary">Benachrichtigungen für Blogbeiträge anzeigen</string> + <string name="notify_blog_posts_setting_summary_26">Benachrichtigungen für Blogbeiträge konfigurieren</string> + <string name="notify_vibration_setting">Vibration</string> + <string name="notify_lock_screen_setting_title">Sperrbildschirm</string> + <string name="notify_lock_screen_setting_summary">Zeigt Benachrichtigungen auf dem Sperrbildschirm an</string> + <string name="notify_sound_setting">Tonsignal</string> + <string name="notify_sound_setting_default">Standardklingelton</string> + <string name="notify_sound_setting_disabled">Keine</string> + <string name="choose_ringtone_title">Klingelton auswählen</string> + <string name="cannot_load_ringtone">Klingelton kann nicht geladen werden</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Feedback</string> + <string name="send_feedback">Feedback abschicken</string> + <!--Link Warning--> + <string name="link_warning_title">Link-Warnung</string> + <string name="link_warning_intro">Du willst folgenden Link mit einer externen App öffnen.</string> + <string name="link_warning_text">Dies kann zu deiner Identifzierung benutzt werden. Überlege, ob die Person, die dir diesen Link geschickt hat, vertrauenswürdig ist und ob du ihn nicht besser mit Orfox öffnest.</string> + <string name="link_warning_open_link">Link öffnen</string> + <!--Crash Reporter--> + <string name="crash_report_title">Briar-Absturzbericht</string> + <string name="briar_crashed">Es tut uns leid, Briar ist abgestürzt.</string> + <string name="not_your_fault">Das ist nicht deine Schuld.</string> + <string name="please_send_report">Bitte hilf uns, Briar zu verbessern, indem du einen Absturzbericht sendest.</string> + <string name="report_is_encrypted">Wir versprechen, dass der Bericht verschlüsselt ist und über eine sichere Verbindung geschickt wird.</string> + <string name="feedback_title">Feedback</string> + <string name="describe_crash">Beschreibe was passiert ist (optional)</string> + <string name="enter_feedback">Gib dein Feedback ein</string> + <string name="optional_contact_email">Deine E-Mail-Adresse (optional)</string> + <string name="include_debug_report_crash">Anonymisierte Daten über den Absturz anhängen</string> + <string name="include_debug_report_feedback">Anonymisierte Daten über dieses Gerät anhängen</string> + <string name="could_not_load_report_data">Konnte Daten des Berichts nicht laden</string> + <string name="send_report">Bericht abschicken</string> + <string name="close">Schließen</string> + <string name="dev_report_saved">Der Bericht wurde gespeichert. Er wird verschickt, wenn du dich das nächste Mal bei Briar anmeldest.</string> + <!--Sign Out--> + <string name="progress_title_logout">Von Briar abmelden...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Bildschirmüberlagerung erkannt</string> + <string name="screen_filter_body">Eine andere App überlagert Briar. Um deine Sicherheit zu gewährleisten, reagiert Briar in diesem Fall nicht auf deine Eingaben.\n\nDie folgenden Apps könnten überlagern:\n\n%1$s</string> + <string name="screen_filter_allow">Erlauben diesen Apps die Bildschirmüberlagerung</string> + <!--Permission Requests--> + <string name="permission_camera_title">Berechtigung Kamera</string> + <string name="permission_camera_request_body">Um den QR-Code zu scannen, benötigt Briar Zugriff auf die Kamera.</string> + <string name="permission_camera_denied_body">Du hast den Zugriff auf die Kamera verweigert, aber das Hinzufügen von Kontakten erfordert die Verwendung der Kamera.\n\nBitte gewähre den Zugriff.</string> + <string name="permission_camera_denied_toast">Berechtigung für Kamera wurde nicht gewährt</string> + <string name="qr_code">QR-Code</string> + <string name="show_qr_code_fullscreen">QR-Code im Vollbildmodus anzeigen</string> +</resources> diff --git a/mailbox-android/src/main/res/values-es/strings.xml b/mailbox-android/src/main/res/values-es/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..4d11571de1715e84d11722ce48c85e3b032cb28c --- /dev/null +++ b/mailbox-android/src/main/res/values-es/strings.xml @@ -0,0 +1,395 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Bienvenido a Briar</string> + <string name="setup_name_explanation">Tu nombre de usuario aparecerá junto a cualquier contenido que publiques. No puedes cambiarlo después de crear tu cuenta.</string> + <string name="setup_next">Siguiente</string> + <string name="setup_password_intro">Elija una contraseña</string> + <string name="setup_password_explanation">Su cuenta Briar se almacena cifrada en su dispositivo, no en la nube. Si olvida su contraseña o desinstala Briar, no hay manera de recuperar su cuenta.\n\nElija una contraseña larga que sea difÃcil de adivinar, como cuatro palabras aleatorias o diez letras, números y sÃmbolos al azar.</string> + <string name="setup_doze_title">Conexiones de fondo</string> + <string name="setup_doze_intro">Para recibir mensajes, Briar necesita mantenerse conectado en segundo plano.</string> + <string name="setup_doze_explanation">Para recibir mensajes, Briar necesita mantenerse conectado en segundo plano. Desactive las optimizaciones de la baterÃa para que Briar pueda permanecer conectado.</string> + <string name="setup_doze_button">Permitir conexiones</string> + <string name="choose_nickname">Elige tu nombre de usuario</string> + <string name="choose_password">Elige tu contraseña</string> + <string name="confirm_password">Confirma tu contraseña</string> + <string name="name_too_long">El nombre es demasiado largo</string> + <string name="password_too_weak">La contraseña es demasiado débil</string> + <string name="passwords_do_not_match">Las contraseñas no coinciden</string> + <string name="create_account_button">Registrar una nueva cuenta</string> + <string name="more_info">Más información</string> + <string name="don_t_ask_again">No preguntes de nuevo</string> + <string name="setup_huawei_text">Por favor toque el botón de abajo y asegúrese de que Briar está protegido en la pantalla \"Aplicaciones protegidas\".</string> + <string name="setup_huawei_button">Proteger Briar</string> + <string name="setup_huawei_help">Si Briar no se agrega a la lista de aplicaciones protegidas, no podrá ejecutarse en segundo plano.</string> + <string name="warning_dozed">%s no pudo ejecutarse en proceso de fondo</string> + <!--Login--> + <string name="enter_password">Contraseña</string> + <string name="try_again">Contraseña incorrecta, inténtalo de nuevo</string> + <string name="sign_in_button">Identificarse</string> + <string name="forgotten_password">Olvidé mi contraseña</string> + <string name="dialog_title_lost_password">Contraseña olvidada</string> + <string name="dialog_message_lost_password">Tu cuenta de Briar se almacena de manera cifrada en tu dispositivo y no en ninguna nube, asà que no podemos reiniciar tu contraseña. ¿Deseas eliminar tu cuenta y empezar de nuevo?\n\nAdvertencia: tus identidades, contactos y mensajes se perderán para siempre.</string> + <string name="startup_failed_notification_title">Briar no pudo iniciarse</string> + <string name="startup_failed_notification_text">Toca para más información.</string> + <string name="startup_failed_activity_title">Fallo al iniciar Briar</string> + <string name="startup_failed_db_error">Por alguna razón, su base de datos Briar está dañada irreparablemente. Su cuenta, sus datos y todos sus contactos se pierden. Desafortunadamente, necesita reinstalar Briar o crear una nueva cuenta seleccionando `He olvidado mi contraseña\' en la solicitud de contraseña.</string> + <string name="startup_failed_data_too_old_error">Su cuenta fue creada con una versión antigua de esta aplicación y no se puede abrir con esta versión. Debe reinstalar la versión antigua o crear una nueva cuenta seleccionando \'He olvidado mi contraseña\' en la solicitud de contraseña.</string> + <string name="startup_failed_data_too_new_error">La versión de esta apli es demasiado antigua. Por favor, actualiza a la última versión y prueba de nuevo.</string> + <string name="startup_failed_service_error">Briar no pudo iniciar un complemento necesario. Reinstalar Briar suele solucionar el problema. Sin embargo, ten en cuenta que perderás tu cuenta y todos los datos asociados ya que Briar no almacena esta información en ningún servidor central.</string> + <plurals name="expiry_warning"> + <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. Su cuenta expirará en %d dÃas y no podrá ser renovada.</item> + </plurals> + <string name="expiry_update">La fecha de caducidad de las pruebas se ha ampliado. Su cuenta expirará en %d dÃas.</string> + <string name="expiry_date_reached">Esta versión ha caducado.\n¡Gracias por probarla!</string> + <string name="download_briar">Para continuar usando Briar, por favor descargue la versión 1.0.</string> + <string name="create_new_account">Necesitarás crear una nueva cuenta, pero puedes usar el mismo usuario.</string> + <string name="download_briar_button">Descargar Briar 1.0</string> + <string name="startup_open_database">Descifrando la base de datos...</string> + <string name="startup_migrate_database">Actualizando la base de datos...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Abrir el panel de navegación</string> + <string name="nav_drawer_close_description">Cierra el panel de navegación</string> + <string name="contact_list_button">Contactos</string> + <string name="groups_button">Grupos privados</string> + <string name="forums_button">Foros</string> + <string name="blogs_button">Blogs</string> + <string name="settings_button">Configuración</string> + <string name="sign_out_button">Cerrar la sesión</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="reminder_notification_title">Desconectado de Briar</string> + <string name="reminder_notification_dismiss">Descartar</string> + <string name="ongoing_notification_title">Conectado a Briar</string> + <string name="ongoing_notification_text">Toca para abrir Briar.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Tienes un nuevo mensaje privado.</item> + <item quantity="other">Tienes %d nuevos mensajes privados.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Tienes un nuevo mensaje de grupo.</item> + <item quantity="other">Tienes %d nuevos mensajes de grupo.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Hay una nueva publicación en el foro.</item> + <item quantity="other">Hay %d nuevas publicaciones en el foro.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Hay una nueva entrada de blog.</item> + <item quantity="other">Hay %d nuevas entradas de blog.</item> + </plurals> + <!--Misc--> + <string name="now">ahora</string> + <string name="show">Mostrar</string> + <string name="hide">Ocultar</string> + <string name="ok">De acuerdo</string> + <string name="cancel">Cancelar</string> + <string name="got_it">Entendido</string> + <string name="delete">Borrar</string> + <string name="accept">Aceptar</string> + <string name="decline">Rechazar</string> + <string name="options">Configuración</string> + <string name="online">En lÃnea</string> + <string name="offline">Desconectado</string> + <string name="send">Enviar</string> + <string name="allow">Permitir</string> + <string name="open">Abrir</string> + <string name="no_data">Sin datos</string> + <string name="ellipsis">…</string> + <string name="text_too_long">El texto es demasiado largo</string> + <string name="show_onboarding">Mostrar diálogo de ayuda</string> + <string name="fix">Reparar</string> + <string name="help">Ayuda</string> + <string name="sorry">Disculpe</string> + <!--Contacts and Private Conversations--> + <string name="date_no_private_messages">Sin mensajes.</string> + <string name="no_private_messages">No hay mensajes que mostrar</string> + <string name="message_hint">Escribe un mensaje</string> + <string name="delete_contact">Eliminar contacto</string> + <string name="dialog_title_delete_contact">Confirmar eliminación de contacto</string> + <string name="dialog_message_delete_contact">¿Seguro que quieres eliminar este contacto y todos los mensajes intercambiados entre vosotros?</string> + <string name="contact_deleted_toast">Contacto eliminado</string> + <!--Adding Contacts--> + <string name="add_contact_title">Añadir un contacto</string> + <string name="face_to_face">Debes reunirte con la persona a la que quieras añadir como contacto.\n\nHaciéndolo asà prevendrás que nadie te suplante o pueda leer tus mensajes en el futuro.</string> + <string name="continue_button">Continuar</string> + <string name="connection_failed">La conexión falló</string> + <string name="try_again_button">Prueba de nuevo</string> + <string name="waiting_for_contact_to_scan">Esperando a que el contacto escanee y conecte contigo\u2026</string> + <string name="exchanging_contact_details">Intercambiando información de contacto\u2026</string> + <string name="contact_added_toast">Contacto añadido: %s</string> + <string name="contact_already_exists">El contacto %s ya existe</string> + <string name="contact_exchange_failed">El intercambio del contacto falló</string> + <string name="qr_code_invalid">El código QR no es válido</string> + <string name="qr_code_unsupported">El código QR que intenta escanear pertenece a una versión anterior de %s que ya no es compatible.\n\nAsegúrese de que ambos estén ejecutando la última versión y luego inténtelo de nuevo.</string> + <string name="camera_error">Error de cámara</string> + <string name="connecting_to_device">Conectando al dispositivo\u2026</string> + <string name="authenticating_with_device">Autentificándose con el dispositivo\u2026</string> + <string name="connection_aborted_local">¡Conexión interrumpida! Esto podrÃa significar que alguien está intentando interferir con su conexión</string> + <string name="connection_aborted_remote">¡La conexión ha sido interrumpida por tu contacto! Esto podrÃa significar que alguien está intentando interceptar la conexión</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Presenta a tus contactos</string> + <string name="introduction_onboarding_text">Presenta a tus contactos entre sà para ahorrarles encontrarse en persona para poder conectar mediante Briar.</string> + <string name="introduction_menu_item">Presentar contactos</string> + <string name="introduction_activity_title">Seleccionar contacto</string> + <string name="introduction_not_possible">Usted ya tiene una introducción en curso con estos contactos. Por favor, deje que esto termine primero. Si usted o sus contactos raramente están en lÃnea, esto puede tomar algún tiempo.</string> + <string name="introduction_message_title">Presentar a dos contactos</string> + <string name="introduction_message_hint">Añade un mensaje (opcional)</string> + <string name="introduction_button">Presentar contactos</string> + <string name="introduction_sent">Tu presentación se ha mandado.</string> + <string name="introduction_error">Ocurrió un error realizando la presentación.</string> + <string name="introduction_response_error">Error al responder a la presentación</string> + <string name="introduction_request_sent">Le has preguntado a %1$s si quiere que se le presente a %2$s.</string> + <string name="introduction_request_received">%1$s ha pedido presentarte a %2$s. ¿Quieres añadir a %2$s a tu lista de contactos?</string> + <string name="introduction_request_exists_received">%1$s ha pedido presentarte a %2$s, pero %2$s ya está en tu lista de contactos. %1$s puede no saberlo, asà que puedes responderle de todas maneras:</string> + <string name="introduction_request_answered_received">%1$s ha pedido presentarte a %2$s.</string> + <string name="introduction_response_accepted_sent">Has aceptado la presentación a %1$s.</string> + <string name="introduction_response_declined_sent">Has rechazado la presentación a %1$s.</string> + <string name="introduction_response_accepted_received">%1$s aceptó la presentación de %2$s.</string> + <string name="introduction_response_declined_received">%1$s rechazó la presentación a %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s dice que %2$s rechazó la presentación.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">nuevo contacto añadido.</item> + <item quantity="other">%d nuevos contactos añadido</item> + </plurals> + <!--Private Groups--> + <string name="groups_created_by">Creado por %s</string> + <plurals name="messages"> + <item quantity="one">%d mensaje</item> + <item quantity="other">%d mensajes</item> + </plurals> + <string name="groups_group_is_empty">Este grupo está vacÃo</string> + <string name="groups_group_is_dissolved">Este grupo ha sido disuelto</string> + <string name="groups_remove">Eliminar</string> + <string name="groups_create_group_title">Crear grupo privado</string> + <string name="groups_create_group_button">Crear grupo</string> + <string name="groups_create_group_invitation_button">Enviar invitación</string> + <string name="groups_create_group_hint">Elige un nombre para tu grupo privado</string> + <string name="groups_invitation_sent">Se ha mandado la invitación de grupo</string> + <string name="groups_message_sent">Mensaje enviado</string> + <string name="groups_member_list">Integrantes</string> + <string name="groups_invite_members">Invitar miembros</string> + <string name="groups_member_created_you">Tú creaste el grupo</string> + <string name="groups_member_created">%s creó el grupo</string> + <string name="groups_member_joined_you">Te uniste al grupo</string> + <string name="groups_member_joined">%s se unió al grupo</string> + <string name="groups_leave">Abandonar grupo</string> + <string name="groups_leave_dialog_title">Confirmación de la salida del grupo</string> + <string name="groups_leave_dialog_message">¿Estás seguro de querer salir de este grupo?</string> + <string name="groups_dissolve">Disolver grupo</string> + <string name="groups_dissolve_dialog_title">Confirmación de la disolución del grupo</string> + <string name="groups_dissolve_dialog_message">¿Estás seguro de querer disolver el grupo?\n\nLos demás miembros no podrán continuar la conversación y puede que nunca reciban los últimos mensajes.</string> + <string name="groups_dissolve_button">Disolver</string> + <string name="groups_dissolved_dialog_title">El grupo ha sido disuelto</string> + <string name="groups_dissolved_dialog_message">El creador de este grupo lo ha disuelto.\n\nYa no puedes escribir mensajes al grupo y puede que no recibas todas las publicaciones que se hayan escrito.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Invitaciones de grupo</string> + <string name="groups_invitations_invitation_sent">Has invitado a %1$s a ingresar en el grupo «%2$s».</string> + <string name="groups_invitations_invitation_received">%1$s te ha invitado a unirte al grupo «%2$s».</string> + <string name="groups_invitations_joined">Te has unido al grupo</string> + <string name="groups_invitations_declined">Invitación de grupo declinada</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d invitación de grupo sin responder</item> + <item quantity="other">%d invitaciones de grupo sin responder</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Aceptaste la invitación de grupo de %s.</string> + <string name="groups_invitations_response_declined_sent">Declinaste la invitación de grupo de %s.</string> + <string name="groups_invitations_response_accepted_received">%s ha aceptado la invitación al grupo.</string> + <string name="groups_invitations_response_declined_received">%s ha declinado la invitación al grupo.</string> + <string name="sharing_status_groups">Solo el creador puede invitar nuevos miembros al grupo. Abajo se listan todos los participantes actuales.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Revelar contactos</string> + <string name="groups_reveal_dialog_message">Puedes elegir si revelar los contactos a los actuales y futuros integrantes de este grupo.\n\nRevelar los contactos mejora la velocidad y la fiabilidad de tu conexión, porque puedes comunicarte con los contactos revelados incluso cuando el creador del grupo no se encuentra conectado.</string> + <string name="groups_reveal_visible">Las relaciones entre los contactos son visibles al grupo</string> + <string name="groups_reveal_visible_revealed_by_us">Las relaciones entre los contactos son visibles al grupo (las revelaste tú)</string> + <string name="groups_reveal_visible_revealed_by_contact">Las relaciones entre los contactos son visibles al grupo (las reveló %s)</string> + <string name="groups_reveal_invisible">Las relaciones entre los contactos no son visibles al grupo</string> + <!--Forums--> + <string name="create_forum_title">Crear foro</string> + <string name="choose_forum_hint">Elige un nombre para el foro</string> + <string name="create_forum_button">Crear foro</string> + <string name="forum_created_toast">Foro creado</string> + <string name="no_forum_posts">No hay publicaciones para mostrar</string> + <string name="no_posts">Sin publicaciones</string> + <plurals name="posts"> + <item quantity="one">%d publicación</item> + <item quantity="other">%d publicaciones</item> + </plurals> + <string name="forum_message_reply_hint">Nueva respuesta</string> + <string name="btn_reply">Responder</string> + <string name="forum_leave">Abandonar foro</string> + <string name="dialog_title_leave_forum">Confirmación abandono del foro</string> + <string name="dialog_message_leave_forum">¿Estás seguro de que quieres dejar este foro?\n\nCualquier contacto con el que hayas compartido este foro puede dejar de recibir actualizaciones.</string> + <string name="dialog_button_leave">Abandonar</string> + <string name="forum_left_toast">Foro abandonado</string> + <!--Forum Sharing--> + <string name="forum_share_button">Compartir foro</string> + <string name="contacts_selected">Contactos seleccionados</string> + <string name="activity_share_toolbar_header">Elige contactos</string> + <string name="forum_shared_snackbar">Foro compartido con los contactos seleccionados</string> + <string name="forum_share_message">Añade un mensaje (opcional)</string> + <string name="forum_share_error">Hubo un error compartiendo este foro.</string> + <string name="forum_invitation_received">%1$s ha compartido el foro \"%2$s\" contigo.</string> + <string name="forum_invitation_sent">Has compartido el foro \"%1$s\" con %2$s.</string> + <string name="forum_invitations_title">Invitaciones a foros</string> + <string name="forum_invitation_exists">Ya aceptaste una invitación a este foro. Aceptar más invitaciones hará que tu conexión al foro sea más rápida y confiable.</string> + <string name="forum_joined_toast">Foro en el que se ha inscrito</string> + <string name="forum_declined_toast">La invitación ha sido rechazada</string> + <string name="shared_by_format">Compartido por %s</string> + <string name="forum_invitation_already_sharing">Ya se está compartiendo</string> + <string name="forum_invitation_response_accepted_sent">Aceptaste la invitación al foro de %s.</string> + <string name="forum_invitation_response_declined_sent">Rechazaste la invitación al foro de %s.</string> + <string name="forum_invitation_response_accepted_received">%s aceptó la invitación al foro.</string> + <string name="forum_invitation_response_declined_received">%s rechazó la invitación al foro.</string> + <string name="sharing_status">Estado de la compartición</string> + <string name="sharing_status_forum">Cualquier miembro de un foro puede compartirlo con sus contactos. Estás compartiendo este foro con los contactos listados a continuación. Puede haber otros miembros que no puedes ver.</string> + <string name="shared_with">Compartido con %1$d (%2$d en lÃnea)</string> + <plurals name="forums_shared"> + <item quantity="one">%d foro compartido por contactos</item> + <item quantity="other">%d foros compartidos por contactos</item> + </plurals> + <string name="nobody">Nadie</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">No hay publicaciones para mostrar</string> + <string name="read_more">leer más</string> + <string name="blogs_write_blog_post">Escribir artÃculo del blog</string> + <string name="blogs_write_blog_post_body_hint">Escriba su entrada en el blog</string> + <string name="blogs_publish_blog_post">Publicar</string> + <string name="blogs_blog_post_created">Creado artÃculo del blog</string> + <string name="blogs_blog_post_received">Recibido nuevo artÃculo del blog</string> + <string name="blogs_blog_post_scroll_to">Desplazarse hasta</string> + <string name="blogs_remove_blog">Eliminar blog</string> + <string name="blogs_remove_blog_ok">Eliminar</string> + <string name="blogs_blog_removed">Blog eliminado</string> + <string name="blogs_reblog_comment_hint">Añade un comentario (opcional)</string> + <string name="blogs_reblog_button">Rebloguear</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Compartir blog</string> + <string name="blogs_sharing_error">Hubo un error al compartir este blog.</string> + <string name="blogs_sharing_button">Compartir blog</string> + <string name="blogs_sharing_snackbar">Blog compartido con los contactos seleccionados</string> + <string name="blogs_sharing_response_accepted_sent">Aceptaste la invitación al blog de %s.</string> + <string name="blogs_sharing_response_declined_sent">Rechazaste la invitación al blog de %s.</string> + <string name="blogs_sharing_response_accepted_received">%s aceptó la invitación al blog.</string> + <string name="blogs_sharing_response_declined_received">%s rechazó la invitación al blog.</string> + <string name="blogs_sharing_invitation_received">%1$s ha compartido el blog \"%2$s\" contigo.</string> + <string name="blogs_sharing_invitation_sent">Has compartido el blog \"%1$s\" con %2$s.</string> + <string name="blogs_sharing_invitations_title">Invitaciones a blogs</string> + <string name="blogs_sharing_joined_toast">Suscrito al blog</string> + <string name="blogs_sharing_declined_toast">La invitación ha sido rechazada</string> + <string name="sharing_status_blog">Cualquiera que se suscriba a un blog puede compartirlo con sus contactos. Estás compartiendo este blog con contactos listados a continuación. Puede haber otros suscriptores que no puedes ver.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Importar canal RSS</string> + <string name="blogs_rss_feeds_import_button">Importar</string> + <string name="blogs_rss_feeds_import_hint">Introduce la URL del canal RSS</string> + <string name="blogs_rss_feeds_import_error">Lo sentimos, hubo un error importando tu canal.</string> + <string name="blogs_rss_feeds_manage">Administrar canales RSS</string> + <string name="blogs_rss_feeds_manage_imported">Importado:</string> + <string name="blogs_rss_feeds_manage_author">Autor:</string> + <string name="blogs_rss_feeds_manage_updated">Última actualización:</string> + <string name="blogs_rss_remove_feed">Eliminar canal RSS</string> + <string name="blogs_rss_remove_feed_dialog_message">¿Estás seguro de que quieres quitar este feed?\n\nLos mensajes se eliminarán del dispositivo, pero no de los dispositivos de otras personas.\n\nEs posible que los contactos con los que hayas compartido esta fuente dejen de recibir actualizaciones.</string> + <string name="blogs_rss_remove_feed_ok">Eliminar</string> + <string name="blogs_rss_feeds_manage_delete_error">¡El canal no pudo ser eliminado!</string> + <string name="blogs_rss_feeds_manage_empty_state">No hay canales RSS que mostrar\n\nToque el icono + para importar un feed</string> + <string name="blogs_rss_feeds_manage_error">Hubo un problema cargando tus canales RSS. Por favor, prueba más tarde.</string> + <!--Settings Display--> + <string name="display_settings_title">Mostrar</string> + <string name="pref_theme_title">Tema decorativo</string> + <string name="pref_theme_light">Claro</string> + <string name="pref_theme_dark">Oscuro</string> + <string name="pref_theme_system">Sistema por defecto</string> + <!--Settings Network--> + <string name="network_settings_title">Redes</string> + <string name="bluetooth_setting">Conectar mediante Bluetooth</string> + <string name="bluetooth_setting_enabled">Cuando haya contactos cerca</string> + <string name="bluetooth_setting_disabled">Solo al añadir contactos</string> + <string name="tor_network_setting">Conectar a través de Tor</string> + <string name="tor_network_setting_never">Nunca</string> + <string name="tor_network_setting_wifi">Solo con wifi</string> + <string name="tor_network_setting_always">Con wifi o datos móviles</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Seguridad</string> + <string name="change_password">Cambiar contraseña</string> + <string name="choose_new_password">Nueva contraseña</string> + <string name="confirm_new_password">Confirme la nueva contraseña</string> + <string name="password_changed">La contraseña ha sido cambiada.</string> + <string name="panic_setting">Configuración del botón de pánico</string> + <string name="panic_setting_title">Botón de pánico</string> + <string name="panic_setting_hint">Configura cómo reaccionará Briar cuando uses una aplicación de botón de pánico</string> + <string name="panic_app_setting_title">Aplicación botón de pánico</string> + <string name="unknown_app">una aplicación desconocida</string> + <string name="panic_app_setting_summary">No se ha seleccionado aplicación</string> + <string name="panic_app_setting_none">Ninguna</string> + <string name="dialog_title_connect_panic_app">Confirmar aplicación de pánico</string> + <string name="dialog_message_connect_panic_app">¿Seguro que quieres permitir que %1$s lance acciones destructivas de botón de pánico?</string> + <string name="panic_setting_signout_title">Cerrar sesión</string> + <string name="panic_setting_signout_summary">Cerrar la sesión de Briar si se pulsa un botón de pánico</string> + <string name="purge_setting_title">Eliminar cuenta</string> + <string name="purge_setting_summary">Eliminar tu cuenta de Briar si se pulsa un botón de pánico. Advertencia: esto eliminará permanentemente tus identidades, contactos y mensajes</string> + <string name="uninstall_setting_title">Desinstalar Briar</string> + <string name="uninstall_setting_summary">Requerirá confirmación manual en el momento de pánico</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Notificaciones</string> + <string name="notify_private_messages_setting_title">Mensajes privados</string> + <string name="notify_private_messages_setting_summary">Notificar mensajes privados</string> + <string name="notify_private_messages_setting_summary_26">Configurar alertas para mensajes privados</string> + <string name="notify_group_messages_setting_title">Mensajes de grupo</string> + <string name="notify_group_messages_setting_summary">Notificar mensajes de grupo</string> + <string name="notify_group_messages_setting_summary_26">Configurar alertas para mensajes de grupo</string> + <string name="notify_forum_posts_setting_title">Publicaciones en foros</string> + <string name="notify_forum_posts_setting_summary">Notificar publicaciones en foros</string> + <string name="notify_forum_posts_setting_summary_26">Configurar alertas para los mensajes del foro</string> + <string name="notify_blog_posts_setting_title">Entradas de blog</string> + <string name="notify_blog_posts_setting_summary">Notificar entradas de blog</string> + <string name="notify_blog_posts_setting_summary_26">Configurar alertas para entradas de blog</string> + <string name="notify_vibration_setting">Vibrar</string> + <string name="notify_lock_screen_setting_title">Pantalla de bloqueo</string> + <string name="notify_lock_screen_setting_summary">Notificaciones en la pantalla de bloqueo</string> + <string name="notify_sound_setting">Sonar</string> + <string name="notify_sound_setting_default">Tono de notificación predeterminado</string> + <string name="notify_sound_setting_disabled">Ninguna</string> + <string name="choose_ringtone_title">Elegir alerta sonora</string> + <string name="cannot_load_ringtone">No se puede cargar el timbre</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Retroalimentación</string> + <string name="send_feedback">Enviar comentario</string> + <!--Link Warning--> + <string name="link_warning_title">Advertencia sobre el enlace</string> + <string name="link_warning_intro">Estás a punto de abrir el siguiente enlace con otra aplicación</string> + <string name="link_warning_text">Esto puede usarse para identificarte. Piensa si confÃas en la persona que te envió el enlace y considera la opción de abrirlo con Orfox.</string> + <string name="link_warning_open_link">Abrir enlace</string> + <!--Crash Reporter--> + <string name="crash_report_title">Informe de error de Briar</string> + <string name="briar_crashed">Lo sentimos, Briar ha fallado.</string> + <string name="not_your_fault">No es tu culpa.</string> + <string name="please_send_report">Por favor, ayúdanos a construir mejor Briar enviándonos un informe de error.</string> + <string name="report_is_encrypted">Prometemos que el informe se cifrará y se enviará de forma segura.</string> + <string name="feedback_title">Danos tu opinión</string> + <string name="describe_crash">Describe qué ha ocurrido (opcional)</string> + <string name="enter_feedback">Escribe tu comentario</string> + <string name="optional_contact_email">Tu correo electrónico (opcional)</string> + <string name="include_debug_report_crash">Incluir información anónima sobre el error</string> + <string name="include_debug_report_feedback">Incluir información anónima sobre este dispositivo</string> + <string name="could_not_load_report_data">No se pudieron cargar los datos del informe.</string> + <string name="send_report">Enviar informe</string> + <string name="close">Cerrar</string> + <string name="dev_report_saved">Informe guardado. Se enviará la próxima vez que inicies Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">Saliendo de Briar…</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Superposición de pantalla detectada</string> + <string name="screen_filter_body">Otra aplicación se está mostrando por encima de Briar. Por seguridad, Briar no reaccionará a los toques mientras otras aplicaciones se muestren por encima.\n\nLas siguientes aplis pueden ser las causantes:\n\n%1$s</string> + <string name="screen_filter_allow">Permitir a estas aplicaciones a mostrarse por encima</string> + <!--Permission Requests--> + <string name="permission_camera_title">Permiso de cámara</string> + <string name="permission_camera_request_body">Para escanear el código QR, Briar necesita acceso a la cámara.</string> + <string name="permission_camera_denied_body">Ha denegado el acceso a la cámara, pero para añadir contactos se requiere el uso de la cámara.\n\nPor favor considere la posibilidad de conceder el acceso.</string> + <string name="permission_camera_denied_toast">No se concedió el permiso de cámara</string> + <string name="qr_code">Código QR</string> + <string name="show_qr_code_fullscreen">Mostrar código QR a pantalla completa</string> +</resources> diff --git a/mailbox-android/src/main/res/values-eu/strings.xml b/mailbox-android/src/main/res/values-eu/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..e8d5f47bd734336afe8ef6a3a152c40ec64ab609 --- /dev/null +++ b/mailbox-android/src/main/res/values-eu/strings.xml @@ -0,0 +1,413 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Ongi etorri Briar-era</string> + <string name="setup_name_explanation">Zure ezizena argitaratzen dituzun eduki guztien ondoan agertuko da. Ezin dezakezu aldatu kontua sortu eta gero.</string> + <string name="setup_next">Hurrengoa</string> + <string name="setup_password_intro">Aukeratu pasahitz bat</string> + <string name="setup_password_explanation">Zure Briar kontua zure gailuan zifratuta gordetzen da, ez hodeian. Briar desinstalatzen baduzu edo pasahitza ahazten baduzu, ez dago zure kontua eta datuak berreskuratzeko modurik.\n\nAukeratu asmatzeko zaila den pasahitz luze bat, adibidez ausazko lau hitz edo ausazko hamar letra, zenbaki eta ikur.</string> + <string name="setup_doze_title">Atzeko planoko konexioak</string> + <string name="setup_doze_intro">Mezuak jasotzeko, Briar bigarren planoak konektatuta mantendu behar da.</string> + <string name="setup_doze_explanation">Mezuak jasotzeko, Briar bigarren planoak konektatuta mantendu behar da. Mesedez desgaitu bateria optimizazioak Briar konektatuta mantendu dadin.</string> + <string name="setup_doze_button">Baimendu konexioak</string> + <string name="choose_nickname">Hautatu zure ezizena</string> + <string name="choose_password">Hautatu zure pasahitza</string> + <string name="confirm_password">Berretsi zure pasahitza</string> + <string name="name_too_long">Izena luzeegia da</string> + <string name="password_too_weak">Pasahitza ahulegia da</string> + <string name="passwords_do_not_match">Pasahitzak ez datoz bat</string> + <string name="create_account_button">Sortu kontua</string> + <string name="more_info">Informazio gehiago</string> + <string name="don_t_ask_again">Ez galdetu berriro</string> + <string name="setup_huawei_text">Sakatu beheko botoia eta ziurtatu Briar babestuta dagoela \"Babestutako aplikazioak\" pantailan.</string> + <string name="setup_huawei_button">Babestu Briar</string> + <string name="setup_huawei_help">Briar ez bada babestutako aplikazioen zerrendara gehitu, ezin izango du bigarren planoan ibili.</string> + <string name="warning_dozed">%s ezin izan da bigarren planoan abiatu</string> + <!--Login--> + <string name="enter_password">Pasahitza</string> + <string name="try_again">Pasahitz okerra, saiatu berriro</string> + <string name="sign_in_button">Hasi saioa</string> + <string name="forgotten_password">Nire pasahitza ahaztu dut</string> + <string name="dialog_title_lost_password">Pasahitz galdua</string> + <string name="dialog_message_lost_password">Zure Briar kontua zure gailuan zifratuta gordetzen da, ez hodeian, beraz ezin dugu zure pasahitza berrezarri. Zure kontua ezabatu eta berriro hasi nahi duzu?\n\nKontuz: Zure identitateak, kontaktuak eta mezuak betirako galduko dira.</string> + <string name="startup_failed_notification_title">Ezin izan da Briar abiatu</string> + <string name="startup_failed_notification_text">Sakatu informazio gehiagorako</string> + <string name="startup_failed_activity_title">Briar abio-hutsegitea</string> + <string name="startup_failed_db_error">Dena delakoagatik, zure Briar datu-basea hondatuta dago eta ezin da konpondu. Zure kontua, zure datuak eta zure kontaktuak galdu dira. Zoritxarrez Briar berrinstalatu behar duzu eta kontu berria sortu \'Pasahitza ahaztu dut\' aukeratuz.</string> + <string name="startup_failed_data_too_old_error">Zure kontua aplikazio honen bertsio zahar batekin sortu zen eta ezin da bertsio honekin ireki. Aurreko bertsioa instalatu dezakezu edo kontua berri bat sortu \'Pasahitza ahaztu dit\' aukeratuz.</string> + <string name="startup_failed_data_too_new_error">Aplikazioaren bertsio hau zaharregia da. Eguneratu azken bertsiora eta saiatu berriro.</string> + <string name="startup_failed_service_error">Briar aplikazioak ezin izan du ezinbesteko plugin bat abiatu. Briar berrinstalatzeak arazoa konpondu ohi du. Hala ere, jakin zure kontua eta datuak galduko dituzula Briar aplikazioak ez baititu zerbitzari zentralak erabiltzen zure datuak gordetzeko.</string> + <plurals name="expiry_warning"> + <item quantity="one">Hau Briar-en probetarako bertsio bat da. Zure kontua egun %d barru iraungituko da eta ezin da berriztu.</item> + <item quantity="other">Hau Briar-en probetarako bertsio bat da. Zure kontua %d egun barru iraungituko da eta ezin da berriztu.</item> + </plurals> + <string name="expiry_update">Probetarako iraungitze data luzatu da. Zure kontua %d egun barru iraungituko da.</string> + <string name="expiry_date_reached">Programa hau iraungitu da.\nEskerrik asko probatzeagatik!</string> + <string name="download_briar">Briar erabiltzen jarraitzeko, deskargatu 1.0 bertsioa.</string> + <string name="create_new_account">Kontu berri bat sortu beharko duzu, baina erabiltzaile-izen berdina erabili dezakezu.</string> + <string name="download_briar_button">Deskargatu Briar 1.0</string> + <string name="startup_open_database">Datu-basea deszifratzen...</string> + <string name="startup_migrate_database">Datu-basea eguneratzen...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Ireki nabigazio tiradera</string> + <string name="nav_drawer_close_description">Itxi nabigazio tiradera</string> + <string name="contact_list_button">Kontaktuak</string> + <string name="groups_button">Talde pribatuak</string> + <string name="forums_button">Foroak</string> + <string name="blogs_button">Blogak</string> + <string name="settings_button">Ezarpenak</string> + <string name="sign_out_button">Amaitu saioa</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="reminder_notification_title">Briar saioa amaituta</string> + <string name="reminder_notification_text">Sakatu saioa berriro hasteko</string> + <string name="reminder_notification_channel_title">Briar saioaren oroigarria</string> + <string name="reminder_notification_dismiss">Baztertu</string> + <string name="ongoing_notification_title">Briar saioa hasita</string> + <string name="ongoing_notification_text">Ukitu Briar irekitzeko</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Mezu pribatu berri bat.</item> + <item quantity="other">%d mezu pribatu berri.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Talde mezu berri bat.</item> + <item quantity="other">%d talde mezu berri.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Foro sarrera berri bat.</item> + <item quantity="other">%d foro sarrera berri.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Blog sarrera berri bat.</item> + <item quantity="other">%d blog sarrera berri.</item> + </plurals> + <!--Misc--> + <string name="now">orain</string> + <string name="show">Erakutsi</string> + <string name="hide">Ezkutatu</string> + <string name="ok">Ados</string> + <string name="cancel">Utzi</string> + <string name="got_it">Ulertu dut</string> + <string name="delete">Ezabatu</string> + <string name="accept">Onartu</string> + <string name="decline">Ukatu</string> + <string name="options">Aukerak</string> + <string name="online">Konektatuta</string> + <string name="offline">Deskonektatuta</string> + <string name="send">Bidali</string> + <string name="allow">Baimendu</string> + <string name="open">Ireki</string> + <string name="no_data">Daturik ez</string> + <string name="ellipsis">…</string> + <string name="text_too_long">Sartutako testua luzeegia da</string> + <string name="show_onboarding">Erakutsi laguntza elkarrizketa-koadroa</string> + <string name="fix">Konpondu</string> + <string name="help">Laguntza</string> + <string name="sorry">Sentitzen dugu</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Kontakturik ez erakusteko\n\nSakatu + ikonoa kontaktua gehitzeko</string> + <string name="date_no_private_messages">Mezurik ez.</string> + <string name="no_private_messages">Mezurik ez erakusteko</string> + <string name="message_hint">Idatzi mezua</string> + <string name="delete_contact">Ezabatu kontaktua</string> + <string name="dialog_title_delete_contact">Berretsi kontaktua ezabatzea</string> + <string name="dialog_message_delete_contact">Ziur kontaktu hau eta berarekin trukatutako mezu guztiak mezu guztiak kendu nahi dituzula?</string> + <string name="contact_deleted_toast">Kontaktua ezabatuta</string> + <!--Adding Contacts--> + <string name="add_contact_title">Gehitu kontaktua</string> + <string name="face_to_face">Aurrez aurre aurkitu behar zara pertsonarekin kontaktua gehitzeko.\n\nHonek inork zure itxurak egitea edo zure mezuak irakurtzea eragotziko du.</string> + <string name="continue_button">Jarraitu</string> + <string name="connection_failed">Konexioak huts egin du</string> + <string name="try_again_button">Saiatu berriro</string> + <string name="waiting_for_contact_to_scan">Kontaktuak eskaneatu dezan eta konektatu dadin zain\u2026</string> + <string name="exchanging_contact_details">Kontaktu-xehetasunak trukatzen\u2016</string> + <string name="contact_added_toast">Kontaktua gehituta: %s</string> + <string name="contact_already_exists">%s kontaktua badago aurretik</string> + <string name="contact_exchange_failed">Kontaktuen trukeak huts egin du</string> + <string name="qr_code_invalid">QR kodea baliogabea da</string> + <string name="qr_code_unsupported">Eskaneatzen saiatu zaren QR kodea %s programaren bertsio zahar bati dagokio eta ez du euskarririk jada.\n\nZiurtatu biak azken bertsioa erabiltzen duzuela eta saiatu berriro.</string> + <string name="camera_error">Kameraren errorea</string> + <string name="connecting_to_device">Gailura konektatzen\u2026</string> + <string name="authenticating_with_device">Gailuarekin autentifikatzen\u2026</string> + <string name="connection_aborted_local">Konexioa eten da! Honek norbait konexioan interferentziak sortzen ari dela esan nahi lezake.</string> + <string name="connection_aborted_remote">Zure kontaktuak eten du konexioa! Norbait zure konexioan interferentziak sortzen saiatzen ari dela esan nahi lezake</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Aurkeztu zure kontaktuak</string> + <string name="introduction_onboarding_text">Zure kontaktuak bata besteari aurkeztu ditzakezu, horrela ez dute aurrez aurre elkartzeko beharra Briar erabiltzeko.</string> + <string name="introduction_menu_item">Egin aurkezpena</string> + <string name="introduction_activity_title">Hautatu kontaktua</string> + <string name="introduction_not_possible">Baduzu aurkezpen bat abian kontaktu hauekin. Baimendu hura bukatzea aurretik. Zure kontaktuak gutxitan konektatzen badira honek denbora bat behar lezake.</string> + <string name="introduction_message_title">Aurkeztu kontaktuak</string> + <string name="introduction_message_hint">Gehitu mezu bat (aukerazkoa)</string> + <string name="introduction_button">Egin aurkezpena</string> + <string name="introduction_sent">Zure aurkezpena bidali da</string> + <string name="introduction_error">Errorea gertatu da aurkezpena egitean.</string> + <string name="introduction_response_error">Errorea aurkezpenari erantzutean</string> + <string name="introduction_request_sent">%1$s erabiltzailea %2$s erabiltzaileari aurkeztea eskatu duzu</string> + <string name="introduction_request_received">%1$s erabiltzaileak %2$s zuri aurkeztea eskatu dizu. %2$s Kontaktuen zerrendara gehitu nahi duzu?</string> + <string name="introduction_request_exists_received">%1$s erabiltzaileak %2$s zuri aurkeztea eskatu dizu, baina %2$s badago zure kontaktuen zerrendan. Agian %1$s erabiltzaileak ez daki, erantzun dezakezu:</string> + <string name="introduction_request_answered_received">%1$s erabiltzaileak %2$s zuri aurkeztea eskatu du.</string> + <string name="introduction_response_accepted_sent">%1$s erabiltzailearen aurkezpena onartu duzu.</string> + <string name="introduction_response_accepted_sent_info">%1$s zure kontaktuetara gehitu aurretik, aurkezpena onartu behar dute ere. Honek denbora bat behar lezake.</string> + <string name="introduction_response_declined_sent">%1$s erabiltzailearen aurkezpena ukatu duzu.</string> + <string name="introduction_response_accepted_received">%1$s erabiltzaileak %2$s erabiltzailearen aurkezpena onartu du.</string> + <string name="introduction_response_declined_received">%1$s erabiltzaileak %2$s erabiltzailearen aurkezpena ukatu du.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s erabiltzaileak dio %2$s erabiltzaileak aurkezpena ukatu duela.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Kontaktu berria gehituta.</item> + <item quantity="other">%d kontaktu berri gehituta.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">Ez dago talderik erakusteko\n\nSakatu + ikonoa talde bat sortzeko, edo eskatu zure kontaktuei taldeak zurekin partekatzea</string> + <string name="groups_created_by">%s erabiltzaileak sortuta</string> + <plurals name="messages"> + <item quantity="one">mezu %d</item> + <item quantity="other">%d mezu</item> + </plurals> + <string name="groups_group_is_empty">Talde hau hutsik dago</string> + <string name="groups_group_is_dissolved">Talde hau disolbatu da</string> + <string name="groups_remove">Kendu</string> + <string name="groups_create_group_title">Sortu talde pribatua</string> + <string name="groups_create_group_button">Sortu taldea</string> + <string name="groups_create_group_invitation_button">Bidali gonbidapena</string> + <string name="groups_create_group_hint">Aukeratu zure talde pribatuaren izena</string> + <string name="groups_invitation_sent">Talde gonbidapena bidali da</string> + <string name="groups_message_sent">Mezua bidalita</string> + <string name="groups_member_list">Kideen zerrenda</string> + <string name="groups_invite_members">Gonbidatu kideak</string> + <string name="groups_member_created_you">Zuk taldea sortu duzu</string> + <string name="groups_member_created"> %s erabiltzaileak taldea sortu du</string> + <string name="groups_member_joined_you">Zu taldera elkartu zara</string> + <string name="groups_member_joined">%s taldera elkartu da</string> + <string name="groups_leave">Utzi taldea</string> + <string name="groups_leave_dialog_title">Berretsi taldea uztea</string> + <string name="groups_leave_dialog_message">Ziur talde hau utzi nahi duzula?</string> + <string name="groups_dissolve">Disolbatu taldea</string> + <string name="groups_dissolve_dialog_title">Berretsi taldea disolbatzea</string> + <string name="groups_dissolve_dialog_message">Ziur talde hau disolbatu nahi duzula?\n\nBeste kideek ezin izango dute elkarrizketarekin jarraitu eta ez dituzu azken mezuak jasoko.</string> + <string name="groups_dissolve_button">Disolbatu</string> + <string name="groups_dissolved_dialog_title">Taldea disolbatu da</string> + <string name="groups_dissolved_dialog_message">Talde honen sortzaileak taldea disolbatu du.\n\nEzin dituzu jada mezuak bidali talde honetara eta agian ez dituzu jasoko idatzi diren mezu guztiak.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Talde gonbidapenak</string> + <string name="groups_invitations_invitation_sent">%1$s erabiltzailea \"%2$s\" taldera gonbidatu duzu.</string> + <string name="groups_invitations_invitation_received">%1$s erabiltzailea \"%2$s\" taldera gonbidatu zaitu.</string> + <string name="groups_invitations_joined">Taldera elkartuta</string> + <string name="groups_invitations_declined">Talde gonbidapena ukatuta</string> + <plurals name="groups_invitations_open"> + <item quantity="one">talde ireki gonbidapen %d</item> + <item quantity="other">%d talde ireki gonbidapen</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">%s erabiltzailearen talde gonbidapena onartu duzu.</string> + <string name="groups_invitations_response_declined_sent">%s erabiltzailearen talde gonbidapena ukatu duzu. </string> + <string name="groups_invitations_response_accepted_received">%s erabiltzaileak talde gonbidapena onartu du.</string> + <string name="groups_invitations_response_declined_received">%s erabiltzaileak talde gonbidapena ukatu du.</string> + <string name="sharing_status_groups">Sortzaileak besterik ezin ditu kide berriak gehitu taldera. Behean oraingo kide guztiak daude.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Argitara eman kontaktuak</string> + <string name="groups_reveal_dialog_message">Taldeko oraingo eta etorkizuneko kide guztiei kontaktuak argitara eman ala ez aukeratu dezakezu.\n\nKontaktuak partekatzean zure taldera konexioa azkarragoa eta egonkorragoa izango da, argitara emandako kontaktuekin komunikatu zaitezkeelako sortzailea deskonektatuta badago ere.</string> + <string name="groups_reveal_visible">Kontaktuen erlazioa taldean ikusgai dago</string> + <string name="groups_reveal_visible_revealed_by_us">Kontaktuen erlazioa taldean ikusgai dago (Zuk argitara emana)</string> + <string name="groups_reveal_visible_revealed_by_contact">Kontaktuen erlazioa taldean ikusgai dago (%s erabiltzaileak argitara emana)</string> + <string name="groups_reveal_invisible">Kontaktuen erlazioa ez dago taldean ikusgai</string> + <!--Forums--> + <string name="no_forums">Ez dago fororik erakusteko\n\nSakatu + ikonoa talde bat sortzeko, edo eskatu zure kontaktuei foroak zurekin partekatzea</string> + <string name="create_forum_title">Sortu foroa</string> + <string name="choose_forum_hint">Hautatu zure foroaren izena</string> + <string name="create_forum_button">Sortu foroa</string> + <string name="forum_created_toast">Foroa sortuta</string> + <string name="no_forum_posts">Ez dago mezurik erakusteko</string> + <string name="no_posts">Sarrerarik ez</string> + <plurals name="posts"> + <item quantity="one">Bidalketa %d</item> + <item quantity="other">%d sarrera</item> + </plurals> + <string name="forum_new_entry_posted">Foroko sarrera argitaratuta</string> + <string name="forum_new_message_hint">Sarrera berria</string> + <string name="forum_message_reply_hint">Erantzun berria</string> + <string name="btn_reply">Erantzun</string> + <string name="forum_leave">Utzi foroa</string> + <string name="dialog_title_leave_forum">Berretsi foroa uztea</string> + <string name="dialog_message_leave_forum">Ziur foro hau utzi nahi duzula?\n\nForo hau beste norbaitekin partekatu baduzu agian ez dituzte eguneraketak jasoko.</string> + <string name="dialog_button_leave">Utzi</string> + <string name="forum_left_toast">Foroa utzi du</string> + <!--Forum Sharing--> + <string name="forum_share_button">Partekatu foroa</string> + <string name="contacts_selected">Kontaktuak hautatuta</string> + <string name="activity_share_toolbar_header">Hautatu kontaktuak</string> + <string name="no_contacts_selector">Ez dago kontakturik erakusteko\n\nItzuli hona kontakturen bat gehitu eta gero</string> + <string name="forum_shared_snackbar">Foroa partekatuta hautatutako kontaktuekin</string> + <string name="forum_share_message">Gehitu mezua (aukerazkoa)</string> + <string name="forum_share_error">Errore bat egon da foro hau partekatzean.</string> + <string name="forum_invitation_received">%1$s erabiltzaileak \"%2$s\" foroa partekatu du zurekin.</string> + <string name="forum_invitation_sent">\"%1$s\" foroa partekatu duzu %2$s erabiltzailearekin.</string> + <string name="forum_invitations_title">Forora gonbidapenak</string> + <string name="forum_invitation_exists">Foro honetarako gonbidapen bat onartu duzu jada. Gonbidapen gehiago onartzeak foroarekin konexioa azkarrago eta egonkorragoa egingo du.</string> + <string name="forum_joined_toast">Forora elkartuta</string> + <string name="forum_declined_toast">Gonbidapena ukatuta</string> + <string name="shared_by_format">%s erabiltzaileak partekatuta</string> + <string name="forum_invitation_already_sharing">Dagoeneko partekatzen</string> + <string name="forum_invitation_response_accepted_sent"> %s erabiltzailearen foro gonbidapena onartu duzu.</string> + <string name="forum_invitation_response_declined_sent">%s erabiltzailearen foro gonbidapena ukatu duzu.</string> + <string name="forum_invitation_response_accepted_received">%s erabiltzaileak foro gonbidapena onartu du.</string> + <string name="forum_invitation_response_declined_received"> %s erabiltzaileak foro gonbidapena ukatu du.</string> + <string name="sharing_status">Partekatze egoera</string> + <string name="sharing_status_forum">Foroko edozein kidek partekatu dezake bere kontaktuekin. Honako erabiltzaileekin partekatzen duzu zuk. Ikusten ez dituzun kide gehiago egon daitezke.</string> + <string name="shared_with">%1$d erabiltzaileekin partekatuta (%2$d konektatuta)</string> + <plurals name="forums_shared"> + <item quantity="one">Kontaktuek partekatutako foro %d</item> + <item quantity="other">Kontaktuek partekatutako %d foro</item> + </plurals> + <string name="nobody">Inor ez</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Ez dago mezurik erakusteko</string> + <string name="read_more">irakurri gehiago</string> + <string name="blogs_write_blog_post">Idatzi blog sarrera</string> + <string name="blogs_write_blog_post_body_hint">Idatzi zure blog sarrera</string> + <string name="blogs_publish_blog_post">Argitaratu</string> + <string name="blogs_blog_post_created">Blog sarrera sortuta</string> + <string name="blogs_blog_post_received">Blog sarrera berria jasota</string> + <string name="blogs_blog_post_scroll_to">Korritu hona</string> + <string name="blogs_feed_empty_state">Ez dago sarrerarik erakusteko\n\nZure kontaktuen eta harpidetutako sarrerak bidalketak hemen agertuko dira\n\nSakatu arkatzaren ikonoa sarrera bat idazteko</string> + <string name="blogs_remove_blog">Kendu bloga</string> + <string name="blogs_remove_blog_dialog_message">Ziur blog hau kendu nahi duzula?\n\nSarrerak zure gailutik kenduko dira baina ez besteen gailuetatik.\n\nBlog hau beste inorekin partekatu baduzu agian eguneraketak jasotzeari utziko diote.</string> + <string name="blogs_remove_blog_ok">Kendu</string> + <string name="blogs_blog_removed">Blog-a kenduta</string> + <string name="blogs_reblog_comment_hint">Gehitu iruzkina (aukerazkoa)</string> + <string name="blogs_reblog_button">Birblogeatu</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Partekatu bloga</string> + <string name="blogs_sharing_error">Errore bat egon da blog hau partekatzean.</string> + <string name="blogs_sharing_button">Partekatu bloga</string> + <string name="blogs_sharing_snackbar">Bloga hautatutako kontaktuekin partekatuta</string> + <string name="blogs_sharing_response_accepted_sent">%s erabiltzailearen blog gonbidapena onartu duzu.</string> + <string name="blogs_sharing_response_declined_sent">%s erabiltzailearen blog gonbidapena ukatu duzu.</string> + <string name="blogs_sharing_response_accepted_received">%s erabiltzaileak blog gonbidapena onartu du.</string> + <string name="blogs_sharing_response_declined_received">%s erabiltzaileak blog gonbidapena ukatu du.</string> + <string name="blogs_sharing_invitation_received">%1$s erabiltzaileak \"%2$s\" bloga partekatu du zurekin.</string> + <string name="blogs_sharing_invitation_sent">\"%1$s\" bloga partekatu duzu %2$s erabiltzailearekin.</string> + <string name="blogs_sharing_invitations_title">Blog gonbidapenak</string> + <string name="blogs_sharing_joined_toast">Blog-era harpidetuta</string> + <string name="blogs_sharing_declined_toast">Gonbidapena ukatuta</string> + <string name="sharing_status_blog">Blog batetara harpidetutako edonork berau partekatu dezake bere kontaktuekin. Honako kontaktuekin partekatzen duzu zuk. Ikusten ez dituzun harpidedun gehiago egon daitezke.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Inportatu RSS jarioa</string> + <string name="blogs_rss_feeds_import_button">Inportatu</string> + <string name="blogs_rss_feeds_import_hint">Sartu RSS jarioaren URLa</string> + <string name="blogs_rss_feeds_import_error">Sentitzen dugu! Zure jarioa inportatzean errore bat gertatu da.</string> + <string name="blogs_rss_feeds_manage">Kudeatu RSS jarioak</string> + <string name="blogs_rss_feeds_manage_imported">Inportatuta:</string> + <string name="blogs_rss_feeds_manage_author">Egilea:</string> + <string name="blogs_rss_feeds_manage_updated">Azken eguneraketa:</string> + <string name="blogs_rss_remove_feed">Kendu jarioa:</string> + <string name="blogs_rss_remove_feed_dialog_message">Ziur jario hau kendu nahi duzula?\n\nSarrerak zure gailutik kenduko dira baina ez besteen gailuetatik.\n\nJario hau beste inorekin partekatu baduzu agian eguneraketak jasotzeari utziko diote.</string> + <string name="blogs_rss_remove_feed_ok">Kendu</string> + <string name="blogs_rss_feeds_manage_delete_error">Ezin izan da jarioa ezabatu!</string> + <string name="blogs_rss_feeds_manage_empty_state">RSS jariorik ez erakusteko\n\nSakatu + ikonoa jario bat inportatzeko</string> + <string name="blogs_rss_feeds_manage_error">Arazo bat egon da zure jarioak kargatzean. Saiatu berriro geroago.</string> + <!--Settings Display--> + <string name="pref_language_title">Hizkuntza eta eskualdea</string> + <string name="pref_language_changed">Ezarpen hauek Brfiar berrabiaraztean jarriko dira indarrean. Amaitu saioa eta berrabiarazi Briar.</string> + <string name="pref_language_default">Sisteman lehenetsia</string> + <string name="display_settings_title">Erakutsi</string> + <string name="pref_theme_title">Azalgaia</string> + <string name="pref_theme_light">Argia</string> + <string name="pref_theme_dark">Iluna</string> + <string name="pref_theme_auto">Automatikoa (Egunez)</string> + <string name="pref_theme_system">Sistemak lehenetsia</string> + <!--Settings Network--> + <string name="network_settings_title">Sareak</string> + <string name="bluetooth_setting">Konektatu Bluetooth bidez</string> + <string name="bluetooth_setting_enabled">Kontaktuak hurbil daudeneak</string> + <string name="bluetooth_setting_disabled">Kontaktuak gehitzean besterik ez</string> + <string name="tor_network_setting">Konektatu Tor bidez</string> + <string name="tor_network_setting_never">Inoiz ez</string> + <string name="tor_network_setting_wifi">Wi-Fi erabiltzean besterik ez</string> + <string name="tor_network_setting_always">Wi-Fi edo datu mugikorrak erabiltzean</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Segurtasuna</string> + <string name="change_password">Aldatu pasahitza</string> + <string name="current_password">Oraingo pasahitza</string> + <string name="choose_new_password">Pasahitz berria</string> + <string name="confirm_new_password">Berretsi pasahitz berria</string> + <string name="password_changed">Pasahitza aldatu da.</string> + <string name="panic_setting">Larrialdi botoiaren ezarpena</string> + <string name="panic_setting_title">Larrialdi botoia</string> + <string name="panic_setting_hint">Konfiguratu Briar aplikazioak nola jokatuko duen larrialdi botoiaren aplikazioa erabiltzean</string> + <string name="panic_app_setting_title">Larrialdi botoiaren aplikazioa</string> + <string name="unknown_app">aplikazio ezezagun bat</string> + <string name="panic_app_setting_summary">Ez da aplikaziorik ezarri</string> + <string name="panic_app_setting_none">Bat ere ez</string> + <string name="dialog_title_connect_panic_app">Berretsi larrialdi-aplikazioa</string> + <string name="dialog_message_connect_panic_app">Ziur %1$s baimendu nahi duzula larrialdi botoiaren ekintza suntsitzaileak burutzea?</string> + <string name="panic_setting_signout_title">Amaitu saioa</string> + <string name="panic_setting_signout_summary">Amaitu saioa larrialdi botoia zapaltzen bada</string> + <string name="purge_setting_title">Ezabatu kontua</string> + <string name="purge_setting_summary">Ezabatu kontua Briar larrialdi botoia zapaltzen bada. Kontuz: Honek behin betiko ezabatuko ditu zure identitateak, kontaktuak eta mezuak</string> + <string name="uninstall_setting_title">Desinstalatu Briar</string> + <string name="uninstall_setting_summary">Honek eskuzko berrespena behar du larrialdi egoeran</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Jakinarazpenak</string> + <string name="notify_sign_in_title">Gogorarazi saioa hasteko</string> + <string name="notify_sign_in_summary">Erakutsi oroigarri bat telefonoa abiatzean edo aplikazioa eguneratzean.</string> + <string name="notify_private_messages_setting_title">Mezu pribatuak</string> + <string name="notify_private_messages_setting_summary">Erakutsi mezu pribatuen alertak</string> + <string name="notify_private_messages_setting_summary_26">Konfiguratu mezu pribatuen alertak</string> + <string name="notify_group_messages_setting_title">Talde mezuak</string> + <string name="notify_group_messages_setting_summary">Erakutsi taldeetako mezuen alertak</string> + <string name="notify_group_messages_setting_summary_26">Konfiguratu taldeetako mezuen alertak</string> + <string name="notify_forum_posts_setting_title">Foroko sarrerak</string> + <string name="notify_forum_posts_setting_summary">Erakutsi foroko sarreren alertak</string> + <string name="notify_forum_posts_setting_summary_26">Konfiguratu foroko mezuen alertak</string> + <string name="notify_blog_posts_setting_title">Blog sarrerak</string> + <string name="notify_blog_posts_setting_summary">Erakutsi blog sarreren alertak</string> + <string name="notify_blog_posts_setting_summary_26">Konfiguratu blog sarrerentzako alertak</string> + <string name="notify_vibration_setting">Bibratu</string> + <string name="notify_lock_screen_setting_title">Blokeo-pantaila</string> + <string name="notify_lock_screen_setting_summary">Erakutsi jakinarazpenak blokeo-pantailan</string> + <string name="notify_sound_setting">Soinua</string> + <string name="notify_sound_setting_default">Lehenetsitako dei-doinua</string> + <string name="notify_sound_setting_disabled">Bat ere ez</string> + <string name="choose_ringtone_title">Hautatu dei-doinua</string> + <string name="cannot_load_ringtone">Ezin izan da dei-doinua kargatu</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Iruzkinak</string> + <string name="send_feedback">Bidali iruzkinak</string> + <!--Link Warning--> + <string name="link_warning_title">Estekari buruzko abisua</string> + <string name="link_warning_intro">Honako esteka hau kanpo aplikazio batekin irekitzear zaude.</string> + <string name="link_warning_text">Hau zu identifikatzeko erabili daiteke. Pentsatu esteka hau bidali dizun pertsonarengan konfiantza duzun eta baloratu Orfox bidez irekitzea.</string> + <string name="link_warning_open_link">Ireki esteka</string> + <!--Crash Reporter--> + <string name="crash_report_title">Briar kraskatze errorea</string> + <string name="briar_crashed">Briar kraskatu da.</string> + <string name="not_your_fault">Ez da zure errua.</string> + <string name="please_send_report">Lagundu Briar hobetzen kraskatze txostena guri bidaliz.</string> + <string name="report_is_encrypted">Txostena zifratuta dagoela eta modu seguruan bidaliko dela agintzen dizugu.</string> + <string name="feedback_title">Iruzkinak</string> + <string name="describe_crash">Deskribatu zer gertatu den (aukerazkoa)</string> + <string name="enter_feedback">Idatzi zure iruzkinak</string> + <string name="optional_contact_email">Zure e-mail helbidea (aukerazkoa)</string> + <string name="include_debug_report_crash">Gehitu kraskatzeari buruzko informazio anonimoa</string> + <string name="include_debug_report_feedback">Gehitu gailu honi buruzko informazio anonimoa</string> + <string name="could_not_load_report_data">Ezin izan dira kargatu txostenaren datuak.</string> + <string name="send_report">Bidali txostena</string> + <string name="close">Itxi</string> + <string name="dev_report_saved">Txostena gordeta. Briar saioa hasten duzunean bidaliko da.</string> + <!--Sign Out--> + <string name="progress_title_logout">Briar saioa amaitzen...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Pantaila gainjartzea antzeman da</string> + <string name="screen_filter_body">Briar aplikazioaren gainean marrazten ari den beste aplikazio bat dago, Briar aplikazioak ez dio ukimenari erantzungo beste aplikazio bat gainean marrazten dagoen bitartean.\n\nHauek dira gainean marrazten egon daitezkeen aplikazioak:\n\n%1$s</string> + <string name="screen_filter_allow">Baimendu aplikazio hauei gainean idazten</string> + <!--Permission Requests--> + <string name="permission_camera_title">Kamera baimena</string> + <string name="permission_camera_request_body">QR kodea eskaneatzeko Briar-ek kamera atzitu behar du.</string> + <string name="permission_camera_denied_body">Kameraatzitzeko baimena ukatu duzu, baina kontaktuak gehitzeko kamera behar da.\n\nMesedez baimendu sarbidea.</string> + <string name="permission_camera_denied_toast">Eza kameraren baimenik eman</string> + <string name="qr_code">QR kodea</string> + <string name="show_qr_code_fullscreen">Erakutsi QR kodea pantaila osoan</string> +</resources> diff --git a/mailbox-android/src/main/res/values-fa/strings.xml b/mailbox-android/src/main/res/values-fa/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..10c315a94b040a5f0b053dae7a77a0deeb7e01dc --- /dev/null +++ b/mailbox-android/src/main/res/values-fa/strings.xml @@ -0,0 +1,456 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">به برایر خوش آمدید</string> + <string name="setup_name_explanation">نام مستعارتان کنار هر مطلب شما قرار خواهد Ú¯Ø±ÙØª Ùˆ بعد از ایجاد ØØ³Ø§Ø¨ کاربری امکان تغییر آن وجود ندارد.</string> + <string name="setup_next">بعدی</string> + <string name="setup_password_intro">یک رمز عبور انتخاب کنید</string> + <string name="setup_password_explanation">ØØ³Ø§Ø¨ کاربری برایر شما به صورت رمزگذاری شده روی وسیله شما به جای ØØ§Ùظه ابری ذخیره شده است. اگر شما رمز عبور خود را ÙØ±Ø§Ù…وش کنید یا برایر را پاک کنید، راهی برای بازیابی ØØ³Ø§Ø¨ کاربری شما وجود نخواهد داشت. + +یک رمز عبور طولانی انتخاب کنید Ú©Ù‡ ØØ¯Ø³ آن سخت باشد، مثل چهار عبارت تصادÙÛŒ یا ده لغت تصادÙÛŒ با اعداد Ùˆ نماد ها.</string> + <string name="setup_doze_title">اتصال های پس زمینه</string> + <string name="setup_doze_intro">برای Ø¯Ø±ÛŒØ§ÙØª پیام، برایر نیاز دارد تا در پس زمینه اتصال داشته باشد.</string> + <string name="setup_doze_explanation">برای Ø¯Ø±ÛŒØ§ÙØª پیام، برایر نیاز دارد تا در پس زمینه اتصال داشته باشد. Ù„Ø·ÙØ§ بهینه سازی باتری را غیر ÙØ¹Ø§Ù„ کنید تا برایر بتواند به اتصال خود ادامه دهد.</string> + <string name="setup_doze_button">دادن اجازه به اتصالات</string> + <string name="choose_nickname">نام مستعار خود را انتخاب کنید</string> + <string name="choose_password">رمز عبور خود را انتخاب کنید</string> + <string name="confirm_password">رمز عبور خود را تایید کنید</string> + <string name="name_too_long">نام بیش از ØØ¯ طولانی Ù…ÛŒ باشد</string> + <string name="password_too_weak">رمز عبور ضعی٠می باشد</string> + <string name="passwords_do_not_match">رمز های عبور مطابقت ندارند </string> + <string name="create_account_button">ایجاد ØØ³Ø§Ø¨ کاربری</string> + <string name="more_info">اطلاعات بیشتر</string> + <string name="don_t_ask_again">دیگر نپرس</string> + <string name="setup_huawei_text">Ù„Ø·ÙØ§ روی دکمه زیر کلیک کنید Ùˆ مطمئن شوید Ú©Ù‡ از برایر در ØµÙØÙ‡ \"برنامه های Ù…ØØ§Ùظت شده\" Ù…ØØ§Ùظت Ù…ÛŒ شود.</string> + <string name="setup_huawei_button">ØÙاظت از برایر</string> + <string name="setup_huawei_help">اگر برایر به Ùهرست برنامه های Ù…ØØ§Ùظت شده اضاÙÙ‡ نشده، نمی تواند در پس زمینه مشغول به کار باشد.</string> + <string name="warning_dozed">ناتوانی %s برای اجراء در پس زمینه</string> + <!--Login--> + <string name="enter_password">رمز عبور</string> + <string name="try_again">رمز عبور اشتباه است، Ù„Ø·ÙØ§ دوباره سعی کنید</string> + <string name="sign_in_button">ورود</string> + <string name="forgotten_password">رمز عبور را ÙØ±Ø§Ù…وش کرده ام</string> + <string name="dialog_title_lost_password">رمز عبور گمشده</string> + <string name="dialog_message_lost_password">ØØ³Ø§Ø¨ کاربری برایر شما به صورت رمزنگاری شده روی سیستم شما به جای ØØ§Ùظه ابری ذخیره شده است برای همین ما نمی توانیم رمز عبور شما را به صورت مجدد تنظیم کنیم. آیا مایل هستید تا ØØ³Ø§Ø¨ کاربری شما را پاک کنیم Ùˆ دوباره از ابتدا شروع کنیم؟ + +اخطار: هویت های شما، مخاطبان شما Ùˆ پیام های شما برای همیشه از بین خواهند Ø±ÙØª.</string> + <string name="startup_failed_notification_title">برایر نمی تواند شروع به کار کند.</string> + <string name="startup_failed_notification_text">برای اطلاعات بیشتر کلیک کنید</string> + <string name="startup_failed_activity_title">خطا در شروع برایر</string> + <string name="startup_failed_db_error">به دلایلی، دیتابیس برایر شما خراب شده Ùˆ قابل Ø§ØµÙ„Ø§Ø Ù†ÛŒØ³Øª. ØØ³Ø§Ø¨ کاربری شما، داده های شما Ùˆ تمام مخاطبان شما از بین Ø±ÙØªÙ‡ اند. Ù…ØªØ§Ø³ÙØ§Ù†Ù‡ØŒ شما یا باید برایر را دوباره نصب کنید یا یک ØØ³Ø§Ø¨ کاربری جدید با انتخاب \'رمز عبور ام را ÙØ±Ø§Ù…وش کرده ام\' انتخاب کنید.</string> + <string name="startup_failed_data_too_old_error">ØØ³Ø§Ø¨ کاربری شما با یک نسخه قدیمی از این برنامه ایجاد شده است Ùˆ به همین خاطربا این نسخه نمی تواند باز شود. شما باید نسخه قدیمی را دوباره نصب کنید یا یک ØØ³Ø§Ø¨ کاربری جدید با \"رمز عبور ام را ÙØ±Ø§Ù…وش کرده ام\" در پرامپت رمز عبور ایجاد کنید.</string> + <string name="startup_failed_data_too_new_error">این نسخه از برنامه قدیمی Ù…ÛŒ باشد. Ù„Ø·ÙØ§ به آخرین نسخه از برنامه ارتقاء داده Ùˆ دوباره سعی کنید.</string> + <string name="startup_failed_service_error">برایر نمی تواند یک پلاگین ضروری را اجراء کند. نصب دوباره برایر معمولا این مشکل را ØÙ„ میکند. هرچند، توجه داشته باشید Ú©Ù‡ ØØ³Ø§Ø¨ کاربری Ùˆ تمام داده های مرتبط با آن را از دست خواهید داد از آنجایی Ú©Ù‡ برایر از هیچ سرور مرکزی برای ذخیره داده های شما Ø§Ø³ØªÙØ§Ø¯Ù‡ نمی کند.</string> + <plurals name="expiry_warning"> + <item quantity="one">این یک نسخه آزمایشی از برایر Ù…ÛŒ باشد. ØØ³Ø§Ø¨ کاربری شما در %d روز آینده به پایان Ù…ÛŒ رسد Ùˆ امکان تمدید آن وجود نخواهد داشت.</item> + <item quantity="other">این یک نسخه آزمایشی از برایر Ù…ÛŒ باشد. ØØ³Ø§Ø¨ کاربری شما در %d روز آینده به پایان Ù…ÛŒ رسد Ùˆ امکان تمدید آن وجود نخواهد داشت.</item> + </plurals> + <string name="expiry_update">تاریخ اتمام آزمایش Ø§ÙØ²Ø§ÛŒØ´ ÛŒØ§ÙØªÙ‡ است. ØØ³Ø§Ø¨ کاربری شما در %d روز آینده به پایان Ù…ÛŒ رسد.</string> + <string name="expiry_date_reached">این نرم Ø§ÙØ²Ø§Ø± منقضی شده است. + +بابت تست از شما سپاسگزاریم.</string> + <string name="download_briar">برای اینکه به Ø§Ø³ØªÙØ§Ø¯Ù‡ خود از برایر ادامه دهید، Ù„Ø·ÙØ§ نسخه Û±.Û° را دانلود کنید.</string> + <string name="create_new_account">لازم است تا یک ØØ³Ø§Ø¨ کاربری جدید ایجاد کنید، Ù…ÛŒ توانید از نام مستعار یکسان برای ØØ³Ø§Ø¨ های کاربری Ø§Ø³ØªÙØ§Ø¯Ù‡ کنید.</string> + <string name="download_briar_button">دانلود برایر 1.0</string> + <string name="startup_open_database">رمزگشایی سیستم ...</string> + <string name="startup_migrate_database">به روز رسانی سیستم ...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">باز کردن منوی برنامه</string> + <string name="nav_drawer_close_description">بستن منوی برنامه</string> + <string name="contact_list_button">مخاطبین</string> + <string name="groups_button">گروه های خصوصی</string> + <string name="forums_button">تالار های Ú¯ÙØªÙ…ان</string> + <string name="blogs_button">بلاگ ها</string> + <string name="settings_button">تنظیمات</string> + <string name="sign_out_button">خروج</string> + <!--Transports--> + <string name="transport_tor">اینترنت</string> + <string name="transport_bt">بلوتوث</string> + <string name="transport_lan">وای ÙØ§ÛŒ</string> + <!--Notifications--> + <string name="reminder_notification_title">از برایر خارج شد</string> + <string name="reminder_notification_channel_title">یادآور ورود برایر</string> + <string name="ongoing_notification_title">وارد برایر شد</string> + <string name="ongoing_notification_text">برای باز کردن برایر کلیک کنید.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">%dپیام خصوصی جدید</item> + <item quantity="other">%dپیام خصوصی جدید</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">پیام گروه جدید</item> + <item quantity="other">%d پیام گروه جدید</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">پست ÙØ±ÙˆÙ… جدید</item> + <item quantity="other">%d پست ÙØ±ÙˆÙ… جدید</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">پست پلاگ جدید</item> + <item quantity="other">%d پست بلاگ جدید</item> + </plurals> + <!--Misc--> + <string name="now">هم اکنون</string> + <string name="show">نمایش</string> + <string name="hide">پنهان کردن</string> + <string name="ok">تأیید</string> + <string name="cancel">لغو</string> + <string name="got_it">متوجه شدم</string> + <string name="delete">ØØ°Ù</string> + <string name="accept">Ù¾Ø°ÛŒØ±ÙØªÙ†</string> + <string name="decline">رد کردن</string> + <string name="options">گزینه ها</string> + <string name="online">آنلاین</string> + <string name="offline">Ø¢Ùلاین</string> + <string name="send">ارسال</string> + <string name="allow">اجازه دادن</string> + <string name="open">باز کردن</string> + <string name="no_data">داده ای موجود نمی باشد</string> + <string name="ellipsis">…</string> + <string name="text_too_long">متن وارد شده بیش از ØØ¯ طولانی Ù…ÛŒ باشد</string> + <string name="show_onboarding">نمایش پنجره راهنما</string> + <string name="fix">اصلاØ</string> + <string name="help">راهنما</string> + <string name="sorry">ببخشید</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">مخاطبی برای نشان دادن وجود ندارد + +روی علامت + برای Ø§ÙØ²ÙˆØ¯Ù† مخاطب کلیک کنید</string> + <string name="date_no_private_messages">هیچ پیامی موجود نیست</string> + <string name="no_private_messages">هیچ پیامی برای نشان دادن وجود ندارد</string> + <string name="message_hint">نوشتن پیام</string> + <string name="delete_contact">ØØ°Ù مخاطب</string> + <string name="dialog_title_delete_contact">تایید ØØ°Ù مخاطب</string> + <string name="dialog_message_delete_contact">آیا مطمئن هستید Ú©Ù‡ میخواهید این مخاطب Ùˆ تمام پیام های تبادل شده با آن را ØØ°Ù کنید؟</string> + <string name="contact_deleted_toast">مخاطب ØØ°Ù شد</string> + <!--Adding Contacts--> + <string name="add_contact_title">Ø§ÙØ²ÙˆØ¯Ù† مخاطب</string> + <string name="face_to_face">برای اضاÙÙ‡ کردن ÙØ±Ø¯ به عنوان مخاطب باید با او به صورت ØØ¶ÙˆØ±ÛŒ ملاقات کنید. +این از جعل هویت شما Ùˆ یا از خوانده شدن پیام هایتان در آینده جلوگیری خواهد کرد.</string> + <string name="continue_button">ادامه</string> + <string name="connection_failed">اتصال ناموÙÙ‚ بود</string> + <string name="try_again_button">دوباره سعی کنید</string> + <string name="waiting_for_contact_to_scan">انتظار برای اسکن Ùˆ اتصال مخاطبu2026\</string> + <string name="exchanging_contact_details">تبادیل جزییات مخاطبu2026\</string> + <string name="contact_added_toast">مخاطب اضاÙÙ‡ شد: %s</string> + <string name="contact_already_exists">مخاطب %s از قبل وجود دارد</string> + <string name="contact_exchange_failed">تبادل مخاطب با خطا مواجه شد</string> + <string name="qr_code_invalid">کد QR نامعتبر Ù…ÛŒ باشد</string> + <string name="qr_code_unsupported">کد QR Ú©Ù‡ شما سعی دارید اسکن کنید متعلق به یک نسخه قدیمی از %s میباشد Ú©Ù‡ دیگر پشتیبانی نمی شود. + +Ù„Ø·ÙØ§ مطمئن شوید Ú©Ù‡ هردوی شما از آخرین نسخه Ø§Ø³ØªÙØ§Ø¯Ù‡ میکنید Ùˆ دوباره Ø§Ù…ØªØØ§Ù† کنید.</string> + <string name="camera_error">خطای دوربین</string> + <string name="connecting_to_device">اتصال به دستگاهu2026\</string> + <string name="authenticating_with_device">تصدیق سازی با دستگاه u2026\</string> + <string name="connection_aborted_local">اتصال قطع شد! این میتواند نشان دهنده این باشد Ú©Ù‡ شخصی قصد دارد در اتصال شما اختلال ایجاد کند</string> + <string name="connection_aborted_remote">اتصال توسط مخاطب شما بی نتیجه ماند! این ممکن است نشان دهنده این باشد Ú©Ù‡ شخصی سعی دارد تا در اتصال شما اختلال ایجاد کند</string> + <!--Introductions--> + <string name="introduction_onboarding_title">معرÙÛŒ مخاطبان</string> + <string name="introduction_onboarding_text">شما Ù…ÛŒ توانید مخاطبان خود را به یکدیگر معرÙÛŒ کنید، در این صورت دیگر نیازی به دیدار ØØ¶ÙˆØ±ÛŒ برای اتصال روی برایر نمی باشد.</string> + <string name="introduction_menu_item">معرÙÛŒ کردن</string> + <string name="introduction_activity_title">انتخاب مخاطب</string> + <string name="introduction_not_possible">شما همین الان یک معرÙÛŒ در مرØÙ„Ù‡ انجام با این مخاطبان دارید. Ù„Ø·ÙØ§ اجازه دهید تا این معرÙÛŒ به پایان برسد. اگر شما Ùˆ یا مخاطبانتان به ندرت آنلاین هستید، ممکن است Ú©Ù…ÛŒ زمان ببرد.</string> + <string name="introduction_message_title">معرÙÛŒ مخاطبین</string> + <string name="introduction_message_hint">Ø§ÙØ²ÙˆØ¯Ù† یک پیام (اختیاری)</string> + <string name="introduction_button">معرÙÛŒ کردن</string> + <string name="introduction_sent">معرÙÛŒ شما ÙØ±Ø³ØªØ§Ø¯Ù‡ شد.</string> + <string name="introduction_error">خطایی در معرÙÛŒ کردن رخ داده است.</string> + <string name="introduction_response_error">خطا در هنگام پاسخ به معرÙÛŒ</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_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_response_accepted_sent">شما معرÙÛŒ به %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_accepted_received">%1$s معرÙÛŒ به %2$s را Ù¾Ø°ÛŒØ±ÙØª.</string> + <string name="introduction_response_declined_received">%1$s معرÙÛŒ به %2$s را رد کرد.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s Ù…ÛŒ گوید Ú©Ù‡ %2$s دعوت نامه را رد کرد.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">مخاطب جدید Ø§ÙØ²ÙˆØ¯Ù‡ شد.</item> + <item quantity="other">%d مخاطب جدید Ø§ÙØ²ÙˆØ¯Ù‡ شد.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">هیچ گروهی برای نمایش وجود ندارد + +روی آیکون + برای ایجاد یک گروه کلیک کنید، یا از مخاطبان خود بخواهید تا گروهی را با شما به اشتراک بگذارند</string> + <string name="groups_created_by">ایجاد شده توسط %s</string> + <plurals name="messages"> + <item quantity="one">%d پیام</item> + <item quantity="other">%d پیام</item> + </plurals> + <string name="groups_group_is_empty">این گروه خالی Ù…ÛŒ باشد</string> + <string name="groups_group_is_dissolved">این گروه منØÙ„ شده است</string> + <string name="groups_remove">ØØ°Ù</string> + <string name="groups_create_group_title">ایجاد گروه خصوصی</string> + <string name="groups_create_group_button">ایجاد گروه</string> + <string name="groups_create_group_invitation_button">ارسال دعوت نامه</string> + <string name="groups_create_group_hint">یک نام برای گروه شخصی خود انتخاب کنید</string> + <string name="groups_invitation_sent">دعوت نامه گروه ÙØ±Ø³ØªØ§Ø¯Ù‡ شد</string> + <string name="groups_message_sent">پیام ÙØ±Ø³ØªØ§Ø¯Ù‡ شد</string> + <string name="groups_member_list">لیست اعضا</string> + <string name="groups_invite_members">دعوت اعضا</string> + <string name="groups_member_created_you">شما گروه را ایجاد کردید</string> + <string name="groups_member_created">%s گروه را ایجاد کرد</string> + <string name="groups_member_joined_you">شما به عضویت گروه درآمدید</string> + <string name="groups_member_joined">%sعضو گروه شد</string> + <string name="groups_leave">ترک گروه</string> + <string name="groups_leave_dialog_title">تایید ترک گروه</string> + <string name="groups_leave_dialog_message">مطمئن هستید Ú©Ù‡ میخواهید این گروه را ترک کنید؟</string> + <string name="groups_dissolve">انØÙ„ال گروه</string> + <string name="groups_dissolve_dialog_title">تایید انØÙ„ال گروه</string> + <string name="groups_dissolve_dialog_message">آیا از انØÙ„ال این گروه اطمینان دارید؟ + +سایر اعضاء قادر نخواهند بود تا مکالمات خود را ادامه دهند Ùˆ ممکن است آخرین پیام ها را Ø¯Ø±ÛŒØ§ÙØª نکنند.</string> + <string name="groups_dissolve_button">انØÙ„ال</string> + <string name="groups_dissolved_dialog_title">گروه انØÙ„ال ÛŒØ§ÙØª</string> + <string name="groups_dissolved_dialog_message">ایجاد کننده این گروه آن را منØÙ„ کرده است. + +شما از این به بعد قادر نخواهید بود پیام های دیگری در گروه بنویسید Ùˆ ممکن است تمام پست هایی Ú©Ù‡ نوشته شده اند را Ø¯Ø±ÛŒØ§ÙØª نکنید.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">دعوت نامه های گروه</string> + <string name="groups_invitations_invitation_sent">شما %1$s را برای عضویت به گروه \"%2$s\" دعوت کردید.</string> + <string name="groups_invitations_invitation_received">%1$s شما را دعوت کرده تا عضو گروه \"%2$s\" شوید.</string> + <string name="groups_invitations_joined">عضو گروه شد</string> + <string name="groups_invitations_declined">دعوت نامه گروه رد شد</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d دعوتنامه سرگشاده</item> + <item quantity="other">%d دعوت نامه سرگشاده</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">شما دعوت نامه گروه از %s را Ù¾Ø°ÛŒØ±ÙØªÛŒØ¯.</string> + <string name="groups_invitations_response_declined_sent">شما دعوت نامه گروه از %s را رد کردید.</string> + <string name="groups_invitations_response_accepted_received">%sدعوت نامه گروه را Ù¾Ø°ÛŒØ±ÙØª.</string> + <string name="groups_invitations_response_declined_received">%s دعوت نامه گروه را رد کرد.</string> + <string name="sharing_status_groups">Ùقط سازنده گروه Ù…ÛŒ تواند اعضای جدید را به گروه دعوت کند. در پایین تمام اعضای ÙØ¹Ù„ÛŒ گروه آمده است.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">نشان دادن مخاطبان</string> + <string name="groups_reveal_dialog_message">شما میتوانید مخاطبان را به تمام اعضای ÙØ¹Ù„ÛŒ Ùˆ آینده این گروه نشان دهید. + +نشان دادن مخاطبان اتصال شما به گروه را سریع تر Ùˆ قابل اطمینان تر میکند، چراکه میتوانید با مخاطبان نشان داده شده ارتباط برقرار کنید ØØªÛŒ در موقعی Ú©Ù‡ گروه Ø¢Ùلاین Ù…ÛŒ باشد.</string> + <string name="groups_reveal_visible">ارتباط مخاطب برای گروه قابل دیدن Ù…ÛŒ باشد</string> + <string name="groups_reveal_visible_revealed_by_us">ارتباط مخاطب برای گروه قابل دیدن Ù…ÛŒ باشد (آشکار شده توسط شما)</string> + <string name="groups_reveal_visible_revealed_by_contact">ارتباط مخاطب برای گروه قابل یدن Ù…ÛŒ باشد (آشکار شده توسط %s)</string> + <string name="groups_reveal_invisible">ارتباط مخاطب برای گروه قابل دیدن نمی باشد</string> + <!--Forums--> + <string name="no_forums">هیچ ÙØ±ÙˆÙ…ÛŒ برای نمایش وجود ندارد + +روی آیکون + برای ایجاد ÙØ±ÙˆÙ… کلیک کنید یا از مخاطبانتان بخواهید تا با شما ÙØ±ÙˆÙ… به اشتراک بگذارند</string> + <string name="create_forum_title">ایجاد ÙØ±ÙˆÙ…</string> + <string name="choose_forum_hint">انتخاب یک نام برای ÙØ±ÙˆÙ…</string> + <string name="create_forum_button">ایجاد ÙØ±ÙˆÙ…</string> + <string name="forum_created_toast">ÙØ±ÙˆÙ… ایجاد شد</string> + <string name="no_forum_posts">هیچ پستی برای نشان دادن وجود ندارد</string> + <string name="no_posts">هیچ پستی وجود ندارد</string> + <plurals name="posts"> + <item quantity="one">%d پست</item> + <item quantity="other">%d پست</item> + </plurals> + <string name="forum_new_entry_posted">پست ÙØ±ÙˆÙ… انتشار ÛŒØ§ÙØª</string> + <string name="forum_new_message_hint">پست جدید</string> + <string name="forum_message_reply_hint">پاسخ جدید</string> + <string name="btn_reply">پاسخ</string> + <string name="forum_leave">ترک ÙØ±ÙˆÙ…</string> + <string name="dialog_title_leave_forum">تأیید ترک ÙØ±ÙˆÙ…</string> + <string name="dialog_message_leave_forum">آیا اطمینان دارید Ú©Ù‡ میخواهید این ÙØ±ÙˆÙ… را ترک کنید؟ + +هر مخاطبی Ú©Ù‡ این ÙØ±ÙˆÙ… را با آنها به اشتراک گذاشته اید ممکن است آپدیت دیگری Ø¯Ø±ÛŒØ§ÙØª نکنند.</string> + <string name="dialog_button_leave">ترک</string> + <string name="forum_left_toast">ترک ÙØ±ÙˆÙ…</string> + <!--Forum Sharing--> + <string name="forum_share_button">اشتراک گذاری ÙØ±ÙˆÙ…</string> + <string name="contacts_selected">مخاطبان انتخاب شدند</string> + <string name="activity_share_toolbar_header">انتخاب مخاطبان</string> + <string name="no_contacts_selector">هیچ مخاطبی برای نمایش دادن وجود ندارد + +Ù„Ø·ÙØ§ بعد از Ø§ÙØ²ÙˆØ¯Ù† مخاطب برگردید.</string> + <string name="forum_shared_snackbar">ÙØ±ÙˆÙ… با مخاطبان انتخاب شده به اشتراک گذاشته شد</string> + <string name="forum_share_message">Ø§ÙØ²ÙˆØ¯Ù† یک پیام (اختیاری)</string> + <string name="forum_share_error">خطایی با اشتراک گذاری این ÙØ±ÙˆÙ… رخ داد</string> + <string name="forum_invitation_received">%1$s ÙØ±ÙˆÙ… \"%2$s\" را با شما به اشتراک گذاشته است.</string> + <string name="forum_invitation_sent">شما ÙØ±ÙˆÙ… \"%1$s\" را با %2$s به اشتراک گذاشتید.</string> + <string name="forum_invitations_title">دعوت نامه های ÙØ±ÙˆÙ…</string> + <string name="forum_invitation_exists">شما دعوت به این ÙØ±ÙˆÙ… را Ù¾Ø°ÛŒØ±ÙØªÙ‡ بودید. + +Ù¾Ø°ÛŒØ±ÙØªÙ† دعوت نامه های بیشتر باعث Ù…ÛŒ شود تا اتصال شما به ÙØ±ÙˆÙ… سریع تر Ùˆ قابل اطمینان تر شود.</string> + <string name="forum_joined_toast">عضو ÙØ±ÙˆÙ… شد</string> + <string name="forum_declined_toast">دعوت نامه رد شد</string> + <string name="shared_by_format">به اشتراک گذاشته شده توسط %s</string> + <string name="forum_invitation_already_sharing">در ØØ§Ù„ به اشتراک گذاری</string> + <string name="forum_invitation_response_accepted_sent">شما دعوت نامه ÙØ±ÙˆÙ… از %s را Ù¾Ø°ÛŒØ±ÙØªÛŒØ¯.</string> + <string name="forum_invitation_response_declined_sent">شما دعوت نامه ÙØ±ÙˆÙ… از %s را رد کردید.</string> + <string name="forum_invitation_response_accepted_received">%s دعوت نامه ÙØ±ÙˆÙ… را Ù¾Ø°ÛŒØ±ÙØª.</string> + <string name="forum_invitation_response_declined_received">%s دعوت نامه ÙØ±ÙˆÙ… را رد کرد.</string> + <string name="sharing_status">به اشتراک گذاری وضعیت</string> + <string name="sharing_status_forum">هر عضو ÙØ±ÙˆÙ… Ù…ÛŒ تواند آن را با دیگر مخاطبان خود به اشتراک بگذارد. شما این ÙØ±ÙˆÙ… را با مخاطبان زیر به اشتراک Ù…ÛŒ گذارید. ممکن است اعضای دیگری هم باشند Ú©Ù‡ شما نمی توانید آن ها را ببینید.</string> + <string name="shared_with">به اشتراک گذاشته شده با %1$d (%2$d Ù†ÙØ± آنلاین)</string> + <plurals name="forums_shared"> + <item quantity="one"> %d ÙØ±ÙˆÙ… به اشتراک گذاشته شده توسط مخاطبان</item> + <item quantity="other">%d ÙØ±ÙˆÙ… به اشتراک گذاشته شده توسط مخاطبان</item> + </plurals> + <string name="nobody">هیچکس</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">هیچ پستی برای نشان دادن وجود ندارد</string> + <string name="read_more">بیشتر بخوانید</string> + <string name="blogs_write_blog_post">نوشتن پست بلاگ</string> + <string name="blogs_write_blog_post_body_hint">پست بلاگ خود را بنویسید</string> + <string name="blogs_publish_blog_post">انتشار</string> + <string name="blogs_blog_post_created">پست بلاگ ایجاد شد</string> + <string name="blogs_blog_post_received">پست جدید بلاگ Ø¯Ø±ÛŒØ§ÙØª شد</string> + <string name="blogs_blog_post_scroll_to">ØØ±Ú©Øª به</string> + <string name="blogs_feed_empty_state">هیچ پستی برای نشان دادن وجود ندارد + +پست های مخاطبان Ùˆ بلاگ هایی Ú©Ù‡ مشترک آن ها هستید اینجا نشان داده خواهند شد + +روی آیکون خودکار برای ایجاد یک پست کلیک کنید</string> + <string name="blogs_remove_blog">ØØ°Ù بلاگ</string> + <string name="blogs_remove_blog_dialog_message">آیا اطمینان دارید Ú©Ù‡ میخواهید این بلاگ را ØØ°Ù کنید؟ + +پست ها از روی دستگاه شما ØØ°Ù خواهند شد اما از روی دستگاه سایر Ø§ÙØ±Ø§Ø¯ ØØ°Ù نخواهد شد. + +هر مخاطبی Ú©Ù‡ شما این بلاگ را با آن ها به اشتراک گذاشته اید ممکن است از این به بعد آپدیتی Ø¯Ø±ÛŒØ§ÙØª نکند.</string> + <string name="blogs_remove_blog_ok">ØØ°Ù</string> + <string name="blogs_blog_removed">بلاگ ØØ°Ù شد</string> + <string name="blogs_reblog_comment_hint">Ø§ÙØ²ÙˆØ¯Ù† یک کامنت (اختیاری)</string> + <string name="blogs_reblog_button">ریبلاگ</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">به اشتراک گذاری بلاگ</string> + <string name="blogs_sharing_error">خطایی با اشتراک گذاری این بلاگ وجود داشت.</string> + <string name="blogs_sharing_button">به اشتراک گذاری بلاگ</string> + <string name="blogs_sharing_snackbar">بلاگ با مخاطبان انتخاب شده به اشتراک گذاشته شد</string> + <string name="blogs_sharing_response_accepted_sent">شما دعوت نامه بلاگ از طر٠%s را Ù¾Ø°ÛŒØ±ÙØªÛŒØ¯.</string> + <string name="blogs_sharing_response_declined_sent">شما دعوت نامه بلاگ از %s را رد کردید.</string> + <string name="blogs_sharing_response_accepted_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_sent">شما بلاگ \"%1$s\" را با %2$s به اشتراک گذاشته اید.</string> + <string name="blogs_sharing_invitations_title">دعوت نامه های بلاگ</string> + <string name="blogs_sharing_joined_toast">به اشتراک بلاگ درآمد</string> + <string name="blogs_sharing_declined_toast">دعوت نامه رد شد</string> + <string name="sharing_status_blog">هرکسی Ú©Ù‡ به اشتراک یک بلاگ در بیاید Ù…ÛŒ تواند آن را با مخاطبان خود به اشتراک بگذارد. شما این بلاگ را با مخاطبان زیر به اشتراک میگذارید. ممکن است مشترکان دیگری هم باشند Ú©Ù‡ شما نتوانید آن ها را ببینید.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">وارد کردن خوراک RSS</string> + <string name="blogs_rss_feeds_import_button">وارد کردن</string> + <string name="blogs_rss_feeds_import_hint">آدرس خوراک RSS را وارد کنید</string> + <string name="blogs_rss_feeds_import_error">متاسÙیم! وارد کردن خوراک شما با خطا مواجه شده است.</string> + <string name="blogs_rss_feeds_manage">مدیریت خوراک های RSS</string> + <string name="blogs_rss_feeds_manage_imported">وارد شده:</string> + <string name="blogs_rss_feeds_manage_author">نویسنده:</string> + <string name="blogs_rss_feeds_manage_updated">آخرین به روز رسانی:</string> + <string name="blogs_rss_remove_feed">ØØ°Ù Ùید</string> + <string name="blogs_rss_remove_feed_dialog_message">آیا مطمئن هستید Ú©Ù‡ میخواهید این خوراک را ØØ°Ù کنید؟ + +پست ها از دستگاه شما پاک خواهند شد اما روی دستگاه سایر Ø§ÙØ±Ø§Ø¯ باقی خواهند ماند + +هر مخاطبی Ú©Ù‡ با آن این خوراک را به اشتراک گذاشته اید ممکن است دیگر آپدیت Ø¯Ø±ÛŒØ§ÙØª نکند.</string> + <string name="blogs_rss_remove_feed_ok">ØØ°Ù</string> + <string name="blogs_rss_feeds_manage_delete_error">خوراک نمی تواند پاک شود!</string> + <string name="blogs_rss_feeds_manage_empty_state">هیچ خوراک RSS برای نمایش وجود ندارد + +برای وارد کردن خوراک روی آیکون + کلیک کنید</string> + <string name="blogs_rss_feeds_manage_error">مشکلی با بارگذاری Ùیدهای شما وجود داشت. Ù„Ø·ÙØ§ بعدا Ø§Ù…ØªØØ§Ù† کنید.</string> + <!--Settings Display--> + <string name="pref_language_title">زبان Ùˆ منطقه</string> + <string name="pref_language_changed">این تنظیمات زمانی Ú©Ù‡ برایر را ری استارت کنید تاثیر خود را Ù…ÛŒ گذارند. Ù„Ø·ÙØ§ خارج شوید Ùˆ برایر را ری استارت کنید.</string> + <string name="pref_language_default">پیش ÙØ±Ø¶ سیستم</string> + <string name="display_settings_title">نمایش</string> + <string name="pref_theme_title">قالب</string> + <string name="pref_theme_light">روشن</string> + <string name="pref_theme_dark">تاریک</string> + <string name="pref_theme_auto">خودکار ( روز)</string> + <string name="pref_theme_system">پیش ÙØ±Ø¶ سیستم</string> + <!--Settings Network--> + <string name="network_settings_title">شبکه ها</string> + <string name="bluetooth_setting">اتصال از طریق بلوتوث</string> + <string name="bluetooth_setting_enabled">هر زمانی Ú©Ù‡ مخاطبان نزدیک هستند</string> + <string name="bluetooth_setting_disabled">Ùقط در هنگام Ø§ÙØ²ÙˆØ¯Ù† مخاطبان</string> + <string name="tor_network_setting">اتصال از طریق تور</string> + <string name="tor_network_setting_never">هرگز</string> + <string name="tor_network_setting_wifi">Ùقط در هنگام Ø§Ø³ØªÙØ§Ø¯Ù‡ از وای ÙØ§ÛŒ</string> + <string name="tor_network_setting_always">هنگام Ø§Ø³ØªÙØ§Ø¯Ù‡ از وای ÙØ§ÛŒ یا موبایل دیتا</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">امنیت</string> + <string name="change_password">تغییر رمز عبور</string> + <string name="current_password">رمز عبور ÙØ¹Ù„ÛŒ</string> + <string name="choose_new_password">رمز عبور جدید</string> + <string name="confirm_new_password">تائید رمز جدید</string> + <string name="password_changed">رمز عبور تغییر کرده است</string> + <string name="panic_setting">برپایی دکمه هراس</string> + <string name="panic_setting_title">دکمه هراس</string> + <string name="panic_setting_hint">تنظیم Ù†ØÙˆÙ‡ واکنش برایر هنگام ÙØ¹Ø§Ù„ سازی دکمه هراس</string> + <string name="panic_app_setting_title">برنامه دکمه هراس</string> + <string name="unknown_app">یک برنامه ناشناخته</string> + <string name="panic_app_setting_summary">هیچ برنامه تنظیم نشده است</string> + <string name="panic_app_setting_none">هیچکدام</string> + <string name="dialog_title_connect_panic_app">تایید برنامه هراس</string> + <string name="dialog_message_connect_panic_app">آیا مطمئن هستید Ú©Ù‡ میخواهید به %1$s اجازه دهید تا باعث عملیات مخرب دکمه هراس بشود؟</string> + <string name="panic_setting_signout_title">خروج</string> + <string name="panic_setting_signout_summary">در صورت کلیک بر روی کلید هراس از برایر خارج شو</string> + <string name="purge_setting_title">ØØ°Ù ØØ³Ø§Ø¨ کاربری</string> + <string name="purge_setting_summary">پاک کردن ØØ³Ø§Ø¨ کاربری برایر شما در صورتی Ú©Ù‡ دکمه هراس ÙØ´Ø§Ø± داده شود. اخطار: این باعث پاک شدن دائمی تمام هویت ها، مخاطبان Ùˆ پیام های شما خواهد شد</string> + <string name="uninstall_setting_title">پاک کردن برایر</string> + <string name="uninstall_setting_summary">این نیازمند تایید دستی در موعد هراس میباشد</string> + <!--Settings Notifications--> + <string name="notification_settings_title">نوتیÙیکیشن ها</string> + <string name="notify_private_messages_setting_title">پیام های خصوصی</string> + <string name="notify_private_messages_setting_summary">نمایش هشدار برای پیام های خصوصی</string> + <string name="notify_private_messages_setting_summary_26">تنظیم هشدار برای پیام های شخصی</string> + <string name="notify_group_messages_setting_title">پیام های گروه</string> + <string name="notify_group_messages_setting_summary">نمایش هشدار برای پیام های گروه</string> + <string name="notify_group_messages_setting_summary_26">تنظیم هشدار برای پیام های گروه</string> + <string name="notify_forum_posts_setting_title">پست های تالار Ú¯ÙØªÙ…ان</string> + <string name="notify_forum_posts_setting_summary">نمایش هشدار برای پست های تالار Ú¯ÙØªÙ…ان</string> + <string name="notify_forum_posts_setting_summary_26">تنظیم هشدار برای پست های تالار Ú¯ÙØªÙ…ان</string> + <string name="notify_blog_posts_setting_title">پست های بلاگ</string> + <string name="notify_blog_posts_setting_summary">نمایش هشدار برای پست های بلاگ</string> + <string name="notify_blog_posts_setting_summary_26">تنظیم هشدار برای پست های بلاگ</string> + <string name="notify_vibration_setting">لرزش</string> + <string name="notify_lock_screen_setting_title">Ù‚ÙÙ„ ØµÙØÙ‡</string> + <string name="notify_lock_screen_setting_summary">نمایش نوتیÙیکشن روی ØµÙØÙ‡ Ù‚ÙÙ„</string> + <string name="notify_sound_setting">صدا</string> + <string name="notify_sound_setting_default">رینگتون پیش ÙØ±Ø¶</string> + <string name="notify_sound_setting_disabled">هیچکدام</string> + <string name="choose_ringtone_title">انتخاب رینگتون</string> + <string name="cannot_load_ringtone">ناتوانی در بارگذاری رینگتون</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">بازخورد</string> + <string name="send_feedback">ارسال بازخورد</string> + <!--Link Warning--> + <string name="link_warning_title">هشدار لینک</string> + <string name="link_warning_intro">با باز کردن لینک زیر شما یک برنامه بیرونی را باز خواهید کرد.</string> + <string name="link_warning_text">این Ù…ÛŒ تواند برای شناسایی شما مورد Ø§Ø³ØªÙØ§Ø¯Ù‡ قرار بگیرد. قبل از باز کردن آن به قابل اطمینان بودن شخصی Ú©Ù‡ آن را برای شما ارسال کرده Ùکر کنید Ùˆ بعد برای Ø§ØØªÛŒØ§Ø· آن را با Ø§Ø±ÙØ§Ú©Ø³ باز کنید.</string> + <string name="link_warning_open_link">باز کردن لینک</string> + <!--Crash Reporter--> + <string name="crash_report_title">گزارش خطای برایر</string> + <string name="briar_crashed">ببخشید، برایر از کار Ø§ÙØªØ§Ø¯Ù‡ است.</string> + <string name="not_your_fault">این تقصیر شما نیست.</string> + <string name="please_send_report">Ù„Ø·ÙØ§ با ÙØ±Ø³ØªØ§Ø¯Ù† گزارش خطا به ما Ú©Ù…Ú© کنید تا برایر را بهتر کنیم.</string> + <string name="report_is_encrypted">به شما اطمینان Ù…ÛŒ دهیم Ú©Ù‡ گزارش شما رمزنگاری شده Ùˆ به صورت امن ÙØ±Ø³ØªØ§Ø¯Ù‡ Ù…ÛŒ شود.</string> + <string name="feedback_title">بازخورد</string> + <string name="describe_crash">ØªÙˆØ¶ÛŒØ Ø¯Ù‡ÛŒØ¯ Ú†Ù‡ Ø§ØªÙØ§Ù‚ÛŒ Ø§ÙØªØ§Ø¯ (اختیاری)</string> + <string name="enter_feedback">بازخورد خود را وارد کنید</string> + <string name="optional_contact_email">آدرس ایمیل شما (اختیاری)</string> + <string name="include_debug_report_crash">قرار دادن داده های ناشناس مربوط به خرابی</string> + <string name="include_debug_report_feedback">قرار دادن داده های ناشناس درباره این دستگاه</string> + <string name="could_not_load_report_data">امکان بارگذاری داده های گزارش وجود ندارد.</string> + <string name="send_report">ارسال گزارش</string> + <string name="close">بستن</string> + <string name="dev_report_saved">گزارش ذخیره شد. Ø¯ÙØ¹Ù‡ بعدی Ú©Ù‡ وارد برایر شدید ÙØ±Ø³ØªØ§Ø¯Ù‡ خواهد شد.</string> + <!--Sign Out--> + <string name="progress_title_logout">خروج از برایر...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">قرارگیری ØµÙØÙ‡ شناسایی شد</string> + <string name="screen_filter_body">برنامه ای دیگری روی برایر قرار Ú¯Ø±ÙØªÙ‡ است. برای ØÙاظت از امنیت شما، برایر پاسخگو به لمس های ØµÙØÙ‡ نمایش تا زمانی Ú©Ù‡ برنامه دیگری بالای آن قرار دارد نخواهد بود. + +این برنامه ها ممکن است روی برایر قرار Ú¯Ø±ÙØªÙ‡ باشند: + +%1$s</string> + <string name="screen_filter_allow">به این برنامه ها اجازه بده تا روی برایر قرار بگیرند</string> + <!--Permission Requests--> + <string name="permission_camera_title">دسترسی به دوربین</string> + <string name="permission_camera_request_body">برای اسکن کردن کد QR دسترسی به دوربین لازم است.</string> + <string name="permission_camera_denied_body">شما دسترسی به دوربین را رد کرده اید، اما Ø§ÙØ²ÙˆØ¯Ù† مخاطب نیاز به دوربین دارد. + +Ù„Ø·ÙØ§ اجازه دسترسی را بدهید.</string> + <string name="permission_camera_denied_toast">اجازه دسترسی به دوربین Ù¾Ø°ÛŒØ±ÙØªÙ‡ نشد</string> + <string name="qr_code">کد QR</string> + <string name="show_qr_code_fullscreen">نمایش کد QR به صورت Ùول اسکرین</string> +</resources> diff --git a/mailbox-android/src/main/res/values-fi/strings.xml b/mailbox-android/src/main/res/values-fi/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..2d98404f5035497e3a738016e6c5660454563886 --- /dev/null +++ b/mailbox-android/src/main/res/values-fi/strings.xml @@ -0,0 +1,413 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Tervetuloa Briariin</string> + <string name="setup_name_explanation">Nimimerkkisi tulee näkymään julkaisemasi sisällön yhteydessä. Et voi muuttaa nimimerkkiä sen jälkeen kun olet luonut tilin.</string> + <string name="setup_next">Seuraava</string> + <string name="setup_password_intro">Valitse salasana</string> + <string name="setup_password_explanation">Sinun Briar tili on tallennettu salattuna sinun laitteelle, ei pilvipalvelimelle. Jos unohdat salasanasi tai poistat Briarin asennuksen, ei ole mitään keinoa jolla tilisi voisi palauttaa.\n\nValitse pitkä salasana, joka on vaikea arvata, esimerkiksi neljä sattumanvaraista sanaa tai kymmenen sattumanvaraista kirjainta, numeroa ja symbolia.</string> + <string name="setup_doze_title">Taustayhteydet</string> + <string name="setup_doze_intro">Vastaanottaakseen viestejä, Briarin täytyy pitää yhteyttä yllä taustalla.</string> + <string name="setup_doze_explanation">Vastaanottaakseen viestejä, Briarin täytyy pitää yhteyttä yllä taustalla. Ole hyvä ja kytke pois akun optimisaatiot, jotta Briar voisi pitää yhteyden yllä.</string> + <string name="setup_doze_button">Salli yhteydet</string> + <string name="choose_nickname">Valitse nimimerkki</string> + <string name="choose_password">Valitse salasana</string> + <string name="confirm_password">Vahvista salasana</string> + <string name="name_too_long">Nimi on liian pitkä</string> + <string name="password_too_weak">Salasana on liian heikko</string> + <string name="passwords_do_not_match">Salasanat eivät täsmää</string> + <string name="create_account_button">Luo tili</string> + <string name="more_info">Lisätietoja</string> + <string name="don_t_ask_again">Älä kysy uudelleen</string> + <string name="setup_huawei_text">Napsauta alla olevaa nappia varmistaaksesi, että Briar on suojattu \"Suojatut sovellukset\" -näkymässä.</string> + <string name="setup_huawei_button">Suojaa Briar</string> + <string name="setup_huawei_help">Jos Briaria ei lisätä suojattujen sovellusten listalle, se ei voi toimia taustalla.</string> + <string name="warning_dozed">%s ei voinut toimia taustalla</string> + <!--Login--> + <string name="enter_password">Salasana</string> + <string name="try_again">Väärä salasana, yritä uudelleen</string> + <string name="sign_in_button">Kirjaudu sisään</string> + <string name="forgotten_password">Olen unohtanut salasanani</string> + <string name="dialog_title_lost_password">Unohtunut salasana</string> + <string name="dialog_message_lost_password">Sinun Briar tili on tallennettu salattuna sinun laitteelle, ei pilvipalvelimelle, joten emme voi palauttaa salasanaasi. Haluatko poistaa tilisi ja aloittaa alusta?\n\nVaroitus: Tulet menettämään tunnuksesi, yhteystietosi ja viestisi lopullisesti.</string> + <string name="startup_failed_notification_title">Briarin käynnistys epäonnistui</string> + <string name="startup_failed_notification_text">Napauta nähdäksesi lisätietoja.</string> + <string name="startup_failed_activity_title">Briarin käynnistys epäonnistui</string> + <string name="startup_failed_db_error">Jostain syystä sinun Briar tietokanta on korruptoitunut korjauskelvottomaksi. Tilisi, tietosi ja kaikki yhteystietosi on menetetty. Valitettavasti, sinun täytyy asentaa Briar uudelleen ja luoda uusi tili valitsemalla \'Olen unohtanut salasanani\' kun sinulta kysytään salasanaa.</string> + <string name="startup_failed_data_too_old_error">Sinun tili luotiin vanhalla versiolla eikä sitä voida avata tällä versiolla. Sinun täytyy joko asentaa vanha versio uudelleen tai luoda uusi tili valitsemalla \'Olen unohtanut salasanani\' kun sinulta kysytään salasanaa.</string> + <string name="startup_failed_data_too_new_error">Tämän sovelluksen versio on liian vanha. Päivitä viimeisimpään versioon ja yritä uudelleen.</string> + <string name="startup_failed_service_error">Briar ei kyennyt käynnistämään vaadittua liitännäistä. Briarin uudelleenasennus yleensä korjaa ongelman. Huomaa kuitenkin, että tulet menettämään tilisi ja kaikki siihen liittyvä data koska Briar ei käytä palvelimia sinun tietojesi säilyttämiseen.</string> + <plurals name="expiry_warning"> + <item quantity="one">Tämä on Briarin testiversio. Sinun tilisi tulee vanhentumaan %d päivän päästä eikä sitä voi uusia.</item> + <item quantity="other">Tämä on Briarin testiversio. Sinun tilisi tulee vanhentumaan %d päivän päästä eikä sitä voi uusia.</item> + </plurals> + <string name="expiry_update">Testiaikaa on pidennetty. Tilisi tulee nyt vanhentumaan %d päivän kuluttua.</string> + <string name="expiry_date_reached">Tämä sovellus on vanhentunut.\nKiitos testaamisesta!</string> + <string name="download_briar">Jatkaaksesi Briarin käyttöä, lataa versio 1.0.</string> + <string name="create_new_account">Sinun täytyy luoda uusi tili, mutta voit käyttää samaa tunnusta.</string> + <string name="download_briar_button">Lataa Briar 1.0</string> + <string name="startup_open_database">Puretaan tietokannan salaus...</string> + <string name="startup_migrate_database">Päivitetään tietokanta...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Avaa navigointilaatikko</string> + <string name="nav_drawer_close_description">Sulje navigointilaatikko</string> + <string name="contact_list_button">Yhteystiedot</string> + <string name="groups_button">Yksityiset ryhmät</string> + <string name="forums_button">Foorumit</string> + <string name="blogs_button">Blogit</string> + <string name="settings_button">Asetukset</string> + <string name="sign_out_button">Kirjaudu ulos</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="reminder_notification_title">Uloskirjautunut Briarista</string> + <string name="reminder_notification_text">Napauta kirjautuaksesi takaisin sisään.</string> + <string name="reminder_notification_channel_title">Briarin sisäänkirjautumisen muistutus</string> + <string name="reminder_notification_dismiss">Hylkää</string> + <string name="ongoing_notification_title">Kirjautunut Briariin</string> + <string name="ongoing_notification_text">Napauta avataksesi Briar.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Uusi yksityisviesti.</item> + <item quantity="other">%d uutta yksityisviestiä.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Uusi ryhmäviesti.</item> + <item quantity="other">%d uutta ryhmäviestiä.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Uusi foorumiviesti.</item> + <item quantity="other">%d uutta foorumiviestiä.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Uusi blogikirjoitus.</item> + <item quantity="other">%d uutta blogikirjoitusta.</item> + </plurals> + <!--Misc--> + <string name="now">nyt</string> + <string name="show">Näytä</string> + <string name="hide">Piilota</string> + <string name="ok">OK</string> + <string name="cancel">Peruuta</string> + <string name="got_it">Selvä</string> + <string name="delete">Poista</string> + <string name="accept">Hyväksy</string> + <string name="decline">Kieltäydy</string> + <string name="options">Valitsimet</string> + <string name="online">Verkossa</string> + <string name="offline">Poissa verkosta</string> + <string name="send">Lähetä</string> + <string name="allow">Salli</string> + <string name="open">Avaa</string> + <string name="no_data">Ei dataa</string> + <string name="ellipsis">…</string> + <string name="text_too_long">Kirjoitettu teksti on liian pitkä</string> + <string name="show_onboarding">Näytä apudialogi</string> + <string name="fix">Korjaa</string> + <string name="help">Ohje</string> + <string name="sorry">Pahoittelemme</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Ei yhteystietoja\n\nNapauta + nappia lisätäksesi yhteystiedon</string> + <string name="date_no_private_messages">Ei viestejä.</string> + <string name="no_private_messages">Ei viestejä</string> + <string name="message_hint">Kirjoita viesti</string> + <string name="delete_contact">Poista yhteystieto</string> + <string name="dialog_title_delete_contact">Vahvista yhteystiedon poistaminen</string> + <string name="dialog_message_delete_contact">Oletko varma, että haluat poistaa tämän yhteyshenkilön ja kaikki hänen kanssa vaihdetut viestit?</string> + <string name="contact_deleted_toast">Yhteystieto poistettu</string> + <!--Adding Contacts--> + <string name="add_contact_title">Lisää yhteystieto</string> + <string name="face_to_face">Sinun täytyy tavata käyttäjä, jonka haluat lisätä yhteystietoihisi.\n\nTämä estää sen, että joku voisi esittää olevansa sinä tai lukea viestejäsi tulevaisuudessa</string> + <string name="continue_button">Jatka</string> + <string name="connection_failed">Yhteys epäonnistui</string> + <string name="try_again_button">Yritä uudelleen</string> + <string name="waiting_for_contact_to_scan">Odotetaan, että käyttäjä skannaa ja saa yhteyden\u2026</string> + <string name="exchanging_contact_details">Yhteystietoja vaihdetaan\u2026</string> + <string name="contact_added_toast">Yhteystieto lisätty: %s</string> + <string name="contact_already_exists">Yhteystieto %s on jo olemassa</string> + <string name="contact_exchange_failed">Yhteystietojen vaihto epäonnistui</string> + <string name="qr_code_invalid">QR koodi on virheellinen</string> + <string name="qr_code_unsupported">Skannaamasi QR-koodi kuuluu %s:in vanhaan versioon, jonka tuki on loppunut.\n\nVarmista että kumpikin teistä käyttää uusinta versiota ja yritä uudelleen.</string> + <string name="camera_error">Kameravirhe</string> + <string name="connecting_to_device">Yhdistetään laitteeseen\u2026</string> + <string name="authenticating_with_device">Tunnistaudutaan laitteen kanssa\u2026</string> + <string name="connection_aborted_local">Yhteys katkaistu! Tämä voi tarkoittaa, että joku muu yrittää häiritä sinun ja toisen käyttäjän välistä yhteyttä</string> + <string name="connection_aborted_remote">Toinen käyttäjä katkaisi yhteyden! Tämä voi tarkoittaa, että joku muu yrittää häiritä sinun ja toisen käyttäjän välistä yhteyttä</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Esittele yhteyshenkilösi</string> + <string name="introduction_onboarding_text">Voit esitellä muita käyttäjiä toisilleen, niin että heidän ei tarvitse tavata kasvokkain ollakseen yhteydessä Briarin kautta.</string> + <string name="introduction_menu_item">Tee esittely</string> + <string name="introduction_activity_title">Valitse yhteystieto</string> + <string name="introduction_not_possible">Sinulla on jo yksi esittely käynnissä näillä yhteystiedoilla. Odota kunnes se tulee valmiiksi. Tämä voi kestää jonkin aikaa jos sinä tai yhteyshenkilösi ovat harvoin netissä.</string> + <string name="introduction_message_title">Esittele yhteyshenkilö</string> + <string name="introduction_message_hint">Lisää viesti (valinnainen)</string> + <string name="introduction_button">Tee esittely</string> + <string name="introduction_sent">Esittelysi on lähetetty.</string> + <string name="introduction_error">Esittelyssä tapahtui virhe.</string> + <string name="introduction_response_error">Esittelyyn vastaamisessa tapahtui virhe</string> + <string name="introduction_request_sent">Olet pyytänyt, että %1$s ja %2$s esitellään toisilleen.</string> + <string name="introduction_request_received">%1$s on pyytänyt, että sinut esitellään käyttäjälle %2$s. Haluatko lisätä käyttäjän %2$s yhteystietoihisi?</string> + <string name="introduction_request_exists_received">%1$s on pyytänyt, että sinut esitellään käyttäjälle %2$s, mutta %2$s on jo yhteystiedoissasi. %1$s ei välttämättä tiedä tätä, joten voit silti vastata:</string> + <string name="introduction_request_answered_received">%1$s on pyytänyt, että sinut esitellään käyttäjälle %2$s.</string> + <string name="introduction_response_accepted_sent">Olet hyväksynyt esittelyn käyttäjälle %1$s.</string> + <string name="introduction_response_accepted_sent_info">Ennen kuin %1$s voidaan lisätä sinun yhteystietoihin, hänen täytyy myös hyväksyä esittely. Tämä voi viedä vähän aikaa.</string> + <string name="introduction_response_declined_sent">Olet kieltäytynyt esittelystä käyttäjälle %1$s.</string> + <string name="introduction_response_accepted_received">%1$s hyväksyi esittelyn käyttäjälle %2$s.</string> + <string name="introduction_response_declined_received">%1$s kieltäytyi esittelystä käyttäjälle %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s sanoo, että %2$s on kieltäytynyt esittelystä.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Uusi yhteystieto lisätty.</item> + <item quantity="other">%d uutta yhteystietoa lisätty.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">Ei ryhmiä\n\nNapauta + nappia luodaksesi ryhmän tai pyydä yhteyshenkilöltä kutsua päästäksesi yhteen heidän ryhmistä.</string> + <string name="groups_created_by">Luonut %s</string> + <plurals name="messages"> + <item quantity="one">%d viesti</item> + <item quantity="other">%d viestiä</item> + </plurals> + <string name="groups_group_is_empty">Tämä ryhmä on tyhjä</string> + <string name="groups_group_is_dissolved">Tämä ryhmä on hajautettu</string> + <string name="groups_remove">Poista</string> + <string name="groups_create_group_title">Luo yksityinen ryhmä</string> + <string name="groups_create_group_button">Luo ryhmä</string> + <string name="groups_create_group_invitation_button">Lähetä kutsu</string> + <string name="groups_create_group_hint">Valitse nimi yksityiselle ryhmällesi</string> + <string name="groups_invitation_sent">Ryhmäkutsu on lähetetty</string> + <string name="groups_message_sent">Viesti lähetetty</string> + <string name="groups_member_list">Jäsenluettelo</string> + <string name="groups_invite_members">Kutsu jäseniä</string> + <string name="groups_member_created_you">Sinä loit ryhmän</string> + <string name="groups_member_created">%s loi ryhmän</string> + <string name="groups_member_joined_you">Olet liittynyt ryhmään</string> + <string name="groups_member_joined">%s liittyi ryhmään</string> + <string name="groups_leave">Lähde ryhmästä</string> + <string name="groups_leave_dialog_title">Vahvista ryhmästä lähtö</string> + <string name="groups_leave_dialog_message">Oletko varma, että haluat lähteä tästä ryhmästä?</string> + <string name="groups_dissolve">Hajauta ryhmä</string> + <string name="groups_dissolve_dialog_title">Vahvista ryhmän hajauttaminen</string> + <string name="groups_dissolve_dialog_message">Oletko varma, että haluat hajauttaa tämän ryhmän?\n\nRyhmän muut jäsenet eivät sen jälkeen voi enää jatkaa ryhmäkeskustelua eivätkä välttämättä tule saamaan viimeisimpiä viestejä.</string> + <string name="groups_dissolve_button">Hajauta</string> + <string name="groups_dissolved_dialog_title">Ryhmä on nyt hajautettu</string> + <string name="groups_dissolved_dialog_message">Tämän ryhmän aloittaja on hajauttanut sen.\n\nEt voi enää kirjoitta uusia viestejä ryhmälle, etkä välttämättä tule saamaan kaikkia tähän mennessä kirjoitettuja viestejä.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Ryhmäkutsut</string> + <string name="groups_invitations_invitation_sent">Olet kutsunut käyttäjän %1$s mukaan ryhmään \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s on kutsunut sinut mukaan ryhmään \"%2$s\".</string> + <string name="groups_invitations_joined">Liittyi ryhmään</string> + <string name="groups_invitations_declined">Kutsu liittyä ryhmään on hylätty</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d avoin ryhmäkutsu</item> + <item quantity="other">%d avointa ryhmäkutsua</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Olet hyväksynyt käyttäjän %s lähettämän ryhmäkutsun.</string> + <string name="groups_invitations_response_declined_sent">Olet kieltäytynyt käyttäjän %s lähettämästä ryhmäkutsusta.</string> + <string name="groups_invitations_response_accepted_received">%s hyväksyi ryhmäkutsun.</string> + <string name="groups_invitations_response_declined_received">%s kieltäytyi ryhmäkutsusta.</string> + <string name="sharing_status_groups">Vain ryhmäkeskustelun aloittaja voi pyytää uusia jäseniä mukaan ryhmään. Alla ovat kaikki ryhmän nykyiset jäsenet.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Näytä yhteystiedot</string> + <string name="groups_reveal_dialog_message">Voit valita haluatko paljastaa yhteytesi muihin käyttäjiin tämän ryhmän nykyisille ja tuleville jäsenille.\n\nKäyttäjä yhteyksien paljastaminen tekee yhteydestä nopeamman ja luotettavamman, koska voit pitää yhteyttä muihin käyttäjiin myös silloin kun ryhmän aloittaja on poissa verkosta.</string> + <string name="groups_reveal_visible">Yhteys käyttäjään on näkyvissä ryhmän jäsenille</string> + <string name="groups_reveal_visible_revealed_by_us">Yhteys käyttäjään on näkyvissä ryhmän jäsenille (sinun paljastamana)</string> + <string name="groups_reveal_visible_revealed_by_contact">Yhteys käyttäjään on näkyvissä ryhmän jäsenille (käyttäjän %s paljastamana)</string> + <string name="groups_reveal_invisible">Yhteys käyttäjään ei ole näkyvissä ryhmän jäsenille</string> + <!--Forums--> + <string name="no_forums">Ei foorumeita\n\nNapauta + nappia luodaksesi foorumin tai pyydä yhteyshenkilöltä kutsua päästäksesi yhteen heidän foorumeista</string> + <string name="create_forum_title">Luo foorumi</string> + <string name="choose_forum_hint">Valitse nimi foorumillesi</string> + <string name="create_forum_button">Luo foorumi</string> + <string name="forum_created_toast">Foorumi luotu</string> + <string name="no_forum_posts">Ei kirjoituksia</string> + <string name="no_posts">Ei viestejä</string> + <plurals name="posts"> + <item quantity="one">%d viesti</item> + <item quantity="other">%d viestiä</item> + </plurals> + <string name="forum_new_entry_posted">Foorumikirjoitus julkaistu</string> + <string name="forum_new_message_hint">Uusi julkaisu</string> + <string name="forum_message_reply_hint">Uusi vastaus</string> + <string name="btn_reply">Vastaa</string> + <string name="forum_leave">Lähde foorumista</string> + <string name="dialog_title_leave_forum">Vahvista foorumista lähteminen</string> + <string name="dialog_message_leave_forum">Oletko varma, että haluat lähteä tästä foorumista?\n\nKäyttäjät, jotka olet kutsunut tähän foorumiin, eivät välttämättä tule enää saamaan päivityksiä.</string> + <string name="dialog_button_leave">Lähde</string> + <string name="forum_left_toast">Lähti foorumista</string> + <!--Forum Sharing--> + <string name="forum_share_button">Jaa foorumi</string> + <string name="contacts_selected">Yhteystiedot valittu</string> + <string name="activity_share_toolbar_header">Valitse yhteystiedot</string> + <string name="no_contacts_selector">Ei yhteystietoja\n\nPalaa tänne, kun olet lisännyt yhteystiedon</string> + <string name="forum_shared_snackbar">Foorumi jaettu valittujen käyttäjien kanssa</string> + <string name="forum_share_message">Lisää viesti (valinnainen)</string> + <string name="forum_share_error">Tämän foorumin jakamisessa tapahtui virhe.</string> + <string name="forum_invitation_received">%1$s on jakanut \"%2$s\" -nimisen foorumin kanssasi.</string> + <string name="forum_invitation_sent">Olet jakanut \"%1$s\" -nimisen foorumin käyttäjälle %2$s.</string> + <string name="forum_invitations_title">Kutsut liittyä foorumeihin</string> + <string name="forum_invitation_exists">Olet jo hyväksynyt kutsun liittyä tähän foorumiin.\n\nUseamman kutsun hyväksyminen tekee foorumista nopeamman ja luotettavamman.</string> + <string name="forum_joined_toast">Liittyi foorumiin</string> + <string name="forum_declined_toast">Kutsu hylätty</string> + <string name="shared_by_format">Jakanut %s</string> + <string name="forum_invitation_already_sharing">On jo jakamassa</string> + <string name="forum_invitation_response_accepted_sent">Olet hyväksynyt käyttäjän %s lähettämän foorumikutsun.</string> + <string name="forum_invitation_response_declined_sent">Olet kieltäytynyt käyttäjän %s lähettämästä foorumikutsusta.</string> + <string name="forum_invitation_response_accepted_received">%s hyväksyi foorumikutsun.</string> + <string name="forum_invitation_response_declined_received">%s kieltäytyi foorumikutsusta.</string> + <string name="sharing_status">Jaetaan tilaa</string> + <string name="sharing_status_forum">Kuka tahansa foorumin jäsen voi jakaa sen tuntemilleen käyttäjille. Olet jakamassa tämän foorumin seuraaville käyttäjille. Voi myös olla muita jäseniä, joita sinä et näe.</string> + <string name="shared_with">Jaettu %1$d kanssa (%2$d verkossa)</string> + <plurals name="forums_shared"> + <item quantity="one">%d foorumi jaettu</item> + <item quantity="other">%d foorumia jaettu</item> + </plurals> + <string name="nobody">Ei kukaan</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Ei kirjoituksia</string> + <string name="read_more">lue lisää</string> + <string name="blogs_write_blog_post">Julkaise blogikirjoitus</string> + <string name="blogs_write_blog_post_body_hint">Kirjoita blogikirjoitus</string> + <string name="blogs_publish_blog_post">Julkaise</string> + <string name="blogs_blog_post_created">Blogikirjoitus julkaistu</string> + <string name="blogs_blog_post_received">Uusi blogikirjoitus vastaanotettu</string> + <string name="blogs_blog_post_scroll_to">Vieritä kohtaan</string> + <string name="blogs_feed_empty_state">Ei kirjoituksia\n\nYhteyshenkilöitesi ja seuraamiesi blogien kirjoitukset tulevat näkymään tässä\n\nNapauta kynää kirjoittaaksesi jotain</string> + <string name="blogs_remove_blog">Poista blogi</string> + <string name="blogs_remove_blog_dialog_message">Oletko varma, että haluat poistaa tämän blogin?\n\nKirjoitukset poistuvat sinun laitteelta, mutta ei muiden laitteilta.\n\nKäyttäjät joiden kanssa olet jakanut tämän blogin eivät välttämättä saa uusia päivityksiä.</string> + <string name="blogs_remove_blog_ok">Poista</string> + <string name="blogs_blog_removed">Blogi poistettu</string> + <string name="blogs_reblog_comment_hint">Lisää kommentti (valinnainen)</string> + <string name="blogs_reblog_button">Jaa blogikirjoitus</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Jaa blogi</string> + <string name="blogs_sharing_error">Tämän blogin jakamisessa tapahtui virhe.</string> + <string name="blogs_sharing_button">Jaa blogi</string> + <string name="blogs_sharing_snackbar">Blogi jaettu valittujen käyttäjien kanssa</string> + <string name="blogs_sharing_response_accepted_sent">Olet hyväksynyt käyttäjän %s lähettämän blogikutsun.</string> + <string name="blogs_sharing_response_declined_sent">Olet kieltäytynyt käyttäjän %s lähettämästä blogikutsusta.</string> + <string name="blogs_sharing_response_accepted_received">%s hyväksyi blogikutsun.</string> + <string name="blogs_sharing_response_declined_received">%s kieltäytyi blogikutsusta.</string> + <string name="blogs_sharing_invitation_received">%1$s on jakanut \"%2$s\" -nimisen blogin kanssasi.</string> + <string name="blogs_sharing_invitation_sent">Olet jakanut \"%1$s\" -nimisen blogin käyttäjälle %2$s.</string> + <string name="blogs_sharing_invitations_title">Blogi kutsut</string> + <string name="blogs_sharing_joined_toast">Blogi tilattu</string> + <string name="blogs_sharing_declined_toast">Kutsu hylätty</string> + <string name="sharing_status_blog">Kuka tahansa joka tilaa blogin voi jakaa sen tuntemilleen käyttäjille. Olet jakamassa tämän blogin seuraaville käyttäjille. Voi myös olla muita blogin tilaajia, joita sinä et näe.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Tuo RSS syöte</string> + <string name="blogs_rss_feeds_import_button">Tuo</string> + <string name="blogs_rss_feeds_import_hint">Syötä RSS syötteen URL osoite</string> + <string name="blogs_rss_feeds_import_error">Pahoittelemme! Syötteen noutamisessa tapahtui virhe.</string> + <string name="blogs_rss_feeds_manage">Muokkaa RSS syötteitä</string> + <string name="blogs_rss_feeds_manage_imported">Tuotu:</string> + <string name="blogs_rss_feeds_manage_author">Tekijä:</string> + <string name="blogs_rss_feeds_manage_updated">Viimeksi päivitetty:</string> + <string name="blogs_rss_remove_feed">Poista syöte</string> + <string name="blogs_rss_remove_feed_dialog_message">Oletko varma, että haluat poistaa tämän syötteen?\n\nKirjoitukset poistuvat sinun laitteelta, mutta ei muiden laitteilta.\n\nKäyttäjät joiden kanssa olet jakanut tämän syötteen eivät välttämättä saa uusia päivityksiä.</string> + <string name="blogs_rss_remove_feed_ok">Poista</string> + <string name="blogs_rss_feeds_manage_delete_error">Syötteen poistaminen epäonnistui!</string> + <string name="blogs_rss_feeds_manage_empty_state">Ei RSS syötteitä\n\nNapauta + nappia lisätäksesi syötteen</string> + <string name="blogs_rss_feeds_manage_error">Syötteiden lataamisessa tapahtui virhe. Yritä myöhemmin uudelleen.</string> + <!--Settings Display--> + <string name="pref_language_title">Kieli & alue</string> + <string name="pref_language_changed">Tämä asetus otetaan käyttöön kun uudelleenkäynnistät Briarin. Kirjaudu ulos ja käynnistä Briar uudelleen.</string> + <string name="pref_language_default">Järjestelmäoletus</string> + <string name="display_settings_title">Näytä</string> + <string name="pref_theme_title">Teema</string> + <string name="pref_theme_light">Vaalea</string> + <string name="pref_theme_dark">Tumma</string> + <string name="pref_theme_auto">Automaattinen (päiväsaika)</string> + <string name="pref_theme_system">Järjestelmäoletus</string> + <!--Settings Network--> + <string name="network_settings_title">Verkot</string> + <string name="bluetooth_setting">Yhdistä Bluetoothin kautta</string> + <string name="bluetooth_setting_enabled">Silloin kun yhteyshenkilöt ovat lähellä</string> + <string name="bluetooth_setting_disabled">Vain kun yhteyshenkilöitä lisätään</string> + <string name="tor_network_setting">Yhdistä Tor-verkon kautta</string> + <string name="tor_network_setting_never">Ei koskaan</string> + <string name="tor_network_setting_wifi">Vain kun on Wi-Fi yhteys</string> + <string name="tor_network_setting_always">Kun on Wi-Fi tai mobiilidatayhteys</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Turvallisuus</string> + <string name="change_password">Vaihda salasana</string> + <string name="current_password">Nykyinen salasana</string> + <string name="choose_new_password">Uusi salasana</string> + <string name="confirm_new_password">Vahvista uusi salasana</string> + <string name="password_changed">Salasana on vaihdettu.</string> + <string name="panic_setting">Paniikkinapin asetus</string> + <string name="panic_setting_title">Paniikkinappi</string> + <string name="panic_setting_hint">Säädä miten Briar tulee käyttäytymään kun käytät paniikkinappisovellusta</string> + <string name="panic_app_setting_title">Paniikkinappisovellus</string> + <string name="unknown_app">tuntematon sovellus</string> + <string name="panic_app_setting_summary">Sovellusta ei ole valittu</string> + <string name="panic_app_setting_none">Ei mitään</string> + <string name="dialog_title_connect_panic_app">Vahvista paniikkisovellus</string> + <string name="dialog_message_connect_panic_app">Oletko varma, että haluat myöntää ohjelmalle %1$s luvan laukaista tuhoa aiheuttavia paniikkinapin toimintoja?</string> + <string name="panic_setting_signout_title">Kirjaudu ulos</string> + <string name="panic_setting_signout_summary">Kirjaudu ulos Briarista jos paniikkinappia on painettu</string> + <string name="purge_setting_title">Poista tili</string> + <string name="purge_setting_summary">Poista Briar tilisi jos paniikkinappia on painettu. Varoitus: Tämä tulee pysyvästi poistamaan sinun tunnukset, yhteystiedot ja viestit</string> + <string name="uninstall_setting_title">Poista Briarin asennus</string> + <string name="uninstall_setting_summary">Tämä tulee vaatimaan manuaalisen varmennuksen paniikkitilanteessa</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Ilmoitukset</string> + <string name="notify_sign_in_title">Muistuta minua kirjautumaan sisään</string> + <string name="notify_sign_in_summary">Näytä muistutus kun puhelin käynnistyy tai kun sovellus on päivitetty</string> + <string name="notify_private_messages_setting_title">Yksityisviestit</string> + <string name="notify_private_messages_setting_summary">Näytä ilmoitukset yksityisviesteistä</string> + <string name="notify_private_messages_setting_summary_26">Aseta ilmoitukset yksityisviesteille</string> + <string name="notify_group_messages_setting_title">Ryhmäviestit</string> + <string name="notify_group_messages_setting_summary">Näytä ilmoitukset ryhmäviesteistä</string> + <string name="notify_group_messages_setting_summary_26">Aseta ilmoitukset ryhmäviesteille</string> + <string name="notify_forum_posts_setting_title">Foorumikirjoitukset</string> + <string name="notify_forum_posts_setting_summary">Näytä ilmoitukset foorumikirjoituksista</string> + <string name="notify_forum_posts_setting_summary_26">Aseta ilmoitukset foorumikirjoituksille</string> + <string name="notify_blog_posts_setting_title">Blogikirjoitukset</string> + <string name="notify_blog_posts_setting_summary">Näytä ilmoitukset blogikirjoituksista</string> + <string name="notify_blog_posts_setting_summary_26">Aseta ilmoitukset blogikirjoituksille</string> + <string name="notify_vibration_setting">Värinä</string> + <string name="notify_lock_screen_setting_title">Lukitusnäyttö</string> + <string name="notify_lock_screen_setting_summary">Näytä ilmoitukset lukitusnäytöllä</string> + <string name="notify_sound_setting">Ääni</string> + <string name="notify_sound_setting_default">Oletussoittoääni</string> + <string name="notify_sound_setting_disabled">Ei mikään</string> + <string name="choose_ringtone_title">Valitse soittoääni</string> + <string name="cannot_load_ringtone">Soittoäänen lataaminen epäonnistui</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Palaute</string> + <string name="send_feedback">Lähetä palautetta</string> + <!--Link Warning--> + <string name="link_warning_title">Linkkivaroitus</string> + <string name="link_warning_intro">Olet aikomassa avata seuraavan linkin toisessa sovelluksessa.</string> + <string name="link_warning_text">Tätä voidaan käyttää sinun tunnistamiseen. Mieti luotatko käyttäjään, joka lähetti sinulle kyseisen linkin, ja harkitse sen avaamista Orfoxilla.</string> + <string name="link_warning_open_link">Avaa linkki</string> + <!--Crash Reporter--> + <string name="crash_report_title">Briar kaatumisilmoitus</string> + <string name="briar_crashed">Pahoittelemme, Briar on kaatunut.</string> + <string name="not_your_fault">Tämä ei ole sinun syysi.</string> + <string name="please_send_report">Auta meitä rakentamaan parempi Briar lähettämällä meille kaatumisilmoitus.</string> + <string name="report_is_encrypted">Lupaamme, että ilmoitus on salattu ja lähetetty turvallisesti.</string> + <string name="feedback_title">Palaute</string> + <string name="describe_crash">Kuvaile mitä tapahtui (valinnainen)</string> + <string name="enter_feedback">Kirjoita palaute</string> + <string name="optional_contact_email">Sähköpostiosoite (valinnainen)</string> + <string name="include_debug_report_crash">Liitä anonyymiä dataa kaatumisesta</string> + <string name="include_debug_report_feedback">Liitä anonyymiä dataa tästä laitteesta</string> + <string name="could_not_load_report_data">Ilmoituksen tietojen lataaminen epäonnistui.</string> + <string name="send_report">Lähetä ilmoitus</string> + <string name="close">Sulje</string> + <string name="dev_report_saved">Ilmoitus tallennettu. Sen lähetys tapahtuu seuraavan kerran kun kirjaudut sisään Briariin.</string> + <!--Sign Out--> + <string name="progress_title_logout">Kirjaudutaan ulos Briarista...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Näyttökerros havaittu</string> + <string name="screen_filter_body">Toinen sovellus on piirtämässä Briarin päälle. Suojellakseen sinun turvallisuutta, Briar ei tule vastaamaan kosketuksiin silloin kun toinen sovellus on piirtämässä Briarin päälle.\n\nOn mahdollista, että seuraavat sovellukset piirtävät päälle:\n\n%1$s</string> + <string name="screen_filter_allow">Salli näiden sovellusten piirtää päälle</string> + <!--Permission Requests--> + <string name="permission_camera_title">Kameran käyttöoikeus</string> + <string name="permission_camera_request_body">Skannatakseen QR koodin, Briar tarvitsee luvan käyttää kameraa.</string> + <string name="permission_camera_denied_body">Olet kieltänyt käyttämästä kameraa, mutta yhteyshenkilöiden lisääminen vaatii kameran käyttöä.\n\nOle hyvä ja harkitse kameraluvan myöntämistä.</string> + <string name="permission_camera_denied_toast">Kameran käyttöoikeutta ei myönnetty</string> + <string name="qr_code">QR-koodi</string> + <string name="show_qr_code_fullscreen">Näytä QR-koodi koko näytöllä</string> +</resources> diff --git a/mailbox-android/src/main/res/values-fr/strings.xml b/mailbox-android/src/main/res/values-fr/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..c1cae74584ecae1dfc2edbe624689b5d1ca8b5ca --- /dev/null +++ b/mailbox-android/src/main/res/values-fr/strings.xml @@ -0,0 +1,413 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Bienvenue à Briar</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_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_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_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_button">Autoriser les connexions</string> + <string name="choose_nickname">Choisir votre pseudonyme</string> + <string name="choose_password">Choisir votre mot de passe</string> + <string name="confirm_password">Confirmer votre mot de passe</string> + <string name="name_too_long">Le nom est trop long</string> + <string name="password_too_weak">Le mot de passe est trop faible</string> + <string name="passwords_do_not_match">Les mots de passe ne correspondent pas</string> + <string name="create_account_button">Créer un compte</string> + <string name="more_info">Plus d’informations</string> + <string name="don_t_ask_again">Ne plus demander</string> + <string name="setup_huawei_text">Veuillez toucher le bouton ci-dessous et vous assurer que Briar est protégée dans l’écran « Applis protégées ».</string> + <string name="setup_huawei_button">Protéger Briar</string> + <string name="setup_huawei_help">Si Briar n’est pas ajoutée à la liste des applis protégées, elle ne pourra pas fonctionner en arrière-plan.</string> + <string name="warning_dozed">%s n’a pas pu fonctionner en arrière-plan</string> + <!--Login--> + <string name="enter_password">Mot de passe</string> + <string name="try_again">Le mot de passe est erroné, ressayez</string> + <string name="sign_in_button">Connexion</string> + <string name="forgotten_password">J’ai oublié mon mot de passe</string> + <string name="dialog_title_lost_password">Mot de passe oublié</string> + <string name="dialog_message_lost_password">Votre compte Briar est enregistré chiffré sur votre appareil, pas dans le nuage, et nous ne pouvons donc pas réinitialiser votre mot de passe. Voulez-vous supprimer votre compte et recommencer ?\n\nAttention : vos identités, contacts et messages seront perdus irrémédiablement.</string> + <string name="startup_failed_notification_title">Impossible de démarrer Briar</string> + <string name="startup_failed_notification_text">Toucher pour plus d’informations.</string> + <string name="startup_failed_activity_title">Échec de démarrage de Briar</string> + <string name="startup_failed_db_error">Pour quelque raison, votre base de données Briar est corrompue sans espoir de réparation. Votre compte, vos données et tous vos contacts sont perdus. Malheureusement, vous devez réinstaller Briar et créer un nouveau compte en choisissant « J’ai oublié mon mot de passe » dans 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. Vous devez soit réinstaller l’ancienne version, soit créer un nouveau compte en choisissant « J’ai oublié mon mot de passe » dans l’invite de mot de passe.</string> + <string name="startup_failed_data_too_new_error">Cette version de l’appli est trop ancienne. Veuillez la mettre à niveau vers la dernière version et ressayer.</string> + <string name="startup_failed_service_error">Briar n’a pas pu démarrer un greffon exigé. Réinstaller Briar résout généralement ce problème. Veuillez cependant noter que vous perdrez votre compte et toutes données relatives puisque Briar n’utilise pas de serveurs centralisés sur lesquels enregistrer vos données.</string> + <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="other">Ceci est une version de test de Briar. Votre compte arrivera à expiration dans %d jours et ne pourra pas être renouvelé.</item> + </plurals> + <string name="expiry_update">La date de fin de test a été repoussée. Votre compte arrivera maintenant à expiration dans %d jours.</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 version 1.0.</string> + <string name="create_new_account">Vous devrez créer un nouveau compte, mais vous pouvez utiliser le même pseudonyme.</string> + <string name="download_briar_button">Télécharger Briar 1.0</string> + <string name="startup_open_database">Déchiffrement de la base de données…</string> + <string name="startup_migrate_database">Mise à niveau de la base de données…</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Ouvrir le tiroir de navigation</string> + <string name="nav_drawer_close_description">Fermer le tiroir de navigation</string> + <string name="contact_list_button">Contacts</string> + <string name="groups_button">Groupes privés</string> + <string name="forums_button">Forums</string> + <string name="blogs_button">Blogues</string> + <string name="settings_button">Paramètres</string> + <string name="sign_out_button">Déconnexion</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="reminder_notification_title">Déconnecté de Briar</string> + <string name="reminder_notification_text">Touchez pour vous reconnecter</string> + <string name="reminder_notification_channel_title">Rappel de connexion à Briar</string> + <string name="reminder_notification_dismiss">Fermer</string> + <string name="ongoing_notification_title">Connecté à Briar</string> + <string name="ongoing_notification_text">Toucher pour ouvrir Briar.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Nouveau message privé.</item> + <item quantity="other">%d nouveaux messages privés.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Nouveau message de groupe.</item> + <item quantity="other">%d nouveaux messages de groupe.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Un nouvel article de forum.</item> + <item quantity="other">%d nouveaux articles de forum.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Nouveau billet de blogue.</item> + <item quantity="other">%d nouveaux billets de blogue.</item> + </plurals> + <!--Misc--> + <string name="now">maintenant</string> + <string name="show">Afficher</string> + <string name="hide">Cacher</string> + <string name="ok">OK</string> + <string name="cancel">Annuler</string> + <string name="got_it">Compris</string> + <string name="delete">Supprimer</string> + <string name="accept">Accepter</string> + <string name="decline">Refuser</string> + <string name="options">Options</string> + <string name="online">En ligne</string> + <string name="offline">Hors ligne</string> + <string name="send">Envoyer</string> + <string name="allow">Autoriser</string> + <string name="open">Ouvrir</string> + <string name="no_data">Aucune donnée</string> + <string name="ellipsis">...</string> + <string name="text_too_long">Le texte saisi est trop long</string> + <string name="show_onboarding">Afficher la fenêtre d’aide</string> + <string name="fix">Corriger</string> + <string name="help">Aide</string> + <string name="sorry">Désolé</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Aucun contact à afficher\n\nTouchez l’icône + pour ajouter un contact</string> + <string name="date_no_private_messages">Aucun message.</string> + <string name="no_private_messages">Aucun message à afficher</string> + <string name="message_hint">Rédiger le message</string> + <string name="delete_contact">Supprimer le contact</string> + <string name="dialog_title_delete_contact">Confirmer la suppression du contact</string> + <string name="dialog_message_delete_contact">Voulez-vous vraiment supprimer ce contact et tous les messages associés ?</string> + <string name="contact_deleted_toast">Le contact a été supprimé</string> + <!--Adding Contacts--> + <string name="add_contact_title">Ajouter un contact</string> + <string name="face_to_face">Vous devez rencontrer la personne que vous voulez ajouter comme contact, afin d’éviter que quelqu’un se fasse passer pour vous et puisse lire vos messages à l’avenir.</string> + <string name="continue_button">Continuer</string> + <string name="connection_failed">Échec de connexion</string> + <string name="try_again_button">Ressayer</string> + <string name="waiting_for_contact_to_scan">En attente de lecture du code QR par le contact et de sa connexion\u2026</string> + <string name="exchanging_contact_details">Échange des renseignements de contact\u2026</string> + <string name="contact_added_toast">Contact ajouté : %s</string> + <string name="contact_already_exists">Le contact %s existe déjà </string> + <string name="contact_exchange_failed">Échec d’échange de contacts</string> + <string name="qr_code_invalid">Le code QR est invalide</string> + <string name="qr_code_unsupported">Le code QR que vous tentez de lire appartient à une ancienne version de %s qui n’est plus prise en charge.\n\nVeuillez vous assurer d’utiliser tous les deux la dernière version et ressayer.</string> + <string name="camera_error">Erreur de la caméra</string> + <string name="connecting_to_device">Connexion à l’appareil\u2026</string> + <string name="authenticating_with_device">Autentification avec l’appareil\u2026</string> + <string name="connection_aborted_local">La connexion a été interrompue ! Cela pourrait signifier que quelqu’un tente d’interférer avec votre connexion.</string> + <string name="connection_aborted_remote">Votre contact a interrompu la connexion ! Cela pourrait signer que quelqu’un tente d’interférer avec votre connexion</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Présenter vos contacts</string> + <string name="introduction_onboarding_text">Vous pouvez présenter vos contacts mutuellement, afin qu’ils n’aient pas à se rencontrer en personne pour se connecter les uns aux autres avec Briar.</string> + <string name="introduction_menu_item">Faire les présentations</string> + <string name="introduction_activity_title">Sélectionner un contact </string> + <string name="introduction_not_possible">Une présentation est déjà en cours avec ces contacts. Veuillez d’abord lui permettre de se terminer. Si vous ou vos contacts êtes rarement en ligne, cela peut prendre du temps.</string> + <string name="introduction_message_title">Présenter des contacts</string> + <string name="introduction_message_hint">Ajouter un message (facultatif)</string> + <string name="introduction_button">Faire les présentations</string> + <string name="introduction_sent">Votre présentation a été envoyée.</string> + <string name="introduction_error">Une erreur est survenue lors de la présentation.</string> + <string name="introduction_response_error">Erreur de réponse à la présentation</string> + <string name="introduction_request_sent">Vous avez demandé de présenter %1$s à %2$s.</string> + <string name="introduction_request_received">%1$s a demandé de vous présenter à %2$s. Souhaitez-vous ajouter %2$s à votre liste de contacts ?</string> + <string name="introduction_request_exists_received">%1$s a demandé de vous présenter à %2$s, mais %2$s est déjà dans votre liste de contacts. Puisque %1$s pourrait ne pas le savoir, vous pouvez tout de même répondre :</string> + <string name="introduction_request_answered_received">%1$s a demandé de vous présenter à %2$s.</string> + <string name="introduction_response_accepted_sent">Vous avez accepté d’être présenté à %1$s.</string> + <string name="introduction_response_accepted_sent_info">Avant que %1$s ne soit ajouté à vos contacts, ce contact doit aussi accepter la présentation. Cela peut prendre du temps. </string> + <string name="introduction_response_declined_sent">Vous avez refusé d’être présenté à %1$s.</string> + <string name="introduction_response_accepted_received">%1$s a accepté d’être présenté à %2$s.</string> + <string name="introduction_response_declined_received">%1$s a refusé d’être présenté à %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s annonce que %2$s a refusé la présentation.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Un nouveau contact a été ajouté.</item> + <item quantity="other">%d nouveaux contacts ont été ajoutés.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">Aucun groupe à afficher\n\nTouchez l’icône + pour créer un groupe ou demandez à vos contacts de partager des groupes avec vous</string> + <string name="groups_created_by">Créé par %s</string> + <plurals name="messages"> + <item quantity="one">%d message</item> + <item quantity="other">%d messages</item> + </plurals> + <string name="groups_group_is_empty">Ce groupe est vide</string> + <string name="groups_group_is_dissolved">Ce groupe a été dissous</string> + <string name="groups_remove">Supprimer</string> + <string name="groups_create_group_title">Créer un groupe privé</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_hint">Choisir un nom pour votre groupe privé</string> + <string name="groups_invitation_sent">L’invitation de groupe a été envoyée</string> + <string name="groups_message_sent">Le message a été envoyé</string> + <string name="groups_member_list">Liste 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">%s a créé le groupe</string> + <string name="groups_member_joined_you">Vous vous êtes joint au groupe</string> + <string name="groups_member_joined">%s s’est joint au groupe</string> + <string name="groups_leave">Quitter le groupe</string> + <string name="groups_leave_dialog_title">Confirmer la sortie du groupe</string> + <string name="groups_leave_dialog_message">Voulez-vous vraiment quitter ce groupe ?</string> + <string name="groups_dissolve">Dissoudre le groupe</string> + <string name="groups_dissolve_dialog_title">Confirmer la dissolution du groupe</string> + <string name="groups_dissolve_dialog_message">Voulez-vous vraiment dissoudre ce groupe ?\n\nLes autres participants ne pourront pas poursuivre leur conversation et ne recevront peut-être pas les derniers messages.</string> + <string name="groups_dissolve_button">Dissoudre</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> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Invitations de 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_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_declined">L’invitation de groupe a été refusée</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d invitation de groupe en attente</item> + <item quantity="other">%d invitations de groupe en attente</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Vous avez accepté l’invitation de 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_accepted_received">%s a accepté l’invitation de groupe.</string> + <string name="groups_invitations_response_declined_received">%s a refusé l’invitation de 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--> + <string name="groups_reveal_contacts">Dévoiler les contacts</string> + <string name="groups_reveal_dialog_message">Vous pouvez choisir de dévoiler les contacts à tous les participants actuels et futurs de ce groupe.\n\nDévoiler les contacts accélère et fiabilise votre connexion au groupe, car vous pouvez communiquer avec les contacts dévoilés même si le créateur du groupe est hors ligne.</string> + <string name="groups_reveal_visible">Votre lien avec le contact est visible par le groupe</string> + <string name="groups_reveal_visible_revealed_by_us">Votre lien avec le contact est visible par le groupe (dévoilé par vous)</string> + <string name="groups_reveal_visible_revealed_by_contact">Votre lien avec le contact est visible par le groupe (dévoilé par %s)</string> + <string name="groups_reveal_invisible">Votre lien avec le contact n’est pas visible par le groupe</string> + <!--Forums--> + <string name="no_forums">Aucun forum à afficher\n\nTouchez l’icône + pour créer un forum ou demandez à vos contacts de partager des forums avec vous</string> + <string name="create_forum_title">Créer un forum</string> + <string name="choose_forum_hint">Choisir un nom pour votre forum </string> + <string name="create_forum_button">Créer un forum</string> + <string name="forum_created_toast">Le forum a été créé</string> + <string name="no_forum_posts">Aucun article à afficher</string> + <string name="no_posts">Aucun article</string> + <plurals name="posts"> + <item quantity="one">%d article</item> + <item quantity="other">%d articles</item> + </plurals> + <string name="forum_new_entry_posted">Un article de forum a été publié</string> + <string name="forum_new_message_hint">Nouvelle article</string> + <string name="forum_message_reply_hint">Nouvelle réponse</string> + <string name="btn_reply">Répondre</string> + <string name="forum_leave">Quitter le forum</string> + <string name="dialog_title_leave_forum">Confirmer la sortie du forum</string> + <string name="dialog_message_leave_forum">Voulez-vous vraiment quitter ce forum ?\n\nLes contacts avec qui vous l’avez partagé pourraient ne plus en recevoir les mises à jour.</string> + <string name="dialog_button_leave">Quitter</string> + <string name="forum_left_toast">À quitté le forum</string> + <!--Forum Sharing--> + <string name="forum_share_button">Partager le forum</string> + <string name="contacts_selected">Des contacts ont été sélectionnés</string> + <string name="activity_share_toolbar_header">Choisir des contacts</string> + <string name="no_contacts_selector">Aucun contact à afficher.\n\nVeuillez revenir ici après avoir ajouté un contact</string> + <string name="forum_shared_snackbar">Le forum a été partagé avec les contacts choisis</string> + <string name="forum_share_message">Ajouter un message (facultatif)</string> + <string name="forum_share_error">Une erreur est survenue lors du partage de ce forum.</string> + <string name="forum_invitation_received">%1$s a partagé le forum « %2$s » avec vous.</string> + <string name="forum_invitation_sent">Vous avez partagé le forum « %1$s » avec %2$s.</string> + <string name="forum_invitations_title">Invitations au forum</string> + <string name="forum_invitation_exists">Vous avez déjà accepté une invitation à ce forum.\n\n En acceptant d’autres invitations, vous rendrez la communication vers ce forum plus rapide et plus fiable.</string> + <string name="forum_joined_toast">Vous vous êtes joint au forum</string> + <string name="forum_declined_toast">L’invitation a été refusée</string> + <string name="shared_by_format">Partagé par %s</string> + <string name="forum_invitation_already_sharing">Le forum est déjà partagé</string> + <string name="forum_invitation_response_accepted_sent">Vous avez accepté l’invitation de %s au forum.</string> + <string name="forum_invitation_response_declined_sent">Vous avez refusé l’invitation de %s au forum.</string> + <string name="forum_invitation_response_accepted_received">%s a accepté l’invitation au forum.</string> + <string name="forum_invitation_response_declined_received">%s a refusé l’invitation au forum.</string> + <string name="sharing_status">État de partage</string> + <string name="sharing_status_forum">Tous les participants d’un forum peuvent le partager avec leurs contacts. Vous partagez ce forum avec les contacts suivants. Il peut aussi y avoir d’autres participants que vous ne pouvez pas voir.</string> + <string name="shared_with">Partagé avec %1$d (%2$d en ligne)</string> + <plurals name="forums_shared"> + <item quantity="one">%d forum partagé par des contacts</item> + <item quantity="other">%d forums partagés par des contacts</item> + </plurals> + <string name="nobody">Personne</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Aucun billet à afficher</string> + <string name="read_more">en lire davantage</string> + <string name="blogs_write_blog_post">Écrire un billet de blogue</string> + <string name="blogs_write_blog_post_body_hint">Tapez votre billet de blogue</string> + <string name="blogs_publish_blog_post">Publier</string> + <string name="blogs_blog_post_created">Le billet de blogue a été créé</string> + <string name="blogs_blog_post_received">Un nouvel billet de blogue a été reçu</string> + <string name="blogs_blog_post_scroll_to">Atteindre</string> + <string name="blogs_feed_empty_state">Aucun billet à afficher.\n\n\Les billets de vos contacts et les blogues auxquels vous vous abonnez apparaîtront ici.\n\nTouchez l’icône de crayon pour rédiger un billet</string> + <string name="blogs_remove_blog">Supprimer le blogue</string> + <string name="blogs_remove_blog_dialog_message">Voulez-vous vraiment supprimer ce blogue ?\nLes billets seront supprimés de votre appareil mais pas des appareils d’autrui.\n\nLes contacts avec qui vous avez partagé ce blogue pourraient ne plus en recevoir les mises à jour.</string> + <string name="blogs_remove_blog_ok">Supprimer</string> + <string name="blogs_blog_removed">Le blogue a été supprimé</string> + <string name="blogs_reblog_comment_hint">Ajouter un commentaire (facultatif)</string> + <string name="blogs_reblog_button">Rebloguer</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Partager le blogue</string> + <string name="blogs_sharing_error">Une erreur est survenue lors du partage du blogue.</string> + <string name="blogs_sharing_button">Partager le blogue</string> + <string name="blogs_sharing_snackbar">Le blogue a été partagé avec les contacts choisis</string> + <string name="blogs_sharing_response_accepted_sent">Vous avez accepté l’invitation de %s au blogue.</string> + <string name="blogs_sharing_response_declined_sent">Vous avez refusé l’invitation de %s au blogue.</string> + <string name="blogs_sharing_response_accepted_received">%s a accepté l’invitation au blogue.</string> + <string name="blogs_sharing_response_declined_received">%s a refusé l’invitation au blogue.</string> + <string name="blogs_sharing_invitation_received">%1$s a partagé le blogue « %2$s » avec vous.</string> + <string name="blogs_sharing_invitation_sent">Vous avez partagé le blogue « %1$s » avec %2$s.</string> + <string name="blogs_sharing_invitations_title">Invitations au blogue</string> + <string name="blogs_sharing_joined_toast">Est abonné au blogue</string> + <string name="blogs_sharing_declined_toast">L’invitation a été refusée</string> + <string name="sharing_status_blog">Quiconque est abonné à un blogue peut le partager avec ses contacts. Vous partagez ce blogue avec les contacts suivants. Il peut aussi y avoir d’autres abonnés que vous ne pouvez pas voir.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Importer un fil RSS</string> + <string name="blogs_rss_feeds_import_button">Importer</string> + <string name="blogs_rss_feeds_import_hint">Saisir l’URL du fil RSS</string> + <string name="blogs_rss_feeds_import_error">Nous sommes désolé ! Une erreur est survenue lors de l’importation de votre fil.</string> + <string name="blogs_rss_feeds_manage">Gérer les fils RSS</string> + <string name="blogs_rss_feeds_manage_imported">Importés :</string> + <string name="blogs_rss_feeds_manage_author">Auteur :</string> + <string name="blogs_rss_feeds_manage_updated">Dernière mise à jour :</string> + <string name="blogs_rss_remove_feed">Supprimer le fil</string> + <string name="blogs_rss_remove_feed_dialog_message">Voulez-vous vraiment supprimer ce fil ?\nLes billets seront supprimés de votre appareil mais pas des appareils d’autrui.\n\nLes contacts avec qui vous avez partagé ce fil pourraient ne plus en recevoir les mises à jour.</string> + <string name="blogs_rss_remove_feed_ok">Supprimer</string> + <string name="blogs_rss_feeds_manage_delete_error">Impossible de supprimer le fil !</string> + <string name="blogs_rss_feeds_manage_empty_state">Aucun fil RSS à afficher\n\nTouchez l’icône + pour importer un fil</string> + <string name="blogs_rss_feeds_manage_error">Un problème est survenu lors du chargement de vos fils. Veuillez ressayer ultérieurement.</string> + <!--Settings Display--> + <string name="pref_language_title">Langue et région</string> + <string name="pref_language_changed">Ce paramètre prendra effet une fois que vous aurez redémarré Briar. Veuillez vous déconnecter et redémarrer Briar.</string> + <string name="pref_language_default">Valeur par défaut du système</string> + <string name="display_settings_title">Affichage</string> + <string name="pref_theme_title">Thème</string> + <string name="pref_theme_light">Clair</string> + <string name="pref_theme_dark">Sombre</string> + <string name="pref_theme_auto">Automatique (journée)</string> + <string name="pref_theme_system">Valeur par défaut du système</string> + <!--Settings Network--> + <string name="network_settings_title">Réseaux</string> + <string name="bluetooth_setting">Se connecter par Bluetooth</string> + <string name="bluetooth_setting_enabled">Lorsque des contacts sont à proximité</string> + <string name="bluetooth_setting_disabled">Uniquement lors de l’ajout de contacts</string> + <string name="tor_network_setting">Se connecter avec Tor</string> + <string name="tor_network_setting_never">Jamais</string> + <string name="tor_network_setting_wifi">Seulement par Wi-Fi</string> + <string name="tor_network_setting_always">En utilisant le Wi-Fi ou le service mobile de données</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Sécurité</string> + <string name="change_password">Changer le mot de passe</string> + <string name="current_password">Mot de passe actuel</string> + <string name="choose_new_password">Nouveau mot de passe</string> + <string name="confirm_new_password">Confirmer le nouveau mot de passe</string> + <string name="password_changed">Le mot de passe a été changé.</string> + <string name="panic_setting">Paramètres du bouton d’urgence</string> + <string name="panic_setting_title">Bouton d’urgence</string> + <string name="panic_setting_hint">Configurer la réaction de Briar lorsque vous utilisez une application de bouton d’urgence</string> + <string name="panic_app_setting_title">Application de bouton d’urgence</string> + <string name="unknown_app">une appli inconnue</string> + <string name="panic_app_setting_summary">Aucune appli n’a été définie</string> + <string name="panic_app_setting_none">Aucune</string> + <string name="dialog_title_connect_panic_app">Confirmer l’application d’urgence</string> + <string name="dialog_message_connect_panic_app">Voulez-vous vraiment autoriser %1$s à déclencher les actions destructrices du bouton d’urgence ?</string> + <string name="panic_setting_signout_title">Déconnexion</string> + <string name="panic_setting_signout_summary">Se déconnecter de Briar lorsqu’on appuie sur un bouton d’urgence</string> + <string name="purge_setting_title">Supprimer le compte</string> + <string name="purge_setting_summary">Supprimer votre compte Briar lorsqu’on appuie sur un bouton d’urgence. Attention : cela supprimera définitivement vos identités, contacts et messages</string> + <string name="uninstall_setting_title">Désinstaller Briar</string> + <string name="uninstall_setting_summary">Une confirmation manuelle est exigée en cas d’événement d’urgence</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Notifications</string> + <string name="notify_sign_in_title">Rappelez-moi de me connecter</string> + <string name="notify_sign_in_summary">Afficher un rappel lors du démarrage du téléphone ou si l’appli a été mise à jour</string> + <string name="notify_private_messages_setting_title">Messages privés</string> + <string name="notify_private_messages_setting_summary">Afficher des notifications pour les messages privés</string> + <string name="notify_private_messages_setting_summary_26">Configurer les alertes pour les messages privés</string> + <string name="notify_group_messages_setting_title">Messages de groupe</string> + <string name="notify_group_messages_setting_summary">Afficher des alertes pour les messages de groupe</string> + <string name="notify_group_messages_setting_summary_26">Configurer les alertes pour les messages de groupe</string> + <string name="notify_forum_posts_setting_title">Articles de forum</string> + <string name="notify_forum_posts_setting_summary">Afficher des alertes pour les articles de forum</string> + <string name="notify_forum_posts_setting_summary_26">Configurer les alertes pour les articles de forum</string> + <string name="notify_blog_posts_setting_title">Billets de blogue</string> + <string name="notify_blog_posts_setting_summary">Afficher des alertes pour les billets de blogue</string> + <string name="notify_blog_posts_setting_summary_26">Configurer les alertes pour les billets de forum</string> + <string name="notify_vibration_setting">Vibrer</string> + <string name="notify_lock_screen_setting_title">Écran de verrouillage</string> + <string name="notify_lock_screen_setting_summary">Afficher les notifications sur l’écran de verrouillage</string> + <string name="notify_sound_setting">Son</string> + <string name="notify_sound_setting_default">Sonnerie par défaut</string> + <string name="notify_sound_setting_disabled">Aucun</string> + <string name="choose_ringtone_title">Choisir une sonnerie</string> + <string name="cannot_load_ringtone">Impossible de charger la sonnerie</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Rétroaction</string> + <string name="send_feedback">Envoyer une rétroaction</string> + <!--Link Warning--> + <string name="link_warning_title">Avertissement de lien</string> + <string name="link_warning_intro">Vous êtes sur le point d’ouvrir le lien suivant avec une appli externe.</string> + <string name="link_warning_text">Cela pourrait être utilisé pour vous identifier. Décidez si vous faites confiance à la personne qui vous a envoyé ce lien et envisagez de l’ouvrir avec Orfox.</string> + <string name="link_warning_open_link">Ouvrir le lien</string> + <!--Crash Reporter--> + <string name="crash_report_title">Rapport de plantage de Briar</string> + <string name="briar_crashed">Désolé, Briar a planté.</string> + <string name="not_your_fault">Vous n’y êtes pour rien.</string> + <string name="please_send_report">Veuillez nous aider à améliorer Briar en nous envoyant un rapport de plantage.</string> + <string name="report_is_encrypted">Nous promettons que le rapport est chiffré et envoyé en toute sécurité. </string> + <string name="feedback_title">Rétroaction</string> + <string name="describe_crash">Décrivez ce qui s’est produit (facultatif)</string> + <string name="enter_feedback">Saisir votre rétroaction</string> + <string name="optional_contact_email">Votre adresse courriel (facultative)</string> + <string name="include_debug_report_crash">Inclure des données anonymes concernant le plantage</string> + <string name="include_debug_report_feedback">Inclure des données anonymes concernant cet appareil</string> + <string name="could_not_load_report_data">Impossible de charger les données du rapport.</string> + <string name="send_report">Envoyer le rapport</string> + <string name="close">Fermer</string> + <string name="dev_report_saved">Le rapport a été enregistré. Il sera envoyé lors de votre prochaine connexion à Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">Déconnexion de Briar…</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Une superposition d’écran a été détectée</string> + <string name="screen_filter_body">Une autre appli s’affiche par-dessus Briar. Pour protéger votre sécurité, Briar ne répondra pas au toucher si une autre appli s’affiche par-dessus.\n\nLes applis suivantes pourraient s’afficher par-dessus Briar : \n\n%1$s</string> + <string name="screen_filter_allow">Permettre à ces applis de s’afficher par-dessus</string> + <!--Permission Requests--> + <string name="permission_camera_title">Accès à la caméra</string> + <string name="permission_camera_request_body">Pour lire le code QR, Briar doit accéder à la caméra.</string> + <string name="permission_camera_denied_body">Vous avez refusé l’accès à la caméra, mais l’ajout de contacts exige l’utilisation de celle-ci.\n\nVeuillez envisager d’y accorder l’accès.</string> + <string name="permission_camera_denied_toast">L’accès à la caméra n’a pas été accordé</string> + <string name="qr_code">Code QR</string> + <string name="show_qr_code_fullscreen">Afficher le code QR en plein écran</string> +</resources> diff --git a/mailbox-android/src/main/res/values-gl/strings.xml b/mailbox-android/src/main/res/values-gl/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..9b3a6273db75be05cb15908e6d08e0c1544ec2df --- /dev/null +++ b/mailbox-android/src/main/res/values-gl/strings.xml @@ -0,0 +1,409 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Benvida a Briar</string> + <string name="setup_name_explanation">O seu alcume mostrarase xunto a todas as mensaxes que publique. Pode cambialo tras crear a súa conta.</string> + <string name="setup_next">Seguinte</string> + <string name="setup_password_intro">Escolla un Contrasinal</string> + <string name="setup_password_explanation">A súa conta en Briar gárdase cifrada no seu dispositivo, non na nube. Si esquece o contrasinal ou desinstala Briar, non haberá xeito de recuperar a súa conta.\n\nEscolla un contrasinal longo que sexa difÃcil de supoñer, algo como catro palabras ao chou, ou dez letras aleatorias, números e sÃmbolos.</string> + <string name="setup_doze_title">Conexións en segundo plano</string> + <string name="setup_doze_intro">Para recibir mensaxes, Briar precisa estar conectada en segundo plano.</string> + <string name="setup_doze_explanation">Para recibir mensaxes, Briar precisa estar conectada en segundo plano. Por favor desactive as optimizacións de baterÃa para que Briar poida permanecer conectada.</string> + <string name="setup_doze_button">Permitir conexións</string> + <string name="choose_nickname">Escolle o teu alcume</string> + <string name="choose_password">Escolle a túa clave</string> + <string name="confirm_password">Confirma a túa clave</string> + <string name="name_too_long">O nome é demasiado longo</string> + <string name="password_too_weak">A clave é demasiado débil</string> + <string name="passwords_do_not_match">As claves non coinciden</string> + <string name="create_account_button">Crea a conta</string> + <string name="more_info">Máis información</string> + <string name="don_t_ask_again">Non preguntar de novo</string> + <string name="setup_huawei_text">Por favor toque o botón inferior e asegúrese de que Briar está protexida na pantalla \"Apps Protexidas\"</string> + <string name="setup_huawei_button">Protexer Briar</string> + <string name="setup_huawei_help">Si Briar non se engade ao listado de apps protexidas, non poderá funcionar en segundo plano.</string> + <string name="warning_dozed">%s non foi quen de funcionar en segundo plano</string> + <!--Login--> + <string name="enter_password">Contrasinal</string> + <string name="try_again">Clave incorrecta, tenteo de novo</string> + <string name="sign_in_button">Iniciar sesión</string> + <string name="forgotten_password">EsquecÃn a miña clave</string> + <string name="dialog_title_lost_password">Clave perdida</string> + <string name="dialog_message_lost_password">Briar almacena a súa configuración encriptada no dispositivo, non na nube, asà que non podemos restabelecer a súa clave. QuerrÃas borrar a túa conta e empezar de novo?\n\nPrecaución: As túas identidades, contactos e mensaxes serán eliminadas de forma permanente.</string> + <string name="startup_failed_notification_title">Briar non puido iniciarse</string> + <string name="startup_failed_notification_text">Toque para máis información.</string> + <string name="startup_failed_activity_title">Fallo de Inicio de Briar</string> + <string name="startup_failed_db_error">Por algún motivo, a súa base de datos de Briar está defectuosa sen remedio. A súa conta, os seus datos e contactos perdéronse. Desgraciadamente, debe reinstalar Briar ou crear unha nova conta escollendo \'EsquecÃn o meu contrasinal\' cando se lle solicite o contrasinal.</string> + <string name="startup_failed_data_too_old_error">A súa conta foi creada con unha versión anterior da aplicación e non se pode abrir con esta versión. Deberá reinstalar a versión anterior ou ben crear unha nova conta escollendo \'EsquecÃn o meu contrasinal\' cando se lle solicite o contrasinal.</string> + <string name="startup_failed_data_too_new_error">Esta versión da app é moi antiga. Actualice por favor a última versión e inténteo de novo.</string> + <string name="startup_failed_service_error"> Briar non puido iniciar un complemento necesario. Xeralmente reinstalar Briar resolve este problema. Teña en conta que entón perderá a súa conta e todos os datos asociados a esta pois Briar non está a utilizar servidores centrais para almacenar os seus datos.</string> + <plurals name="expiry_warning"> + <item quantity="one">Esta versión de Briar é para probas. A conta caducará en %d dÃa e non se pode anovar.</item> + <item quantity="other">Esta versión de Briar é para probas. A conta caducará en %d dÃas e non se pode anovar.</item> + </plurals> + <string name="expiry_update">A data de caducidade de probas foi alongada. Agora a súa conta caduca en %d dÃas.</string> + <string name="expiry_date_reached">Este software caducou.\nGrazas por probalo!</string> + <string name="download_briar">Para continuar utilizando Briar, descargue por favor a versión 1.0.</string> + <string name="create_new_account">Precisa crear unha nova conta, pero pode utilizar o mesmo alcume.</string> + <string name="download_briar_button">Descargar Briar 1.0</string> + <string name="startup_open_database">Descifrando a Base de datos...</string> + <string name="startup_migrate_database">Actualizando a Base de datos...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Abra a gaveta de navegación</string> + <string name="nav_drawer_close_description">Peche a gaveta de navegación</string> + <string name="contact_list_button">Contactos</string> + <string name="groups_button">Grupos Privados</string> + <string name="forums_button">Foros</string> + <string name="blogs_button">Blogues</string> + <string name="settings_button">Axustes</string> + <string name="sign_out_button">Finalizar sesión</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="reminder_notification_title">Desconectou de Briar</string> + <string name="reminder_notification_channel_title">Recordatorio para conectar a Briar</string> + <string name="ongoing_notification_title">Conectado a Briar</string> + <string name="ongoing_notification_text">Toque para abrir Briar</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Nova mensaxe privada.</item> + <item quantity="other">%d novas mensaxes privadas.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Nova mensaxe de grupo.</item> + <item quantity="other">%d novas mensaxes de grupo.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Nova publicación de foro.</item> + <item quantity="other">%d nova publicación de foro.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Nova publicación de blog.</item> + <item quantity="other">%d novas publicacións de blog.</item> + </plurals> + <!--Misc--> + <string name="now">agora</string> + <string name="show">Amosar</string> + <string name="hide">Agochar</string> + <string name="ok">OK</string> + <string name="cancel">Cancelar</string> + <string name="got_it">Comprendido</string> + <string name="delete">Eliminar</string> + <string name="accept">Aceptar</string> + <string name="decline">Rexeitar</string> + <string name="options">Opcións</string> + <string name="online">Conectado</string> + <string name="offline">Desconectado</string> + <string name="send">Enviar</string> + <string name="allow">Permitir</string> + <string name="open">Abrir</string> + <string name="no_data">Sen datos</string> + <string name="ellipsis">...</string> + <string name="text_too_long">O texto inserido e demasiado longo</string> + <string name="show_onboarding">Amosar xanela de axuda</string> + <string name="fix">Arranxar</string> + <string name="help">Axuda</string> + <string name="sorry">Desculpe</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Sen contactos a mostrar\n\nToque na icona + para engadir contactos</string> + <string name="date_no_private_messages">Sen mensaxes</string> + <string name="no_private_messages">Sen mensaxes que mostrar</string> + <string name="message_hint">Esciba unha mensaxe</string> + <string name="delete_contact">Eliminar contacto</string> + <string name="dialog_title_delete_contact">Confirme a eliminación do contacto</string> + <string name="dialog_message_delete_contact">Segura de querer eliminar este contacto e todas as mensaxes que intercambiaron?</string> + <string name="contact_deleted_toast">Contacto eliminado</string> + <!--Adding Contacts--> + <string name="add_contact_title">Engada un contacto</string> + <string name="face_to_face">Debe encontrarse coa persoa que quere engadir como contacto.\n\nEsto evitará que calquera poida suplantala ou ler as súas mensaxes no futuro.</string> + <string name="continue_button">Continuar</string> + <string name="connection_failed">Fallou a conexión</string> + <string name="try_again_button">Tenteo de novo</string> + <string name="waiting_for_contact_to_scan">Agardando polo contacto para escanear e conectar\u2026</string> + <string name="exchanging_contact_details">Intercambiando detalles do contacto\u2026</string> + <string name="contact_added_toast">Contacto engadido: %s</string> + <string name="contact_already_exists">O contacto %s xa existe</string> + <string name="contact_exchange_failed">Fallo no intercambio de contacto</string> + <string name="qr_code_invalid">O código QR non é válido</string> + <string name="qr_code_unsupported">O código QR que intenta escanear pertence a unha versión antiga de %s que xa non está soportada.\n\nPor favor, asegúrese que ambas utilizan a última versión e inténteno de novo.</string> + <string name="camera_error">Fallo na cámara</string> + <string name="connecting_to_device">Conectando co dispositivo\u2026</string> + <string name="authenticating_with_device">Autenticándose co dispositivo\u2026</string> + <string name="connection_aborted_local">Conexión cancelada! Esto poderÃa significar que alguén está intentando entremeterse na súa conexión.</string> + <string name="connection_aborted_remote">Conexión rexeitada polo seu contacto! Esto poderÃa indicar que alguén está intentando interferir na súa conexión</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Presente os seus contactos</string> + <string name="introduction_onboarding_text">Pode presentar aos seus contactos, asà non precisan encontrarse en persoa para conectar a través de Briar.</string> + <string name="introduction_menu_item">Preséntese</string> + <string name="introduction_activity_title">Escoller contacto</string> + <string name="introduction_not_possible">Xa ten unha presentación en progreso con estes contactos. Por favor, deixe que remate o proceso. Si vostede ou os contactos se conectan con pouca asiduidade esto poderÃa levar algún tempo.</string> + <string name="introduction_message_title">Introducir Contactos</string> + <string name="introduction_message_hint">Engadir unha mensaxe (opcional)</string> + <string name="introduction_button">Preséntese</string> + <string name="introduction_sent">Enviouse a súa presentación.</string> + <string name="introduction_error">Algo fallou ao enviar a presentación.</string> + <string name="introduction_response_error">Fallo respondendo a presentación</string> + <string name="introduction_request_sent">Solicitou presentar %1$s a %2$s.</string> + <string name="introduction_request_received">%1$s solicitou presentala a %2$s. Quere engadir a %2$s ao seu listado de contactos?</string> + <string name="introduction_request_exists_received">%1$s solicitou presentala a %2$s, pero %2$s xa está no seu listado de contactos. Xa que %1$s poderÃa non sabelo, pode responder igualmente:</string> + <string name="introduction_request_answered_received">%1$s solicitou presentala a %2$s.</string> + <string name="introduction_response_accepted_sent">Aceptou a presentación a %1$s.</string> + <string name="introduction_response_accepted_sent_info">Antes de engadir %1$s aos seus contactos, eles precisan aceptar a presentación tamén. Esto poderÃa levar algún tempo.</string> + <string name="introduction_response_declined_sent">Vostede rexeitou a presentación a %1$s.</string> + <string name="introduction_response_accepted_received">%1$s aceptou a presentación a %2$s.</string> + <string name="introduction_response_declined_received">%1$s rexeitou a presentación a %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s di que %2$srexeitou a presentación.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Novo contacto engadido.</item> + <item quantity="other">%d novos contactos engadidos.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">Sen grupos para mostrar\n\nToque na icona + para crear un grupo, ou pida aos seus contactos que compartan grupos con vostede</string> + <string name="groups_created_by">Creado por %s</string> + <plurals name="messages"> + <item quantity="one">%d mensaxe</item> + <item quantity="other">%d mensaxes</item> + </plurals> + <string name="groups_group_is_empty">Este grupo está valeiro</string> + <string name="groups_group_is_dissolved">Este grupo foi disolto</string> + <string name="groups_remove">Eliminar</string> + <string name="groups_create_group_title">Crear Grupo Privado</string> + <string name="groups_create_group_button">Crear Grupo</string> + <string name="groups_create_group_invitation_button">Enviar Convite</string> + <string name="groups_create_group_hint">Escolla un nome para o seu grupo privado</string> + <string name="groups_invitation_sent">Enviouse o convite de grupo</string> + <string name="groups_message_sent">Mensaxe enviada</string> + <string name="groups_member_list">Lista de Membros</string> + <string name="groups_invite_members">Convidar a Membros</string> + <string name="groups_member_created_you">Vostede creou o grupo</string> + <string name="groups_member_created">%s creou o grupo</string> + <string name="groups_member_joined_you">Vostede ingresou no grupo</string> + <string name="groups_member_joined">%s unÃuse ao grupo</string> + <string name="groups_leave">Deixar Grupo</string> + <string name="groups_leave_dialog_title">Confirme que deixa o Grupo</string> + <string name="groups_leave_dialog_message">Está certo de que quere deixar este grupo?</string> + <string name="groups_dissolve">Desfacer o grupo</string> + <string name="groups_dissolve_dialog_title">Confirme a disolución do grupo</string> + <string name="groups_dissolve_dialog_message">Segura de querer desfacer o grupo?\n\nO resto da membresÃa non poderá continuar a conversa e poderÃa non recibir as últimas mensaxes.</string> + <string name="groups_dissolve_button">Desfacer</string> + <string name="groups_dissolved_dialog_title">O grupo foi desfeito</string> + <string name="groups_dissolved_dialog_message">A persoa creadora do grupo desfÃxoo.\n\nXa non poderá escribir mensaxes ao grupo e poderÃa non ter recibido todas as mensaxes que foran escritas.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Convites de Grupo</string> + <string name="groups_invitations_invitation_sent">Convidou a %1$s a unirse ao grupo \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s convidouna a unirse ao grupo \"%2$s\".</string> + <string name="groups_invitations_joined">Xa está no grupo</string> + <string name="groups_invitations_declined">Rexeitou o convite ao grupo</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d convite de grupo aberto</item> + <item quantity="other">%d convites de grupo abertos</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Aceptou o convite de grupo de %s.</string> + <string name="groups_invitations_response_declined_sent">Rexeitou o convite de grupo de %s.</string> + <string name="groups_invitations_response_accepted_received">%s aceptou o convite de grupo.</string> + <string name="groups_invitations_response_declined_received">%s rexeitou o convite de grupo.</string> + <string name="sharing_status_groups">Só a persoa creadora poder convidar a novos membros ao grupo. Abaixo está a membresÃa do grupo.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Revelar contactos</string> + <string name="groups_reveal_dialog_message">Pode escoller si revela os contactos a todos os compoñentes actuais e futuros do grupo.\n\Si revela os contactos a conexión do grupo será máis rápida e fiable, xa que poderá comunicarse cos contactos revelados incluso si a creadora do grupo non está en liña.</string> + <string name="groups_reveal_visible">A relación do contacto é visible para o grupo</string> + <string name="groups_reveal_visible_revealed_by_us">A relación co contacto é visible para o grupo (revelada por vostede)</string> + <string name="groups_reveal_visible_revealed_by_contact">A relación con contacto é visible para o grupo (revelada por %s)</string> + <string name="groups_reveal_invisible">A relación co contacto non é visible para o grupo</string> + <!--Forums--> + <string name="no_forums">Si foros que mostrar\n\nToque na icona + para crear un foro, ou solicite aos contactos que compartan foros con vostede</string> + <string name="create_forum_title">Crear Foro</string> + <string name="choose_forum_hint">Escolla un nome para o seu foro</string> + <string name="create_forum_button">Crear Foro</string> + <string name="forum_created_toast">Foro creado</string> + <string name="no_forum_posts">Sen publicacións que mostrar</string> + <string name="no_posts">Non hai mensaxes</string> + <plurals name="posts"> + <item quantity="one">%d publicación</item> + <item quantity="other">%d publicacións</item> + </plurals> + <string name="forum_new_entry_posted">Foro público publicado</string> + <string name="forum_new_message_hint">Nova publicación</string> + <string name="forum_message_reply_hint">Nova Resposta</string> + <string name="btn_reply">Respostar</string> + <string name="forum_leave">Deixar foro</string> + <string name="dialog_title_leave_forum">Confirme a saÃda do foro</string> + <string name="dialog_message_leave_forum">Segura de querer deixar este foro?\n\nTodos os contactos cos que comparteu este foro poderÃan deixar de recibir actualizacións.</string> + <string name="dialog_button_leave">SaÃr</string> + <string name="forum_left_toast">SaÃr do foro</string> + <!--Forum Sharing--> + <string name="forum_share_button">Compartir Foro</string> + <string name="contacts_selected">Contactos selecionados</string> + <string name="activity_share_toolbar_header">Escolla Contactos</string> + <string name="no_contacts_selector">Sen contactos que mostrar\n\nPor favor, volte aquà tras engadir un contacto</string> + <string name="forum_shared_snackbar">Foro compartido cos contactos escollidos</string> + <string name="forum_share_message">Engadir unha mensaxe (opcional)</string> + <string name="forum_share_error">Algo fallou ao compartir este foro.</string> + <string name="forum_invitation_received">%1$s compartiu este foro \"%2$s\" con vostede.</string> + <string name="forum_invitation_sent">Compartiu este foro \"%1$s\" con %2$s.</string> + <string name="forum_invitations_title">Convites a foros</string> + <string name="forum_invitation_exists">Xa aceptara o convite a este foro\n\nAceptando máis convites fará a súa conexión ao foro máis rápida e fiable.</string> + <string name="forum_joined_toast">Uniuse ao foro</string> + <string name="forum_declined_toast">Rexeitou o convite</string> + <string name="shared_by_format">Compartido por %s</string> + <string name="forum_invitation_already_sharing">Xa compartindo</string> + <string name="forum_invitation_response_accepted_sent">Aceptou o convite de %s ao foro.</string> + <string name="forum_invitation_response_declined_sent">Rexeitou o convite de %s ao foro.</string> + <string name="forum_invitation_response_accepted_received">%s aceptou o convite ao foro.</string> + <string name="forum_invitation_response_declined_received">%s rexeitou o convite ao foro.</string> + <string name="sharing_status">Estado do compartido</string> + <string name="sharing_status_forum">Calquera compoñente do foro pode compartilo cos seus contactos. Vostede pode compartir este foro cos seguintes contactos. Pode haber outras persoas que vostede non pode ver.</string> + <string name="shared_with">Compartido con %1$d (%2$d en liña)</string> + <plurals name="forums_shared"> + <item quantity="one">%d foro compartido por contactos</item> + <item quantity="other">%d foros compartidos por contactos</item> + </plurals> + <string name="nobody">Ninguén</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Sen publicacións que mostrar</string> + <string name="read_more">ler mais</string> + <string name="blogs_write_blog_post">Escribir entrada de Blog</string> + <string name="blogs_write_blog_post_body_hint">Escriba a súa entrada no blog</string> + <string name="blogs_publish_blog_post">Publicar</string> + <string name="blogs_blog_post_created">Entrada no blog creada</string> + <string name="blogs_blog_post_received">Nova entrada de blog recibida</string> + <string name="blogs_blog_post_scroll_to">Desplazarse a</string> + <string name="blogs_feed_empty_state">Sen entradas que mostrar\n\nAs entradas dos seus contactos e blogs aos que está subscrita aparecerán aquÃ\n\nToque na icona do lapis para escribir unha entrada</string> + <string name="blogs_remove_blog">Eliminar Blog</string> + <string name="blogs_remove_blog_dialog_message">Segura de que quere eliminar este blog?\n\nAs entradas eliminaranse do seu dispositivo pero non dos dispositivos de outras persoas.\n\nCalquera contacto co que compartira este blog poderÃa deixar de recibir actualizacións.</string> + <string name="blogs_remove_blog_ok">Eliminar</string> + <string name="blogs_blog_removed">Blog eliminado</string> + <string name="blogs_reblog_comment_hint">Engadir un comentario (optativo)</string> + <string name="blogs_reblog_button">Compartir</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Compartir blog</string> + <string name="blogs_sharing_error">Algo fallou ao compartir o blog</string> + <string name="blogs_sharing_button">Compartir blog</string> + <string name="blogs_sharing_snackbar">Blog compartido cos contactos escollidos</string> + <string name="blogs_sharing_response_accepted_sent">Aceptou o convite ao blog de %s.</string> + <string name="blogs_sharing_response_declined_sent">Rexeitou o convite ao blog de %s.</string> + <string name="blogs_sharing_response_accepted_received">%s aceptou o convite ao blog.</string> + <string name="blogs_sharing_response_declined_received">%s rexeitou o convite ao blog.</string> + <string name="blogs_sharing_invitation_received">%1$s compartiu o blog \"%2$s\" con vostede.</string> + <string name="blogs_sharing_invitation_sent">Vostede compartiu o blog \"%1$s\" con %2$s.</string> + <string name="blogs_sharing_invitations_title">Convites a Blog</string> + <string name="blogs_sharing_joined_toast">Subscrita ao blog</string> + <string name="blogs_sharing_declined_toast">Rexeitou o convite</string> + <string name="sharing_status_blog">Calquera que se subscribe a un blog pode compartilo cos seus contactos. Pode compartir este blog cos seguintes contactos. PoderÃa haber outras subscritoras que vostede non pode ver.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Importar fonte RSS</string> + <string name="blogs_rss_feeds_import_button">Importar</string> + <string name="blogs_rss_feeds_import_hint">Introduza o URL da fonte RSS</string> + <string name="blogs_rss_feeds_import_error">Lamentámolo! Algo fallou ao importar a fonte.</string> + <string name="blogs_rss_feeds_manage">Xestionar Fontes RSS</string> + <string name="blogs_rss_feeds_manage_imported">Importado:</string> + <string name="blogs_rss_feeds_manage_author">Autor/a:</string> + <string name="blogs_rss_feeds_manage_updated">Última actualización:</string> + <string name="blogs_rss_remove_feed">Eliminar fonte</string> + <string name="blogs_rss_remove_feed_dialog_message">Está segura de que quere eliminar esta fonte?\n\nAs entradas eliminaranse do seu dispositivo pero non dos dispositivos de outras persoas\n\nTodas as persoas coas que compartiu esta fonte poderÃan deixar de recibir actualizacións.</string> + <string name="blogs_rss_remove_feed_ok">Eliminar</string> + <string name="blogs_rss_feeds_manage_delete_error">Non se puido eliminar a fonte!</string> + <string name="blogs_rss_feeds_manage_empty_state">Sen fontes RSS que mostrar\n\nToque na icona + para importar unha fonte</string> + <string name="blogs_rss_feeds_manage_error">Aconteceu un problema ao cargar as súas fontes. Por favor, inténteo máis tarde.</string> + <!--Settings Display--> + <string name="pref_language_title">Idioma & rexión</string> + <string name="pref_language_changed">Este axuste terá efecto cando reinicie Briar. Por favor desconecte e volte a iniciar Briar.</string> + <string name="pref_language_default">Por omisión do sistema</string> + <string name="display_settings_title">Pantalla</string> + <string name="pref_theme_title">Decorado</string> + <string name="pref_theme_light">Claro</string> + <string name="pref_theme_dark">Oscuro</string> + <string name="pref_theme_auto">Automático (no dÃa)</string> + <string name="pref_theme_system">Por omisión do sistema</string> + <!--Settings Network--> + <string name="network_settings_title">Redes</string> + <string name="bluetooth_setting">Conectar vÃa Bluetooth</string> + <string name="bluetooth_setting_enabled">En claquera momento que un contacto estea preto</string> + <string name="bluetooth_setting_disabled">Só ao engadir contactos</string> + <string name="tor_network_setting">Conectar vÃa Tor</string> + <string name="tor_network_setting_never">Nunca</string> + <string name="tor_network_setting_wifi">Só utilizando Wi-Fi</string> + <string name="tor_network_setting_always">Utilizando Wi-Fi ou datos móbiles</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Seguridade</string> + <string name="change_password">Cambiar contrasinal</string> + <string name="current_password">Contrasinal actual</string> + <string name="choose_new_password">Novo contrasinal</string> + <string name="confirm_new_password">Confirme o novo contrasinal</string> + <string name="password_changed">Cambiou o contrasinal</string> + <string name="panic_setting">Axustes do botón do pánico</string> + <string name="panic_setting_title">Botón do pánico</string> + <string name="panic_setting_hint">Axuste como debe reaccionar Briar cando utilice a app botón do pánico</string> + <string name="panic_app_setting_title">App Botón do pánico</string> + <string name="unknown_app">unha aplicación descoñecida</string> + <string name="panic_app_setting_summary">Non se estableceu unha app</string> + <string name="panic_app_setting_none">Ningún</string> + <string name="dialog_title_connect_panic_app">Confirme a App do pánico</string> + <string name="dialog_message_connect_panic_app">Está segura de querer permitir a %1$s activar accións destrutivas do botón do pánico?</string> + <string name="panic_setting_signout_title">Finalizar sesión</string> + <string name="panic_setting_signout_summary">Desconecte de Briar si o botón do pánico se preme</string> + <string name="purge_setting_title">Eliminar conta</string> + <string name="purge_setting_summary">Elimina a súa conta en Briar si se preme o botón do pánico. Coidado: Esto eliminará permanentemente as súas identidade, contactos e mensaxes</string> + <string name="uninstall_setting_title">Desinstalar Briar</string> + <string name="uninstall_setting_summary">Esto require confirmación manual no evento do pánico</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Notificacións</string> + <string name="notify_private_messages_setting_title">Mensaxes privadas</string> + <string name="notify_private_messages_setting_summary">Mostra alertas para mensaxes privadas</string> + <string name="notify_private_messages_setting_summary_26">Configurar alertas para mensaxes privadas</string> + <string name="notify_group_messages_setting_title">Mensaxes de grupo</string> + <string name="notify_group_messages_setting_summary">Mostra alertas para mensaxes de grupo</string> + <string name="notify_group_messages_setting_summary_26">Configurar alertas para mensaxes de grupo</string> + <string name="notify_forum_posts_setting_title">Entradas no foro</string> + <string name="notify_forum_posts_setting_summary">Mostra alertas para mensaxes nos foros</string> + <string name="notify_forum_posts_setting_summary_26">Configurar alertas para mensaxes nos foros</string> + <string name="notify_blog_posts_setting_title">Entradas no Blog</string> + <string name="notify_blog_posts_setting_summary">Mostra alertas para entradas no blog</string> + <string name="notify_blog_posts_setting_summary_26">Configurar alertas para entradas no blog</string> + <string name="notify_vibration_setting">Vibrar</string> + <string name="notify_lock_screen_setting_title">Bloquear pantalla</string> + <string name="notify_lock_screen_setting_summary">Mostra notificacións na pantalla bloqueada</string> + <string name="notify_sound_setting">Son</string> + <string name="notify_sound_setting_default">Son por omisión</string> + <string name="notify_sound_setting_disabled">Ningún</string> + <string name="choose_ringtone_title">Escolla son</string> + <string name="cannot_load_ringtone">Non se cargou o son</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Comente</string> + <string name="send_feedback">EnvÃe comentario</string> + <!--Link Warning--> + <string name="link_warning_title">Aviso de ligazón</string> + <string name="link_warning_intro">Vai abrir a seguinte ligazón nunha aplicación externa.</string> + <string name="link_warning_text">Esto pode utilizarse para identificala. Pense si confÃa na persoa que lle enviou a ligazón e considere abrila con Orfox.</string> + <string name="link_warning_open_link">Abrir ligazón</string> + <!--Crash Reporter--> + <string name="crash_report_title">Informe de fallo de Briar</string> + <string name="briar_crashed">Lamentámolo, Briar fallou.</string> + <string name="not_your_fault">Non é culpa súa.</string> + <string name="please_send_report">Axúdenos por favor a mellorar Briar enviándonos un informe do fallo.</string> + <string name="report_is_encrypted">Prometemos que o informe está cifrado e enviado con seguridade.</string> + <string name="feedback_title">Comente</string> + <string name="describe_crash">Describa que aconteceu (optativo)</string> + <string name="enter_feedback">Escriba o seu comentario</string> + <string name="optional_contact_email">O seu enderezo e-mail (optativo)</string> + <string name="include_debug_report_crash">IncluÃr datos anónimos sobre o fallo</string> + <string name="include_debug_report_feedback">IncluÃr datos anónimos sobre este dispositivo</string> + <string name="could_not_load_report_data">Non se puideron cargar os datos do informe.</string> + <string name="send_report">Enviar informe</string> + <string name="close">Pechar</string> + <string name="dev_report_saved">Informe gardado. Enviarase a seguinte vez que se conecte con Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">Desconectando de Briar...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Detectouse unha sobreescrita da pantalla</string> + <string name="screen_filter_body">Outra aplicación estase mostrando enriba de Briar. Para protexer a súa seguridade, Briar non responderá a toques cando outra aplicación está debuxando enriba.\n\nAs seguintes aplicacións poderÃan estar debuxando enriba:\n\n%1$s</string> + <string name="screen_filter_allow">Permitir a estas aplicación mostrarse enriba</string> + <!--Permission Requests--> + <string name="permission_camera_title">Permiso da cámara</string> + <string name="permission_camera_request_body">Para escanear códigos QR, Briar precisa acceso a cámara.</string> + <string name="permission_camera_denied_body">Denegou o permiso de acceso a cámara, pero é necesario para engadir contactos.\n\nPor favor, considere conceder o permiso.</string> + <string name="permission_camera_denied_toast">Non concedeu o acceso a cámara</string> + <string name="qr_code">Código QR</string> + <string name="show_qr_code_fullscreen">Mostrar o código QR a pantalla completa</string> +</resources> diff --git a/mailbox-android/src/main/res/values-he/strings.xml b/mailbox-android/src/main/res/values-he/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..d7bf70bd175715cddc8b5de634e88be83a8f3a58 --- /dev/null +++ b/mailbox-android/src/main/res/values-he/strings.xml @@ -0,0 +1,256 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_next">הב×</string> + <string name="choose_nickname">בחרו ×›×™× ×•×™</string> + <string name="choose_password">בחרו סיסמה</string> + <string name="confirm_password">×שרו ×ת הסיסמה</string> + <string name="name_too_long">×”×©× ×רוך מדי</string> + <string name="password_too_weak">הסיסמה חלשה מדי</string> + <string name="passwords_do_not_match">הסיסמ×ות ×œ× ×ª×•×מות</string> + <string name="create_account_button">יצירת חשבון</string> + <!--Login--> + <string name="enter_password">סיסמה</string> + <string name="try_again">הסיסמה שגוייה, × ×¡×• שוב</string> + <string name="sign_in_button">×”×›× ×¡×•</string> + <string name="forgotten_password">שכחתי ×ת הסיסמה שלי</string> + <string name="dialog_title_lost_password">הסיסמה × ×בדה</string> + <string name="dialog_message_lost_password">חשבון הברי×ר ×©×œ×›× ×©×ž×•×¨ ומוצפן על המכשיר, ×œ× ×‘×¢× ×Ÿ, כך ×©×œ× × ×•×›×œ לשחזר ×ת הסיסמה שלכ×. למחוק ×ת החשבון ×©×œ×›× ×•×œ×”×ª×—×™×œ מחדש? + +זהירות: הזהויות שלכ×, ×× ×©×™ הקשר וההודעות ×™×בדו לצמיתות.</string> + <string name="startup_failed_notification_title">×פליקציית ברי×ר × ×›×©×œ×” ב×יתחול</string> + <string name="startup_failed_activity_title">×יתחול ברי×ר × ×›×©×œ</string> + <string name="startup_failed_service_error">ברי×ר ×œ× ×”×¦×œ×™×— ל×תחל תוסף הכרחי. ×”×ª×§× ×ª ברי×ר מחדש לרוב פותרת בעייה זו. שימו לב ש××– ת×בדו ×ת ×—×©×‘×•× ×›× ×•×›×œ המידע המשוייך ×ליו כיוון שברי×ר ×œ× ×ž×©×ª×ž×© ×‘×©×¨×ª×™× ×ž×¨×›×–×™×™× ×œ×©×ž×™×¨×ª המידע ×©×œ×›× ×¢×œ×™×”×.</string> + <string name="expiry_date_reached">פג תוקפה של ×ª×•×›× ×” זו. +תודה ×œ×›× ×©×‘×“×§×ª×.</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">פתחו ×ת סרגל ×”× ×™×•×•×˜</string> + <string name="nav_drawer_close_description">סגרו ×ת סרגל ×”× ×™×•×•×˜</string> + <string name="contact_list_button">×× ×©×™ קשר</string> + <string name="groups_button">קבוצות פרטיות</string> + <string name="forums_button">פורומי×</string> + <string name="blogs_button">בלוגי×</string> + <string name="settings_button">הגדרות</string> + <string name="sign_out_button">יצי××”</string> + <!--Transports--> + <string name="transport_tor">××™× ×˜×¨× ×˜</string> + <string name="transport_bt">בלוטות\'</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="ongoing_notification_title">×ž×—×•×‘×¨×™× ×œ×‘×¨×™×ר</string> + <string name="ongoing_notification_text">לחצו על ×ž× ×ª לפתוח ×ת ברי×ר</string> + <plurals name="private_message_notification_text"> + <item quantity="one">הודעה פרטית חדשה.</item> + <item quantity="two">%d הודעות פריטות חדשות.</item> + <item quantity="many">%d הודעות פריטות חדשות.</item> + <item quantity="other">%d הודעות פריטות חדשות.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">הודעה קבוצתית חדשה.</item> + <item quantity="two">%d הודעות קבוצתיות חדשות.</item> + <item quantity="many">%d הודעות קבוצתיות חדשות.</item> + <item quantity="other">%d הודעות קבוצתיות חדשות.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">פוסט חדש בפורומי×.</item> + <item quantity="two">%d ×¤×•×¡×˜×™× ×—×“×©×™× ×‘×¤×•×¨×•×ž×™×.</item> + <item quantity="many">%d ×¤×•×¡×˜×™× ×—×“×©×™× ×‘×¤×•×¨×•×ž×™×.</item> + <item quantity="other">%d ×¤×•×¡×˜×™× ×—×“×©×™× ×‘×¤×•×¨×•×ž×™×.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">פוסט חדש בבלוגי×.</item> + <item quantity="two">%d ×¤×•×¡×˜×™× ×—×“×©×™× ×‘×‘×œ×•×’×™×.</item> + <item quantity="many">%d ×¤×•×¡×˜×™× ×—×“×©×™× ×‘×‘×œ×•×’×™×.</item> + <item quantity="other">%d ×¤×•×¡×˜×™× ×—×“×©×™× ×‘×‘×œ×•×’×™×.</item> + </plurals> + <!--Misc--> + <string name="now">עכשיו</string> + <string name="show">הצג</string> + <string name="hide">הסתר</string> + <string name="ok">×ישור</string> + <string name="cancel">ביטול</string> + <string name="got_it">×”×‘× ×ª×™</string> + <string name="delete">מחק</string> + <string name="accept">קבל</string> + <string name="decline">סרב</string> + <string name="options">×פשרויות</string> + <string name="online">מחובר</string> + <string name="offline">×œ× ×ž×—×•×‘×¨</string> + <string name="send">שלח</string> + <string name="allow">להתיר</string> + <string name="open">פתח</string> + <string name="no_data">×œ× × ×ž×¦× ×ž×™×“×¢</string> + <string name="ellipsis">...</string> + <string name="text_too_long">הטקסט ×©×”×–× ×ª× ×רוך מדי</string> + <string name="show_onboarding">הצג עזרה</string> + <string name="help">עזרה</string> + <!--Contacts and Private Conversations--> + <string name="date_no_private_messages">×ין הודעות.</string> + <string name="message_hint">כתבו הודעה</string> + <string name="delete_contact">מחיקת ×יש קשר</string> + <string name="dialog_title_delete_contact">×ישור מחיקת ×יש קשר</string> + <string name="dialog_message_delete_contact">×”×× ××ª× ×‘×˜×•×—×™× ×©××ª× ×¨×•×¦×™× ×œ×ž×—×•×§ ×ת ×יש הקשר וכל ההתכתבות ×יתו?</string> + <string name="contact_deleted_toast">×יש הקשר × ×ž×—×§</string> + <!--Adding Contacts--> + <string name="add_contact_title">הוספת ×יש קשר</string> + <string name="face_to_face">××ª× ×—×™×™×‘×™× ×œ×”×¤×’×© ×¢× ×”××“× ×©×ותו תרצו להוסיף ×›×יש קשר. + +×–×ת על ×ž× ×ª ×œ×ž× ×•×¢ מצב שבו ×ž×ª×—×–×™× ××œ×™×›× ×ו קור××™× ×”×•×“×¢×•×ª ×©×œ×›× ×‘×¢×ª×™×“.</string> + <string name="continue_button">המשך</string> + <string name="connection_failed">חיבור × ×›×©×œ</string> + <string name="try_again_button">× ×¡×• שוב</string> + <string name="waiting_for_contact_to_scan">ממתין ש×יש הקשר יסרוק ויתחבר\u2026</string> + <string name="exchanging_contact_details">מחליף ×¤×¨×˜×™× ×©×œ ×יש קשר\u2026</string> + <string name="contact_added_toast">×יש קשר × ×•×¡×£: %s</string> + <string name="contact_already_exists">×יש קשר %s ×§×™×™× ×›×‘×¨</string> + <string name="contact_exchange_failed">החלפת ×× ×©×™ קשר × ×›×©×œ×”</string> + <string name="qr_code_invalid">קוד ×”- QR ××™× ×• תקף</string> + <string name="connecting_to_device">מתחבר למכשיר\u2026</string> + <string name="authenticating_with_device">מזדהה מול המכשיר\u2026</string> + <string name="connection_aborted_remote">החיבור בוטל על ידי ×יש הקשר! ×–×” עלול לומר שמישהו ×ž× ×¡×” להפריע לחיבור שלכ×</string> + <!--Introductions--> + <string name="introduction_onboarding_title">הציגו ×ת ×× ×©×™ קשר שלכ×</string> + <string name="introduction_onboarding_text">××ª× ×™×›×•×œ×™× ×œ×”×¦×™×’ ×ת ×× ×©×™ הקשר ×©×œ×›× ×חד ×œ×©× ×™, כך ×©×”× ×œ× ×¦×¨×™×›×™× ×œ×”×¤×’×© ×¤× ×™×-מול-×¤× ×™× ×¢×œ ×ž× ×ª להתחבר בברי×ר.</string> + <string name="introduction_menu_item">הציגו ×יש קשר</string> + <string name="introduction_activity_title">בחרו ×יש קשר</string> + <string name="introduction_message_title">הציגו ×× ×©×™ קשר</string> + <string name="introduction_message_hint">הוסיפו הודעה (×œ× ×—×•×‘×”)</string> + <string name="introduction_button">הציגו ×יש קשר</string> + <string name="introduction_sent">הצגת ×יש קשר × ×©×œ×—×”.</string> + <string name="introduction_error">הייתה שגי××” בעת הצגת ×יש קשר.</string> + <string name="introduction_response_error">שגי××” בעת התגובה להצגת ×יש קשר</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_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_response_accepted_sent">×”×¡×›×ž×ª× ×œ×”×™×•×ª ×ž×•×¦×’×™× ×‘×¤× ×™ %1$s.</string> + <string name="introduction_response_declined_sent">×¡×™×¨×‘×ª× ×œ×”×™×•×ª ×ž×•×¦×’×™× ×‘×¤× ×™ %1$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_by_introducee">%1$s ××•×ž×¨×™× ×©- %2$s סירבו להיות ×ž×•×¦×’×™× ×‘×¤× ×™×”×.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">× ×•×¡×£ ×יש קשר חדש.</item> + <item quantity="two">× ×•×¡×¤×• %d ×× ×©×™ קשר חדשי×.</item> + <item quantity="many">× ×•×¡×¤×• %d ×× ×©×™ קשר חדשי×.</item> + <item quantity="other">× ×•×¡×¤×• %d ×× ×©×™ קשר חדשי×.</item> + </plurals> + <!--Private Groups--> + <string name="groups_created_by">× ×•×¦×¨ על ידי %s</string> + <plurals name="messages"> + <item quantity="one">הודעה %d</item> + <item quantity="two">%d הודעות</item> + <item quantity="many">%d הודעות</item> + <item quantity="other">%d הודעות</item> + </plurals> + <string name="groups_group_is_empty">קבוצה זו ×”×™× ×” ריקה</string> + <string name="groups_group_is_dissolved">קבוצה זו התפזרה</string> + <string name="groups_remove">להסיר</string> + <string name="groups_create_group_title">יצירת קבוצה פרטית</string> + <string name="groups_create_group_button">יצירת קבוצה</string> + <string name="groups_create_group_invitation_button">שליחת ×”×–×ž× ×”</string> + <string name="groups_create_group_hint">בחרו ×©× ×œ×§×‘×•×¦×” הפרטית שלכ×</string> + <string name="groups_invitation_sent">×”×–×ž× ×” קבוצתית × ×©×œ×—×”</string> + <string name="groups_message_sent">ההודעה × ×©×œ×—×”</string> + <string name="groups_member_list">רשימת משתתפי×</string> + <string name="groups_invite_members">×”×–×ž× ×ª משתתפי×</string> + <string name="groups_member_created_you">×™×¦×¨×ª× ×ת הקבוצה</string> + <string name="groups_member_created">%s יצר ×ת הקבוצה</string> + <string name="groups_member_joined_you">×”×¦×˜×¨×¤×ª× ×œ×§×‘×•×¦×”</string> + <string name="groups_member_joined">%s הצטרפו לקבוצה</string> + <string name="groups_leave">עזיבת הקבוצה</string> + <string name="groups_leave_dialog_title">×שרו ×ת עזיבת הקבוצה</string> + <string name="groups_leave_dialog_message">×”×× ××ª× ×‘×˜×•×—×™× ×©×ª×¨×¦×• לעזוב ×ת הקבוצה?</string> + <string name="groups_dissolve">פיזור הקבוצה</string> + <string name="groups_dissolve_dialog_title">×שרו פיזור הקבוצה</string> + <string name="groups_dissolve_dialog_message">×”×× ××ª× ×‘×˜×•×—×™× ×©×ª×¨×¦×• לפזר ×ת הקבוצה? + +כל ×”×ž×©×ª×ª×¤×™× ×œ× ×™×•×›×œ×• להמשיך ×ת השיחה ×•×¢×œ×•×œ×™× ×œ× ×œ×§×‘×œ ×ת ההודעות ×”××—×¨×•× ×•×ª.</string> + <string name="groups_dissolve_button">פיזור</string> + <string name="groups_dissolved_dialog_title">הקבוצה פוזרה</string> + <string name="groups_dissolved_dialog_message">יוצר הקבוצה פיזר ×ותה. + +×œ× ×ª×•×›×œ×• יותר לכתוב הודעות לקבוצה ו×ולי ××£ ×œ× ×ª×§×‘×œ×• ×ת כל ההודעות ×©× ×›×ª×‘×•.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">×”×–×ž× ×•×ª קבוצתיות</string> + <string name="groups_invitations_invitation_sent">×”×–×ž× ×ª× ×ת %1$s להצטרף לקבוצה \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s ×”×–×ž×™× ×• ××ª×›× ×œ×”×¦×˜×¨×£ לקבוצה \"%2$s\".</string> + <string name="groups_invitations_joined">×”×¦×˜×¨×¤×ª× ×œ×§×‘×•×¦×”</string> + <string name="groups_invitations_declined">×”×–×ž× ×” קבוצתית × ×“×—×ª×”</string> + <plurals name="groups_invitations_open"> + <item quantity="one">×”×–×ž× ×” קבוצתית פתוחה %d</item> + <item quantity="two">%d×”×–×ž× ×•×ª קבוצתית פתוחות </item> + <item quantity="many">%d×”×–×ž× ×•×ª קבוצתית פתוחות </item> + <item quantity="other">%d×”×–×ž× ×•×ª קבוצתית פתוחות </item> + </plurals> + <string name="groups_invitations_response_accepted_sent">×”×¡×›×ž×ª× ×œ×”×–×ž× ×” הקבוצתית מ- %s.</string> + <string name="groups_invitations_response_declined_sent">×¡×™×¨×‘×ª× ×œ×”×–×ž× ×” הקבוצתית מ- %s.</string> + <string name="groups_invitations_response_accepted_received">%s הסכימו ×œ×”×–×ž× ×” הקבוצתית.</string> + <string name="groups_invitations_response_declined_received">%s סרבו ×œ×”×–×ž× ×” הקבוצתית.</string> + <string name="sharing_status_groups">רק היוצר יכול להזמין ×ž×©×ª×ª×¤×™× ×—×“×©×™× ×œ×§×‘×•×¦×”. להלן כל ×”×ž×©×ª×ª×¤×™× ×”× ×•×›×—×™×™× ×©×œ הקבוצה.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">הצגת ×× ×©×™ קשר</string> + <string name="groups_reveal_dialog_message">××ª× ×™×›×•×œ×™× ×œ×‘×—×•×¨ ×× ×œ×—×©×•×£ ×ת ×× ×©×™ הקשר ×©×œ×›× ×œ×ž×©×ª×ª×¤×™× ×”× ×•×›×—×™×™× ×•×”×¢×ª×™×“×™×™× ×©×œ קבוצה זו. + +חשיפת ×× ×©×™ הקשר ×ª×’×¨×•× ×œ×—×™×‘×•×¨ ×¢× ×”×§×‘×•×¦×” להיות מהיר ו×מין יותר, ×›×™ תוכלו לתקשר ×¢× ×× ×©×™ הקשר ×©× ×—×©×¤×• ×’× ×× ×™×•×¦×¨ הקבוצה ××™× ×• מחובר.</string> + <string name="groups_reveal_visible">×”×™×—×¡×™× ×¢× ×”×יש קשר ×’×œ×•×™×™× ×œ×§×‘×•×¦×”</string> + <string name="groups_reveal_visible_revealed_by_us">×”×™×—×¡×™× ×¢× ×”×יש קשר ×’×œ×•×™×™× ×œ×§×‘×•×¦×” (× ×—×©×¤×• על ידיכ×)</string> + <string name="groups_reveal_visible_revealed_by_contact">×”×™×—×¡×™× ×¢× ×”×יש קשר ×’×œ×•×™×™× ×œ×§×‘×•×¦×” (× ×—×©×¤×• על %s)</string> + <string name="groups_reveal_invisible">×”×™×—×¡×™× ×¢× ×”×יש קשר ××™× × ×’×œ×•×™×™× ×œ×§×‘×•×¦×”</string> + <!--Forums--> + <string name="create_forum_title">יצירת פורו×</string> + <string name="choose_forum_hint">בחרו ×©× ×œ×¤×•×¨×•× ×©×œ×›×</string> + <string name="create_forum_button">יצירת פורו×</string> + <string name="forum_created_toast">×”×¤×•×¨×•× × ×•×¦×¨</string> + <string name="no_posts">×ין פוסטי×</string> + <plurals name="posts"> + <item quantity="one">פוסט %d</item> + <item quantity="two">%d פוסטי×</item> + <item quantity="many">%d פוסטי×</item> + <item quantity="other">%d פוסטי×</item> + </plurals> + <string name="forum_message_reply_hint">תגובה חדשה</string> + <string name="btn_reply">להשיב</string> + <string name="forum_leave">עזיבת הפורו×</string> + <string name="dialog_title_leave_forum">×שרו ×ת עזיבת הפורו×</string> + <string name="dialog_button_leave">לעזוב</string> + <!--Forum Sharing--> + <string name="forum_share_button">שיתוף הפורו×</string> + <string name="contacts_selected">×× ×©×™ קשר × ×‘×—×¨×•</string> + <string name="activity_share_toolbar_header">בחרו ×× ×©×™ קשר</string> + <string name="forum_shared_snackbar">×©×™×ª×¤×ª× ×ת ×”×¤×•×¨×•× ×¢× ×× ×©×™ הקשר ×©× ×‘×—×¨×•</string> + <string name="forum_share_message">הוסיפו הודעה (×œ× ×—×•×‘×”)</string> + <string name="forum_share_error">הייתה שגי××” בעת שיתוף הפורו×.</string> + <string name="forum_invitation_received">%1$s שיתפו ×ת ×”×¤×•×¨×•× \"%2$s\" ×יתכ×.</string> + <string name="forum_invitation_sent">×©×™×ª×¤×ª× ×ת ×”×¤×•×¨×•× \"%1$s\" ×¢× %2$s.</string> + <string name="forum_invitations_title">×”×–×ž× ×•×ª לפורו×</string> + <string name="shared_by_format">שותף על ידי %s</string> + <!--Blogs--> + <string name="blogs_remove_blog_ok">להסיר</string> + <!--Blog Sharing--> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import_button">ייב×</string> + <string name="blogs_rss_feeds_manage_author">מחבר:</string> + <string name="blogs_rss_feeds_manage_updated">עודכן ל××—×¨×•× ×”:</string> + <string name="blogs_rss_remove_feed_ok">להסיר</string> + <!--Settings Display--> + <string name="display_settings_title">מציג</string> + <!--Settings Network--> + <!--Settings Security and Panic--> + <string name="security_settings_title">×בטחה</string> + <string name="choose_new_password">×¡×™×¡×ž× ×—×“×©×”</string> + <string name="panic_app_setting_none">כלו×</string> + <string name="panic_setting_signout_title">יצי××”</string> + <string name="purge_setting_title">מחק חשבון</string> + <!--Settings Notifications--> + <string name="notification_settings_title">הודעות מערכת</string> + <string name="notify_private_messages_setting_title">הודעות פרטיות</string> + <string name="notify_lock_screen_setting_title">× ×¢×œ מסך</string> + <string name="notify_sound_setting_disabled">כלו×</string> + <!--Settings Feedback--> + <!--Link Warning--> + <!--Crash Reporter--> + <string name="close">סגור</string> + <!--Sign Out--> + <!--Screen Filters & Tapjacking--> + <!--Permission Requests--> +</resources> diff --git a/mailbox-android/src/main/res/values-hi/strings.xml b/mailbox-android/src/main/res/values-hi/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..26ad565487feef375dcf89148595955cba227d83 --- /dev/null +++ b/mailbox-android/src/main/res/values-hi/strings.xml @@ -0,0 +1,395 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Briar में आपका सà¥à¤µà¤¾à¤—त है</string> + <string name="setup_name_explanation">आपके उपनाम आप पोसà¥à¤Ÿ किसी à¤à¥€ सामगà¥à¤°à¥€ के बगल में दिखाया जाà¤à¤—ा। आप अपना खाता बनाने के बाद इसे बदल नहीं सकते</string> + <string name="setup_next">अगला</string> + <string name="setup_password_intro">अपना पासवरà¥à¤¡ चà¥à¤¨à¥‡à¤‚</string> + <string name="setup_password_explanation">आपका बà¥à¤°à¤¿à¤¯à¤° खाता आपके डिवाइस पर à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ किया गया है, न कि कà¥à¤²à¤¾à¤‰à¤¡ में। यदि आप अपना पासवरà¥à¤¡ à¤à¥‚ल जाते हैं या बियर को अनइंसà¥à¤Ÿà¥‰à¤² करते हैं, तो आपका खाता पà¥à¤¨à¤°à¥à¤ªà¥à¤°à¤¾à¤ªà¥à¤¤ करने का कोई तरीका नहीं है। \ N \ n à¤à¤• लंबे पासवरà¥à¤¡ चà¥à¤¨à¥‡à¤‚ जो अनà¥à¤®à¤¾à¤¨ लगाने में मà¥à¤¶à¥à¤•िल हो, जैसे चार यादृचà¥à¤›à¤¿à¤• शबà¥à¤¦, या दस यादृचà¥à¤›à¤¿à¤• वरà¥à¤£, संखà¥à¤¯à¤¾à¤à¤‚ और पà¥à¤°à¤¤à¥€à¤•ों।</string> + <string name="setup_doze_title">पृषà¥à¤ à¤à¥‚मि कनेकà¥à¤¶à¤¨</string> + <string name="setup_doze_intro">संदेश पà¥à¤°à¤¾à¤ªà¥à¤¤ करने के लिà¤, बैर को पृषà¥à¤ à¤à¥‚मि में जà¥à¤¡à¤¼à¥‡ रहने की आवशà¥à¤¯à¤•ता है।</string> + <string name="setup_doze_explanation">संदेश पà¥à¤°à¤¾à¤ªà¥à¤¤ करने के लिà¤, बैर को पृषà¥à¤ à¤à¥‚मि में जà¥à¤¡à¤¼à¥‡ रहने की आवशà¥à¤¯à¤•ता है। कृपया बैटरी ऑपà¥à¤Ÿà¤¿à¤®à¤¾à¤‡à¤œà¥‡à¤¶à¤¨ अकà¥à¤·à¤® करें ताकि बà¥à¤°à¤¿à¤¯à¤° कनेकà¥à¤Ÿ रह सकें।</string> + <string name="setup_doze_button">कनेकà¥à¤¶à¤¨ की अनà¥à¤®à¤¤à¤¿ दें</string> + <string name="choose_nickname">आपका मà¥à¤‚हबोला नाम चà¥à¤¨à¥‡à¤‚</string> + <string name="choose_password">अपना पासवरà¥à¤¡ चà¥à¤¨à¥‡à¤‚</string> + <string name="confirm_password">अपने पासवरà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ करें</string> + <string name="name_too_long">नाम बहà¥à¤¤ लंबा है</string> + <string name="password_too_weak">पासवरà¥à¤¡ बहà¥à¤¤ कमजोर है</string> + <string name="passwords_do_not_match">पासवरà¥à¤¡ मेल नहीं खाते</string> + <string name="create_account_button">खाता बनाà¤à¤‚</string> + <string name="more_info">अधिक जानकारी</string> + <string name="don_t_ask_again">फिर से मत पूछो</string> + <string name="setup_huawei_text">कृपया नीचे दिठगठबटन को टैप करें और सà¥à¤¨à¤¿à¤¶à¥à¤šà¤¿à¤¤ करें कि \"संरकà¥à¤·à¤¿à¤¤ à¤à¤ªà¥à¤¸\" सà¥à¤•à¥à¤°à¥€à¤¨ पर बियर सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ है</string> + <string name="setup_huawei_button">Briar की रकà¥à¤·à¤¾ करें</string> + <string name="setup_huawei_help">अगर Briar संरकà¥à¤·à¤¿à¤¤ à¤à¤ªà¥à¤¸ सूची में नहीं जोड़ा गया है, तो यह पृषà¥à¤ à¤à¥‚मि में चलने में असमरà¥à¤¥ होगा।</string> + <string name="warning_dozed">%sपृषà¥à¤ à¤à¥‚मि में चलाने में असमरà¥à¤¥ था</string> + <!--Login--> + <string name="enter_password">पासवरà¥à¤¡</string> + <string name="try_again">गलत पासवरà¥à¤¡, फिर से पà¥à¤°à¤¯à¤¾à¤¸ करें</string> + <string name="sign_in_button">साइन इन करें</string> + <string name="forgotten_password">मà¥à¤à¥‡ अपना पासवरà¥à¤¡ याद नहीं है</string> + <string name="dialog_title_lost_password">पासवरà¥à¤¡ खो गया</string> + <string name="dialog_message_lost_password">आपका बà¥à¤°à¤¿à¤¯à¤° खाता आपके डिवाइस पर à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ किया गया है, बादल में नहीं, इसलिठहम आपका पासवरà¥à¤¡ रीसेट नहीं कर सकते। कà¥à¤¯à¤¾ आप अपना खाता हटाना चाहते हैं और फिर से शà¥à¤°à¥‚ करना चाहते हैं? \ N \ n सावधानी: आपकी पहचान, संपरà¥à¤• और संदेश सà¥à¤¥à¤¾à¤¯à¥€ रूप से खो जाà¤à¤‚गे</string> + <string name="startup_failed_notification_title">बियर शà¥à¤°à¥‚ नहीं हो सका</string> + <string name="startup_failed_notification_text">अधिक जानकारी के लिठटैप करें।</string> + <string name="startup_failed_activity_title">बà¥à¤°à¤¿à¤¯à¤° सà¥à¤Ÿà¤¾à¤°à¥à¤Ÿà¤…प विफलता</string> + <string name="startup_failed_db_error">किसी कारण से, आपका बà¥à¤°à¤¿à¤¯à¤° डेटाबेस मरमà¥à¤®à¤¤ से परे दूषित हो गया है। आपका खाता, आपका डेटा और आपके सà¤à¥€ संपरà¥à¤• खो गठहैं। दà¥à¤°à¥à¤à¤¾à¤—à¥à¤¯à¤µà¤¶, आपको पासवरà¥à¤¡ पà¥à¤°à¥‰à¤®à¥à¤ªà¥à¤Ÿ पर \'मेरा पासवरà¥à¤¡ à¤à¥‚ल गया है\' चà¥à¤¨à¤•र बà¥à¤°à¤¿à¤¯à¤° को पà¥à¤¨à¤°à¥à¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करने या à¤à¤• नया खाता सेट अप करने की आवशà¥à¤¯à¤•ता है।</string> + <string name="startup_failed_data_too_old_error">आपका खाता इस à¤à¤ª के पà¥à¤°à¤¾à¤¨à¥‡ संसà¥à¤•रण के साथ बनाया गया था और इस संसà¥à¤•रण के साथ खोला नहीं जा सकता है। आपको या तो पà¥à¤°à¤¾à¤¨à¥‡ संसà¥à¤•रण को पà¥à¤¨à¤°à¥à¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करना होगा या पासवरà¥à¤¡ पà¥à¤°à¥‰à¤®à¥à¤ªà¥à¤Ÿ पर \'मैं अपना पासवरà¥à¤¡ à¤à¥‚ल गया हूं\' चà¥à¤¨à¤•र à¤à¤• नया खाता सेट करना होगा।</string> + <string name="startup_failed_data_too_new_error">à¤à¤ª का यह संसà¥à¤•रण बहà¥à¤¤ पà¥à¤°à¤¾à¤¨à¤¾ है। कृपया नवीनतम संसà¥à¤•रण में अपगà¥à¤°à¥‡à¤¡ करें और पà¥à¤¨à¤ƒ पà¥à¤°à¤¯à¤¾à¤¸ करें।</string> + <string name="startup_failed_service_error">बà¥à¤°à¤¿à¤¯à¤° à¤à¤• आवशà¥à¤¯à¤• पà¥à¤²à¤—इन पà¥à¤°à¤¾à¤°à¤‚ठकरने में असमरà¥à¤¥ था बरिअर को पà¥à¤¨à¤ƒ सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करना आमतौर पर इस समसà¥à¤¯à¤¾ को हल करता है हालांकि, कृपया धà¥à¤¯à¤¾à¤¨ दें कि बियर आपके डेटा को सà¥à¤Ÿà¥‹à¤° करने के लिठकेंदà¥à¤°à¥€à¤¯ सरà¥à¤µà¤° का उपयोग नहीं कर रहा है, इसके बाद आप अपने खाता और उसके साथ जà¥à¤¡à¤¼à¥‡ सà¤à¥€ डेटा खो देंगे।</string> + <plurals name="expiry_warning"> + <item quantity="one">यह Briar का à¤à¤• परीकà¥à¤·à¤£ संसà¥à¤•रण है आपका खाता %dदिनों में समापà¥à¤¤ हो जाà¤à¤—ा और नवीनीकरण नहीं किया जा सकता है</item> + <item quantity="other">यह Briar का à¤à¤• परीकà¥à¤·à¤£ संसà¥à¤•रण है आपका खाता %dदिनों में समापà¥à¤¤ हो जाà¤à¤—ा और नवीनीकरण नहीं किया जा सकता है</item> + </plurals> + <string name="expiry_update">परीकà¥à¤·à¤£ समापà¥à¤¤à¤¿ तिथि बढ़ा दी गई है। आपका खाता अब %d दिनों में समापà¥à¤¤ हो जाà¤à¤—ा</string> + <string name="expiry_date_reached">यह सॉफà¥à¤Ÿà¤µà¥‡à¤¯à¤° समापà¥à¤¤ हो गया है। \n परीकà¥à¤·à¤£ के लिठधनà¥à¤¯à¤µà¤¾à¤¦!</string> + <string name="download_briar">बà¥à¤°à¤¿à¤¯à¤° का उपयोग जारी रखने के लिà¤, कृपया संसà¥à¤•रण 1.0 डाउनलोड करें।</string> + <string name="create_new_account">आपको à¤à¤• नया खाता बनाना होगा, लेकिन आप उसी उपनाम का उपयोग कर सकते हैं।</string> + <string name="download_briar_button">बà¥à¤°à¤¾à¤¯à¤° 1.0 डाउनलोड करें</string> + <string name="startup_open_database">डेटाबेस डिकà¥à¤°à¤¿à¤ªà¥à¤Ÿ कर रहा है ...</string> + <string name="startup_migrate_database">डाटाबेस का उनà¥à¤¨à¤¯à¤¨ ...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">नेविगेशन डà¥à¤°à¥‰à¤µà¤° खोलें</string> + <string name="nav_drawer_close_description">नेविगेशन डà¥à¤°à¥‰à¤µà¤° को बंद करें</string> + <string name="contact_list_button">संपरà¥à¤•</string> + <string name="groups_button">निजी समूह</string> + <string name="forums_button">मंच</string> + <string name="blogs_button">बà¥à¤²à¥‰à¤—</string> + <string name="settings_button">सेटिंगà¥à¤¸</string> + <string name="sign_out_button">साइन आउट</string> + <!--Transports--> + <string name="transport_tor">इंटरनेट</string> + <string name="transport_bt">बà¥à¤²à¥‚टूथ</string> + <string name="transport_lan">वाई - फाई</string> + <!--Notifications--> + <string name="reminder_notification_dismiss">खारिज करना</string> + <string name="ongoing_notification_title">बà¥à¤°à¤¾à¤¯à¤° में हसà¥à¤¤à¤¾à¤•à¥à¤·à¤° किà¤</string> + <string name="ongoing_notification_text">बà¥à¤°à¤¿à¤¯à¤° को खोलने के लिठसà¥à¤ªà¤°à¥à¤¶ करें</string> + <plurals name="private_message_notification_text"> + <item quantity="one">नया निजी संदेश</item> + <item quantity="other">%dनया निजी संदेश</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">नया समूह संदेश</item> + <item quantity="other">%dनया समूह संदेश</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">नया मंच पोसà¥à¤Ÿ</item> + <item quantity="other">%dनया मंच पोसà¥à¤Ÿ</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">नठबà¥à¤²à¥‰à¤— पोसà¥à¤Ÿ</item> + <item quantity="other">%dनठबà¥à¤²à¥‰à¤— पोसà¥à¤Ÿ</item> + </plurals> + <!--Misc--> + <string name="now">अà¤à¥€ व</string> + <string name="show">दिखाना</string> + <string name="hide">छिपाना</string> + <string name="ok">ठीक</string> + <string name="cancel">रदà¥à¤¦ करना</string> + <string name="got_it">समठगया</string> + <string name="delete">हटाना</string> + <string name="accept">सà¥à¤µà¥€à¤•ारें</string> + <string name="decline">पतन</string> + <string name="options">विकलà¥à¤ª</string> + <string name="online">ऑनलाइन</string> + <string name="offline">ऑफलाइन</string> + <string name="send">à¤à¥‡à¤œà¤¨à¤¾</string> + <string name="allow">अनà¥à¤®à¤¤à¤¿ दें</string> + <string name="open">खोलें </string> + <string name="no_data">नो डाटा </string> + <string name="ellipsis">…</string> + <string name="text_too_long">पà¥à¤°à¤µà¥‡à¤¶ किया हà¥à¤† पाठबहà¥à¤¤ लंबा है</string> + <string name="show_onboarding">सहायता संवाद दिखाà¤à¤‚</string> + <string name="fix">ठीक कर</string> + <string name="help">सहायता</string> + <string name="sorry">माफ़ कीजिये</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">कोई संपरà¥à¤• दिखाने के लिठ\ n \ n टैप + आइकन टैप करने के लिठकोई संपरà¥à¤• नहीं है</string> + <string name="date_no_private_messages">कोई संदेश नहीं।</string> + <string name="no_private_messages">दिखाने के लिठकोई संदेश नहीं</string> + <string name="message_hint">संदेश लिखें</string> + <string name="delete_contact">संपरà¥à¤• मिटा दें</string> + <string name="dialog_title_delete_contact">संपरà¥à¤• हटाने की पà¥à¤·à¥à¤Ÿà¤¿ करें</string> + <string name="dialog_message_delete_contact">कà¥à¤¯à¤¾ आप निशà¥à¤šà¤¿à¤¤ हैं कि आप इस संपरà¥à¤• और सà¤à¥€ संदेशों को इस संपरà¥à¤• से निकाला जाना चाहते हैं?</string> + <string name="contact_deleted_toast">संपरà¥à¤• हटा दिया गया</string> + <!--Adding Contacts--> + <string name="add_contact_title">संपरà¥à¤• जोड़ना</string> + <string name="face_to_face">आपको उस वà¥à¤¯à¤•à¥à¤¤à¤¿ के साथ मिलना चाहिठजिसे आप संपरà¥à¤• के रूप में जोड़ना चाहते हैं। \ N \ n यह किसी को à¤à¤µà¤¿à¤·à¥à¤¯ में आपके पà¥à¤°à¤¤à¤¿à¤°à¥‚पण या पढ़ने के बाद से किसी को à¤à¥€ रोकेगा।</string> + <string name="continue_button">जारी रहना</string> + <string name="connection_failed">कनेकà¥à¤¶à¤¨ विफल</string> + <string name="try_again_button">पà¥à¤¨à¤ƒ पà¥à¤°à¤¯à¤¾à¤¸ करें</string> + <string name="waiting_for_contact_to_scan">सà¥à¤•ैन करने और कनेकà¥à¤Ÿ करने के लिठसंपरà¥à¤• की पà¥à¤°à¤¤à¥€à¤•à¥à¤·à¤¾ कर रहा है \ u2026</string> + <string name="exchanging_contact_details">संपरà¥à¤• विवरणों का आदान-पà¥à¤°à¤¦à¤¾à¤¨ करें \ u2026</string> + <string name="contact_added_toast">संपरà¥à¤• जोड़ा गया:%s</string> + <string name="contact_already_exists">संपरà¥à¤•%s पहले से मौजूद है</string> + <string name="contact_exchange_failed">संपरà¥à¤• विनिमय विफल</string> + <string name="qr_code_invalid">QR कोड अमानà¥à¤¯ है</string> + <string name="qr_code_unsupported">कà¥à¤¯à¥‚आर कोड जिसे आप सà¥à¤•ैन करने का पà¥à¤°à¤¯à¤¾à¤¸ कर रहे हैं वह पà¥à¤°à¤¾à¤¨à¥‡ संसà¥à¤•रण से संबंधित है %sजिसका अब समरà¥à¤¥à¤¿à¤¤ नहीं है। \ N \ n कृपया सà¥à¤¨à¤¿à¤¶à¥à¤šà¤¿à¤¤ करें कि आप दोनों नवीनतम संसà¥à¤•रण चला रहे हैं और फिर पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें।</string> + <string name="camera_error">कैमरा तà¥à¤°à¥à¤Ÿà¤¿</string> + <string name="connecting_to_device">उपकरण \ u2026 से कनेकà¥à¤Ÿ हो रहा है</string> + <string name="authenticating_with_device">डिवाइस के साथ पà¥à¤°à¤®à¤¾à¤£à¥€à¤•रण \ u2026</string> + <string name="connection_aborted_local">कनेकà¥à¤¶à¤¨ निरसà¥à¤¤ कर दिया गया! इसका मतलब यह हो सकता है कि कोई आपके कनेकà¥à¤¶à¤¨ में हसà¥à¤¤à¤•à¥à¤·à¥‡à¤ª करने का पà¥à¤°à¤¯à¤¾à¤¸ कर रहा है</string> + <string name="connection_aborted_remote">आपके संपरà¥à¤• से कनेकà¥à¤¶à¤¨ निरसà¥à¤¤! इसका मतलब यह हो सकता है कि कोई आपके कनेकà¥à¤¶à¤¨ में हसà¥à¤¤à¤•à¥à¤·à¥‡à¤ª करने का पà¥à¤°à¤¯à¤¾à¤¸ कर रहा है</string> + <!--Introductions--> + <string name="introduction_onboarding_title">अपने संपरà¥à¤•ों का परिचय दें</string> + <string name="introduction_onboarding_text">आप अपने संपरà¥à¤•ों को à¤à¤• दूसरे से जोड़ सकते हैं, इसलिठउनà¥à¤¹à¥‡à¤‚ बà¥à¤°à¤¿à¤¯à¤° से जà¥à¤¡à¤¼à¤¨à¥‡ के लिठवà¥à¤¯à¤•à¥à¤¤à¤¿à¤—त रूप से मिलने की जरूरत नहीं है।</string> + <string name="introduction_menu_item">परिचय करें</string> + <string name="introduction_activity_title">संपरà¥à¤• का चयन करें</string> + <string name="introduction_not_possible">इन संपरà¥à¤•ों के साथ आपके पास पहले से ही à¤à¤• परिचय पà¥à¤°à¤—ति है। कृपया इसे पहले खतà¥à¤® करने की अनà¥à¤®à¤¤à¤¿ दें। यदि आप या आपके संपरà¥à¤• शायद ही कà¤à¥€ ऑनलाइन हैं, तो इसमें कà¥à¤› समय लग सकता है।</string> + <string name="introduction_message_title">संपरà¥à¤•ों का परिचय</string> + <string name="introduction_message_hint">à¤à¤• संदेश जोड़ें (वैकलà¥à¤ªà¤¿à¤•)</string> + <string name="introduction_button">परिचय करें</string> + <string name="introduction_sent">आपका परिचय à¤à¥‡à¤œà¤¾ गया है।</string> + <string name="introduction_error">परिचय बनाने में à¤à¤• तà¥à¤°à¥à¤Ÿà¤¿ हà¥à¤ˆà¥¤</string> + <string name="introduction_response_error">परिचय का जवाब देने में तà¥à¤°à¥à¤Ÿà¤¿</string> + <string name="introduction_request_sent">आपने%2$s से%1$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_answered_received">%1$sने आपको%2$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_declined_sent">आपने%1$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_by_introducee">%1$sकहते हैं कि%2$sने परिचय को असà¥à¤µà¥€à¤•ार कर दिया</string> + <plurals name="introduction_notification_text"> + <item quantity="one">नया संपरà¥à¤• जोड़ा।</item> + <item quantity="other">%dनया संपरà¥à¤• जोड़ा।</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">कोई समूह दिखाने के लिठ\ n \ n समूह बनाने के लिठ+ आइकन टैप करें, या अपने संपरà¥à¤•ों को समूहों के साथ साà¤à¤¾ करने के लिठकहें</string> + <string name="groups_created_by">के दà¥à¤µà¤¾à¤°à¤¾ बनाई गई%s</string> + <plurals name="messages"> + <item quantity="one">संदेशों%d</item> + <item quantity="other">संदेशों %d</item> + </plurals> + <string name="groups_group_is_empty">यह समूह खाली है</string> + <string name="groups_group_is_dissolved">यह समूह à¤à¤‚ग कर दिया गया है</string> + <string name="groups_remove">हटाना</string> + <string name="groups_create_group_title">निजी समूह बनाà¤à¤‚</string> + <string name="groups_create_group_button">समूह बनाà¤à¤</string> + <string name="groups_create_group_invitation_button">निमंतà¥à¤°à¤£ à¤à¥‡à¤œà¤¨à¤¾</string> + <string name="groups_create_group_hint">अपने निजी समूह के लिठà¤à¤• नाम चà¥à¤¨à¥‡à¤‚</string> + <string name="groups_invitation_sent">समूह आमंतà¥à¤°à¤£ à¤à¥‡à¤œà¤¾ गया है</string> + <string name="groups_message_sent">मैसेज बेजा गया</string> + <string name="groups_member_list">सदसà¥à¤¯ सूची</string> + <string name="groups_invite_members">सदसà¥à¤¯à¥‹à¤‚ को आमंतà¥à¤°à¤¿à¤¤ करो</string> + <string name="groups_member_created_you">आपने समूह बनाया है</string> + <string name="groups_member_created">%sसमूह बनाया</string> + <string name="groups_member_joined_you">आप समूह में शामिल हो गà¤</string> + <string name="groups_member_joined">%sसमूह में शामिल हो गà¤</string> + <string name="groups_leave">समूह छोड़ दें</string> + <string name="groups_leave_dialog_title">समूह छोड़ने की पà¥à¤·à¥à¤Ÿà¤¿ करें</string> + <string name="groups_leave_dialog_message">कà¥à¤¯à¤¾ आप वाकई इस समूह को छोड़ना चाहते हैं?</string> + <string name="groups_dissolve">समूह à¤à¤‚ग करें</string> + <string name="groups_dissolve_dialog_title">डिसोलà¥à¤µà¤¿à¤‚ग गà¥à¤°à¥à¤ª की पà¥à¤·à¥à¤Ÿà¤¿ करें</string> + <string name="groups_dissolve_dialog_message">कà¥à¤¯à¤¾ आप निशà¥à¤šà¤¿à¤¤ हैं कि आप इस समूह को à¤à¤‚ग करना चाहते हैं? \ N \ n अनà¥à¤¯ सà¤à¥€ सदसà¥à¤¯ अपनी बातचीत जारी नहीं रख पाà¤à¤‚गे और शायद नवीनतम संदेश पà¥à¤°à¤¾à¤ªà¥à¤¤ न हो जाà¤à¤‚गे।</string> + <string name="groups_dissolve_button">à¤à¤‚ग</string> + <string name="groups_dissolved_dialog_title">समूह à¤à¤‚ग कर दिया गया है</string> + <string name="groups_dissolved_dialog_message">इस समूह के निरà¥à¤®à¤¾à¤¤à¤¾ ने उसे à¤à¤‚ग कर दिया है। \ N \ n आप अब समूह को संदेश नहीं लिख सकते हैं और जो सà¤à¥€ पोसà¥à¤Ÿ लिखी गई हैं उनà¥à¤¹à¥‡à¤‚ पà¥à¤°à¤¾à¤ªà¥à¤¤ नहीं हो सकता है।</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">समूह आमंतà¥à¤°à¤£</string> + <string name="groups_invitations_invitation_sent">आपने समूह \"%2$s\" में शामिल होने के लिठ%1$sको आमंतà¥à¤°à¤¿à¤¤ किया है</string> + <string name="groups_invitations_invitation_received">%1$sने आपको \"%2$s\" समूह में शामिल होने के लिठआमंतà¥à¤°à¤¿à¤¤ किया है</string> + <string name="groups_invitations_joined">समूह में शामिल</string> + <string name="groups_invitations_declined">समूह आमंतà¥à¤°à¤£ असà¥à¤µà¥€à¤•ृत हà¥à¤†</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%dखà¥à¤²à¤¾ समूह आमंतà¥à¤°à¤£</item> + <item quantity="other">%dखà¥à¤²à¤¾ समूह आमंतà¥à¤°à¤£</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">आपने%s से समूह निमंतà¥à¤°à¤£ सà¥à¤µà¥€à¤•ार कर लिया है</string> + <string name="groups_invitations_response_declined_sent">आपने%s से समूह निमंतà¥à¤°à¤£ को मना कर दिया</string> + <string name="groups_invitations_response_accepted_received">%sसमूह निमंतà¥à¤°à¤£ से मना कर दिया</string> + <string name="groups_invitations_response_declined_received">%sसमूह निमंतà¥à¤°à¤£ से मना कर दिया</string> + <string name="sharing_status_groups">केवल निरà¥à¤®à¤¾à¤¤à¤¾ समूह में नठसदसà¥à¤¯à¥‹à¤‚ को आमंतà¥à¤°à¤¿à¤¤ कर सकता है। नीचे समूह के सà¤à¥€ मौजूदा सदसà¥à¤¯ हैं</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">संपरà¥à¤• पà¥à¤°à¤•ट करें</string> + <string name="groups_reveal_dialog_message">आप यह समूह चà¥à¤¨ सकते हैं कि इस समूह के सà¤à¥€ वरà¥à¤¤à¤®à¤¾à¤¨ और à¤à¤µà¤¿à¤·à¥à¤¯ के सदसà¥à¤¯à¥‹à¤‚ के संपरà¥à¤•ों को पà¥à¤°à¤•ट करना है। \ N \ n संपरà¥à¤•ों का सà¥à¤µà¤¾à¤—त करते हà¥à¤ समूह से आपका कनेकà¥à¤¶à¤¨ तेज़ और अधिक विशà¥à¤µà¤¸à¤¨à¥€à¤¯ बना देता है, कà¥à¤¯à¥‹à¤‚कि आप समूह के निरà¥à¤®à¤¾à¤¤à¤¾ ऑफ़लाइन होने पर à¤à¥€ पता चला संपरà¥à¤•ों के साथ संवाद कर सकते हैं।</string> + <string name="groups_reveal_visible">संपरà¥à¤• संबंध समूह को दिखाई देता है</string> + <string name="groups_reveal_visible_revealed_by_us">संपरà¥à¤• संबंध समूह को दिखाई देता है (आपके दà¥à¤µà¤¾à¤°à¤¾ पता चला है)</string> + <string name="groups_reveal_visible_revealed_by_contact">संपरà¥à¤• संबंध समूह को दिखाई देता है (%s दà¥à¤µà¤¾à¤°à¤¾ पता चला है)</string> + <string name="groups_reveal_invisible">संपरà¥à¤• संबंध समूह को दिखाई नहीं दे रहा है</string> + <!--Forums--> + <string name="no_forums">कोई फोरम दिखाने के लिठ\ n \ n फोरम बनाने के लिठ+ आइकन टैप करें, या अपने संपरà¥à¤•ों को आपके साथ मंच साà¤à¤¾ करने के लिठकहें</string> + <string name="create_forum_title">फोरम बनाà¤à¤</string> + <string name="choose_forum_hint">अपने मंच का नाम चà¥à¤¨à¥‡à¤‚</string> + <string name="create_forum_button">फोरम बनाà¤à¤</string> + <string name="forum_created_toast">फोरम बनाया</string> + <string name="no_forum_posts">दिखाने के लिठकोई पोसà¥à¤Ÿ नहीं</string> + <string name="no_posts">कोई पोसà¥à¤Ÿ नहीं</string> + <plurals name="posts"> + <item quantity="one">%dपदों</item> + <item quantity="other">%dपदों</item> + </plurals> + <string name="forum_message_reply_hint">नया उतà¥à¤¤à¤°</string> + <string name="btn_reply">जवाब दें</string> + <string name="forum_leave">फोरम छोड़ें</string> + <string name="dialog_title_leave_forum">फोरम छोड़ने की पà¥à¤·à¥à¤Ÿà¤¿ करें</string> + <string name="dialog_message_leave_forum">कà¥à¤¯à¤¾ आप वाकई इस मंच को छोड़ना चाहते हैं? \ N \ n आपके दà¥à¤µà¤¾à¤°à¤¾ इस मंच को साà¤à¤¾ करने वाले किसी à¤à¥€ संपरà¥à¤• के साथ अपडेट पà¥à¤°à¤¾à¤ªà¥à¤¤ करना बंद हो सकता है।</string> + <string name="dialog_button_leave">छोड़ना</string> + <string name="forum_left_toast">वाम मंच</string> + <!--Forum Sharing--> + <string name="forum_share_button">शेयर फ़ोरम</string> + <string name="contacts_selected">संपरà¥à¤• चयनित</string> + <string name="activity_share_toolbar_header">संपरà¥à¤• चà¥à¤¨à¥‡à¤‚</string> + <string name="no_contacts_selector">कोई संपरà¥à¤• दिखाने के लिठ\ n \ n संपरà¥à¤• जोड़ने के बाद यहां वापस आà¤à¤‚</string> + <string name="forum_shared_snackbar">चयनित संपरà¥à¤•ों के साथ फ़ोरम साà¤à¤¾ किया गया</string> + <string name="forum_share_message">à¤à¤• संदेश जोड़ें (वैकलà¥à¤ªà¤¿à¤•)</string> + <string name="forum_share_error">इस फ़ोरम को साà¤à¤¾ करने में कोई तà¥à¤°à¥à¤Ÿà¤¿ थी।</string> + <string name="forum_invitation_received">%1$sने आपके साथ \"%2$s\" मंच साà¤à¤¾ किया है</string> + <string name="forum_invitation_sent">आपने%2$s के साथ \"%1$s\" मंच साà¤à¤¾ किया है</string> + <string name="forum_invitations_title">फोरम निमंतà¥à¤°à¤£</string> + <string name="forum_invitation_exists">आपने पहले से ही इस मंच पर à¤à¤• निमंतà¥à¤°à¤£ सà¥à¤µà¥€à¤•ार कर लिया है। \ N \ n अधिक आमंतà¥à¤°à¤£ सà¥à¤µà¥€à¤•ार करने से मंच से आपका कनेकà¥à¤¶à¤¨ तेजी से और अधिक विशà¥à¤µà¤¸à¤¨à¥€à¤¯ हो जाà¤à¤—ा।</string> + <string name="forum_joined_toast">फोरम में शामिल</string> + <string name="forum_declined_toast">आमंतà¥à¤°à¤£ में कमी आई</string> + <string name="shared_by_format">%s दà¥à¤µà¤¾à¤°à¤¾ साà¤à¤¾ किया गया</string> + <string name="forum_invitation_already_sharing">पहले से ही साà¤à¤¾ करना</string> + <string name="forum_invitation_response_accepted_sent">आपने%s से मंच निमंतà¥à¤°à¤£ सà¥à¤µà¥€à¤•ार कर लिया है</string> + <string name="forum_invitation_response_declined_sent">आपने%s से मंच निमंतà¥à¤°à¤£ को असà¥à¤µà¥€à¤•ार कर दिया है</string> + <string name="forum_invitation_response_accepted_received">%sमंच निमंतà¥à¤°à¤£ सà¥à¤µà¥€à¤•ार कर लिया</string> + <string name="forum_invitation_response_declined_received">%sमंच निमंतà¥à¤°à¤£ मना कर दिया</string> + <string name="sharing_status">शेयरिंग सà¥à¤¥à¤¿à¤¤à¤¿</string> + <string name="sharing_status_forum">फ़ोरम के किसी à¤à¥€ सदसà¥à¤¯ को अपने संपरà¥à¤•ों के साथ साà¤à¤¾ कर सकते हैं आप इस फ़ोरम को निमà¥à¤¨à¤²à¤¿à¤–ित संपरà¥à¤•ों के साथ साà¤à¤¾ कर रहे हैं à¤à¤¸à¥‡ अनà¥à¤¯ सदसà¥à¤¯ à¤à¥€ हो सकते हैं जिनà¥à¤¹à¥‡à¤‚ आप नहीं देख सकते हैं</string> + <string name="shared_with">%1$d (%2$d ऑनलाइन) के साथ साà¤à¤¾ किया गया</string> + <plurals name="forums_shared"> + <item quantity="one">%dसंपरà¥à¤•ों दà¥à¤µà¤¾à¤°à¤¾ साà¤à¤¾ मंच</item> + <item quantity="other">%dसंपरà¥à¤•ों दà¥à¤µà¤¾à¤°à¤¾ साà¤à¤¾ मंच</item> + </plurals> + <string name="nobody">कोई à¤à¥€ नहीं</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">दिखाने के लिठकोई पोसà¥à¤Ÿ नहीं</string> + <string name="read_more">अधिक पढ़ें</string> + <string name="blogs_write_blog_post">बà¥à¤²à¥‰à¤— पोसà¥à¤Ÿ लिखें</string> + <string name="blogs_write_blog_post_body_hint">अपना बà¥à¤²à¥‰à¤— पोसà¥à¤Ÿ टाइप करें</string> + <string name="blogs_publish_blog_post">पà¥à¤°à¤•ाशित करना</string> + <string name="blogs_blog_post_created">बà¥à¤²à¥‰à¤— पोसà¥à¤Ÿ बनाया</string> + <string name="blogs_blog_post_received">नया बà¥à¤²à¥‰à¤— पोसà¥à¤Ÿ पà¥à¤°à¤¾à¤ªà¥à¤¤ हà¥à¤†</string> + <string name="blogs_blog_post_scroll_to">सà¥à¤•à¥à¤°à¥‰à¤² टू</string> + <string name="blogs_feed_empty_state">दिखाने के लिठकोई पोसà¥à¤Ÿ नहीं \ n \ n आपके संपरà¥à¤•ों और बà¥à¤²à¥‰à¤—ों से पोसà¥à¤Ÿ की जाने वाली पोसà¥à¤Ÿ यहां दिखाई देगी \ n \ n à¤à¤• पोसà¥à¤Ÿ लिखने के लिठपेन आइकन टैप करें</string> + <string name="blogs_remove_blog">बà¥à¤²à¥‰à¤— निकालें</string> + <string name="blogs_remove_blog_dialog_message">कà¥à¤¯à¤¾ आप वाकई इस बà¥à¤²à¥‰à¤— को हटाना चाहते हैं? \ N \ n पोसà¥à¤Ÿ आपके डिवाइस से हटा दिठजाà¤à¤‚गे, लेकिन अनà¥à¤¯ लोगों के डिवाइस से नहीं। \ N \ n आपके दà¥à¤µà¤¾à¤°à¤¾ इस बà¥à¤²à¥‰à¤— को साà¤à¤¾ करने वाले किसी à¤à¥€ संपरà¥à¤• को अपडेट पà¥à¤°à¤¾à¤ªà¥à¤¤ करना बंद हो सकता है।</string> + <string name="blogs_remove_blog_ok">हटाना</string> + <string name="blogs_blog_removed">बà¥à¤²à¥‰à¤— हटा दिया गया</string> + <string name="blogs_reblog_comment_hint">à¤à¤• टिपà¥à¤ªà¤£à¥€ जोड़ें (वैकलà¥à¤ªà¤¿à¤•)</string> + <string name="blogs_reblog_button">पà¥à¤¨à¤ƒ बà¥à¤²à¥‰à¤—</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">बà¥à¤²à¥‰à¤— शेयर करें</string> + <string name="blogs_sharing_error">इस बà¥à¤²à¥‰à¤— को साà¤à¤¾ करने में à¤à¤• तà¥à¤°à¥à¤Ÿà¤¿ थी</string> + <string name="blogs_sharing_button">बà¥à¤²à¥‰à¤— शेयरकरें</string> + <string name="blogs_sharing_snackbar">चयनित संपरà¥à¤•ों के साथ साà¤à¤¾ बà¥à¤²à¥‰à¤—</string> + <string name="blogs_sharing_response_accepted_sent">आपने%s से बà¥à¤²à¥‰à¤— निमंतà¥à¤°à¤£ सà¥à¤µà¥€à¤•ार कर लिया है</string> + <string name="blogs_sharing_response_declined_sent">आपने बà¥à¤²à¥‰à¤— आमंतà¥à¤°à¤£ से इनकार कर दिया%s</string> + <string name="blogs_sharing_response_accepted_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_sent">आपने %1$s को%2$s के साथ साà¤à¤¾ किया है</string> + <string name="blogs_sharing_invitations_title">बà¥à¤²à¥‰à¤— आमंतà¥à¤°à¤£</string> + <string name="blogs_sharing_joined_toast">बà¥à¤²à¥‰à¤— के लिठसदसà¥à¤¯à¤¤à¤¾ लें</string> + <string name="blogs_sharing_declined_toast">आमंतà¥à¤°à¤£ में कमी आई</string> + <string name="sharing_status_blog">जो कोई à¤à¥€ बà¥à¤²à¥‰à¤— के लिठसदसà¥à¤¯à¤¤à¤¾ लेता है, उसे अपने संपरà¥à¤•ों के साथ साà¤à¤¾ कर सकता है आप इस बà¥à¤²à¥‰à¤— को निमà¥à¤¨à¤²à¤¿à¤–ित संपरà¥à¤•ों के साथ साà¤à¤¾ कर रहे हैं। à¤à¤¸à¥‡ अनà¥à¤¯ सदसà¥à¤¯ à¤à¥€ हो सकते हैं जिनà¥à¤¹à¥‡à¤‚ आप नहीं देख सकते हैं।</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">आरà¤à¤¸à¤à¤¸ फ़ीड आयात करें</string> + <string name="blogs_rss_feeds_import_button">आयात</string> + <string name="blogs_rss_feeds_import_hint">आरà¤à¤¸à¤à¤¸ फ़ीड का यूआरà¤à¤² दरà¥à¤œ करें</string> + <string name="blogs_rss_feeds_import_error">हमें खेद है! आपकी फ़ीड आयात करने में à¤à¤• तà¥à¤°à¥à¤Ÿà¤¿ हà¥à¤ˆ</string> + <string name="blogs_rss_feeds_manage">आरà¤à¤¸à¤à¤¸ फ़ीड पà¥à¤°à¤¬à¤‚धित करें</string> + <string name="blogs_rss_feeds_manage_imported">आयातित:</string> + <string name="blogs_rss_feeds_manage_author">लेखक:</string> + <string name="blogs_rss_feeds_manage_updated">आखरी अपडेट:</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_ok">हटाना</string> + <string name="blogs_rss_feeds_manage_delete_error">फीड हटाया नहीं जा सका!</string> + <string name="blogs_rss_feeds_manage_empty_state">कोई आरà¤à¤¸à¤à¤¸ फ़ीड दिखाने के लिठफ़ीड नहीं करता \ n \ n फ़ीड आयात करने के लिठ+ आइकन टैप करें</string> + <string name="blogs_rss_feeds_manage_error">आपकी फ़ीड लोड करने में à¤à¤• समसà¥à¤¯à¤¾ थी बाद में पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें।</string> + <!--Settings Display--> + <!--Settings Network--> + <string name="network_settings_title">नेटवरà¥à¤•</string> + <string name="bluetooth_setting">बà¥à¤²à¥‚टूथ के माधà¥à¤¯à¤® से कनेकà¥à¤Ÿ करें</string> + <string name="bluetooth_setting_enabled">जब à¤à¥€ संपरà¥à¤• आस-पास हो</string> + <string name="bluetooth_setting_disabled">केवल जब संपरà¥à¤• जोड़ते हैं</string> + <string name="tor_network_setting">टो के माधà¥à¤¯à¤® से कनेकà¥à¤Ÿ करें</string> + <string name="tor_network_setting_never">कà¤à¥€ नहीà¤</string> + <string name="tor_network_setting_wifi">केवल वाईफ़ाई का उपयोग करते समय</string> + <string name="tor_network_setting_always">वाई-फ़ाई या मोबाइल डेटा का उपयोग करते समय</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">सà¥à¤°à¤•à¥à¤·à¤¾</string> + <string name="change_password">पासवरà¥à¤¡ बदलें</string> + <string name="confirm_new_password">नठपासवरà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ करें</string> + <string name="password_changed">पासवरà¥à¤¡ बदला जा चà¥à¤•ा है।</string> + <string name="panic_setting">आतंक बटन सेटअप</string> + <string name="panic_setting_title">घबराहट होना</string> + <string name="panic_setting_hint">कॉनà¥à¤«à¤¼à¤¿à¤—र करें कि जब आप à¤à¤• आतंक बटन à¤à¤ª का उपयोग करते हैं तो Briar कैसे पà¥à¤°à¤¤à¤¿à¤•à¥à¤°à¤¿à¤¯à¤¾ करेगा</string> + <string name="panic_app_setting_title">आतंक बटन à¤à¤ª</string> + <string name="unknown_app">à¤à¤• अजà¥à¤žà¤¾à¤¤ à¤à¤ª</string> + <string name="panic_app_setting_summary">कोई à¤à¤ª सेट नहीं किया गया है</string> + <string name="panic_app_setting_none">कà¥à¤› à¤à¥€ नहीं</string> + <string name="dialog_title_connect_panic_app">आतंक à¤à¤ª की पà¥à¤·à¥à¤Ÿà¤¿ करें</string> + <string name="dialog_message_connect_panic_app">कà¥à¤¯à¤¾ आप निशà¥à¤šà¤¿à¤¤ हैं कि आप%1$s को विनाशकारी आतंक बटन कà¥à¤°à¤¿à¤¯à¤¾à¤“ं को टà¥à¤°à¤¿à¤—र करने की अनà¥à¤®à¤¤à¤¿ देना चाहते हैं?</string> + <string name="panic_setting_signout_title">साइन आउट</string> + <string name="panic_setting_signout_summary">यदि कोई आतंक बटन दबाया जाता है तो बियर से साइन आउट करें</string> + <string name="purge_setting_title">खाता हटा दो</string> + <string name="purge_setting_summary">यदि आपका आतंक बटन दबाया गया हो तो अपने बà¥à¤°à¤¿à¤¯à¤° खाते को हटा दें। सावधानी: यह आपकी पहचान, संपरà¥à¤• और संदेश को सà¥à¤¥à¤¾à¤¯à¥€ रूप से हटा देगा</string> + <string name="uninstall_setting_title">बरिअर की सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ रदà¥à¤¦ करें</string> + <string name="uninstall_setting_summary">इसके लिठà¤à¤• आतंक घटना में मैनà¥à¤¯à¥à¤…ल पà¥à¤·à¥à¤Ÿà¤¿à¤•रण की आवशà¥à¤¯à¤•ता है</string> + <!--Settings Notifications--> + <string name="notification_settings_title">सूचनाà¤à¤‚</string> + <string name="notify_private_messages_setting_title">निजी संदेश</string> + <string name="notify_private_messages_setting_summary">निजी संदेशों के लिठअलरà¥à¤Ÿ दिखाà¤à¤‚</string> + <string name="notify_private_messages_setting_summary_26">निजी संदेशों के लिठअलरà¥à¤Ÿ कॉनà¥à¤«à¤¼à¤¿à¤—र करें</string> + <string name="notify_group_messages_setting_title">समूह संदेश</string> + <string name="notify_group_messages_setting_summary">समूह संदेशों के लिठअलरà¥à¤Ÿà¥à¤¸ दिखाà¤à¤‚</string> + <string name="notify_group_messages_setting_summary_26">समूह संदेशों के लिठअलरà¥à¤Ÿ कॉनà¥à¤«à¤¼à¤¿à¤—र करें</string> + <string name="notify_forum_posts_setting_title">फ़ोरम पोसà¥à¤Ÿ</string> + <string name="notify_forum_posts_setting_summary">फ़ोरम पोसà¥à¤Ÿ के लिठअलरà¥à¤Ÿà¥à¤¸ दिखाà¤à¤‚</string> + <string name="notify_forum_posts_setting_summary_26">फोरम पोसà¥à¤Ÿ के लिठअलरà¥à¤Ÿ कॉनà¥à¤«à¤¼à¤¿à¤—र करें</string> + <string name="notify_blog_posts_setting_title">वेबदैनिकी डाक</string> + <string name="notify_blog_posts_setting_summary">बà¥à¤²à¥‰à¤— पोसà¥à¤Ÿ के लिठअलरà¥à¤Ÿà¥à¤¸ दिखाà¤à¤‚</string> + <string name="notify_blog_posts_setting_summary_26">बà¥à¤²à¥‰à¤— पोसà¥à¤Ÿ के लिठअलरà¥à¤Ÿ कॉनà¥à¤«à¤¼à¤¿à¤—र करें</string> + <string name="notify_vibration_setting">कांपना</string> + <string name="notify_lock_screen_setting_title">लॉक सà¥à¤•à¥à¤°à¥€à¤¨</string> + <string name="notify_lock_screen_setting_summary">लॉक सà¥à¤•à¥à¤°à¥€à¤¨ पर सूचनाà¤à¤‚ दिखाà¤à¤‚</string> + <string name="notify_sound_setting">धà¥à¤µà¤¨à¤¿</string> + <string name="notify_sound_setting_default">बकाया घंटी</string> + <string name="notify_sound_setting_disabled">कोई नहीं</string> + <string name="choose_ringtone_title">रिंगटोन चà¥à¤¨à¥‡à¤‚</string> + <string name="cannot_load_ringtone">रिंगटोन लोड नहीं कर सकता</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">पà¥à¤°à¤¤à¤¿à¤•à¥à¤°à¤¿à¤¯à¤¾</string> + <string name="send_feedback">पà¥à¤°à¤¤à¤¿à¤•à¥à¤°à¤¿à¤¯à¤¾ à¤à¥‡à¤œà¥‡à¤‚</string> + <!--Link Warning--> + <string name="link_warning_title">लिंक चेतावनी</string> + <string name="link_warning_intro">आप बाहरी à¤à¤ªà¥à¤²à¤¿à¤•ेशन के साथ निमà¥à¤¨ लिंक खोलने वाले हैं</string> + <string name="link_warning_text">इसका इसà¥à¤¤à¥‡à¤®à¤¾à¤² आपको पहचानने के लिठकिया जा सकता है इस बारे में सोचें कि कà¥à¤¯à¤¾ आपको उस वà¥à¤¯à¤•à¥à¤¤à¤¿ पर à¤à¤°à¥‹à¤¸à¤¾ है जिसने आपको यह लिंक à¤à¥‡à¤œà¤¾ है और इसे ऑरà¥à¤«à¤¼à¥‰à¤•à¥à¤¸ के साथ खोलने पर विचार किया है।</string> + <string name="link_warning_open_link">खà¥à¤²à¥€ लिंक</string> + <!--Crash Reporter--> + <string name="crash_report_title">बà¥à¤°à¤¿à¤¯à¤° कà¥à¤°à¥ˆà¤¶ रिपोरà¥à¤Ÿ</string> + <string name="briar_crashed">कà¥à¤·à¤®à¤¾ करें, बियर दà¥à¤°à¥à¤˜à¤Ÿà¤¨à¤¾à¤—à¥à¤°à¤¸à¥à¤¤ हो गया है।</string> + <string name="not_your_fault">यह आपकी गलती नहीं है</string> + <string name="please_send_report">कृपया हमें कà¥à¤°à¥ˆà¤¶ रिपोरà¥à¤Ÿ à¤à¥‡à¤œà¤•र बेहतर बियर बनाने में हमारी सहायता करें</string> + <string name="report_is_encrypted">हम वादा करते हैं कि रिपोरà¥à¤Ÿ à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ की गई है और सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ रूप से à¤à¥‡à¤œà¤¾ गया है।</string> + <string name="feedback_title">पà¥à¤°à¤¤à¤¿à¤•à¥à¤°à¤¿à¤¯à¤¾</string> + <string name="describe_crash">वरà¥à¤£à¤¨ करें कि कà¥à¤¯à¤¾ हà¥à¤† (वैकलà¥à¤ªà¤¿à¤•)</string> + <string name="enter_feedback">अपना फ़ीडबैक दरà¥à¤œ करें</string> + <string name="optional_contact_email">आपका ईमेल पता (वैकलà¥à¤ªà¤¿à¤•)</string> + <string name="include_debug_report_crash">दà¥à¤°à¥à¤˜à¤Ÿà¤¨à¤¾ के बारे में अनाम डेटा शामिल करें</string> + <string name="include_debug_report_feedback">इस डिवाइस के बारे में अनाम डेटा शामिल करें</string> + <string name="could_not_load_report_data">रिपोरà¥à¤Ÿ डेटा लोड नहीं किया जा सका</string> + <string name="send_report">रिपोरà¥à¤Ÿ à¤à¥‡à¤œà¥‹</string> + <string name="close">बंद करे</string> + <string name="dev_report_saved">रिपोरà¥à¤Ÿ सहेजी गई अगली बार जब आप बà¥à¤°à¤¿à¤¯à¤° में पà¥à¤°à¤µà¥‡à¤¶ करेंगे तो उसे à¤à¥‡à¤œà¤¾ जाà¤à¤—ा।</string> + <!--Sign Out--> + <string name="progress_title_logout">बà¥à¤°à¤¿à¤¯à¤° से साइन आउट हो रहा है ...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">सà¥à¤•à¥à¤°à¥€à¤¨ ओवरले का पता लगाया</string> + <string name="screen_filter_body">à¤à¤• और à¤à¤ª बà¥à¤°à¤¿à¤¯à¤° के शीरà¥à¤· पर है। आपकी सà¥à¤°à¤•à¥à¤·à¤¾ की रकà¥à¤·à¤¾ के लिà¤, बà¥à¤°à¤¿à¤¯à¤° सà¥à¤ªà¤°à¥à¤¶ करने का जवाब नहीं देगा, जब किसी अनà¥à¤¯ à¤à¤ª को शीरà¥à¤· पर आ रही है। \ N \ n निमà¥à¤¨ à¤à¤ªà¥à¤²à¤¿à¤•ेशन शीरà¥à¤· पर डà¥à¤°à¤¾à¤‡à¤‚ग कर सकते हैं: \ n \ n%1$s</string> + <string name="screen_filter_allow">इन à¤à¤ªà¥à¤¸ को शीरà¥à¤· पर आकरà¥à¤·à¤¿à¤¤ करने की अनà¥à¤®à¤¤à¤¿ दें</string> + <!--Permission Requests--> + <string name="permission_camera_title">कैमरा अनà¥à¤®à¤¤à¤¿</string> + <string name="permission_camera_request_body">QR कोड को सà¥à¤•ैन करने के लिà¤, Briar को कैमरे तक पहà¥à¤‚च की आवशà¥à¤¯à¤•ता है।</string> + <string name="permission_camera_denied_body">आपने कैमरे तक पहà¥à¤‚च से वंचित किया है, लेकिन संपरà¥à¤• जोड़ने के लिठकैमरे का उपयोग करने की आवशà¥à¤¯à¤•ता है। \ N \ n कृपया पहà¥à¤‚च पà¥à¤°à¤¦à¤¾à¤¨ करने पर विचार करें।</string> + <string name="permission_camera_denied_toast">कैमरा अनà¥à¤®à¤¤à¤¿ नहीं दी गई थी</string> + <string name="qr_code">कà¥à¤¯à¥‚आर कोड</string> + <string name="show_qr_code_fullscreen">कà¥à¤¯à¥‚आर कोड पूरà¥à¤£à¤¸à¥à¤•à¥à¤°à¥€à¤¨ दिखाà¤à¤‚</string> +</resources> diff --git a/mailbox-android/src/main/res/values-it/strings.xml b/mailbox-android/src/main/res/values-it/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..3d4d06b4c83fdf59136bd5253433e301592d1448 --- /dev/null +++ b/mailbox-android/src/main/res/values-it/strings.xml @@ -0,0 +1,413 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Benvenuti su Briar</string> + <string name="setup_name_explanation">Il tuo nickname verrà mostrato accanto ad ogni contenuto pubblicato. Non puoi cambiarlo dopo averlo creato.</string> + <string name="setup_next">Avanti</string> + <string name="setup_password_intro">Scegli una password</string> + <string name="setup_password_explanation">Il tuo account Briar resta memorizzato cifrato nel tuo dispositivo, non nel cloud. Se dimentichi la password o disinstalli Briar, non c\'è modo di ripristinare l\'account.\n\nScegli una password lunga difficile da indovinare, come quattro parole casuali o dieci lettere, numeri e simboli a caso.</string> + <string name="setup_doze_title">Connessioni in background</string> + <string name="setup_doze_intro">Per ricevere messaggi, Briar deve restare connesso in background.</string> + <string name="setup_doze_explanation">Per ricevere messaggi, Briar deve restare connesso in background. Disattiva le ottimizzazioni della batteria per mantenere Briar connesso.</string> + <string name="setup_doze_button">Permetti le connessioni</string> + <string name="choose_nickname">Scegli il tuo nickname</string> + <string name="choose_password">Scegli la tua password</string> + <string name="confirm_password">Conferma la tua password</string> + <string name="name_too_long">Nome troppo lungo</string> + <string name="password_too_weak">La password è troppo debole</string> + <string name="passwords_do_not_match">La password non corrisponde</string> + <string name="create_account_button">Creare Account</string> + <string name="more_info">Ulteriori Informazioni</string> + <string name="don_t_ask_again">Non chiedere più</string> + <string name="setup_huawei_text">Tocca il pulsante qua sotto e assicurati che Briar sia protetto nella schermata \"App protette\"</string> + <string name="setup_huawei_button">Proteggi Briar</string> + <string name="setup_huawei_help">Se Briar non viene aggiunto nell\'elenco di app protette, non potrà funzionare in background.</string> + <string name="warning_dozed">%s non ha potuto funzionare in background</string> + <!--Login--> + <string name="enter_password">Password</string> + <string name="try_again">Password sbagliata, riprova</string> + <string name="sign_in_button">Entra</string> + <string name="forgotten_password">Ho dimenticato la password</string> + <string name="dialog_title_lost_password">Password persa</string> + <string name="dialog_message_lost_password">Il tuo account Briar si trova cifrato sul tuo dispositivo e non nel cloud, quindi non possiamo resettarti la tua password. Vorresti cancellare il tuo account e partire di nuovo?\n\nAttenzione: Le tue identità , contatti e messaggi verranno persi permanentemente.</string> + <string name="startup_failed_notification_title">Briar non è riuscito a partire</string> + <string name="startup_failed_notification_text">Tocca per maggiori informazioni.</string> + <string name="startup_failed_activity_title">Fallimento Avvio Briar</string> + <string name="startup_failed_db_error">Per qualche motivo, il tuo database di Briar è danneggiato in modo irreparabile. Il tuo account, i tuoi dati e tutti i tuoi contatti sono perduti. Sfortunatamente devi reinstallare Briar o registrare un nuovo account scegliendo \'Ho dimenticato la password\'.</string> + <string name="startup_failed_data_too_old_error">Il tuo account è stato creato con una vecchia versione dell\'app e non può essere aperto in questa versione. Devi reinstallare la vecchia versione oppure impostare un nuovo account scegliendo \'Ho dimenticato la password\' alla richiesta di password.</string> + <string name="startup_failed_data_too_new_error">Questa versione dell\'app è troppo vecchia. Aggiornala alla versione più recente e riprova.</string> + <string name="startup_failed_service_error">Briar non è stato in grado di caricare un plugin richiesto. Reinstallare Briar di solito sistema questo problema. Però ricorda che perderai il tuo account e tutti i dati ad esso associati poichè Briar non usa server centralizzati per mantenere i tuoi dati.</string> + <plurals name="expiry_warning"> + <item quantity="one">Questa è una versione di prova di Briar. Il tuo account scadrà fra %d giorno e non può essere rinnovato.</item> + <item quantity="other">Questa è una versione di prova di Briar. Il tuo account scadrà fra %d giorni e non può essere rinnovato.</item> + </plurals> + <string name="expiry_update">La scadenza della versione di prova è stata prorogata. Il tuo account ora scadrà fra %d giorni.</string> + <string name="expiry_date_reached">Questo software è scaduto.\nGrazie per il test!</string> + <string name="download_briar">Per continuare ad usare Briar, scarica la versione 1.0.</string> + <string name="create_new_account">Avrai bisogno di creare un nuovo account, ma puoi usare lo stesso nickname.</string> + <string name="download_briar_button">Scarica Briar 1.0</string> + <string name="startup_open_database">Decrittazione database...</string> + <string name="startup_migrate_database">Aggiornamento database...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Apri la barra di navigazione</string> + <string name="nav_drawer_close_description">Chiudi la barra di navigazione</string> + <string name="contact_list_button">Contatti</string> + <string name="groups_button">Gruppi privati</string> + <string name="forums_button">Forum</string> + <string name="blogs_button">Blog</string> + <string name="settings_button">Impostazioni</string> + <string name="sign_out_button">Esci</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="reminder_notification_title">Uscito da Briar</string> + <string name="reminder_notification_text">Tocca per riaccedere.</string> + <string name="reminder_notification_channel_title">Promemoria accesso a Briar</string> + <string name="reminder_notification_dismiss">Ignora</string> + <string name="ongoing_notification_title">Entrato in Briar</string> + <string name="ongoing_notification_text">Tocca per aprire Briar.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Nuovo messaggio privato.</item> + <item quantity="other">%d nuovi messaggi privati.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Nuovo messaggio di gruppo.</item> + <item quantity="other">%d nuovi messaggi di gruppo.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Nuovo messaggio sul forum.</item> + <item quantity="other">%d nuovi messaggi sul forum.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Nuovo post sul blog.</item> + <item quantity="other">%d nuovi post sul blog</item> + </plurals> + <!--Misc--> + <string name="now">ora</string> + <string name="show">Mostra</string> + <string name="hide">Nascondi</string> + <string name="ok">OK</string> + <string name="cancel">Annulla</string> + <string name="got_it">Ho capito</string> + <string name="delete">Cancella</string> + <string name="accept">Accetta</string> + <string name="decline">Declina</string> + <string name="options">Opzioni</string> + <string name="online">Connesso</string> + <string name="offline">Disconnesso</string> + <string name="send">Invia</string> + <string name="allow">Abilita</string> + <string name="open">Apri</string> + <string name="no_data">Nessun dato</string> + <string name="ellipsis">...</string> + <string name="text_too_long">Il testo inserito è troppo lungo</string> + <string name="show_onboarding">Mostra l\'aiuto</string> + <string name="fix">Correggi</string> + <string name="help">Aiuto</string> + <string name="sorry">Scusa</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Nessun contatto da mostrare\n\nClicca l\'icona + per aggiungere un contatto</string> + <string name="date_no_private_messages">Nessun messaggio.</string> + <string name="no_private_messages">Nessun messaggio da mostrare</string> + <string name="message_hint">Scrivi un messaggio</string> + <string name="delete_contact">Elimina contatto</string> + <string name="dialog_title_delete_contact">Conferma cancellazione contatto</string> + <string name="dialog_message_delete_contact">Sei sicuro di voler rimuovere questo contatto e tutti i messaggi scambiati con esso?</string> + <string name="contact_deleted_toast">Contatto cancellato</string> + <!--Adding Contacts--> + <string name="add_contact_title">Aggiungi un Contatto</string> + <string name="face_to_face">Devi incontrarti con la persona che vuoi aggiungere come contatto.\n\nQuesto evita che qualcuno ti impersoni o legga i tuoi messaggi in futuro.</string> + <string name="continue_button">Continua</string> + <string name="connection_failed">Connessione fallita</string> + <string name="try_again_button">Riprova</string> + <string name="waiting_for_contact_to_scan">Aspettando il contatto per la scansione ed il collegamento\u2026</string> + <string name="exchanging_contact_details">Scambio dettagli contatto\u2026</string> + <string name="contact_added_toast">Contatto aggiunto: %s</string> + <string name="contact_already_exists">Il contatto %s esiste già </string> + <string name="contact_exchange_failed">Scambio di contatto fallito</string> + <string name="qr_code_invalid">Il codice QR non è valido</string> + <string name="qr_code_unsupported">Il codice QR che state tentando di scansionare appartiene ad una vecchia versione di %s che non è più supportata.\n\nAssicuratevi entrambi di utilizzare la versione più recente e poi riprovare.</string> + <string name="camera_error">Errore fotocamera</string> + <string name="connecting_to_device">Connessione al dispositivo\u2026</string> + <string name="authenticating_with_device">Autenticazione con il dispositivo\u2026</string> + <string name="connection_aborted_local">Connessione annullata! Potrebbe significare che qualcuno stia interferendo con la tua connessione</string> + <string name="connection_aborted_remote">Connessione abortita dal tuo contatto!Questo può voler dire che qualcuno sta cercando di interferire con la tua connessione</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Introduzione tuoi contatti</string> + <string name="introduction_onboarding_text">Puoi presentare i tuoi contatti fra di loro, così non hanno bisogno di incontrarsi di persona per connettersi a Briar.</string> + <string name="introduction_menu_item">Crea l\'introduzione</string> + <string name="introduction_activity_title">Seleziona Contatto</string> + <string name="introduction_not_possible">Hai già un introduzione in corso con questi contatti. Si prega di consentire che prima questo finisca. Se tu o i tuoi contatti sono raramente online, questo potrebbe richiedere un po\' di tempo.</string> + <string name="introduction_message_title">Introduzione Contatti</string> + <string name="introduction_message_hint">Aggiungi un messaggio (facoltativo)</string> + <string name="introduction_button">Crea l\'introduzione</string> + <string name="introduction_sent">La tua introduzione è stata inviata.</string> + <string name="introduction_error">C\'è stato un errore nella creazione dell\'introduzione</string> + <string name="introduction_response_error">Errore durante la risposta all\' introduzione</string> + <string name="introduction_request_sent">Hai richiesto di introdurre %1$s a %2$s.</string> + <string name="introduction_request_received">%1$s ha chiesto di introdurti in %2$s. Vuoi aggiungere %2$s alla tua lista contatti?</string> + <string name="introduction_request_exists_received">%1$s ha chiesto di introdurti in %2$s, ma %2$s è già nella tua lista contatti. Dato che %1$s può non saperlo, puoi comunque rispondere:</string> + <string name="introduction_request_answered_received">%1$s ha richiesto di introdurti a %2$s.</string> + <string name="introduction_response_accepted_sent">Hai accettato l\'introduzione a %1$s.</string> + <string name="introduction_response_accepted_sent_info">Prima che %1$s venga aggiunto ai tuoi contatti, dovranno anche loro accettare l\'introduzione. Questo potrebbe richiedere un po\' di tempo.</string> + <string name="introduction_response_declined_sent">Hai declinato l\'introduzione a %1$s.</string> + <string name="introduction_response_accepted_received">%1$s ha accettato l\'introduzione a %2$s.</string> + <string name="introduction_response_declined_received">%1$s ha declinato l\'introduzione a %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s dice che %2$s ha declinato l\'introduzione.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Aggiunto nuovo contatto</item> + <item quantity="other">Aggiunti %d nuovi contatti.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">Nessun gruppo da mostrare\n\nClicca l\'icona + per creare un gruppo, o chiedi ai tuoi contatti di condividere gruppi con te</string> + <string name="groups_created_by">Creato da %s</string> + <plurals name="messages"> + <item quantity="one">%d messaggio</item> + <item quantity="other">%d messaggi</item> + </plurals> + <string name="groups_group_is_empty">Questo gruppo e\' vuoto</string> + <string name="groups_group_is_dissolved">Questo gruppo e\' stato sciolto</string> + <string name="groups_remove">Rimuovere</string> + <string name="groups_create_group_title">Crea gruppo privato</string> + <string name="groups_create_group_button">Crea gruppo</string> + <string name="groups_create_group_invitation_button">Invia invito</string> + <string name="groups_create_group_hint">Scegli un nome per il tuo gruppi privato</string> + <string name="groups_invitation_sent">Invito a partecipare al gruppo spedito</string> + <string name="groups_message_sent">Messaggio inviato</string> + <string name="groups_member_list">Lista membri</string> + <string name="groups_invite_members">Invita Membri</string> + <string name="groups_member_created_you">Hai creato un nuovo gruppo</string> + <string name="groups_member_created">%s e\' il creatore del gruppo.</string> + <string name="groups_member_joined_you">Ti sei unito al gruppo</string> + <string name="groups_member_joined">%s si è unito al gruppo</string> + <string name="groups_leave">Lascia gruppo</string> + <string name="groups_leave_dialog_title">Abbandonare il gruppo</string> + <string name="groups_leave_dialog_message">Sei sicuro di voler abbandonare questo gruppo?</string> + <string name="groups_dissolve">Sciogli il gruppo</string> + <string name="groups_dissolve_dialog_title">Conferma lo scioglimento del gruppo</string> + <string name="groups_dissolve_dialog_message">Sei sicuro di voler sciogliere questo gruppo?\n\nTutti gli altri membri non saranno più in grado di continuare le loro conversazioni e potrebbero non ricevere gli ultimi messaggi.</string> + <string name="groups_dissolve_button">Sciogli</string> + <string name="groups_dissolved_dialog_title">Il gruppo è stato dissolto</string> + <string name="groups_dissolved_dialog_message">Il creatore di questo gruppo l\'ha sciolto.\n\nNon puoi più scrivere messaggi in questo gruppo e potresti non ricevere tutti i messaggi che sono stati scritti.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Inviti spediti</string> + <string name="groups_invitations_invitation_sent">Hai invitato %1$s ad unirsi al gruppo \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s ti ha invitato ad unirti al gruppo \"%2$s\".</string> + <string name="groups_invitations_joined">Unito al gruppo</string> + <string name="groups_invitations_declined">Invito al gruppo rifiutato</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d invito al gruppo aperto.</item> + <item quantity="other">%d inviti al gruppo aperti.</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Hai accettato l\'invito al gruppo da %s.</string> + <string name="groups_invitations_response_declined_sent">Hai rifiutato l\'invito al gruppo da %s.</string> + <string name="groups_invitations_response_accepted_received">%s ha accettato l\'invito al gruppo.</string> + <string name="groups_invitations_response_declined_received">%s ha rifiutato l\'invito al gruppo.</string> + <string name="sharing_status_groups">Solo il creatore può invitare nuovi membri nel gruppo. Sotto ci sono i membri correnti del gruppo.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Rivelare contatti</string> + <string name="groups_reveal_dialog_message">Puoi scegliere se rivelare i contatti a tutti i membri correnti e futuri di questo gruppo.\n\nRivelare i contatti fa diventare la connessione al gruppo più veloce e più affidabile, perchè puoi comunicare con i contatti rivelati anche quando il creatore del gruppo è offline.</string> + <string name="groups_reveal_visible">La relazione fra i contatti è visibile al gruppo</string> + <string name="groups_reveal_visible_revealed_by_us">La relazione fra i contatti è visibile al gruppo (rivelata da te)</string> + <string name="groups_reveal_visible_revealed_by_contact">La relazione fra i contatti è visibile al gruppo (rivelata da %s)</string> + <string name="groups_reveal_invisible">La relazione fra i contatti non è visibile al gruppo</string> + <!--Forums--> + <string name="no_forums">Nessun forum da mostrare\n\nClicca l\'icona + per creare un forum, o chiedi ai tuoi contatti di condividere forum con te</string> + <string name="create_forum_title">Crea Forum</string> + <string name="choose_forum_hint">Scegli un nome per il tuo forum</string> + <string name="create_forum_button">Crea Forum</string> + <string name="forum_created_toast">Forum creato</string> + <string name="no_forum_posts">Nessun post da mostrare</string> + <string name="no_posts">Nessun post.</string> + <plurals name="posts"> + <item quantity="one">%d post</item> + <item quantity="other">%d post</item> + </plurals> + <string name="forum_new_entry_posted">Post pubblicato sul forum</string> + <string name="forum_new_message_hint">Nuovo post</string> + <string name="forum_message_reply_hint">Nuova Risposta</string> + <string name="btn_reply">Rispondi</string> + <string name="forum_leave">Lascia Forum</string> + <string name="dialog_title_leave_forum">Conferma l\'abbandono del forum</string> + <string name="dialog_message_leave_forum">Sei sicuro che vuoi lasciare questo forum?\n\nTutti i contatti con cui hai condiviso questo forum potrebbero smettere di ricevere aggiornamenti.</string> + <string name="dialog_button_leave">Lascia</string> + <string name="forum_left_toast">Forum lasciato</string> + <!--Forum Sharing--> + <string name="forum_share_button">Condividi Forum</string> + <string name="contacts_selected">Contatti selezionati</string> + <string name="activity_share_toolbar_header">Scegli Contatti</string> + <string name="no_contacts_selector">Nessun contatto da mostrare\n\nPer favore torna qui dopo aver aggiunto un contatto</string> + <string name="forum_shared_snackbar">Forum condiviso con i contatti scelti</string> + <string name="forum_share_message">Aggiungi un messaggio (facoltativo)</string> + <string name="forum_share_error">C\'è stato un errore nella condivisione di questo forum.</string> + <string name="forum_invitation_received">%1$s ha condiviso il forum \"%2$s\" con te.</string> + <string name="forum_invitation_sent">Hai condiviso il forum \"%1$s\" con %2$s.</string> + <string name="forum_invitations_title">Inviti Forum</string> + <string name="forum_invitation_exists">Hai già accettato un invito a questo forum.\n\nAccettare più inviti renderà la tua connessione a questo forum più veloce e affidabile.</string> + <string name="forum_joined_toast">Unito al forum</string> + <string name="forum_declined_toast">Invito declinato</string> + <string name="shared_by_format">Condiviso da %s</string> + <string name="forum_invitation_already_sharing">Già in condivisione</string> + <string name="forum_invitation_response_accepted_sent">Hai accettato l\'invito al forum da %s</string> + <string name="forum_invitation_response_declined_sent">Hai declinato l\'invito al forum da %s</string> + <string name="forum_invitation_response_accepted_received">%s ha accettato il tuo invito al forum.</string> + <string name="forum_invitation_response_declined_received">%s ha declinato il tuo invito al forum.</string> + <string name="sharing_status">Stato Condivisione</string> + <string name="sharing_status_forum">Ogni membro del forum può condividere con esso i suoi contatti. Stai condividendo questo forum con i seguenti contatti. Ci potrebbero inoltre essere altri membri che non puoi vedere.</string> + <string name="shared_with">Condiviso con %1$d (%2$d online)</string> + <plurals name="forums_shared"> + <item quantity="one">%d forum condiviso dai contatti</item> + <item quantity="other">%d forum condivisi dai contatti</item> + </plurals> + <string name="nobody">Nessuno</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Nessun post da mostrare</string> + <string name="read_more">leggi ancora</string> + <string name="blogs_write_blog_post">Scrivere un post sul blog</string> + <string name="blogs_write_blog_post_body_hint">Scrivi il tuo post del blog</string> + <string name="blogs_publish_blog_post">Pubblica</string> + <string name="blogs_blog_post_created">Post blog creato</string> + <string name="blogs_blog_post_received">Ricevuto nuovo post del blog</string> + <string name="blogs_blog_post_scroll_to">Scorri a</string> + <string name="blogs_feed_empty_state">Nessun post da mostrare\n\nI post dei tuoi contatti e blog a cui sei iscritto appariranno qui\n\nClicca l\'icona di penna per scrivere un post</string> + <string name="blogs_remove_blog">Rimuovi Blog</string> + <string name="blogs_remove_blog_dialog_message">Sei sicuro di voler rimuovere questo blog?\n\nI post saranno rimossi dal tuo dispositivo ma non dai dispositivi delle altre persone.\n\nTutti i contatti con cui hai condiviso questo blog potrebbero smettere di ricevere aggiornamenti.</string> + <string name="blogs_remove_blog_ok">Rimuovi</string> + <string name="blogs_blog_removed">Blog rimosso</string> + <string name="blogs_reblog_comment_hint">Aggiungi un commento (facoltativo)</string> + <string name="blogs_reblog_button">Reblog</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Condividi Blog</string> + <string name="blogs_sharing_error">C\'è stato un errore nella condivisione di questo blog.</string> + <string name="blogs_sharing_button">Condividi Blog</string> + <string name="blogs_sharing_snackbar">Blog condiviso con i contatti selezionati</string> + <string name="blogs_sharing_response_accepted_sent">Hai accettato l\'invito al blog da %s.</string> + <string name="blogs_sharing_response_declined_sent">Hai declinato l\'invito al blog da %s.</string> + <string name="blogs_sharing_response_accepted_received">%s ha accettato l\'invito al blog.</string> + <string name="blogs_sharing_response_declined_received">%s ha declinato l\'invito al blog.</string> + <string name="blogs_sharing_invitation_received">%1$s ha condiviso il blog \"%2$s\" con te.</string> + <string name="blogs_sharing_invitation_sent">Hai condiviso il blog \"%1$s\" con %2$s.</string> + <string name="blogs_sharing_invitations_title">Inviti Blog</string> + <string name="blogs_sharing_joined_toast">Iscritto al blog</string> + <string name="blogs_sharing_declined_toast">Invito declinato</string> + <string name="sharing_status_blog">Chiunque si iscrive ad un blog può condividerlo con i suoi contatti. Stai condividendo questo blog con i seguenti contatti. Ci potrebbero inoltre essere altri membri che non puoi vedere.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Importa RSS Feed</string> + <string name="blogs_rss_feeds_import_button">Importa</string> + <string name="blogs_rss_feeds_import_hint">Inserire l\'URL dell\'RSS feed</string> + <string name="blogs_rss_feeds_import_error">Ci dispiace! C\'è stato un errore nell\'importazione del tuo feed.</string> + <string name="blogs_rss_feeds_manage">Gestisci gli RSS Feed</string> + <string name="blogs_rss_feeds_manage_imported">Importato:</string> + <string name="blogs_rss_feeds_manage_author">Autore:</string> + <string name="blogs_rss_feeds_manage_updated">Ultimo Aggiornamento:</string> + <string name="blogs_rss_remove_feed">Rimuovi feed</string> + <string name="blogs_rss_remove_feed_dialog_message">Sei sicuro di voler rimuovere questo feed?\n\nI post saranno rimossi dal tuo dispositivo ma non dai dispositivi delle altre persone.\n\nTutti i contatti con cui hai condiviso questo feed potrebbero smettere di ricevere aggiornamenti.</string> + <string name="blogs_rss_remove_feed_ok">Rimuovi</string> + <string name="blogs_rss_feeds_manage_delete_error">Non è stato possibile cancellare il feed!</string> + <string name="blogs_rss_feeds_manage_empty_state">Nessun feed RSS da mostrare\n\nClicca l\'icona + per importare un feed</string> + <string name="blogs_rss_feeds_manage_error">C\'è stato un problema nel caricare i tuoi feeds. Per favore riprova fra poco.</string> + <!--Settings Display--> + <string name="pref_language_title">Lingua & regione</string> + <string name="pref_language_changed">Questa impostazione avrà effetto quando riavvierai Briar. Per favore, esci e riavvia Briar.</string> + <string name="pref_language_default">Default del sistema</string> + <string name="display_settings_title">Visualizza</string> + <string name="pref_theme_title">Tema</string> + <string name="pref_theme_light">Chiaro</string> + <string name="pref_theme_dark">Scuro</string> + <string name="pref_theme_auto">Automatico ( Dì )</string> + <string name="pref_theme_system">Predefinito di sistema</string> + <!--Settings Network--> + <string name="network_settings_title">Reti</string> + <string name="bluetooth_setting">Connessione attraverso Bluetooth</string> + <string name="bluetooth_setting_enabled">Quando i contatti sono vicini</string> + <string name="bluetooth_setting_disabled">Solo con l\'aggiunta di contatti</string> + <string name="tor_network_setting">Connetti via Tor</string> + <string name="tor_network_setting_never">Mai</string> + <string name="tor_network_setting_wifi">Solo se usando Wi-Fi</string> + <string name="tor_network_setting_always">Nel caso di uso Wi-Fi o dati mobile</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Sicurezza</string> + <string name="change_password">Cambia password</string> + <string name="current_password">Password attuale</string> + <string name="choose_new_password">Nuova password</string> + <string name="confirm_new_password">Confermare nuova password</string> + <string name="password_changed">La password è stata cambiata.</string> + <string name="panic_setting">Impostazione pulsante panico</string> + <string name="panic_setting_title">Pulsante panico</string> + <string name="panic_setting_hint">Configura come Briar reagirà quando userai un\'app pulsante panico</string> + <string name="panic_app_setting_title">App Pulsante Panico</string> + <string name="unknown_app">un\'app sconosciuta</string> + <string name="panic_app_setting_summary">Nessun app è stata impostata</string> + <string name="panic_app_setting_none">Nessuno</string> + <string name="dialog_title_connect_panic_app">Conferma App Panico</string> + <string name="dialog_message_connect_panic_app">Sei sicuro di voler consentire %1$s di attivare le azioni distruttive del pulsante panico?</string> + <string name="panic_setting_signout_title">Esci</string> + <string name="panic_setting_signout_summary">Uscire da Briar se viene premuto un pulsante di panico</string> + <string name="purge_setting_title">Elimina Account</string> + <string name="purge_setting_summary">Cancella il tuo account Briar se un panic button è premuto. Attenzione: ciò cancellerà permanentemente le tue identità , contatti e messaggi</string> + <string name="uninstall_setting_title">Disinstalla Briar</string> + <string name="uninstall_setting_summary">Questo richiede una conferma manuale in un evento panico</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Notifiche</string> + <string name="notify_sign_in_title">Ricordami di accedere</string> + <string name="notify_sign_in_summary">Mostra un promemoria quando si avvia il telefono o l\'app è stata aggiornata</string> + <string name="notify_private_messages_setting_title">Messaggi privati</string> + <string name="notify_private_messages_setting_summary">Mostra avvisi per i messaggi privati</string> + <string name="notify_private_messages_setting_summary_26">Configurare avvisi per messaggi privati</string> + <string name="notify_group_messages_setting_title">Messaggi di gruppo</string> + <string name="notify_group_messages_setting_summary">Mostra avvisi per messaggi di gruppo</string> + <string name="notify_group_messages_setting_summary_26">Configurare avvisi per messaggi di gruppo</string> + <string name="notify_forum_posts_setting_title">Post di forum</string> + <string name="notify_forum_posts_setting_summary">Mostra avvisi per i post di forum</string> + <string name="notify_forum_posts_setting_summary_26">Configurare avvisi per post di forum</string> + <string name="notify_blog_posts_setting_title">Post di blog</string> + <string name="notify_blog_posts_setting_summary">Mostra avvisi per post di blog</string> + <string name="notify_blog_posts_setting_summary_26">Configurare avvisi per post di blog</string> + <string name="notify_vibration_setting">Vibrazione</string> + <string name="notify_lock_screen_setting_title">Blocca schermo</string> + <string name="notify_lock_screen_setting_summary">Mostra notifiche sul blocca schermo</string> + <string name="notify_sound_setting">Suono</string> + <string name="notify_sound_setting_default">Suoneria di default</string> + <string name="notify_sound_setting_disabled">Nessuno</string> + <string name="choose_ringtone_title">Scegli suoneria</string> + <string name="cannot_load_ringtone">Impossibile caricare la suoneria</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Feedback</string> + <string name="send_feedback">Invia feedback</string> + <!--Link Warning--> + <string name="link_warning_title">Attenzione Link</string> + <string name="link_warning_intro">Stai per aprire il seguente link con un\' app esterna</string> + <string name="link_warning_text">Ciò può essere usato per identificarti. Pensa se ti fidi della persona che ti ha inviato questo link e considera se aprirlo con Orfox.</string> + <string name="link_warning_open_link">Apri Link</string> + <!--Crash Reporter--> + <string name="crash_report_title">Rapporto Crash Briar</string> + <string name="briar_crashed">Spiacenti, Briar è crashato</string> + <string name="not_your_fault">Questo non è colpa tua.</string> + <string name="please_send_report">Per favore aiutaci a migliorare Briar mandandoci un report del crash.</string> + <string name="report_is_encrypted">Vi promettiamo che il rapporto è cifrato e inviato in modo sicuro.</string> + <string name="feedback_title">Feedback</string> + <string name="describe_crash">Descrivi cosa è successo (facoltativo)</string> + <string name="enter_feedback">Immetti il tuo feedback</string> + <string name="optional_contact_email">Il tuo indirizzo email (facoltativo)</string> + <string name="include_debug_report_crash">Includere dati anonimi riguardo al crash</string> + <string name="include_debug_report_feedback">Includere dati anonimi riguardo al tuo dispositivo</string> + <string name="could_not_load_report_data">Non è stato possibile caricare i dati del report.</string> + <string name="send_report">Invia report</string> + <string name="close">Chiudi</string> + <string name="dev_report_saved">Report salvato. Verrà spedito la prossima volta che loggherai in Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">Uscire da Briar ...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">È stata rilevata un\'overlay sullo schermo</string> + <string name="screen_filter_body">Un\'altra app si sta sovrapponendo a Briar. Per proteggere la tua sicurezza, Briar non risponderà ai tocchi quando un\'app si sovrappone.\n\nLe seguenti app potrebbero sovrapporsi:\n\n%1$s</string> + <string name="screen_filter_allow">Permetti a queste app di sovrapporsi</string> + <!--Permission Requests--> + <string name="permission_camera_title">Autorizzazione fotocamera</string> + <string name="permission_camera_request_body">Per scansionare il codice QR, Briar deve accedere alla fotocamera.</string> + <string name="permission_camera_denied_body">Hai negato l\'accesso alla fotocamera, ma questa serve per aggiungere i contatti.\n\nConsidera la possibilità di concedere l\'accesso.</string> + <string name="permission_camera_denied_toast">Autorizzazione fotocamera non concessa</string> + <string name="qr_code">Codice QR</string> + <string name="show_qr_code_fullscreen">Mostra codice QR a tutto schermo</string> +</resources> diff --git a/mailbox-android/src/main/res/values-ja/strings.xml b/mailbox-android/src/main/res/values-ja/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..2514e51e9e9a23e7e61eb8d831f9cb246a669d4e --- /dev/null +++ b/mailbox-android/src/main/res/values-ja/strings.xml @@ -0,0 +1,131 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_next">次ã¸</string> + <string name="choose_nickname">ニックãƒãƒ¼ãƒ を入力</string> + <string name="choose_password">パスワードを入力</string> + <string name="confirm_password">確èªã®ãŸã‚å†åº¦ãƒ‘スワードを入力</string> + <string name="name_too_long">åå‰ãŒé•·éŽãŽã¾ã™ã€‚</string> + <string name="password_too_weak">パスワードãŒå¼±ã™ãŽã¾ã™ã€‚</string> + <string name="passwords_do_not_match">パスワードãŒä¸€è‡´ã—ã¾ã›ã‚“。</string> + <string name="create_account_button">アカウントを作æˆ</string> + <!--Login--> + <string name="enter_password">パスワード</string> + <string name="try_again">パスワードãŒé–“é•ã£ã¦ã„ã¾ã™ã€‚ã‚‚ã†ä¸€åº¦å…¥åŠ›ã—ã¦ãã ã•ã„。</string> + <string name="sign_in_button">Sign In</string> + <string name="forgotten_password">パスワードを忘れã¾ã—ãŸã€‚</string> + <string name="dialog_title_lost_password">パスワードを紛失</string> + <string name="dialog_message_lost_password">ã‚ãªãŸã®Briarアカウントã¯ã‚¯ãƒ©ã‚¦ãƒ‰ä¸Šã§ã¯ãªãã€æš—å·åŒ–ã•ãŸä¸Šã§ã‚ãªãŸã®ãƒ‡ãƒã‚¤ã‚¹ã«ä¿å˜ã•ã¦ã„ã¾ã™ã€‚ã—ãŸãŒã£ã¦Briarã¯ãƒ‘スワードをリセットã§ãã¾ã›ã‚“。アカウントを削除ã—ã¯ã˜ã‚ã‹ã‚‰ã‚„りãªãŠã—ã¾ã™ã‹ï¼Ÿæ³¨æ„ï¼ã‚ãªãŸã®IDã€é€£çµ¡å…ˆã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã¯æ°¸ä¹…ã«å‰Šé™¤ã•れã¾ã™ã€‚</string> + <string name="startup_failed_notification_title">Briarã‚’èµ·å‹•ã§ãã¾ã›ã‚“。</string> + <string name="startup_failed_activity_title">èµ·å‹•ã«å¤±æ•—</string> + <string name="startup_failed_service_error">プラグインã®èµ·å‹•ã«å¤±æ•—ã—ã¾ã—ãŸã€‚Briarã‚’å†ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹ã“ã¨ã§é€šå¸¸ã¯ç›´ã‚Šã¾ã™ã€‚Briarã¯ä¸å¤®ã‚µãƒ¼ãƒã«ãƒ‡ãƒ¼ã‚¿ã‚’ä¿å˜ã—ã¦ã„ãªã„ãŸã‚ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¨ãれã«é–¢é€£ã™ã‚‹æƒ…å ±ã¯å…¨ã¦å¤±ã‚れるã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。</string> + <string name="expiry_date_reached">ã“ã®ã‚½ãƒ•ãƒˆã®æœ‰åŠ¹æœŸé™ãŒåˆ‡ã‚Œã¾ã—ãŸã€‚テストã«å‚åŠ ã—ã¦ãã ã•りã‚りãŒã¨ã†ã”ã–ã„ã¾ã™ï¼</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">ナビゲーションを開ã</string> + <string name="nav_drawer_close_description">ナビゲーションを閉ã˜ã‚‹</string> + <string name="contact_list_button">連絡先</string> + <string name="groups_button">Private Groups</string> + <string name="forums_button">フォーラム</string> + <string name="blogs_button">Blogs</string> + <string name="settings_button">Settings</string> + <string name="sign_out_button">サインアウト</string> + <!--Transports--> + <string name="transport_tor">インターãƒãƒƒãƒˆ</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="ongoing_notification_title">Briarã«ã‚µã‚¤ãƒ³ã‚¤ãƒ³</string> + <string name="ongoing_notification_text">Briarã‚’é–‹ã</string> + <plurals name="private_message_notification_text"> + <item quantity="other">%dä»¶ã®æ–°è¦ãƒ—ライベートメッセージ</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="other">%dä»¶ã®æ–°è¦ã‚°ãƒ«ãƒ¼ãƒ—メッセージ</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="other">%dä»¶ã®æ–°è¦ãƒ•ォーラム投稿</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="other">%dä»¶ã®æ–°è¦ãƒ–ãƒã‚°ãƒã‚¹ãƒˆ</item> + </plurals> + <!--Misc--> + <string name="now">ç¾åœ¨</string> + <string name="show">表示</string> + <string name="hide">éžè¡¨ç¤º</string> + <string name="ok">OK</string> + <string name="cancel">ã‚ャンセル</string> + <string name="got_it">了解</string> + <string name="delete">削除</string> + <string name="accept">承èª</string> + <string name="decline">å´ä¸‹</string> + <string name="options">オプション</string> + <string name="online">オプション</string> + <string name="offline">オフライン</string> + <string name="send">é€ä¿¡</string> + <string name="allow">許å¯</string> + <string name="open">é–‹ã</string> + <string name="no_data">データãªã—</string> + <string name="ellipsis">...</string> + <string name="text_too_long">入力ã•ã‚ŒãŸæ–‡ç« ãŒé•·ã™ãŽã¾ã™ã€‚</string> + <string name="show_onboarding">ヘルプを表示</string> + <string name="help">ヘルプ</string> + <!--Contacts and Private Conversations--> + <string name="date_no_private_messages">メッセージãŒã‚りã¾ã›ã‚“。</string> + <string name="message_hint">メッセージ入力</string> + <string name="delete_contact">連絡先を削除</string> + <string name="contact_deleted_toast">連絡先ã®å‰Šé™¤å®Œäº†</string> + <!--Adding Contacts--> + <string name="add_contact_title">é€£çµ¡å…ˆã‚’è¿½åŠ </string> + <string name="continue_button">ç¶šã‘ã‚‹</string> + <string name="connection_failed">接続失敗</string> + <string name="try_again_button">ã‚‚ã†ä¸€åº¦ã‚„り直ã—ã¦ãã ã•ã„</string> + <!--Introductions--> + <!--Private Groups--> + <string name="groups_remove">削除</string> + <string name="groups_create_group_title">プライベートグループ作æˆ</string> + <string name="groups_create_group_button">グループ作æˆ</string> + <string name="groups_create_group_invitation_button">招待ã™ã‚‹</string> + <string name="groups_create_group_hint">プライベートグループã«åå‰ã‚’ã¤ã‘ã‚‹</string> + <string name="groups_member_list">メンãƒãƒ¼ä¸€è¦§</string> + <!--Private Group Invitations--> + <!--Private Groups Revealing Contacts--> + <!--Forums--> + <string name="btn_reply">返信</string> + <!--Forum Sharing--> + <!--Blogs--> + <string name="blogs_publish_blog_post">公開</string> + <string name="blogs_remove_blog_ok">解除</string> + <!--Blog Sharing--> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import_button">インãƒãƒ¼ãƒˆ</string> + <string name="blogs_rss_feeds_manage_author">著者:</string> + <string name="blogs_rss_feeds_manage_updated">最終更新:</string> + <string name="blogs_rss_remove_feed_ok">解除</string> + <!--Settings Display--> + <string name="display_settings_title">表示</string> + <string name="pref_theme_title">テーマ</string> + <string name="pref_theme_light">ライト</string> + <string name="pref_theme_dark">ダーク</string> + <string name="pref_theme_system">システムデフォルト</string> + <!--Settings Network--> + <string name="tor_network_setting_never">二度ã¨ã—ãªã„</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">ã‚»ã‚ュリティ</string> + <string name="change_password">パスワードã®å¤‰æ›´</string> + <string name="confirm_new_password">æ–°ã—ã„パスワードã®ç¢ºèª</string> + <string name="panic_app_setting_none">ãªã—</string> + <string name="panic_setting_signout_title">サインアウト</string> + <string name="purge_setting_title">アカウントを削除</string> + <!--Settings Notifications--> + <string name="notification_settings_title">通知</string> + <string name="notify_private_messages_setting_title">プライベート・メッセージ</string> + <string name="notify_lock_screen_setting_title">ãƒãƒƒã‚¯ç”»é¢</string> + <string name="notify_sound_setting_disabled">ãªã—</string> + <!--Settings Feedback--> + <!--Link Warning--> + <!--Crash Reporter--> + <string name="close">é–‰ã˜ã‚‹</string> + <!--Sign Out--> + <!--Screen Filters & Tapjacking--> + <!--Permission Requests--> +</resources> diff --git a/mailbox-android/src/main/res/values-ms/strings.xml b/mailbox-android/src/main/res/values-ms/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..305294f28d34ac111e53a7c0fc93c85ed6c3d346 --- /dev/null +++ b/mailbox-android/src/main/res/values-ms/strings.xml @@ -0,0 +1,77 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Tetapan Briar</string> + <string name="choose_nickname">Pilih nama samaran anda:</string> + <string name="choose_password">Pilih kata laluan anda:</string> + <string name="confirm_password">Pastikan kata laluan ada:</string> + <string name="name_too_long">Nama samaran terlalu panjang</string> + <string name="password_too_weak">Kata laluan terlalu lemah</string> + <string name="passwords_do_not_match">Kata laluan tidak sepadan</string> + <!--Login--> + <string name="enter_password">Masukkan kata laluan anda:</string> + <string name="startup_failed_notification_title">Briar gagal dimulakan</string> + <string name="startup_failed_notification_text">Anda perlu pasang ulang Briar.</string> + <string name="expiry_date_reached">Aplikasi ini telah tamat tempoh.\nSila pasang ulang versi baru.</string> + <!--Navigation Drawer--> + <string name="contact_list_button">Kenalan</string> + <string name="forums_button">Forum</string> + <string name="settings_button">Tetapan</string> + <string name="sign_out_button">Daftar Keluar</string> + <!--Transports--> + <!--Notifications--> + <string name="ongoing_notification_title">Briar sedang berjalan</string> + <plurals name="private_message_notification_text"> + <item quantity="other">%d mesej peribadi baru.</item> + </plurals> + <!--Misc--> + <string name="cancel">Batal</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Tiada kenalan</string> + <string name="no_private_messages">Tiada mesej</string> + <string name="delete_contact">Padam kenalan</string> + <string name="contact_deleted_toast">Kenalan telah dipadam</string> + <!--Adding Contacts--> + <string name="add_contact_title">Tambah kenalan</string> + <string name="continue_button">Teruskan</string> + <string name="your_invitation_code">Kod jemputan anda adalah</string> + <string name="enter_invitation_code">Sila masukkan kod jemputan kenalan anda:</string> + <string name="connection_failed">Sambungan gagal</string> + <string name="could_not_find_contact">Briar tidak dapat mencari kenalan anda berhampiran</string> + <string name="connected_to_contact">Tersambung dengan kenalan</string> + <string name="calculating_confirmation_code">Sedang mencuba kod pengesahan\u2026</string> + <string name="your_confirmation_code">Kod pengesahan anda adalah</string> + <string name="enter_confirmation_code">Sila masukkan kod pengesahan kenalan anda:</string> + <string name="waiting_for_contact">Sedang menunggu kenalan\u2026</string> + <string name="exchanging_contact_details">Sedang bertukar butiran kenalan\u2026</string> + <string name="codes_do_not_match">Kod tidak sepadan</string> + <string name="interfering">Ini menunjukkan bahawa seseorang sedang mengganggu sambungan anda</string> + <string name="contact_added_toast">Kenalan telah ditambah: %s</string> + <!--Introductions--> + <!--Private Groups--> + <!--Private Group Invitations--> + <!--Private Groups Revealing Contacts--> + <!--Forums--> + <string name="create_forum_title">Cipta forum baru</string> + <string name="choose_forum_name">Pilih nama untuk forum anda:</string> + <string name="forum_created_toast">Forum telah dicipta</string> + <!--Forum Sharing--> + <!--Blogs--> + <!--Blog Sharing--> + <!--RSS Feeds--> + <!--Settings Network--> + <string name="bluetooth_setting_disabled">Hanya ketika menambah kenalan</string> + <!--Settings Security and Panic--> + <!--Settings Notifications--> + <string name="notify_private_messages_setting">Papar notifikasi untuk mesej peribadi</string> + <string name="notify_vibration_setting">Getar</string> + <string name="notify_sound_setting">Bunyi</string> + <string name="notify_sound_setting_default">Nada bunyi asal</string> + <string name="notify_sound_setting_disabled">Tiada</string> + <string name="choose_ringtone_title">Pilih nada bunyi</string> + <!--Settings Feedback--> + <!--Link Warning--> + <!--Crash Reporter--> + <string name="crash_report_title">Laporan Kesalahan Briar</string> + <!--Sign Out--> +</resources> diff --git a/mailbox-android/src/main/res/values-nb/strings.xml b/mailbox-android/src/main/res/values-nb/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..dd09db1e4f652a46a4e7e26f72a7d3614cdd98e7 --- /dev/null +++ b/mailbox-android/src/main/res/values-nb/strings.xml @@ -0,0 +1,356 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Velkommen til Briar</string> + <string name="setup_name_explanation">Ditt kallenavn vil bli vist ved siden av innhold du poster. Du kan endre det etter at du har opprettet kontoen din.</string> + <string name="setup_next">Neste</string> + <string name="setup_password_intro">Velg et passord</string> + <string name="setup_password_explanation">Din Briar-konto er lagret kryptert pÃ¥ din enhet, ikke i skyen. Hvis du avinstallerer Briar eller glemmer passordet ditt, gÃ¥r det ikke an Ã¥ gjenopprette kontoen din..\n\nVelg et langt passord som er vanskelig Ã¥ gjette, som fire tilfeldige ord, eller ti tilfeldige bokstaver, tall og symboler.</string> + <string name="setup_doze_title">Bakgrunnstilkoblinger</string> + <string name="setup_doze_intro">For Ã¥ motta meldinger, mÃ¥ Briar forbli tilkoblet i bakgrunnen.</string> + <string name="setup_doze_explanation">For Ã¥ motta meldinger, mÃ¥ Briar forbli tilkoblet i bakgrunnen. Skru av batterioptimiseringer slik at Briar kan forbli tilkoblet.</string> + <string name="setup_doze_button">Tillat tilkoblinger</string> + <string name="choose_nickname">Velg kallenavn</string> + <string name="choose_password">Velg passord</string> + <string name="confirm_password">Bekreft passord</string> + <string name="name_too_long">For langt navn</string> + <string name="password_too_weak">Passordet er for svakt</string> + <string name="passwords_do_not_match">Passordene samsvarer ikke</string> + <string name="create_account_button">Opprett konto</string> + <string name="more_info">Ytterligere informasjon</string> + <string name="don_t_ask_again">Ikke spør igjen</string> + <string name="setup_huawei_text">Trykk pÃ¥ knappen nedenfor for Ã¥ forsikre at Briar er beskyttet i \"Beskyttede programmer\".</string> + <string name="setup_huawei_button">Beskytt Briar</string> + <string name="setup_huawei_help">Hvis Briar ikke er lagt til i listen over beskyttede programmer, vil det ikke kunne kjøre i bakgrunnen.</string> + <string name="warning_dozed">%s klarte ikke Ã¥ kjøre i bakgrunnen</string> + <!--Login--> + <string name="enter_password">Passord</string> + <string name="try_again">Feil passord, prøv igjen</string> + <string name="sign_in_button">Logg inn</string> + <string name="forgotten_password">Jeg har glemt passordet mitt</string> + <string name="dialog_title_lost_password">Tapt passord</string> + <string name="dialog_message_lost_password">Din Briar-konto er lagret kryptert pÃ¥ din enhet, ikke i skyen, sÃ¥ du kan ikke tilbakestille passordet ditt. Ønsker du Ã¥ slette kontoen og starte igjen?\n\nMerk: Identitetene dine, kontaktene og meldingene vil gÃ¥ tapt for alltid.</string> + <string name="startup_failed_notification_title">Briar kunne ikke starte</string> + <string name="startup_failed_activity_title">Oppstartsfeil med Briar</string> + <string name="startup_failed_service_error">Briar kunne ikke starte det nødvendige programtillegget. Reinstallasjon av Briar fikser vanligvis dette problemet. Merk deg dog at kontoen og all data tilknyttet den vil gÃ¥ tapt for godt siden Briar ikke bruker sentrale tjenere Ã¥ lagre dataen din pÃ¥.</string> + <plurals name="expiry_warning"> + <item quantity="one">Dette er en test-versjon av Briar. Din konto vil utløpe om %d dag, og kan ikke fornyes.</item> + <item quantity="other">Dette er en test-versjon av Briar. Din konto vil utløpe om %d dager og kan ikke fornyes.</item> + </plurals> + <string name="expiry_update">Utløpsdatoen for testing har blitt forskjøvet. Kontoen din vil nÃ¥ utløpe om %d dager.</string> + <string name="expiry_date_reached">Denne programvaren har utløpt.\nTakk for at du testet den.</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Ã…pne navigasjonsskuffen</string> + <string name="nav_drawer_close_description">Lukk navigasjonsskuffen</string> + <string name="contact_list_button">Kontakter</string> + <string name="groups_button">Private grupper</string> + <string name="forums_button">Forum</string> + <string name="blogs_button">Blogger</string> + <string name="settings_button">Innstillinger</string> + <string name="sign_out_button">Logg ut</string> + <!--Transports--> + <string name="transport_tor">Internett</string> + <string name="transport_bt">BlÃ¥tann</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="ongoing_notification_title">Logget inn pÃ¥ Briar</string> + <string name="ongoing_notification_text">Trykk for Ã¥ Ã¥pne Briar.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Ny privat melding.</item> + <item quantity="other">%d nye private meldinger.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Ny gruppemelding.</item> + <item quantity="other">%d nye gruppemelindger.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Ny forumpost.</item> + <item quantity="other">%d nye forumposter.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Ny bloggpost.</item> + <item quantity="other">%d nye bloggposter.</item> + </plurals> + <!--Misc--> + <string name="now">nÃ¥</string> + <string name="show">Vis</string> + <string name="hide">Skjul</string> + <string name="ok">OK</string> + <string name="cancel">Avbryt</string> + <string name="got_it">Skjønner</string> + <string name="delete">Slett</string> + <string name="accept">Godta</string> + <string name="decline">AvslÃ¥</string> + <string name="options">Valg</string> + <string name="online">PÃ¥logget</string> + <string name="offline">Frakoblet</string> + <string name="send">Send</string> + <string name="allow">Tillat</string> + <string name="open">Ã…pne</string> + <string name="no_data">Ingen data</string> + <string name="ellipsis">…</string> + <string name="text_too_long">Innskrevet tekst er for lang</string> + <string name="show_onboarding">Vis hjelpedialogvindu</string> + <string name="fix">Fiks</string> + <string name="help">Hjelp</string> + <!--Contacts and Private Conversations--> + <string name="date_no_private_messages">Ingen meldinger.</string> + <string name="message_hint">Skriv melding</string> + <string name="delete_contact">Slett kontakt</string> + <string name="dialog_title_delete_contact">Bekreft sletting av kontakt</string> + <string name="dialog_message_delete_contact">Er du sikker pÃ¥ at du vil fjerne denne kontakten og alle meldinger utvekslet med denne kontakten?</string> + <string name="contact_deleted_toast">Kontakt slettet</string> + <!--Adding Contacts--> + <string name="add_contact_title">Legg til en kontakt</string> + <string name="face_to_face">Du mÃ¥ møte personen du ønsker Ã¥ legge til som kontakt.\n\nDette vil forhindre folk fra Ã¥ etterligne deg eller lese meldingene dine i fremtiden.</string> + <string name="continue_button">Fortsett</string> + <string name="connection_failed">Tilkobling mislyktes</string> + <string name="try_again_button">Prøv igjen</string> + <string name="waiting_for_contact_to_scan">Venter pÃ¥ at kontakten skal skanne og koble til\u2026</string> + <string name="exchanging_contact_details">Utveksler kontaktdetaljer\u2026</string> + <string name="contact_added_toast">Kontakt lagt til: %s</string> + <string name="contact_already_exists">Kontakten %s finnes allerede</string> + <string name="contact_exchange_failed">Kontaktutveksling mislyktes</string> + <string name="qr_code_invalid">QR-koden er ugyldig</string> + <string name="camera_error">Kamerafeil</string> + <string name="connecting_to_device">Kobler til enhet\u2026</string> + <string name="authenticating_with_device">Autentiserer med enhet\u2026</string> + <string name="connection_aborted_local">Tilkobling avbrutt! Dette kan bety at noen prøver Ã¥ tukle med tilkoblingen din</string> + <string name="connection_aborted_remote">Tilkobling avbrutt av din kontakt! Dette kan bety at noen prøver Ã¥ tukle med vedkommendes tilkobling</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Introduser kontaktene dine</string> + <string name="introduction_onboarding_text">Du kan introdusere dine kontakter til hverandre, slik at de ikke trenger Ã¥ møtes personlig for Ã¥ treffes pÃ¥ Briar.</string> + <string name="introduction_menu_item">Introduser ovenfor hverandre</string> + <string name="introduction_activity_title">Velg kontakt</string> + <string name="introduction_message_title">Introduser kontakter</string> + <string name="introduction_message_hint">Legg til melding (valgfritt)</string> + <string name="introduction_button">Introduser ovenfor hverandre</string> + <string name="introduction_sent">Din introduksjon har blitt sendt.</string> + <string name="introduction_error">Feil under utstedelse av introduksjon.</string> + <string name="introduction_response_error">Feil under svar pÃ¥ introduksjon</string> + <string name="introduction_request_sent">Du har spurt %1$s om Ã¥ bli introdusert ovenfor %2$s.</string> + <string name="introduction_request_received">%1$s har spurt om Ã¥ introdusere deg ovenfor %2$s. Ønsker du Ã¥ legge til %2$s pÃ¥ din kontaktliste?</string> + <string name="introduction_request_exists_received">%1$s har spurt om Ã¥ introdusere deg ovenfor %2$s, men %2$s er allerede pÃ¥ din kontaktliste. Siden %1$s kanskje ikke vet dette, kan du fremdeles svare:</string> + <string name="introduction_request_answered_received">%1$s har spurt om Ã¥ introdusere deg ovenfor %2$s.</string> + <string name="introduction_response_accepted_sent">Du er nÃ¥ bekjent %1$s.</string> + <string name="introduction_response_declined_sent">Du avslo introduksjonen med %1$s.</string> + <string name="introduction_response_accepted_received">%1$s er nÃ¥ bekjent %2$s.</string> + <string name="introduction_response_declined_received">%1$s avslo introduksjonen med %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s sier at %2$s avslo introduksjonen.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Ny kontakt lagt til.</item> + <item quantity="other">%d nye kontakter lagt til.</item> + </plurals> + <!--Private Groups--> + <string name="groups_created_by">Opprettet av %s</string> + <plurals name="messages"> + <item quantity="one">%d melding</item> + <item quantity="other">%d meldinger</item> + </plurals> + <string name="groups_group_is_empty">Denne gruppen er tom</string> + <string name="groups_group_is_dissolved">Denne gruppen har blitt oppløst</string> + <string name="groups_remove">Fjern</string> + <string name="groups_create_group_title">Opprett privat gruppe</string> + <string name="groups_create_group_button">Opprett gruppe</string> + <string name="groups_create_group_invitation_button">Send invitasjon</string> + <string name="groups_create_group_hint">Velg et navn for din private gruppe</string> + <string name="groups_invitation_sent">Gruppeinvitasjon sendt</string> + <string name="groups_message_sent">Melding sendt</string> + <string name="groups_member_list">Medlemsliste</string> + <string name="groups_invite_members">Inviter medlemmer</string> + <string name="groups_member_created_you">Du opprettet gruppen</string> + <string name="groups_member_created">%s opprettet gruppen</string> + <string name="groups_member_joined_you">Du tok del i gruppen</string> + <string name="groups_member_joined">%s tok del i gruppen</string> + <string name="groups_leave">Forlat gruppe</string> + <string name="groups_leave_dialog_title">Bekreft at du vil forlate gruppen</string> + <string name="groups_leave_dialog_message">Er du sikker pÃ¥ at du vil forlate denne gruppen?</string> + <string name="groups_dissolve">Oppløs gruppe</string> + <string name="groups_dissolve_dialog_title">Bekreft oppløsning av gruppe</string> + <string name="groups_dissolve_dialog_message">Er du sikker pÃ¥ at du vil oppløse denne gruppen?\n\nAlle andre medlemmer vil ikke kunne fortsette deres samtaler, og vil kanskje ikke motta de seneste meldingene.</string> + <string name="groups_dissolve_button">Oppløs</string> + <string name="groups_dissolved_dialog_title">Gruppen har blitt oppløst</string> + <string name="groups_dissolved_dialog_message">Oppretteren av denne gruppen har oppløst den.\n\nDu kan ikke lenger skrive meldinger til gruppen, og vil kanskje ikke fÃ¥ alle poster som har blitt skrevet.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Gruppeinvitasjoner</string> + <string name="groups_invitations_invitation_sent">Du har invitert %1$s til Ã¥ ta del i gruppen \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s har inviter deg til Ã¥ ta del i gruppen \"%2$s\".</string> + <string name="groups_invitations_joined">Tok del i gruppe</string> + <string name="groups_invitations_declined">Gruppeinvitasjon avslÃ¥tt</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d Ã¥pen gruppeinvitasjon</item> + <item quantity="other">%d Ã¥pne gruppeinvitasjoner</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Du godtok gruppeinvitasjonen fra %s.</string> + <string name="groups_invitations_response_declined_sent">Du avslo gruppeinvitasjoner fra %s.</string> + <string name="groups_invitations_response_accepted_received">%s godtok gruppeinvitasjonen.</string> + <string name="groups_invitations_response_declined_received">%s avslo gruppeinvitasjonen</string> + <string name="sharing_status_groups">Bare grunnleggeren kan invitere nye medlemmer til gruppen. Nedenfor har du alle medlemmene i den.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Avslør kontakter</string> + <string name="groups_reveal_dialog_message">Du kan velge hvorvidt du vil tilkjennegi kontakter ovenfor alle nÃ¥værende og fremtidige medlemmer av denne gruppen.\n\nDette gjør tilkoblingen til gruppen raskere og mer pÃ¥litelig, fordi du kan kommunisere med tilkjennegitte kontakter selv om grunnleggeren av gruppen er frakoblet.</string> + <string name="groups_reveal_visible">Kontaktforhold er synlige for gruppen</string> + <string name="groups_reveal_visible_revealed_by_us">Kontaktforhold er synlige for gruppen (avslørt av deg)</string> + <string name="groups_reveal_visible_revealed_by_contact">Kontaktforhold er synlige for gruppen (avslørt av %s)</string> + <string name="groups_reveal_invisible">Kontaktforhold er ikke synlige for gruppen</string> + <!--Forums--> + <string name="create_forum_title">Opprett forum</string> + <string name="choose_forum_hint">Velg et navn for ditt forum</string> + <string name="create_forum_button">Opprett forum</string> + <string name="forum_created_toast">Forum opprettet</string> + <string name="no_posts">Ingen poster</string> + <plurals name="posts"> + <item quantity="one">%d post</item> + <item quantity="other">%d poster</item> + </plurals> + <string name="forum_message_reply_hint">Nytt svar</string> + <string name="btn_reply">Svar</string> + <string name="forum_leave">Forlat forum</string> + <string name="dialog_title_leave_forum">Bekreft forlating av forum</string> + <string name="dialog_button_leave">Forlat</string> + <!--Forum Sharing--> + <string name="forum_share_button">Del forum</string> + <string name="contacts_selected">Kontakter valgt</string> + <string name="activity_share_toolbar_header">Velg kontakter</string> + <string name="forum_shared_snackbar">Forum delt med valgte kontakter</string> + <string name="forum_share_message">Legg til melding (valgfritt)</string> + <string name="forum_share_error">Feil ved deling av dette forumet.</string> + <string name="forum_invitation_received">%1$s har delt forumet \"%2$s\" med deg.</string> + <string name="forum_invitation_sent">Du har det forumet \"%1$s\" med %2$s.</string> + <string name="forum_invitations_title">Foruminvitasjoner</string> + <string name="shared_by_format">Delt av %s</string> + <string name="forum_invitation_already_sharing">Deler allerede</string> + <string name="forum_invitation_response_accepted_sent">Du godtok foruminvitasjonen fra %s.</string> + <string name="forum_invitation_response_declined_sent">Du avslo foruminvitasjonen fra %s.</string> + <string name="forum_invitation_response_accepted_received">%s godtok foruminvitasjonen.</string> + <string name="forum_invitation_response_declined_received">%s avslo foruminvitasjonen.</string> + <string name="sharing_status">Delingsstatus</string> + <string name="sharing_status_forum">Ethvert medlem av et forum kan dele det med sine kontakter. Du deler dette forumet med følgende kontakter. Det kan ogsÃ¥ være andre medlemmer du ikke kan se.</string> + <string name="shared_with">Delt med %1$d (%2$d pÃ¥logget)</string> + <plurals name="forums_shared"> + <item quantity="one">%d forum delt av kontakter</item> + <item quantity="other">%d forum delt av kontakter</item> + </plurals> + <string name="nobody">Ingen</string> + <!--Blogs--> + <string name="read_more">les mer</string> + <string name="blogs_write_blog_post">Skriv bloggpost</string> + <string name="blogs_publish_blog_post">Offentliggjør</string> + <string name="blogs_blog_post_created">Bloggpost opprettet</string> + <string name="blogs_blog_post_received">Ny bloggpost opprettet</string> + <string name="blogs_blog_post_scroll_to">Rull til</string> + <string name="blogs_remove_blog">Fjern blogg</string> + <string name="blogs_remove_blog_ok">Fjern</string> + <string name="blogs_reblog_comment_hint">Legg til en kommentar (valgfritt)</string> + <string name="blogs_reblog_button">Blogg dette</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Del blogg</string> + <string name="blogs_sharing_error">Feil under deling av denne bloggen.</string> + <string name="blogs_sharing_button">Del blogg</string> + <string name="blogs_sharing_snackbar">Blogg delt med valgte kontakter</string> + <string name="blogs_sharing_response_accepted_sent">Du godtok blogg-invitasjonen fra %s.</string> + <string name="blogs_sharing_response_declined_sent">Du avslo blogg-invitasjonen fra %s.</string> + <string name="blogs_sharing_response_accepted_received">%s godtok blogg-invitasjonen.</string> + <string name="blogs_sharing_response_declined_received">%s avslo blogg-invitasjonen.</string> + <string name="blogs_sharing_invitation_received">%1$s har delt bloggen \"%2$s\" med deg.</string> + <string name="blogs_sharing_invitation_sent">Du har delt bloggen \"%1$s\" med %2$s.</string> + <string name="blogs_sharing_invitations_title">Blogginvitasjoner</string> + <string name="sharing_status_blog">Enhver som abonnerer pÃ¥ bloggen kan dele den med sine kontakter. Du deler denne bloggen med følgende kontakter. Det kan ogsÃ¥ være andre abonnementer du ikke kan se.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Importer RSS-strøm</string> + <string name="blogs_rss_feeds_import_button">Importer</string> + <string name="blogs_rss_feeds_import_hint">Skriv inn nettadresse for RSS-strøm</string> + <string name="blogs_rss_feeds_import_error">Vi beklager! Feil under importering av strøm.</string> + <string name="blogs_rss_feeds_manage">Behandle RSS-strømmer</string> + <string name="blogs_rss_feeds_manage_imported">Importert:</string> + <string name="blogs_rss_feeds_manage_author">Forfatter:</string> + <string name="blogs_rss_feeds_manage_updated">Sist oppdatert:</string> + <string name="blogs_rss_remove_feed">Fjern strøm</string> + <string name="blogs_rss_remove_feed_ok">Fjern</string> + <string name="blogs_rss_feeds_manage_delete_error">Strømmen kunne ikke fjernes!</string> + <string name="blogs_rss_feeds_manage_error">Feil ved lasting av dine strømmer. Prøv igjen senere.</string> + <!--Settings Display--> + <string name="display_settings_title">Vis</string> + <string name="pref_theme_system">Systemforvalg</string> + <!--Settings Network--> + <string name="network_settings_title">Nettverk</string> + <string name="bluetooth_setting">Koble til via BlÃ¥tann</string> + <string name="bluetooth_setting_enabled">NÃ¥r kontakter er i nærheten</string> + <string name="bluetooth_setting_disabled">Bare nÃ¥r kontakter legges til</string> + <string name="tor_network_setting">Koble til via Tor</string> + <string name="tor_network_setting_never">Aldri</string> + <string name="tor_network_setting_wifi">Bare pÃ¥ Wi-Fi</string> + <string name="tor_network_setting_always">NÃ¥r Wi-Fi eller mobildata brukes</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Sikkerhet</string> + <string name="change_password">Endre passord</string> + <string name="choose_new_password">Nytt passord</string> + <string name="confirm_new_password">Bekreft nytt passord</string> + <string name="password_changed">Passordet har blitt endret.</string> + <string name="panic_setting">Oppsett av panikk-knapp</string> + <string name="panic_setting_title">Panikk-knapp</string> + <string name="panic_setting_hint">Sett opp hvordan Briar vil reagere nÃ¥r du bruker panikk-knapp-programmet</string> + <string name="panic_app_setting_title">Panikk-knapp-program</string> + <string name="unknown_app">et ukjent program</string> + <string name="panic_app_setting_summary">Inget program har blitt satt</string> + <string name="panic_app_setting_none">Inget</string> + <string name="dialog_title_connect_panic_app">Bekreft panikk-knapp-program</string> + <string name="dialog_message_connect_panic_app">Er du sikker pÃ¥ at du vil tillate %1$s Ã¥ utløse destruktive panikk-knapp-handlinger?</string> + <string name="panic_setting_signout_title">Logg ut</string> + <string name="panic_setting_signout_summary">Logg ut av Briar hvis panikk-knappen trykkes</string> + <string name="purge_setting_title">Slett konto</string> + <string name="purge_setting_summary">Slett Briar-kontoen din hvis panikk-knappen trykkes. Advarsel: Dette vil slette dine identiteter, kontakter og meldinger for godt.</string> + <string name="uninstall_setting_title">Avinstaller Briar</string> + <string name="uninstall_setting_summary">Dette krever manuell bekreftelse i panikkfall</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Merknader</string> + <string name="notify_private_messages_setting_title">Private meldinger</string> + <string name="notify_private_messages_setting_summary">Vis varsler for private meldinger</string> + <string name="notify_group_messages_setting_title">Gruppemeldinger</string> + <string name="notify_group_messages_setting_summary">Vis varsler for gruppemeldinger</string> + <string name="notify_forum_posts_setting_title">Forumposter</string> + <string name="notify_forum_posts_setting_summary">Vis varsler for forumposter</string> + <string name="notify_blog_posts_setting_title">Bloggposter</string> + <string name="notify_blog_posts_setting_summary">Vis varsler for bloggposter</string> + <string name="notify_vibration_setting">Vibrer</string> + <string name="notify_lock_screen_setting_title">LÃ¥seskjerm</string> + <string name="notify_lock_screen_setting_summary">Vis merknader pÃ¥ lÃ¥seskjermen</string> + <string name="notify_sound_setting">Lyd</string> + <string name="notify_sound_setting_default">Forvalgt ringetone</string> + <string name="notify_sound_setting_disabled">Ingen</string> + <string name="choose_ringtone_title">Velg ringetone</string> + <string name="cannot_load_ringtone">Kan ikke laste inn ringetone</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Tilbakemelding</string> + <string name="send_feedback">Send tilbakemelding</string> + <!--Link Warning--> + <string name="link_warning_title">Lenkeadvarsel</string> + <string name="link_warning_intro">Du er i ferd med Ã¥ følge en lenke med et eksternt program.</string> + <string name="link_warning_text">Dette kan brukes for Ã¥ identifisere deg. Tenk deg om hvorvidt du stoler pÃ¥ personen som sendte denne lenken til deg, og overvei Ã¥ Ã¥pne den i Orfox.</string> + <string name="link_warning_open_link">Ã…pne lenke</string> + <!--Crash Reporter--> + <string name="crash_report_title">Kræsjrapport for Briar</string> + <string name="briar_crashed">Beklager, Briar har kræsjet.</string> + <string name="not_your_fault">Dette er ikke din feil.</string> + <string name="please_send_report">Hjelp til med Ã¥ forbedre Briar ved Ã¥ sende en kræsjrapport.</string> + <string name="report_is_encrypted">Kræsjrapporten vil sendes kryptert og sikkert.</string> + <string name="feedback_title">Tilbakemelding</string> + <string name="describe_crash">Beskriv hva som skjedde (valgfritt)</string> + <string name="enter_feedback">Skriv inn din tilbakemelding</string> + <string name="optional_contact_email">Din e-postadresse (valgfri)</string> + <string name="include_debug_report_crash">Inkluder anonym data om kræsjet</string> + <string name="include_debug_report_feedback">Inkluder anonym data om denne enheten</string> + <string name="could_not_load_report_data">Kunne ikke laste inn kræsjrapportdata.</string> + <string name="send_report">Send kræsjrapport</string> + <string name="close">Lukk</string> + <string name="dev_report_saved">Kræsjrapport lagret. Den vil bli sendt neste gang du logger inn i Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">Logger ut av Briar…</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Skjermoverlag oppdaget</string> + <!--Permission Requests--> + <string name="permission_camera_title">Kameratilgang</string> + <string name="permission_camera_request_body">For Ã¥ skanne QR-koden, trenger Briar tilgang til kameraet.</string> + <string name="permission_camera_denied_body">Du har nektet tilgang til kameraet, men tillegg av kontakter krever bruk av kameraet.\n\nOvervei Ã¥ innvilge tilgang.</string> + <string name="permission_camera_denied_toast">Kameratilgang ble ikke innvilget</string> +</resources> diff --git a/mailbox-android/src/main/res/values-night/color.xml b/mailbox-android/src/main/res/values-night/color.xml new file mode 100644 index 0000000000000000000000000000000000000000..130accabe020d9542ab424acce474acddc7290e4 --- /dev/null +++ b/mailbox-android/src/main/res/values-night/color.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="briar_primary">@color/briar_blue_dark</color> + <color name="briar_accent">@color/briar_green</color> + + <color name="preference_category">@color/briar_accent</color> + <color name="preference_category_background">@color/briar_black_almost</color> + + <color name="color_primary">@color/briar_white</color> + + <color name="msg_in">@color/briar_blue</color> + <color name="msg_out">@color/briar_blue_elio_light</color> + <color name="notice_in">@color/briar_blue_dark</color> + <color name="notice_out">@color/briar_blue_elio</color> + <color name="msg_stroke">@color/msg_stroke_dark</color> + + <color name="window_background">@color/briar_blue_very_dark</color> + <color name="card_background">@color/briar_blue_dark</color> + <color name="item_background_highlight">@color/briar_blue</color> + + <color name="briar_button_background_color">@color/briar_blue_medium</color> + <color name="briar_button_text_neutral">@color/briar_blue_light</color> + <color name="briar_button_text_disabled">#23cccccc</color> + + <color name="thread_indicator">@color/briar_blue</color> + <color name="thread_item_background">@color/window_background</color> + <color name="thread_item_highlight">@color/briar_black</color> + + <color name="divider">@color/briar_black</color> +</resources> \ No newline at end of file diff --git a/mailbox-android/src/main/res/values-nl/strings.xml b/mailbox-android/src/main/res/values-nl/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..7e1551e8e7ea8e8bf43843d3cd1170230a48e81b --- /dev/null +++ b/mailbox-android/src/main/res/values-nl/strings.xml @@ -0,0 +1,413 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Welkom bij Briar</string> + <string name="setup_name_explanation">Je bijnaam wordt getoond bij alle content die je post. Nadat je account is aangemaakt is het niet mogelijk je bijnaam te wijzigen.</string> + <string name="setup_next">Volgende</string> + <string name="setup_password_intro">Voer een wachtwoord in</string> + <string name="setup_password_explanation">Je Briar-account is versleuteld opgeslagen op je apparaat, niet in de cloud. Als je je wachtzin vergeet of Briar deïnstalleert is er geen manier om je account te herstellen.\n\nKies een lange wachtzin dat moeilijk is om te raden, bijvoorbeeld vier willekeurige woorden of tien willekeurige letters, cijfers en symbolen.</string> + <string name="setup_doze_title">Achtergrondverbindingen</string> + <string name="setup_doze_intro">Om berichten te ontvangen dient Briar in de achtergrond verbonden te blijven.</string> + <string name="setup_doze_explanation">Briar moet in de achtergrond verbonden blijven om berichten te ontvangen. Schakel batterij-optimalisaties a.u.b. uit zodat Briar verbonden kan blijven.</string> + <string name="setup_doze_button">Sta verbindingen toe</string> + <string name="choose_nickname">Voer je bijnaam in</string> + <string name="choose_password">Voer je wachtwoord in</string> + <string name="confirm_password">Bevestig je wachtwoord</string> + <string name="name_too_long">Naam is te lang</string> + <string name="password_too_weak">Wachtwoord is te zwak</string> + <string name="passwords_do_not_match">Wachtwoorden komen niet overeen</string> + <string name="create_account_button">Maak account aan</string> + <string name="more_info">Meer informatie</string> + <string name="don_t_ask_again">Vraag niet nog een keer</string> + <string name="setup_huawei_text">Tap a.u.b. op de knop hieronder en ga na dat Briar is beschermd op het scherm \"Beveiligde apps\".</string> + <string name="setup_huawei_button">Bescherm Briar</string> + <string name="setup_huawei_help">Als Briar niet is toegevoegd aan de beschermde apps, is het niet mogelijk om het in de achtergrond te runnen.</string> + <string name="warning_dozed">%s kon niet in de achtergrond runnen</string> + <!--Login--> + <string name="enter_password">Wachtwoord</string> + <string name="try_again">Verkeerd wachtwoord, probeer het nog een keer</string> + <string name="sign_in_button">Log in</string> + <string name="forgotten_password">Ik ben mijn wachtwoord vergeten</string> + <string name="dialog_title_lost_password">Wachtwoord vergeten</string> + <string name="dialog_message_lost_password">Je Briar-account is versleuteld opgeslagen op je apparaat, niet in de cloud, dus kunnen we je wachtwoord niet resetten. Wil je je account verwijderen en opnieuw beginnen?\n\nLet op: Je identiteiten, contacten en berichten zullen permanent verloren gaan.</string> + <string name="startup_failed_notification_title">Briar kon niet opstarten</string> + <string name="startup_failed_notification_text">Tap voor meer informatie.</string> + <string name="startup_failed_activity_title">Opstarten Briar mislukt</string> + <string name="startup_failed_db_error">Om de een of andere reden is je Briar-database corrupt geraakt en niet meer te repareren. Je account, je gegevens en al je contacten zijn verloren. Helaas zul je Briar moeten herinstalleren en een nieuw account aan te maken met \'Ik ben mijn wachtwoord vergeten\' als om je wachtwoord wordt gevraagd.</string> + <string name="startup_failed_data_too_old_error">Je account was aangemaakt met een oude versie van deze app en kan met deze versie niet worden geopend. Je moet of de oude versie installeren of een nieuw account aanmaken door te kiezen \'Ik ben mijn wachtwoord vergeten\' als om je wachtwoord wordt gevraagd.</string> + <string name="startup_failed_data_too_new_error">Deze versie van de is app is te oud. Upgrade a.u.b. naar de laatste versie en probeer het nog een keer.</string> + <string name="startup_failed_service_error">Briar kon de vereiste plug-in niet starten. Herinstalleren van Briar lost dit probleem meestal op. Let op dat je al je je account en alle gegevens die daaraan vast zitten zal verliezen omdat Briar geen centrale servers gebruikt om gegevens op te slaan.</string> + <plurals name="expiry_warning"> + <item quantity="one">Dit is een testversie van Briar. Je account verloopt binnen %d dag en kan niet worden vernieuwd.</item> + <item quantity="other">Dit is een testversie van Briar. Je account verloopt binnen %d dagen en kan niet worden vernieuwd.</item> + </plurals> + <string name="expiry_update">De verloopdatum voor de test is vooruitgeschoven. Je account verloopt nu binnen %d dagen.</string> + <string name="expiry_date_reached">Deze software is verlopen.\nBedankt vor het testen!</string> + <string name="download_briar">Om Briar te blijven gebruiken, download a.u.b. versie 1.0.</string> + <string name="create_new_account">Je moet een nieuw account aanmaken. Je kan dezelfde bijnaam gebruiken.</string> + <string name="download_briar_button">Download Briar 1.0</string> + <string name="startup_open_database">Database aan het ontsleutelen…</string> + <string name="startup_migrate_database">Database aan het upgraden…</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Open de navigatielade</string> + <string name="nav_drawer_close_description">Sluit de navigatielade</string> + <string name="contact_list_button">Contacten</string> + <string name="groups_button">Privégroepen</string> + <string name="forums_button">Fora</string> + <string name="blogs_button">Blogs</string> + <string name="settings_button">Instellingen</string> + <string name="sign_out_button">Log uit</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wifi</string> + <!--Notifications--> + <string name="reminder_notification_title">Uitgelogd van Briar</string> + <string name="reminder_notification_text">Tik om opnieuw in te loggen.</string> + <string name="reminder_notification_channel_title">Briar inlogherinnering</string> + <string name="reminder_notification_dismiss">Afwijzen</string> + <string name="ongoing_notification_title">Ingelogd op Briar</string> + <string name="ongoing_notification_text">Raak aan om Briar te openen.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Nieuwe privéberichten.</item> + <item quantity="other">%d nieuwe privéberichten.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Nieuw groepsbericht.</item> + <item quantity="other">%d nieuwe groepsberichten.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Nieuwe forumpost.</item> + <item quantity="other">%d nieuww forumposts.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Nieuwe blogpost.</item> + <item quantity="other">%d nieuwe blogposts.</item> + </plurals> + <!--Misc--> + <string name="now">nu</string> + <string name="show">Toon</string> + <string name="hide">Verberg</string> + <string name="ok">Oké</string> + <string name="cancel">Annuleer</string> + <string name="got_it">Begrepen</string> + <string name="delete">Verwijder</string> + <string name="accept">Accepteer</string> + <string name="decline">Wijs af</string> + <string name="options">Opties</string> + <string name="online">Online</string> + <string name="offline">Offline</string> + <string name="send">Verstuur</string> + <string name="allow">Sta toe</string> + <string name="open">Open</string> + <string name="no_data">Geen gegevens</string> + <string name="ellipsis">…</string> + <string name="text_too_long">De ingevoerde tekst is te lang</string> + <string name="show_onboarding">Toon helpdialoog</string> + <string name="fix">Fiks</string> + <string name="help">Help</string> + <string name="sorry">Excuses</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Geen contacten om te tonen\n\nTik op het +-icoon om een contact toe te voegen</string> + <string name="date_no_private_messages">Geen berichten.</string> + <string name="no_private_messages">Geen berichten om te tonen</string> + <string name="message_hint">Schrijf een bericht</string> + <string name="delete_contact">Verwijder bericht</string> + <string name="dialog_title_delete_contact">Bevestig verwijderen contact</string> + <string name="dialog_message_delete_contact">Weet je zeker dat je dit contact en alle berichten die met dit contact zijn uitgewisseld wil verwijderen?</string> + <string name="contact_deleted_toast">Contact is verwijderd</string> + <!--Adding Contacts--> + <string name="add_contact_title">Voeg contact toe</string> + <string name="face_to_face">Je moet een persoon in levenden lijve ontmoeten om die als contact toe te voegen.\n\nDit voortkomt dat anderen zich als jou voor kunnen doen of in de toekomst je berichten kunnen lezen.</string> + <string name="continue_button">Ga verder</string> + <string name="connection_failed">Connectie is mislukt</string> + <string name="try_again_button">Probeer nog een keer</string> + <string name="waiting_for_contact_to_scan">Wacht op contact om te scannen en te verbinden\u2026</string> + <string name="exchanging_contact_details">Contactdetails aan het uitwisselen\u2026</string> + <string name="contact_added_toast">Contact toegevoegd: %s</string> + <string name="contact_already_exists">Contact %s bestaat al</string> + <string name="contact_exchange_failed">Uitwisselen contact is mislukt</string> + <string name="qr_code_invalid">De QR-code is ongeldig</string> + <string name="qr_code_unsupported">De QR-code die je probeert te scannen is van een oude ver van %s die niet meer wordt ondersteund.\n\nControleer a.u.b. dat jullie beide de laatste versie gebruiken en probeer het nog een keer.</string> + <string name="camera_error">Camerafout</string> + <string name="connecting_to_device">Aan het verbinden met apparaat\u2026</string> + <string name="authenticating_with_device">Aan het authentificeren met apparaat\u2026</string> + <string name="connection_aborted_local">Verbinding is verbroken! Dit kan betekenen dat iemand probeert zich met je verbinding probeert te bemoeien.</string> + <string name="connection_aborted_remote">Verbinding is door je contact verbroken! Dit kan betekenen dat iemand met je verbinding probeert te bemoeien</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Introduceer je contacten</string> + <string name="introduction_onboarding_text">Je kan je contacten aan elkaar introduceren zodat ze niet in levenden lijve elkaar te hoeven ontmoeten om op Briar in contact te komen.</string> + <string name="introduction_menu_item">Introduceer</string> + <string name="introduction_activity_title">Selecteer contact</string> + <string name="introduction_not_possible">Je bent al met een introductie bezig met deze contacten. Laat dit a.u.b. eerst voltooien. Als jij of je contact weinig online zijn, kan dit even duren.</string> + <string name="introduction_message_title">Intoduceer contacten</string> + <string name="introduction_message_hint">Voeg een bericht toe (optioneel)</string> + <string name="introduction_button">Introduceer</string> + <string name="introduction_sent">Je introductie is verzonden</string> + <string name="introduction_error">Er trad een fout op tijdens het aanmaken van de introductie.</string> + <string name="introduction_response_error">Fout tijdens reageren op een introductie</string> + <string name="introduction_request_sent">Je hebt gevraagd om %1$s te introduceren aan %2$s.</string> + <string name="introduction_request_received">%1$s heeft voorgesteld om je te introduceren aan %2$s. Wil je %2$s toevoegen aan je contactenlijst?</string> + <string name="introduction_request_exists_received">%1$s heeft gevraagd om je te introduceren aan %2$s, maar %2$s staat al in je contactenlijst. Omdat %1$s dit niet mag weten kun je nog steeds antwoorden:</string> + <string name="introduction_request_answered_received">%1$s heeft gevraagd om je te introduceren aan %2$s.</string> + <string name="introduction_response_accepted_sent">Je hebt de introductie aan %1$s geaccepteerd.</string> + <string name="introduction_response_accepted_sent_info">Voordat %1$s toegevoegd wordt aan je contacten, moeten ze de introductie accepteren. Dit kan even duren.</string> + <string name="introduction_response_declined_sent">Je hebt de introductie aan %1$s afgewezen.</string> + <string name="introduction_response_accepted_received">%1$s heeft de introductie aan %2$sgeaccepteerd.</string> + <string name="introduction_response_declined_received">%1$s heeft de introductie aan %2$s afgewezen.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s zegt dat %2$s je introductie heeft afgewezen.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Nieuw contact is toegevoegd.</item> + <item quantity="other">%d nieuwe contacten zijn toegevoegd.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">Geen groepen om te tonen\n\nTap het +-icoon om een groep aan te maken or vraag je contacten om groepen met je te delen</string> + <string name="groups_created_by">Is aangemaakt door %s</string> + <plurals name="messages"> + <item quantity="one">%d bericht</item> + <item quantity="other">%d berichten</item> + </plurals> + <string name="groups_group_is_empty">Deze groep is leeg</string> + <string name="groups_group_is_dissolved">Deze groep is opgeheven</string> + <string name="groups_remove">Verwijder</string> + <string name="groups_create_group_title">Maak privégroep aan</string> + <string name="groups_create_group_button">Maak groep aan</string> + <string name="groups_create_group_invitation_button">Verstuur uitnodiging</string> + <string name="groups_create_group_hint">Voer een naam in voor je privégroep</string> + <string name="groups_invitation_sent">Groepsuitnodiging is verstuurd</string> + <string name="groups_message_sent">Bericht is verstuurd</string> + <string name="groups_member_list">Ledenlijst</string> + <string name="groups_invite_members">Nodig leden uit</string> + <string name="groups_member_created_you">Je hebt de groep aangemaakt</string> + <string name="groups_member_created">%s heeft de groep aangemaakt</string> + <string name="groups_member_joined_you">Je hebt lid geworden van de groep</string> + <string name="groups_member_joined">%s is lid geworden van de groep</string> + <string name="groups_leave">Verlaat groep</string> + <string name="groups_leave_dialog_title">Bevestig verlaten groep</string> + <string name="groups_leave_dialog_message">Weet je zeker dat je deze groep wil verlaten? </string> + <string name="groups_dissolve">Hef groep op</string> + <string name="groups_dissolve_dialog_title">Bevestig opheffen groep</string> + <string name="groups_dissolve_dialog_message">Weet je zeker dat je deze groep wil opheffen?\n\nAlle andere leden zullen dan niet meer hun gesprek voort kunnen zetten en het zou kunnen dat ze de laatste berichten niet ontvangen.</string> + <string name="groups_dissolve_button">Hef op</string> + <string name="groups_dissolved_dialog_title">Groep is opgeheven</string> + <string name="groups_dissolved_dialog_message">De maker van deze groep heeft deze opgeheven.\n\nJe kan niet langer berichten aan de groep sturen en het zou kunnen dat je niet alle posts hebt ontvangen die aan deze groep zijn verstuurd.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Groepsuitnodigingen</string> + <string name="groups_invitations_invitation_sent">Je hebt %1$s uitgenodigd om lid te worden van de groep \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s heeft je uitgenodigd om lid te worden van de groep \"%2$s\".</string> + <string name="groups_invitations_joined">Lid geworden van groep</string> + <string name="groups_invitations_declined">Groepsuitnodiging is afgewezen</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d openstaande groepsuitnodiging</item> + <item quantity="other">%d openstaande groepsuitnodigingen</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Je hebt de groepsuitnodiging van %s geaccepteerd.</string> + <string name="groups_invitations_response_declined_sent">Je hebt de groepsuitnodiging van %s afgewezen.</string> + <string name="groups_invitations_response_accepted_received">%s heeft de groepsuitnodiging geaccepteerd.</string> + <string name="groups_invitations_response_declined_received">%s heeft de groepsuitnodiging afgewezen.</string> + <string name="sharing_status_groups">Alleen degene die een groep heeft aangemaakt kan nieuwe leden voor die groep uitnodigen. Hieronder staan alle huidige leden van de groep.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Openbaar contacten</string> + <string name="groups_reveal_dialog_message">Je kan ervoor kiezen om contacten te openbaren aan alle huidige en toekomstige leden van deze groep.\n\nOpenbaren van contacten maakt je verbinding met de groep sneller en meer betrouwbaar omdat je kan communiceren met geopenbaarde contacten, zelfs als degene die de groep heeft aangemaakt offline is.</string> + <string name="groups_reveal_visible">Contactrelatie is zichtbaar voor de groep</string> + <string name="groups_reveal_visible_revealed_by_us">Contactrelatie is zichtbaar voor de groep (door jou geopenbaard)</string> + <string name="groups_reveal_visible_revealed_by_contact">Contactrelaties zijn zichtbaar voor de groep (geopenbaard door %s)</string> + <string name="groups_reveal_invisible">Contactrelatie is niet zichtbaar voor de groep</string> + <!--Forums--> + <string name="no_forums">Geen fora om te tonen\n\nTap het +-icoon om een forum aan te maken or vraag je contacten om fora met je te delen</string> + <string name="create_forum_title">Maak forum aan</string> + <string name="choose_forum_hint">Voer een naam in voor je forum</string> + <string name="create_forum_button">Maak forum aan</string> + <string name="forum_created_toast">Forum aangemaakt</string> + <string name="no_forum_posts">Geen posts om te tonen</string> + <string name="no_posts">Geen posts</string> + <plurals name="posts"> + <item quantity="one">%d post</item> + <item quantity="other">%d posts</item> + </plurals> + <string name="forum_new_entry_posted">Forumbericht gepubliceerd</string> + <string name="forum_new_message_hint">Nieuw bericht</string> + <string name="forum_message_reply_hint">Nieuwe reactie</string> + <string name="btn_reply">Antwoord</string> + <string name="forum_leave">Verlaat forum</string> + <string name="dialog_title_leave_forum">Bevestig verlaten forum</string> + <string name="dialog_message_leave_forum">Weet je zeker dat dit forum wil verlaten?\n\nHet is mogelijk dat contacten met wie je dit forum hebt gedeeld geen updates meer ontvangen.</string> + <string name="dialog_button_leave">Verlaat</string> + <string name="forum_left_toast">Forum verlaten</string> + <!--Forum Sharing--> + <string name="forum_share_button">Deel forum</string> + <string name="contacts_selected">Contacten geselecteerd</string> + <string name="activity_share_toolbar_header">Kies contacten</string> + <string name="no_contacts_selector">Geen contacten om te tonen\n\nKom a.u.b. hier terug na het toevoegen van een contact</string> + <string name="forum_shared_snackbar">Forum is gedeeld met uitgekozen contacten</string> + <string name="forum_share_message">Voeg een bericht toe (optioneel)</string> + <string name="forum_share_error">Er trad een fout op bij het delen van dit forum.</string> + <string name="forum_invitation_received">%1$s heeft het forum \"%2$s\" met je gedeeld.</string> + <string name="forum_invitation_sent">Jij hebt het forum \"%1$s\" gedeeld met %2$s.</string> + <string name="forum_invitations_title">Forumuitnodigingen</string> + <string name="forum_invitation_exists">Je hebt de uitnodiging van dit forum al eens geaccepteerd.\n\nHet accepteren van meer uitnodigingen zal je verbinding met het forum snellen er meer betrouwbaarder maken.</string> + <string name="forum_joined_toast">Lid geworden van forum</string> + <string name="forum_declined_toast">Uitnodiging afgewezen</string> + <string name="shared_by_format">Is gedeeld door %s</string> + <string name="forum_invitation_already_sharing">Reeds gedeeld</string> + <string name="forum_invitation_response_accepted_sent">Je hebt een forumuitnodiging geaccepteerd van %s.</string> + <string name="forum_invitation_response_declined_sent">Je hebt een forumuitnodiging afgewezen van %s.</string> + <string name="forum_invitation_response_accepted_received">%s heeft de forumuitnodiging geaccepteerd.</string> + <string name="forum_invitation_response_declined_received">%s heeft de forumuitnodiging afgewezen.</string> + <string name="sharing_status">Deelstatus</string> + <string name="sharing_status_forum">Alle leden van een forum kunnen dat forum delen met hun contacten. Momenteel deel je dit forum met de volgende contacten. Er kunnen ook andere leden zijn die je niet kan zien.</string> + <string name="shared_with">Is gedeeld met %1$d (%2$d online)</string> + <plurals name="forums_shared"> + <item quantity="one">%d forum is gedeeld door contacten.</item> + <item quantity="other">%d fora zijn gedeeld door contacten.</item> + </plurals> + <string name="nobody">Niemand</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Geen posts om te tonen</string> + <string name="read_more">lees meer</string> + <string name="blogs_write_blog_post">Schrijf blogpost</string> + <string name="blogs_write_blog_post_body_hint">Schrijf je blogpost</string> + <string name="blogs_publish_blog_post">Publiceer</string> + <string name="blogs_blog_post_created">Blogpost aangemaakt</string> + <string name="blogs_blog_post_received">Nieuwe blogpost ontvangen</string> + <string name="blogs_blog_post_scroll_to">Scroll naar</string> + <string name="blogs_feed_empty_state">Geen posts om te tonen\n\nPosts van je contacten en blogs waar je op bent geabonneerd zullen hier verschijnen\n\nTap het penicoon om een post te schrijven</string> + <string name="blogs_remove_blog">Verwijder bblog</string> + <string name="blogs_remove_blog_dialog_message">Weet je zeker dat je deze blog wil verwijderen?\n\nPosts zullen van je apparaat worden verwijderd maar niet van apparaten van andere mensen.\n\nContacten met wie je deze blog hebt gedeeld zullen geen updates meer ontvangen.</string> + <string name="blogs_remove_blog_ok">Verwijderen</string> + <string name="blogs_blog_removed">Blog is verwijderd</string> + <string name="blogs_reblog_comment_hint">Voeg commentaar toe (optioneel)</string> + <string name="blogs_reblog_button">Reblog</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Deel blog</string> + <string name="blogs_sharing_error">Er was een fout tijdens het delen van deze blog.</string> + <string name="blogs_sharing_button">Deel blog</string> + <string name="blogs_sharing_snackbar">Blog is gedeeld met gekozen contacten</string> + <string name="blogs_sharing_response_accepted_sent">Je hebt de bloguitnodiging van %s geaccepteerd.</string> + <string name="blogs_sharing_response_declined_sent">Je hebt de bloguitnodiging van %s afgewezen.</string> + <string name="blogs_sharing_response_accepted_received">%s heeft de bloguitnodiging geaccepteerd.</string> + <string name="blogs_sharing_response_declined_received">%s heeft de bloguitnodiging afgewezen.</string> + <string name="blogs_sharing_invitation_received">%1$s heeft de blog \"%2$s\" met je gedeeld.</string> + <string name="blogs_sharing_invitation_sent">Je hebt de blog \"%1$s\" gedeeld met %2$s.</string> + <string name="blogs_sharing_invitations_title">Bloguitnodigingen</string> + <string name="blogs_sharing_joined_toast">Geabonneerd op blog</string> + <string name="blogs_sharing_declined_toast">Uitnodiging afgewezen</string> + <string name="sharing_status_blog">Alle leden die lid worden van een blog kunnen deze blog delen met hun contacten. Je deelt deze blog al met de volgende contacten. Er kunnen ook andere leden zijn die je niet kan zien.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Importeer RSS-feed</string> + <string name="blogs_rss_feeds_import_button">Importeer</string> + <string name="blogs_rss_feeds_import_hint">Voer de URL van de RSS-feed in</string> + <string name="blogs_rss_feeds_import_error">Excuses! Er trad een fout op bij het importeren van je feed.</string> + <string name="blogs_rss_feeds_manage">Beheer RSS-feeds</string> + <string name="blogs_rss_feeds_manage_imported">Geïmporteerd:</string> + <string name="blogs_rss_feeds_manage_author">Auteur:</string> + <string name="blogs_rss_feeds_manage_updated">Laatst bijgewerkt:</string> + <string name="blogs_rss_remove_feed">Verwijder feed</string> + <string name="blogs_rss_remove_feed_dialog_message">Weet je zeker dat je deze feed wil verwijderen?\n\nPosts zullen van je apparaat worden verwijderd maar niet van apparaten van andere mensen.\n\nContacten met wie je deze feed hebt gedeeld zullen geen updates meer ontvangen.</string> + <string name="blogs_rss_remove_feed_ok">Verwijderen</string> + <string name="blogs_rss_feeds_manage_delete_error">De feed kon niet worden verwijderd.</string> + <string name="blogs_rss_feeds_manage_empty_state">Geen RSS-feeds om te tonen\n\nTap op het +-icoon om een feed te importeren</string> + <string name="blogs_rss_feeds_manage_error">Er was een probleem met het laden van je feeds. Probeer het later nog een keer.</string> + <!--Settings Display--> + <string name="pref_language_title">Taal & regio</string> + <string name="pref_language_changed">Deze instelling zal werken wanneer u Briar opnieuw opstart. Gelieve uit te loggen en Briar opnieuw te starten.</string> + <string name="pref_language_default">Systeemstandaard</string> + <string name="display_settings_title">Weergeven</string> + <string name="pref_theme_title">Thema</string> + <string name="pref_theme_light">Licht</string> + <string name="pref_theme_dark">Donker</string> + <string name="pref_theme_auto">Automatisch (overdag)</string> + <string name="pref_theme_system">Systeemstandaard</string> + <!--Settings Network--> + <string name="network_settings_title">Netwerken</string> + <string name="bluetooth_setting">Verbind via Bluetooth</string> + <string name="bluetooth_setting_enabled">Alleen als contacten dichtbij zijn</string> + <string name="bluetooth_setting_disabled">Alleen tijdens toevoegen van contacten</string> + <string name="tor_network_setting">Verbind via Tor</string> + <string name="tor_network_setting_never">Nooit</string> + <string name="tor_network_setting_wifi">Alleen tijdens gebruik van wifi</string> + <string name="tor_network_setting_always">Tijdens gebruik van wifi of mobiele dataverbinding</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Beveiliging</string> + <string name="change_password">Wijzig wachtwoord</string> + <string name="current_password">Huidig wachtwoord</string> + <string name="choose_new_password">Nieuw wachtwoord</string> + <string name="confirm_new_password">Nieuw wachtwoord bevestigen</string> + <string name="password_changed">Wachtwoord is gewijzigd</string> + <string name="panic_setting">Paniekknopinstellingen</string> + <string name="panic_setting_title">Paniekknop</string> + <string name="panic_setting_hint">Configureer hoe Briar reageert als je paniekknopapp gebruikt.</string> + <string name="panic_app_setting_title">Paniekknopapp</string> + <string name="unknown_app">een onbekende app</string> + <string name="panic_app_setting_summary">Er is geen app ingesteld</string> + <string name="panic_app_setting_none">Geen</string> + <string name="dialog_title_connect_panic_app">Bevestig paniekapp</string> + <string name="dialog_message_connect_panic_app">Weet je zeker dat je wil toestaan dat %1$s destructieve paniekknopacties mag veroorzaken?</string> + <string name="panic_setting_signout_title">Log uit</string> + <string name="panic_setting_signout_summary">Log uit op Briar als de paniekknop wordt ingedrukt.</string> + <string name="purge_setting_title">Verwijder account</string> + <string name="purge_setting_summary">Verwijder je Briar-account als een paniekknop wordt ingedrukt. Let op: Dit zal permanent je identiteit, contacten en berichten verwijderen.</string> + <string name="uninstall_setting_title">Deïnstalleer Briar</string> + <string name="uninstall_setting_summary">Dit vereist een handmatige bevestiging op een paniekmoment</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Meldingen</string> + <string name="notify_sign_in_title">Herinner me om in te loggen</string> + <string name="notify_sign_in_summary">Stuur een herinnering wanneer de telefoon opstart of als de app is bijgewerkt</string> + <string name="notify_private_messages_setting_title">Privéberichten</string> + <string name="notify_private_messages_setting_summary">Toon meldingen voor privéberichten</string> + <string name="notify_private_messages_setting_summary_26">Configureer alarmen voor privéberichten</string> + <string name="notify_group_messages_setting_title">Groepsberichten</string> + <string name="notify_group_messages_setting_summary">Toon meldingen voor groepsberichten</string> + <string name="notify_group_messages_setting_summary_26">Configureer alarmen voor groepsberichten</string> + <string name="notify_forum_posts_setting_title">Forumposts</string> + <string name="notify_forum_posts_setting_summary">Toon meldingen voor forumposts</string> + <string name="notify_forum_posts_setting_summary_26">Configureer alarmen voor forumposts</string> + <string name="notify_blog_posts_setting_title">Blogposts</string> + <string name="notify_blog_posts_setting_summary">Toon meldingen voor blogposts</string> + <string name="notify_blog_posts_setting_summary_26">Configureer alarmen voor blogposts</string> + <string name="notify_vibration_setting">Tril</string> + <string name="notify_lock_screen_setting_title">Schermvergrendeling</string> + <string name="notify_lock_screen_setting_summary">Toon notificaties over de schermvergrendeling</string> + <string name="notify_sound_setting">Geluid</string> + <string name="notify_sound_setting_default">Standaardringtoon</string> + <string name="notify_sound_setting_disabled">Geen</string> + <string name="choose_ringtone_title">Kies ringtoon</string> + <string name="cannot_load_ringtone">Kan ringtoon niet laden</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Feedback</string> + <string name="send_feedback">Verstuur feedback</string> + <!--Link Warning--> + <string name="link_warning_title">Linkwaarschuwing</string> + <string name="link_warning_intro">Je staat op het punt om de volgende link te open met een externe app.</string> + <string name="link_warning_text">Dit kan gebruikt worden om te achterhalen wie jij bent. Denk na of je de persoon vertrouwd die je deze link heeft gestuurd en overweeg deze link te openen met Orfox.</string> + <string name="link_warning_open_link">Open link</string> + <!--Crash Reporter--> + <string name="crash_report_title">Crashrapport Briar</string> + <string name="briar_crashed">Excuses, Briar is gecrashed.</string> + <string name="not_your_fault">Dit is niet je schuld</string> + <string name="please_send_report">Help ons a.u.b. om Briar te verbeteren door crashrapporten naar ons te sturen.</string> + <string name="report_is_encrypted">We beloven dat het rapport is versleuteld en veilig wordt verzonden.</string> + <string name="feedback_title">Feedback</string> + <string name="describe_crash">Beschrijf wat er is gebeurd (optioneel)</string> + <string name="enter_feedback">Voer je feedback in</string> + <string name="optional_contact_email">Je e-mailadres (optioneel)</string> + <string name="include_debug_report_crash">Voeg geanonimiseerde gegevens toe over de crash.</string> + <string name="include_debug_report_feedback">Voeg geanonimiseerde gegevens over dit apparaat toe.</string> + <string name="could_not_load_report_data">Kon rapportgegevens niet laden.</string> + <string name="send_report">Verstuur rapport</string> + <string name="close">Sluit</string> + <string name="dev_report_saved">Rapport is opgeslagen. Het zal worden verstuurd als je de volgende keer inlogt op Briar </string> + <!--Sign Out--> + <string name="progress_title_logout">Uitloggen van Briar…</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Schermoverlay is gedetecteerd</string> + <string name="screen_filter_body">Een andere app ligt zich bovenop Briar. Om je veiligheid te beschermen zal Briar niet reageren op aanrakingen als er een andere app bovenop ligt.\n\nDe volgende apps proberen waarschijnlijk dit te doen:\n\n%1$s</string> + <string name="screen_filter_allow">Sta toe dat deze apps bovenop te liggen</string> + <!--Permission Requests--> + <string name="permission_camera_title">Cameratoestemming</string> + <string name="permission_camera_request_body">Om de QR-code te scannen moet Briar toegang hebben tot de camera.</string> + <string name="permission_camera_denied_body">Je hebt toegang tot de camera niet vrijgegeven, terwijl het toevoegen van contacten de camera nodig heeft.\n\nOverweeg a.u.b. toegang vrij te geven.</string> + <string name="permission_camera_denied_toast">Cameratoegang niet vrijgegeven</string> + <string name="qr_code">QR-code</string> + <string name="show_qr_code_fullscreen">Toon QR-code op volledig scherm</string> +</resources> diff --git a/mailbox-android/src/main/res/values-oc/strings.xml b/mailbox-android/src/main/res/values-oc/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..4b40026c39b96d2042d9d02ffcf52b2e83a6ad7f --- /dev/null +++ b/mailbox-android/src/main/res/values-oc/strings.xml @@ -0,0 +1,373 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">La benvenguda a Briar</string> + <string name="setup_name_explanation">Vòstre escais-nom serà mostrat al costat de cada de vòstra publicacion. Poiretz pas lo cambiar aprèp la creacion del compte.</string> + <string name="setup_next">Seguent</string> + <string name="setup_password_intro">Causissètz un senhal</string> + <string name="setup_doze_button">Autorizar las connexions</string> + <string name="choose_nickname">Causir un escais-nom</string> + <string name="choose_password">Causir un senhal</string> + <string name="confirm_password">Confirmar lo senhal</string> + <string name="name_too_long">L’escais es tròp long</string> + <string name="password_too_weak">Lo senhal es tròp feble</string> + <string name="passwords_do_not_match">Los senhals correspondon pas</string> + <string name="create_account_button">Crear un compte</string> + <string name="more_info">Mai d’informacions</string> + <string name="don_t_ask_again">Demandar pas mai</string> + <string name="setup_huawei_button">Projècte Briar</string> + <string name="setup_huawei_help">Se Briar es pas ajustat a la lista de las aplicacion protegidas poirà pas s’executar en rèire plan.</string> + <string name="warning_dozed">%s a pas pogut s’executar en rèire plan</string> + <!--Login--> + <string name="enter_password">Senhal</string> + <string name="try_again">Senhal incorècte, tornatz ensajar</string> + <string name="sign_in_button">Se connectar</string> + <string name="forgotten_password">Senhal oblidat</string> + <string name="dialog_title_lost_password">Senhal oblidat</string> + <string name="dialog_message_lost_password">Vòstre compte Briar es salvat e chifrat sus vòstre aparelh, non pas sus un servidor alonhat \"cloud\". De efècte podèm pas reïnicializar vòstre senhal. +Volètz suprimir vòstre compte e ne crear un nòu ?\n +\nMèfi : vòstra identitat, vòstres contactes e messatges serà n perduts per totjorn.</string> + <string name="startup_failed_notification_title">Briar a pas pogut aviar</string> + <string name="startup_failed_notification_text">Tocatz per mai d’informacions.</string> + <string name="startup_failed_activity_title">Fracà s de l’aviada de Briar.</string> + <string name="startup_failed_data_too_new_error">Aquesta version de l’aplicacion es tròp anciana. Mercés de la metre al nivèl de la darrièra e de tornar ensajar.</string> + <string name="startup_failed_service_error">Briar a pas pogut aviar un modul necessari. Tornar installar Briar pòt resolver aquò. Que aquò siá dich : perdretz vòstre compte e totas las donadas ligadas a aqueste. Briar utiliza pas de servidor centralizat per salvar sas donadas.</string> + <string name="expiry_date_reached">Vòstre logicial s’acabèt.\nMercés d’aver ensajat !</string> + <string name="download_briar">Per téner d’utilizar Briar mercés de telecargar la version 1.0.</string> + <string name="create_new_account">Vos caldrà crear un nòu compte, mas podètz emplegar lo meteis escais-nom.</string> + <string name="download_briar_button">Telecargar Briar 1.0</string> + <string name="startup_open_database">Deschirament de la basa de donadas…</string> + <string name="startup_migrate_database">Mesa a nivèl de la basa de donadas…</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Dobrir lo panèl de navigacion</string> + <string name="nav_drawer_close_description">Tampar lo panèl de navigacion</string> + <string name="contact_list_button">Contactes</string> + <string name="groups_button">Grops privats</string> + <string name="forums_button">Fòrums</string> + <string name="blogs_button">Blòges</string> + <string name="settings_button">Paramètres</string> + <string name="sign_out_button">Se desconnectar</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wifi</string> + <!--Notifications--> + <string name="reminder_notification_title">Desconnectat de Briar</string> + <string name="ongoing_notification_title">Connectat a Briar</string> + <string name="ongoing_notification_text">Tocatz per dobrir</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Novèl messatge privat.</item> + <item quantity="other">%d novèls messatges privats</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Novèl messatge gropat</item> + <item quantity="other">%d novèls messatges gropats</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Novèla publicacion al fòrum</item> + <item quantity="other">%d novèlas publicacions al fòrum</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Novèl article sul blòg</item> + <item quantity="other">%d novèls article sul blòg</item> + </plurals> + <!--Misc--> + <string name="now">Ara</string> + <string name="show">Mostrar</string> + <string name="hide">Amagar</string> + <string name="ok">D’acòrdi</string> + <string name="cancel">Anullar</string> + <string name="got_it">Comprés</string> + <string name="delete">Suprimir</string> + <string name="accept">Acceptar</string> + <string name="decline">Refusar</string> + <string name="options">Opcions</string> + <string name="online">En linha</string> + <string name="offline">Fòra linha</string> + <string name="send">Mandar</string> + <string name="allow">Autorizar</string> + <string name="open">Dobrir</string> + <string name="no_data">Pas donada</string> + <string name="ellipsis">...</string> + <string name="text_too_long">Lo tèxte picat es tròp long</string> + <string name="show_onboarding">Mostrar l’ajuda</string> + <string name="fix">Correccion</string> + <string name="help">Ajuda</string> + <string name="sorry">O planhèm</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Cap de contactes de mostrar\n\nTocatz l’icòna + per ajustar un contacte</string> + <string name="date_no_private_messages">Cap messatge</string> + <string name="no_private_messages">Cap de messatge de mostrar</string> + <string name="message_hint">Picatz lo messatge</string> + <string name="delete_contact">Suprimir lo contacte</string> + <string name="dialog_title_delete_contact">Confirmatz la supression del contacte</string> + <string name="dialog_message_delete_contact">Sètz segur de voler suprimir lo contacte e los messatges ligats a el ?</string> + <string name="contact_deleted_toast">Contacte suprimit</string> + <!--Adding Contacts--> + <string name="add_contact_title">Ajustar un contacte</string> + <string name="face_to_face">Vos cal vos amassar amb la persona que volètz apondre als contactes.\n\n Aquò es fach per evitar qu’òm vos raube l’identitat e que vòstres messatges sián legits per d’autres.</string> + <string name="continue_button">Contunhar</string> + <string name="connection_failed">Fracà s de la connexion</string> + <string name="try_again_button">Tornar ensajar</string> + <string name="waiting_for_contact_to_scan">En espèra de la numerizacion e de la connexion al contacte\u2026</string> + <string name="exchanging_contact_details">Escambi dels detalhs del contacte\u2026</string> + <string name="contact_added_toast">Contacte apondut : %s</string> + <string name="contact_already_exists">Lo contacte %s existÃs ja</string> + <string name="contact_exchange_failed">L’escambi de contacte a fracassat</string> + <string name="qr_code_invalid">Lo QR còdi es invalid</string> + <string name="camera_error">Error de camèra</string> + <string name="connecting_to_device">Connexion a l’aparelh\u2026</string> + <string name="authenticating_with_device">Autentificacion amb l’aparelh\u2026</string> + <string name="connection_aborted_local">Avèm copat la connexion ! Poiriá arribar que qualqu’un ensage d’interferir amb vòstra connexion</string> + <string name="connection_aborted_remote">Vòstre contacte a copat la connexion ! Poiriá arribar que qualqu’un ensage d’interferir amb aquela</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Presentatz vòstres contactes</string> + <string name="introduction_onboarding_text">Podètz presentar vòstres contactes, lor caldrà pas se veire per s’apondre e se connectar a Briar.</string> + <string name="introduction_menu_item">Escafar l’introduccion</string> + <string name="introduction_activity_title">Seleccionar contacte</string> + <string name="introduction_message_title">Presentar de contactes</string> + <string name="introduction_message_hint">Apondre un messatge (opcional)</string> + <string name="introduction_button">Escafar l’introduccion</string> + <string name="introduction_sent">Vòstra admission es enviada.</string> + <string name="introduction_error">Una error s’es produsida pendent l’admission</string> + <string name="introduction_response_error">Error pendent la responsa d’admission.</string> + <string name="introduction_request_sent">Avètz demandat a %2$s d’apondre %1$s</string> + <string name="introduction_request_received">%1$s vos prepausa d’apondre %2$s. Volètz apondre %2$s a vòstres contactes ?</string> + <string name="introduction_request_exists_received">%1$s vos demandèt d’apondre %2$s mas %2$s es ja dins vòstra tièra de contactes. Del moment que %1$s o sap pas, podètz çaquelà respondre :</string> + <string name="introduction_request_answered_received">%1$s a demandat d’apondre %2$s.</string> + <string name="introduction_response_accepted_sent">Avètz acceptat d’apondre %1$s.</string> + <string name="introduction_response_declined_sent">Avètz refusat d’apondre %1$s.</string> + <string name="introduction_response_accepted_received">%1$s a acceptat d’apondre %2$s.</string> + <string name="introduction_response_declined_received">%1$s a refusat d’apondre %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s anóncia que %2$s a refusat la convidacion.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Nòu contacte ajustat.</item> + <item quantity="other">%d nòus contactes ajustats.</item> + </plurals> + <!--Private Groups--> + <string name="groups_created_by">Fondat per %s</string> + <plurals name="messages"> + <item quantity="one">1 messatge</item> + <item quantity="other">%d messatges</item> + </plurals> + <string name="groups_group_is_empty">Aqueste grop es void</string> + <string name="groups_group_is_dissolved">Aqueste grop es estat suprimit</string> + <string name="groups_remove">Suprimir</string> + <string name="groups_create_group_title">Crear un grop privat</string> + <string name="groups_create_group_button">Crear un grop</string> + <string name="groups_create_group_invitation_button">Enviar de convidacions</string> + <string name="groups_create_group_hint">Donatz un nom al grop privat</string> + <string name="groups_invitation_sent">Convidacion enviada al grop</string> + <string name="groups_message_sent">Messatge mandat</string> + <string name="groups_member_list">Tièra de membres</string> + <string name="groups_invite_members">Convidar mai de monde</string> + <string name="groups_member_created_you">Avètz creat lo grop</string> + <string name="groups_member_created">%s a fondat lo grop</string> + <string name="groups_member_joined_you">Sètz marcat dins lo grop</string> + <string name="groups_member_joined">%s es marcat dins lo grop</string> + <string name="groups_leave">Quitar lo grop</string> + <string name="groups_leave_dialog_title">Confirmar que volètz quitar lo grop</string> + <string name="groups_leave_dialog_message">Sètz segur de voler quitar lo grop ?</string> + <string name="groups_dissolve">Suprimir lo grop</string> + <string name="groups_dissolve_dialog_title">Confirmar la supression del grop</string> + <string name="groups_dissolve_dialog_message">Sètz segur de voler suprimir lo grop ? \n\nLa rèsta dels participants poiran pas tenir de charrat e poiriá arribar qu’ajan pas los darrièrs messatges.</string> + <string name="groups_dissolve_button">Suprimir</string> + <string name="groups_dissolved_dialog_title">Lo grop es estat suprimit</string> + <string name="groups_dissolved_dialog_message">Lo fondador d’aqueste grop l’a suprimit.\n\nPodètz pas mai escriure de messatges e benlèu qu’avètz pas recebuts totes los messatges.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Convidacion de grop</string> + <string name="groups_invitations_invitation_sent">Avètz convidat %1$s a venir al grop « %2$vs»</string> + <string name="groups_invitations_invitation_received">%1$s vos a convidat a anar al grop « %2$s »</string> + <string name="groups_invitations_joined">Ajustat al grop</string> + <string name="groups_invitations_declined">Convidacion al grop refusada</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d convidacion de grop en espèra</item> + <item quantity="other">%d convidacions de grop en espèra</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Avètz acceptat la convidacion del grop a %s.</string> + <string name="groups_invitations_response_declined_sent">Avètz refusat la convidacion del grop a %s.</string> + <string name="groups_invitations_response_accepted_received">%s a acceptat la convidacion del grop.</string> + <string name="groups_invitations_response_declined_received">%s a refusat la convidacion del grop.</string> + <string name="sharing_status_groups">Pas que lo fondador del grop pòt convidar mai de monde. Vaquà la tièra dels membres actuals.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Revelar los contactes</string> + <string name="groups_reveal_dialog_message">Podètz causir de revelar los contactes a totes los membres actuals e venents d’aqueste grop.\n\nEn revelar los contactes auretz una melhora connexion al grop e mai fiabla perque poiretz comunicar amb los contactes revelats quand lo fondator es fòra linha.</string> + <string name="groups_reveal_visible">Vòstre ligam amb lo contacte es visible pel grop</string> + <string name="groups_reveal_visible_revealed_by_us">Vòstre ligam – revelat per vos – amb lo contacte es visible pel grop </string> + <string name="groups_reveal_visible_revealed_by_contact">Vòstre ligam – revelat per %s – amb lo contacte es invisible pel grop</string> + <string name="groups_reveal_invisible">Vòstre ligam amb lo contacte es invisible pel grop</string> + <!--Forums--> + <string name="create_forum_title">Crear un fòrum</string> + <string name="choose_forum_hint">Donar un nom al fòrum</string> + <string name="create_forum_button">Crear un fòrum</string> + <string name="forum_created_toast">Fòrum creat</string> + <string name="no_posts">Cap publicacion</string> + <plurals name="posts"> + <item quantity="one">%d publicacion</item> + <item quantity="other">%d publicacions</item> + </plurals> + <string name="forum_message_reply_hint">Nòva responsa</string> + <string name="btn_reply">Respondre</string> + <string name="forum_leave">Quitar lo fòrum</string> + <string name="dialog_title_leave_forum">Confirmar la sortida del fòrum</string> + <string name="dialog_button_leave">Quitar</string> + <string name="forum_left_toast">Quitar lo forum</string> + <!--Forum Sharing--> + <string name="forum_share_button">Partejar lo fòrum</string> + <string name="contacts_selected">Contactes seleccionats</string> + <string name="activity_share_toolbar_header">Causissètz de contactes</string> + <string name="forum_shared_snackbar">Fòrom partejat amb los contactes causits</string> + <string name="forum_share_message">Apondre un messatge (opcional)</string> + <string name="forum_share_error">Error en partejar lo fòrum</string> + <string name="forum_invitation_received">%1$s a partejat lo fòrom « %2$s » amb vos.</string> + <string name="forum_invitation_sent">Avètz partejat lo fòrom « %1$s » amb %2$s.</string> + <string name="forum_invitations_title">Convidacion al fòrum</string> + <string name="shared_by_format">Partejat per %s</string> + <string name="forum_invitation_already_sharing">Ja a partejar</string> + <string name="forum_invitation_response_accepted_sent">Avètz acceptat la convidacion al fòrum de %s.</string> + <string name="forum_invitation_response_declined_sent">Avètz refusat la convidacion al fòrum de %s.</string> + <string name="forum_invitation_response_accepted_received">%s a acceptat la convidacion al fòrum.</string> + <string name="forum_invitation_response_declined_received">%s a refusat la convidacion al fòrum.</string> + <string name="sharing_status">Estat del partatge</string> + <string name="sharing_status_forum">Totes los participants d’un fòrum pòdon lo partejar amb lors contactes. Partejatz aqueste fòrum amb los contactes seguents. I a benlèu mai de monde que podètz pas veire.</string> + <string name="shared_with">Partejat amb %1$d (%2$d en linha)</string> + <plurals name="forums_shared"> + <item quantity="one">%d fòrum partejat amb de contactes</item> + <item quantity="other">%d fòrums partejats amb de contactes</item> + </plurals> + <string name="nobody">Degun</string> + <!--Blogs--> + <string name="read_more">Legir la seguida</string> + <string name="blogs_write_blog_post">Escriure un article de blòg</string> + <string name="blogs_publish_blog_post">Publicar</string> + <string name="blogs_blog_post_created">Article salvat</string> + <string name="blogs_blog_post_received">Nòu article recebut</string> + <string name="blogs_blog_post_scroll_to">Anar a</string> + <string name="blogs_remove_blog">Suprimir lo blòg</string> + <string name="blogs_remove_blog_ok">Suprimir</string> + <string name="blogs_blog_removed">Blòg tirat</string> + <string name="blogs_reblog_comment_hint">Apondre un comentari (opcional)</string> + <string name="blogs_reblog_button">Partejar</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Partejar lo blòg</string> + <string name="blogs_sharing_error">Error en partejar lo blòg</string> + <string name="blogs_sharing_button">Fai virar</string> + <string name="blogs_sharing_snackbar">Blòg partejat amb los contactes seleccionats</string> + <string name="blogs_sharing_response_accepted_sent">Avètz acceptat la convidacion al blòg a %s.</string> + <string name="blogs_sharing_response_declined_sent">Avètz refusat la convidacion al blòg a %s.</string> + <string name="blogs_sharing_response_accepted_received">%s a acceptat la convidacion al blòg.</string> + <string name="blogs_sharing_response_declined_received">%s a refusat la convidacion al blòg.</string> + <string name="blogs_sharing_invitation_received">%1$s a partejat lo blòg « %2$s » amb vos.</string> + <string name="blogs_sharing_invitation_sent">Avètz partejat lo blòg « %1$s » amb %2$s.</string> + <string name="blogs_sharing_invitations_title">Convidacion al blòg</string> + <string name="blogs_sharing_joined_toast">S’abonar al blòg</string> + <string name="sharing_status_blog">Qual que siá seguidor d’un blòg pòt lo partejar amb sos contactes. Partejatz lo blòg amb los contactes seguents. I a benlèu mai de monde qu’o seguen que vesètz pas.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Importar de fluxes RSS</string> + <string name="blogs_rss_feeds_import_button">Importar</string> + <string name="blogs_rss_feeds_import_hint">Marcar l’URL del flux RSS</string> + <string name="blogs_rss_feeds_import_error">Una error s’es produisida en importar lo flux</string> + <string name="blogs_rss_feeds_manage">Gerir lo flux RSS</string> + <string name="blogs_rss_feeds_manage_imported">Importat :</string> + <string name="blogs_rss_feeds_manage_author">Autor :</string> + <string name="blogs_rss_feeds_manage_updated">Darrièra mesa a jorn :</string> + <string name="blogs_rss_remove_feed">Suprimir lo flux</string> + <string name="blogs_rss_remove_feed_ok">Suprimir</string> + <string name="blogs_rss_feeds_manage_delete_error">Impossible de suprimir lo flux !</string> + <string name="blogs_rss_feeds_manage_error">Error en cargar vòstres fluxes. Ensajatz mai tard.</string> + <!--Settings Display--> + <string name="pref_language_title">Lenga & region</string> + <string name="pref_language_default">Sistèma per defaut</string> + <string name="display_settings_title">Afichatge</string> + <string name="pref_theme_title">Tèma</string> + <string name="pref_theme_light">Clar</string> + <string name="pref_theme_dark">Escur</string> + <string name="pref_theme_auto">Automatic (Segon l’ora)</string> + <string name="pref_theme_system">Per defaut sistèma</string> + <!--Settings Network--> + <string name="network_settings_title">Ret</string> + <string name="bluetooth_setting">Se connectar per Bluetooth</string> + <string name="bluetooth_setting_enabled">Quand de contactes son prèp</string> + <string name="bluetooth_setting_disabled">Solament en apondre de contctes</string> + <string name="tor_network_setting">Se connectar via Tor</string> + <string name="tor_network_setting_never">Pas jamai</string> + <string name="tor_network_setting_wifi">Solament per wifi</string> + <string name="tor_network_setting_always">Per wifi o donadas mobil</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Seguretat</string> + <string name="change_password">Modificar lo senhal</string> + <string name="current_password">Senhal actual</string> + <string name="choose_new_password">Nòu senhal</string> + <string name="confirm_new_password">Confirmatz lo senhal</string> + <string name="password_changed">Lo senhal a cambiat</string> + <string name="panic_setting">Paramètres del boton urgéncia</string> + <string name="panic_setting_title">Boton urgéncia</string> + <string name="panic_setting_hint">Configurar Briat per l’utilizacion de l’aplicacion del boton d’urgéncia</string> + <string name="panic_app_setting_title">Aplicacion boton urgéncia</string> + <string name="unknown_app">Aplicacion desconeguda</string> + <string name="panic_app_setting_summary">Cap aplicacion causida</string> + <string name="panic_app_setting_none">Cap</string> + <string name="dialog_title_connect_panic_app">Confirmar l’aplicacion Urgéncia</string> + <string name="dialog_message_connect_panic_app">Sètz segur de voler autorizar %1$s a aviar las accions de destruccion del boton Urgéncia ?</string> + <string name="panic_setting_signout_title">Se desconnectar</string> + <string name="panic_setting_signout_summary">Se desconnectar de Briar en apiejant lo boton Urgéncia ?</string> + <string name="purge_setting_title">Suprimir lo compte</string> + <string name="purge_setting_summary">Suprimir vòstre compte en apiejant lo boton Urgéncia. Mèfi, aquò escafarà per totjorn vòstra identitat, vòstres contactes e messatges.</string> + <string name="uninstall_setting_title">Desinstallar Briar</string> + <string name="uninstall_setting_summary">Aquò demanda una confirmacion manuala.</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Notificacions</string> + <string name="notify_private_messages_setting_title">Messatges privats</string> + <string name="notify_private_messages_setting_summary">Notificar los messatges privats</string> + <string name="notify_private_messages_setting_summary_26">Configuratz las alèrtas pels messatges privats</string> + <string name="notify_group_messages_setting_title">Messatges gropats</string> + <string name="notify_group_messages_setting_summary">Notificar los messatges gropats</string> + <string name="notify_group_messages_setting_summary_26">Configuratz las alèrtas pels messatges de grop</string> + <string name="notify_forum_posts_setting_title">Publicacions al fòrum</string> + <string name="notify_forum_posts_setting_summary">Notificar las publicacions al fòrum</string> + <string name="notify_blog_posts_setting_title">Articles de blòg</string> + <string name="notify_blog_posts_setting_summary">Notificar los articles de blòg</string> + <string name="notify_vibration_setting">Vibracion</string> + <string name="notify_lock_screen_setting_title">Verrolhar l’ecran</string> + <string name="notify_lock_screen_setting_summary">Mostrar las notificacions sus l’ecran verrolhat</string> + <string name="notify_sound_setting">Sonariá</string> + <string name="notify_sound_setting_default">Sonariá per defaut</string> + <string name="notify_sound_setting_disabled">Cap</string> + <string name="choose_ringtone_title">Causir la sonariá</string> + <string name="cannot_load_ringtone">Cargament impossible de las sonariás</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Comentaris</string> + <string name="send_feedback">Enviar vòstres comentaris</string> + <!--Link Warning--> + <string name="link_warning_title">Avertiment de ligam</string> + <string name="link_warning_intro">Sètz a man de dobrir lo ligam seguent amb una aplicacion extèrna.</string> + <string name="link_warning_text">Aquò poiriá èsser utilizat per vos identificar. Estimatz la fisança qu’avètz de la persona que vos a enviat lo ligam e pensatz lo dobrir amb Orfox.</string> + <string name="link_warning_open_link">Dobrir lo ligam</string> + <!--Crash Reporter--> + <string name="crash_report_title">Senhalar lo fracà s de Briar</string> + <string name="briar_crashed">Malastre, Briar a arrestat de foncionar.</string> + <string name="not_your_fault">Es pas vòstra fauta.</string> + <string name="please_send_report">Ajudatz-nos a melhorar Briar en nos enviant un rapòrt de fracà s.</string> + <string name="report_is_encrypted">Asseguram que lo rapòrt es chifrat e enviat en tota seguretat.</string> + <string name="feedback_title">Comentaris</string> + <string name="describe_crash">Describètz çò que s’es passat</string> + <string name="enter_feedback">Marcatz vòstres comentaris</string> + <string name="optional_contact_email">Vòstre corrièl (opcional)</string> + <string name="include_debug_report_crash">Ajustar de donas anonimas tocant lo fracà s</string> + <string name="include_debug_report_feedback">Ajustar de donas anonimas tocant aqueste periferic</string> + <string name="could_not_load_report_data">Impossible de cargar las donadas del rapòrt.</string> + <string name="send_report">Enviar lo rapòrt</string> + <string name="close">Tampar</string> + <string name="dev_report_saved">Rapòrt salvat. Serà enviat a vòstra connexion venenta a Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">Desconnecion de Briar...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Superposicion detectada</string> + <!--Permission Requests--> + <string name="permission_camera_title">Permission de la camèra</string> + <string name="permission_camera_request_body">Per numerizar lo còdi QR cal que Briar aja l’accès a la camèra.</string> + <string name="permission_camera_denied_body">Avètz regetat l’accès a la camèra, mas per ajustar de contacte cal utilizar la camèra.\n\n Mercés de li donar l’accès</string> + <string name="permission_camera_denied_toast">La permission a la camèra es pas estada donada</string> + <string name="qr_code">Còdi QR</string> + <string name="show_qr_code_fullscreen">Mostrar lo còdi QR en ecran complèt</string> +</resources> diff --git a/mailbox-android/src/main/res/values-pl/strings.xml b/mailbox-android/src/main/res/values-pl/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..51853e21368433e880e6eca39b19ebf6baa9dbc4 --- /dev/null +++ b/mailbox-android/src/main/res/values-pl/strings.xml @@ -0,0 +1,429 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Witaj w Briar</string> + <string name="setup_name_explanation">Twoja nazwa użytkownika bÄ™dzie wyÅ›wietlana przy każdej zamieszczonej przez Ciebie treÅ›ci. Nie można jej zmienić po tworzeniu konta.</string> + <string name="setup_next">Dalej</string> + <string name="setup_password_intro">Wybierz HasÅ‚o</string> + <string name="setup_password_explanation">Twoje konto Briar jest przechowywane i szyfrowane na Twoim urzÄ…dzeniu nie w chmurze. JeÅ›li zapomnisz hasÅ‚a lub odinstalujesz Briar, nie ma możliwoÅ›ci aby odzyskać Twoje konto.\n\nWybierz dÅ‚ugie hasÅ‚o, które jest trudne do odgadniÄ™cia, czyli takie z losowymi literami numerami i symbolami.</string> + <string name="setup_doze_title">Połączenia w Tle</string> + <string name="setup_doze_intro">Aby otrzymywać wiadomoÅ›ci, Briar musi utrzymywać połączenie w tle.</string> + <string name="setup_doze_explanation">Aby otrzymywać wiadomoÅ›ci, Briar musi utrzymywać połączenie w tle. Wyłącz optymalizacje baterii aby Briar mógÅ‚ zostać połączony.</string> + <string name="setup_doze_button">Pozwól na Połączenia</string> + <string name="choose_nickname">Wybierz nazwÄ™ użytkownika</string> + <string name="choose_password">Wybierz hasÅ‚o</string> + <string name="confirm_password">Potwierdź hasÅ‚o</string> + <string name="name_too_long">Nazwa użytkownika jest zbyt dÅ‚uga</string> + <string name="password_too_weak">HasÅ‚o jest zbyt dÅ‚ugie</string> + <string name="passwords_do_not_match">HasÅ‚a siÄ™ nie zgadzajÄ…</string> + <string name="create_account_button">Utwórz Konto</string> + <string name="more_info">WiÄ™cej Informacji</string> + <string name="don_t_ask_again">Nie pytaj ponownie</string> + <string name="setup_huawei_text">ProszÄ™ dotknąć przycisku poniżej i upewnić siÄ™, że Briar jest na liÅ›cie chronionych aplikacji.</string> + <string name="setup_huawei_button">ChroÅ„ Briar</string> + <string name="setup_huawei_help">JeÅ›li Briar nie bÄ™dzie na liÅ›cie chronionych aplikacji nie bÄ™dzie miaÅ‚ możliwoÅ›ci aby dziaÅ‚ać w tle.</string> + <string name="warning_dozed">%s nie byÅ‚ wstanie dziaÅ‚ać w tle</string> + <!--Login--> + <string name="enter_password">HasÅ‚o</string> + <string name="try_again">ZÅ‚e hasÅ‚o, spróbuj ponownie</string> + <string name="sign_in_button">Zaloguj SiÄ™</string> + <string name="forgotten_password">Przypomnij hasÅ‚o</string> + <string name="dialog_title_lost_password">Nie pamiÄ™tam hasÅ‚a</string> + <string name="dialog_message_lost_password">Twoje konto Briar jest zaszyfrowane na Twoim urzÄ…dzeniu nie w chmurze, wiÄ™c nie bÄ™dzie można zresetować Twojego hasÅ‚a. Czy chcesz usunąć swoje konto i stworzyć nowe?\n\nUwaga: Twoje hasÅ‚a, kontakty i wiadomoÅ›ci bÄ™dÄ… utracone.</string> + <string name="startup_failed_notification_title">Briar nie mógÅ‚ siÄ™ uruchomić</string> + <string name="startup_failed_notification_text">WiÄ™cej informacji</string> + <string name="startup_failed_activity_title">Briar nie mógÅ‚ siÄ™ uruchomić</string> + <string name="startup_failed_db_error">Niestety baza danych Briar zostaÅ‚a uszkodzona i nie można jej naprawić. Twoje konto, dane i kontakty zostaÅ‚y utracone. Niestety musisz przeinstalować Briar lub utworzyć nowe konto wybierajÄ…c opcje \"ZapomniaÅ‚em hasÅ‚a\".</string> + <string name="startup_failed_data_too_old_error">Twoje konto zostaÅ‚o stworzone przez starszÄ… wersjÄ™ aplikacji i nie może zostać otwarte w tej wersji. Musisz zainstalować starszÄ… wersjÄ™ aplikacji lub utworzyć nowe konto klikajÄ…c \"ZapomniaÅ‚em hasÅ‚a\".</string> + <string name="startup_failed_data_too_new_error">Ta wersja aplikacji jest zbyt stara. ProszÄ™ zaktualizować program do najnowszej wersji i spróbować ponownie.</string> + <string name="startup_failed_service_error">Briar nie byÅ‚ w stanie uruchomić wybranego rozszerzenia. Przeinstalowanie Briar zwykle rozwiÄ…zuje ten problem. PamiÄ™taj jednak, że stracisz wtedy swoje konto i wszystkie powiÄ…zanie z nim dane, gdyż Briar nie używa centralnych serwerów by przechowywać dane.</string> + <plurals name="expiry_warning"> + <item quantity="one">To jest testowa wersja Briar. Twoje konto wygaÅ›nie za %d dzieÅ„ i nie bÄ™dzie odnowione.</item> + <item quantity="few">To jest testowa wersja Briar. Twoje konto wygaÅ›nie za %d dni i nie bÄ™dzie odnowione.</item> + <item quantity="many">To jest testowa wersja Briar. Twoje konto wygaÅ›nie za %d dni i nie bÄ™dzie odnowione.</item> + <item quantity="other">To jest testowa wersja Briar. Twoje konto wygaÅ›nie za %d dni i nie bÄ™dzie odnowione.</item> + </plurals> + <string name="expiry_update">Okres testowania zostaÅ‚ wydÅ‚użony. Twoje konto wygaÅ›nie za %d dni.</string> + <string name="expiry_date_reached">Ten program wygasÅ‚.\nDziÄ™kujemy za testy!</string> + <string name="download_briar">Aby dalej korzystać z Briar, proszÄ™ pobrać wersjÄ™ 1.0.</string> + <string name="create_new_account">BÄ™dzie potrzeba stworzenia nowego konta, ale możesz użyć takiej samej nazwy użytkownika.</string> + <string name="download_briar_button">Pobierz Briar 1.0</string> + <string name="startup_open_database">DeszyfrujÄ™ BazÄ™ Danych...</string> + <string name="startup_migrate_database">AktualizujÄ™ BazÄ™ Danych...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Otwórz panel nawigacji</string> + <string name="nav_drawer_close_description">Zamknij panel nawigacji</string> + <string name="contact_list_button">Kontakty</string> + <string name="groups_button">Grupy Prywatne</string> + <string name="forums_button">Fora</string> + <string name="blogs_button">Blogi</string> + <string name="settings_button">Ustawienia</string> + <string name="sign_out_button">Wyloguj siÄ™</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="reminder_notification_title">Wylogowano z Briar</string> + <string name="reminder_notification_channel_title">Przypomnienie o zalogowaniu</string> + <string name="ongoing_notification_title">Zalogowany w Briar</string> + <string name="ongoing_notification_text">Dotknij aby otworzyć Briar</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Nowa prywatna wiadomość</item> + <item quantity="few">%d prywatnych wiadomoÅ›ci.</item> + <item quantity="many">%d prywatnych wiadomoÅ›ci. </item> + <item quantity="other">%d prywatnych wiadomoÅ›ci.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Nowa wiadomość grupowa.</item> + <item quantity="few">%dwiadomoÅ›ci grupowych. </item> + <item quantity="many">%dwiadomoÅ›ci grupowych. </item> + <item quantity="other">%d wiadomoÅ›ci grupowych.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Nowy post z forum.</item> + <item quantity="few">%d nowych postów z forum. </item> + <item quantity="many">%d nowych postów z forum. </item> + <item quantity="other">%d nowych postów z forum.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Nowy post z bloga.</item> + <item quantity="few">%d nowych postów z bloga. </item> + <item quantity="many">%d nowych postów z bloga. </item> + <item quantity="other">%d nowych postów z bloga.</item> + </plurals> + <!--Misc--> + <string name="now">teraz</string> + <string name="show">Pokaż</string> + <string name="hide">Ukryj</string> + <string name="ok">OK</string> + <string name="cancel">Anuluj</string> + <string name="got_it">Rozumiem</string> + <string name="delete">UsuÅ„</string> + <string name="accept">Akceptuj</string> + <string name="decline">Odrzuć</string> + <string name="options">Opcje</string> + <string name="online">Online</string> + <string name="offline">Offline</string> + <string name="send">WyÅ›lij</string> + <string name="allow">Pozwól</string> + <string name="open">Otwórz</string> + <string name="no_data">Brak danych</string> + <string name="ellipsis">...</string> + <string name="text_too_long">Wprowadzony tekst jest zbyt dÅ‚ugi</string> + <string name="show_onboarding">Pokaż okno pomocy</string> + <string name="fix">Napraw</string> + <string name="help">Pomoc</string> + <string name="sorry">Przepraszam</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Brak kontaktów do wyÅ›wietlenia\n\nDotknij ikonkÄ™ + aby dodać kontakt</string> + <string name="date_no_private_messages">Brak wiadomoÅ›ci.</string> + <string name="no_private_messages">Brak wiadomoÅ›ci do pokazania</string> + <string name="message_hint">Typ wiadomoÅ›ci</string> + <string name="delete_contact">UsuÅ„ kontakt</string> + <string name="dialog_title_delete_contact">Potwierdź usuniÄ™cie kontaktu</string> + <string name="dialog_message_delete_contact">Czy na pewno chcesz usunąć ten kontakt i wszystkie wymienione z nim wiadomoÅ›ci?</string> + <string name="contact_deleted_toast">Kontakt usuniÄ™ty</string> + <!--Adding Contacts--> + <string name="add_contact_title">Dodaj kontakt</string> + <string name="face_to_face">Musisz spotkać siÄ™ z osobÄ… którÄ… chcesz dodać jako kontakt.\n\nTo uniemożliwi komukolwiek podszyć siÄ™ pod Ciebie lub czytać wysyÅ‚ane wiadomoÅ›ci.</string> + <string name="continue_button">Kontynuuj</string> + <string name="connection_failed">Połączenie nieudane</string> + <string name="try_again_button">Spróbuj ponownie</string> + <string name="waiting_for_contact_to_scan">Czekanie aż ktoÅ› zeskanuje kod i połączy siÄ™\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_already_exists">Kontakt %s już istnieje</string> + <string name="contact_exchange_failed">Wymiana kontaktów nie powiodÅ‚a siÄ™</string> + <string name="qr_code_invalid">Kod QR jest nie prawidÅ‚owy</string> + <string name="qr_code_unsupported">Kod QR który chcecsz zeskanować jest z wersji %s która nie jest już wspierana.\n\nProszÄ™ upewnić siÄ™ czy oboje używacie najnowszej wersji i spróbować ponownie.</string> + <string name="camera_error">Błąd aparatu</string> + <string name="connecting_to_device">ÅÄ…czenie z urzÄ…dzeniem\u2026</string> + <string name="authenticating_with_device">Autoryzowanie z urzÄ…dzeniem\u2026</string> + <string name="connection_aborted_local">Połączenie przerwane! To może oznaczać że ktoÅ› próbuje podszyć siÄ™ pod Ciebie</string> + <string name="connection_aborted_remote">Połączenie przerwane przez kontakt! To może oznaczać, że ktoÅ› próbuje zagÅ‚uszyć wasze połączenie</string> + <!--Introductions--> + <string name="introduction_onboarding_title">UdostÄ™pnij swoje kontakty.</string> + <string name="introduction_onboarding_text">Możesz udostÄ™pniać kontakty, tak aby osoby nie musiaÅ‚y spotykać siÄ™ osobiÅ›cie.</string> + <string name="introduction_menu_item">UdostÄ™pnij</string> + <string name="introduction_activity_title">Wybierz kontakt</string> + <string name="introduction_not_possible">Masz już jedno udostÄ™pnianie w toku. ProszÄ™ pozwolić aby proces zakoÅ„czyÅ‚ siÄ™. JeÅ›li kontakty sÄ… rzadko online, może to zabrać trochÄ™ czasu.</string> + <string name="introduction_message_title">UdostÄ™pnij kontakty</string> + <string name="introduction_message_hint">Dodaj wiadomość (opcjonalne)</string> + <string name="introduction_button">UdostÄ™pnij</string> + <string name="introduction_sent">UdostÄ™pnianie zostaÅ‚o wysÅ‚ane.</string> + <string name="introduction_error">WystÄ…piÅ‚ błąd podczas udostÄ™pniania.</string> + <string name="introduction_response_error">WystÄ…piÅ‚ błąd podczas odpowiedzi na udostÄ™pnienie</string> + <string name="introduction_request_sent">UdostÄ™pniÅ‚eÅ› %1$s kontaktowi %2$s.</string> + <string name="introduction_request_received">%1$s poprosiÅ‚ o udostÄ™pnienie Twojego kontaktu dla %2$s. Czy chcesz dodać %2$s do listy kontaktów?</string> + <string name="introduction_request_exists_received">%1$s poprosiÅ‚ o udostÄ™pnienie Twojego kontaktu dla %2$s, ale %2$s jest już na liÅ›cie Twoich kontaktów. Jednak %1$s o tym nie wie i możesz odpowiedzieć:</string> + <string name="introduction_request_answered_received">%1$s poprosiÅ‚ aby udostÄ™pnić Twój kontakt dla %2$s.</string> + <string name="introduction_response_accepted_sent">ZaakceptowaÅ‚eÅ› kontakt %1$s.</string> + <string name="introduction_response_accepted_sent_info">Zanim %1$s zostanie dodany jako Twój kontakt, musi także zaakceptować udostÄ™pnienie. To może trochÄ™ potrwać.</string> + <string name="introduction_response_declined_sent">OdrzuciÅ‚eÅ› udostÄ™pnienie kontaktu do %1$s.</string> + <string name="introduction_response_accepted_received">%1$s zaakceptowaÅ‚ udostÄ™pnienie kontaktu %2$s</string> + <string name="introduction_response_declined_received">%1$s odrzuciÅ‚ udostÄ™pnienie kontaktu %2$s</string> + <string name="introduction_response_declined_received_by_introducee">%1$s mówi, że %2$s odrzuciÅ‚ udostÄ™pnienie kontaktu.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Nowy kontakt zostaÅ‚ dodany.</item> + <item quantity="few">%d nowych kontaktów zostaÅ‚o dodanych.</item> + <item quantity="many">%d nowych kontaktów zostaÅ‚o dodanych.</item> + <item quantity="other">%d nowych kontaktów zostaÅ‚o dodanych.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">Brak grup do wyÅ›wietlenia\n\nDotknij ikonki + aby stworzyć grupÄ™ bÄ…dź poprosić kontakty o udostÄ™pnienie grup</string> + <string name="groups_created_by">Stworzone przez %s</string> + <plurals name="messages"> + <item quantity="one">%d wiadomość</item> + <item quantity="few">%d wiadomoÅ›ci</item> + <item quantity="many">%d wiadomoÅ›ci</item> + <item quantity="other">%d wiadomoÅ›ci</item> + </plurals> + <string name="groups_group_is_empty">Grupa jest pusta</string> + <string name="groups_group_is_dissolved">Ta grupa zostaÅ‚a rozwiÄ…zana</string> + <string name="groups_remove">UsuÅ„</string> + <string name="groups_create_group_title">Stwórz GrupÄ™ PrywatnÄ…</string> + <string name="groups_create_group_button">Stwórz GrupÄ™</string> + <string name="groups_create_group_invitation_button">WyÅ›lij Zaproszenie</string> + <string name="groups_create_group_hint">Wybierz nazwÄ™ dla twojej prywatnej grupy</string> + <string name="groups_invitation_sent">Zaproszenie do grupy zostaÅ‚o wysÅ‚ane</string> + <string name="groups_message_sent">Wiadomość wysÅ‚ana</string> + <string name="groups_member_list">Lista Użytkowników</string> + <string name="groups_invite_members">ZaproÅ› Użytkowników</string> + <string name="groups_member_created_you">StworzyÅ‚eÅ› grupÄ™</string> + <string name="groups_member_created">%s stworzyÅ‚ grupÄ™</string> + <string name="groups_member_joined_you">DołączyÅ‚eÅ› do grupy</string> + <string name="groups_member_joined">%s dołączyÅ‚/a do grupy</string> + <string name="groups_leave">Opuść GrupÄ™</string> + <string name="groups_leave_dialog_title">Potwierdź Opuszczenie Grupy</string> + <string name="groups_leave_dialog_message">JesteÅ› pewny, że chcesz opuÅ›cić tÄ… grupÄ™?</string> + <string name="groups_dissolve">Rozwiąż GrupÄ™</string> + <string name="groups_dissolve_dialog_title">Potwierdź RozwiÄ…zanie Grupy</string> + <string name="groups_dissolve_dialog_message">Czy chcesz rozwiÄ…zać tÄ… grupÄ™?\n\nWszyscy czÅ‚onkowie nie bÄ™dÄ… mogli kontynuować swoich konwersacji ani otrzymywać wiadomoÅ›ci.</string> + <string name="groups_dissolve_button">Rozwiąż</string> + <string name="groups_dissolved_dialog_title">Grupa ZostaÅ‚a RozwiÄ…zana</string> + <string name="groups_dissolved_dialog_message">Twórca tej grupy rozwiÄ…zaÅ‚ jÄ….\n\nNie możesz już wiÄ™cej pisać z czÅ‚onkami grupy ani czytać postów które zostaÅ‚y już napisane.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Zaproszenia do Grup</string> + <string name="groups_invitations_invitation_sent">ZaprosiÅ‚eÅ› %1$s aby dołączyÅ‚ do grupy \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s zaprosiÅ‚ ciÄ™ abyÅ› dołączyÅ‚ do grupy \"%2$s\".</string> + <string name="groups_invitations_joined">DołączyÅ‚eÅ› do grupy</string> + <string name="groups_invitations_declined">Zaproszenie do grupy odrzucone</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d otwórz zaproszenie do grupy</item> + <item quantity="few">%dotwórz zaproszenia do grup </item> + <item quantity="many">%dotwórz zaproszenia do grup </item> + <item quantity="other">%d otwórz zaproszenia do grup</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">PrzyjÄ…Å‚eÅ› zaproszenie do grupy od %s.</string> + <string name="groups_invitations_response_declined_sent">OdrzuciÅ‚eÅ› zaproszenie do grupy od %s.</string> + <string name="groups_invitations_response_accepted_received">%s przyjÄ…Å‚ zaproszenie do grupy.</string> + <string name="groups_invitations_response_declined_received">%s odrzuciÅ‚ zaproszenie do grupy.</string> + <string name="sharing_status_groups">Tylko osoba która utworzyÅ‚a grupÄ™ może zapraszać nowych użytkowników do grupy. Poniżej sÄ… osoby, które dołączyÅ‚y do grupy.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Ujawnij kontakty</string> + <string name="groups_reveal_dialog_message">Możesz wybrać czy chcesz ujawnić kontakty dla wszystkich aktualnych i przyszÅ‚ych czÅ‚onków tej grupy.\n\nUjawnienie kontaktów sprawia że połączenie do grupy jest szybsze i bardziej stabilne, ponieważ możesz komunikować siÄ™ z ujawnionymi kontaktami nawet wtedy kiedy twórca grupy jest offline.</string> + <string name="groups_reveal_visible">PowiÄ…zanie kontaktów jest widoczne dla grupy</string> + <string name="groups_reveal_visible_revealed_by_us">Relacje kontaktów sÄ… widoczne dla grupy (ujawnione przez Ciebie)</string> + <string name="groups_reveal_visible_revealed_by_contact">Relacje kontaktów sÄ… widoczne dla grupy (ujawnione przez %s)</string> + <string name="groups_reveal_invisible">Relacje kontaktów sÄ… nie widoczne dla grupy</string> + <!--Forums--> + <string name="no_forums">Brak for do wyÅ›wietlenia\n\nDotknij ikonÄ™ + aby stworzyć forum, lub poproÅ› swoje kontakty o udostÄ™pnienie Ci for.</string> + <string name="create_forum_title">Stwórz Forum</string> + <string name="choose_forum_hint">Wybierz nazwÄ™ dla swojego forum</string> + <string name="create_forum_button">Stwórz Forum</string> + <string name="forum_created_toast">Forum stworzone</string> + <string name="no_forum_posts">Brak postów do pokazania</string> + <string name="no_posts">Brak postów</string> + <plurals name="posts"> + <item quantity="one">%d post</item> + <item quantity="few">%d postów</item> + <item quantity="many">%d postów</item> + <item quantity="other">%d postów</item> + </plurals> + <string name="forum_new_entry_posted">Post na forum opublikowany</string> + <string name="forum_new_message_hint">Nowy Post</string> + <string name="forum_message_reply_hint">Nowa Odpowiedź</string> + <string name="btn_reply">Odpowiedz</string> + <string name="forum_leave">Opuść Forum</string> + <string name="dialog_title_leave_forum">Potwierdź Opuszczenie Forum</string> + <string name="dialog_message_leave_forum">JesteÅ› pewny, że chcesz opuÅ›cić to forum?\n\nWszystkie kontakty którym udostÄ™pniÅ‚eÅ› to forum mogÄ… przestać otrzymywać powiadomienia.</string> + <string name="dialog_button_leave">Opuść</string> + <string name="forum_left_toast">OpuÅ›ciÅ‚/a Forum</string> + <!--Forum Sharing--> + <string name="forum_share_button">UdostÄ™pnij Forum</string> + <string name="contacts_selected">Zaznaczone kontakty</string> + <string name="activity_share_toolbar_header">Wybierz Kontakty</string> + <string name="no_contacts_selector">Brak kontaktów do wyÅ›wietlenia\n\nWróć tu kiedy dodasz kontakt</string> + <string name="forum_shared_snackbar">Forum udostÄ™pnione wybranym kontaktom</string> + <string name="forum_share_message">Dodaj wiadomość (opcjonalne)</string> + <string name="forum_share_error">WystÄ…piÅ‚ problem podczas udostÄ™pniania tego forum.</string> + <string name="forum_invitation_received">%1$s udostÄ™pniÅ‚ Ci forum \"%2$s\"</string> + <string name="forum_invitation_sent">UdostÄ™pniÅ‚eÅ› forum \"%1$s\" użytkownikowi %2$s.</string> + <string name="forum_invitations_title">Zaproszenia do for</string> + <string name="forum_invitation_exists">Już zaakceptowaÅ‚eÅ› zaproszenie do tego forum.\n\nAkceptowanie wiÄ™kszej iloÅ›ci zaproszeÅ„ sprawi, że Twoje połączenie bÄ™dzie szybsze i bardziej stabilne.</string> + <string name="forum_joined_toast">DołączyÅ‚ do forum</string> + <string name="forum_declined_toast">Zaproszenie odrzucone</string> + <string name="shared_by_format">UdostÄ™pnione przez %s</string> + <string name="forum_invitation_already_sharing">Już udostÄ™pnione</string> + <string name="forum_invitation_response_accepted_sent">PrzyjÄ…Å‚eÅ› zaproszenie do forum od %s</string> + <string name="forum_invitation_response_declined_sent">OdrzuciÅ‚eÅ› zaproszenie do forum od %s</string> + <string name="forum_invitation_response_accepted_received">%s przyjÄ…Å‚ zaproszenie do forum.</string> + <string name="forum_invitation_response_declined_received">%s odrzuciÅ‚ zaproszenie do forum.</string> + <string name="sharing_status">Status UdostÄ™pniania</string> + <string name="sharing_status_forum">Każdy czÅ‚onek tego forum może udostÄ™pnić je swoim kontaktom. UdostÄ™pniasz to forum nastÄ™pujÄ…cym kontaktom. MogÄ… tu także być czÅ‚onkowie których nie możesz zobaczyć.</string> + <string name="shared_with">UdostÄ™pniono %1$d (%2$d online)</string> + <plurals name="forums_shared"> + <item quantity="one">%d forum udostÄ™pnione przez kontakty </item> + <item quantity="few">%d for udostÄ™pnionych przez kontakty </item> + <item quantity="many">%d for udostÄ™pnionych przez kontakty </item> + <item quantity="other">%d for udostÄ™pnionych przez kontakty</item> + </plurals> + <string name="nobody">Nikt</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Brak postów do pokazania</string> + <string name="read_more">czytaj wiÄ™cej</string> + <string name="blogs_write_blog_post">Napisz Post Bloga</string> + <string name="blogs_write_blog_post_body_hint">Napisz swój wpis na bloga</string> + <string name="blogs_publish_blog_post">Opublikuj</string> + <string name="blogs_blog_post_created">Wpis na Bloga Utworzony</string> + <string name="blogs_blog_post_received">Otrzymano Nowy Wpis z Bloga</string> + <string name="blogs_blog_post_scroll_to">PrzewiÅ„ Do</string> + <string name="blogs_feed_empty_state">Brak postów do wyÅ›wietlenia\n\nPosty od Twoich kontaktów i blogów które subskrybujesz pojawiÄ… siÄ™ tutaj\n\nDotknij ikonki dÅ‚ugopisu aby napisać post</string> + <string name="blogs_remove_blog">UsuÅ„ Blog</string> + <string name="blogs_remove_blog_dialog_message">JesteÅ› pewny, że chcesz usunąć ten blog?\n\nPosty bÄ™dÄ… usuniÄ™te z Twojego urzÄ…dzenia ale nie z urzÄ…dzeÅ„ innych osób.\n\nWszystkie kontakty którym udostÄ™pniÅ‚eÅ› ten blog mogÄ… przestać otrzymywać powiadomienia.</string> + <string name="blogs_remove_blog_ok">UsuÅ„</string> + <string name="blogs_blog_removed">Blog usuniÄ™ty</string> + <string name="blogs_reblog_comment_hint">Dodaj komentarz (opcjonalne)</string> + <string name="blogs_reblog_button">Podaj dalej</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">UdostÄ™pnij Blog</string> + <string name="blogs_sharing_error">WystÄ…piÅ‚ błąd podczas udostÄ™pniania tego bloga.</string> + <string name="blogs_sharing_button">UdostÄ™pnij Blog</string> + <string name="blogs_sharing_snackbar">Blog udostÄ™pniony wybranym kontaktom</string> + <string name="blogs_sharing_response_accepted_sent">Zaakceptowano zaproszenie do bloga od %s</string> + <string name="blogs_sharing_response_declined_sent">Odrzucono zaproszenie do bloga od %s</string> + <string name="blogs_sharing_response_accepted_received">Użytkownik %s zaakceptowaÅ‚ zaproszenie do bloga.</string> + <string name="blogs_sharing_response_declined_received">Użytkownik %s odrzuciÅ‚ zaproszenie do bloga.</string> + <string name="blogs_sharing_invitation_received">%1$s udostÄ™pniÅ‚/a Ci blog \"%2$s\"</string> + <string name="blogs_sharing_invitation_sent">UdostÄ™pniasz blog \"%1$s\" użytkownikowi %2$s.</string> + <string name="blogs_sharing_invitations_title">Zaproszenia do Blogów</string> + <string name="blogs_sharing_joined_toast">Zasubskrybowano blog</string> + <string name="blogs_sharing_declined_toast">Zaproszenie odrzucone</string> + <string name="sharing_status_blog">Każdy kto subskrybuje blog może go udostÄ™pnić swoim kontaktom. UdostÄ™pniasz ten blog nastÄ™pujÄ…cym kontaktom. MogÄ… być tu także subskrybenci których nie możesz zobaczyć.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Zaimportuj RSS</string> + <string name="blogs_rss_feeds_import_button">Zaimportuj</string> + <string name="blogs_rss_feeds_import_hint">Wprowadź adres URL do RSS</string> + <string name="blogs_rss_feeds_import_error">WystÄ…piÅ‚ błąd podczas importowania.</string> + <string name="blogs_rss_feeds_manage">ZarzÄ…dzaj RSS</string> + <string name="blogs_rss_feeds_manage_imported">Zaimportowane:</string> + <string name="blogs_rss_feeds_manage_author">Autor:</string> + <string name="blogs_rss_feeds_manage_updated">Ostatnio Zaktualizowane:</string> + <string name="blogs_rss_remove_feed">UsuÅ„ RSS</string> + <string name="blogs_rss_remove_feed_dialog_message">JesteÅ› pewny, że chcesz usunąć tÄ… tablicÄ™?\n\nPosty bÄ™dÄ… usuniÄ™te z Twojego urzÄ…dzenia ale nie z urzÄ…dzeÅ„ innych ludzi.\n\nWszystkie kontakty którym udostÄ™pniÅ‚eÅ› ten blog mogÄ… przestać otrzymywać powiadomienia.</string> + <string name="blogs_rss_remove_feed_ok">UsuÅ„</string> + <string name="blogs_rss_feeds_manage_delete_error">KanaÅ‚ nie mógÅ‚ zostać usuniÄ™ty!</string> + <string name="blogs_rss_feeds_manage_empty_state">Brak RSS do wyÅ›wietlenia\n\nDotknij ikonki + aby zaimportować</string> + <string name="blogs_rss_feeds_manage_error">WystÄ…piÅ‚ problem podczas Å‚adowania twoich RSS. ProszÄ™ spróbować ponownie.</string> + <!--Settings Display--> + <string name="pref_language_title">JÄ™zyk & region</string> + <string name="pref_language_changed">Aby zastosować ustawienia musisz zrestartować Briar. ProszÄ™ siÄ™ wylogować i zrestartować Briar.</string> + <string name="pref_language_default">DomyÅ›lny systemu</string> + <string name="display_settings_title">WyÅ›wietl</string> + <string name="pref_theme_title">Motyw</string> + <string name="pref_theme_light">Jasny</string> + <string name="pref_theme_dark">Ciemny</string> + <string name="pref_theme_auto">Automatycznie (w czasie dnia)</string> + <string name="pref_theme_system">DomyÅ›lny Systemu</string> + <!--Settings Network--> + <string name="network_settings_title">Sieci</string> + <string name="bluetooth_setting">Połącz przez Bluetooth</string> + <string name="bluetooth_setting_enabled">Zawsze wtedy gdy kontakty sÄ… w pobliżu</string> + <string name="bluetooth_setting_disabled">Tylko gdy dodajÄ™ kontakty</string> + <string name="tor_network_setting">Połącz przez Tor</string> + <string name="tor_network_setting_never">Nigdy</string> + <string name="tor_network_setting_wifi">Tylko gdy używam Wi-Fi</string> + <string name="tor_network_setting_always">Gdy używam Wi-Fi lub sieci komórkowej</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">BezpieczeÅ„stwo</string> + <string name="change_password">ZmieÅ„ hasÅ‚o</string> + <string name="current_password">Obecne hasÅ‚o</string> + <string name="choose_new_password">Nowe hasÅ‚o</string> + <string name="confirm_new_password">Potwierdź nowe hasÅ‚o</string> + <string name="password_changed">HasÅ‚o zostaÅ‚o zmienione.</string> + <string name="panic_setting">Konfiguracja przycisku wyjÅ›cia awaryjnego</string> + <string name="panic_setting_title">Przycisk wyjÅ›cia awaryjnego</string> + <string name="panic_setting_hint">Skonfiguruj jak Briar ma zareagować gdy wciÅ›niesz przycisk wyjÅ›cia awaryjnego</string> + <string name="panic_app_setting_title">Aplikacja Przycisku WyjÅ›cia Awaryjnego</string> + <string name="unknown_app">nie znana aplikacja</string> + <string name="panic_app_setting_summary">Å»adna aplikacja nie zostaÅ‚a ustawiona</string> + <string name="panic_app_setting_none">Brak</string> + <string name="dialog_title_connect_panic_app">Potwierdź AwaryjnÄ… AplikacjÄ™</string> + <string name="dialog_message_connect_panic_app">Czy na pewno chcesz pozwolić %1$s aby dziaÅ‚aÅ‚a jako przycisk wyjÅ›cia awaryjnego?</string> + <string name="panic_setting_signout_title">Wyloguj siÄ™</string> + <string name="panic_setting_signout_summary">Wyloguj siÄ™ z Briar jeÅ›li przycisk zostanie wciÅ›niÄ™ty</string> + <string name="purge_setting_title">Skasuj Konto</string> + <string name="purge_setting_summary">Skasuj Twoje konto Briar jeÅ›li przycisk wyjÅ›cia awaryjnego zostanie wciÅ›niÄ™ty. Ostrzeżenie: Ta akcja usunie permanentnie Twoje konto, kontakty i wiadomoÅ›ci</string> + <string name="uninstall_setting_title">Odinstaluj Briar</string> + <string name="uninstall_setting_summary">To wymaga manualnego potwierdzenia w przypadku aktywowania</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Powiadomienia</string> + <string name="notify_private_messages_setting_title">Prywatne wiadomoÅ›ci</string> + <string name="notify_private_messages_setting_summary">Pokaż powiadomienia dla prywatnych wiadomoÅ›ci</string> + <string name="notify_private_messages_setting_summary_26">Skonfiguruj powiadomienia dla prywatnych wiadomoÅ›ci</string> + <string name="notify_group_messages_setting_title">WiadomoÅ›ci grupowe</string> + <string name="notify_group_messages_setting_summary">Pokaż powiadomienia dla aplikacji grupowych</string> + <string name="notify_group_messages_setting_summary_26">Skonfiguruj powiadomienia dla wiadomoÅ›ci grupowych</string> + <string name="notify_forum_posts_setting_title">Posty na forum</string> + <string name="notify_forum_posts_setting_summary">Pokazuj powiadomienia dla postów w forach</string> + <string name="notify_forum_posts_setting_summary_26">Skonfiguruj powiadomienia dla postów w forach</string> + <string name="notify_blog_posts_setting_title">Wpisy na blogach</string> + <string name="notify_blog_posts_setting_summary">Pokazuj powiadomienia dla wpisów na blogach</string> + <string name="notify_blog_posts_setting_summary_26">Skonfiguruj alerty dla wpisów na blogach</string> + <string name="notify_vibration_setting">Wibruj</string> + <string name="notify_lock_screen_setting_title">Ekran blokady</string> + <string name="notify_lock_screen_setting_summary">Pokaż powiadomienia na zablokowanym ekranie</string> + <string name="notify_sound_setting">DźwiÄ™k</string> + <string name="notify_sound_setting_default">DomyÅ›lny dzwonek</string> + <string name="notify_sound_setting_disabled">Brak</string> + <string name="choose_ringtone_title">Wybierz dzwonek</string> + <string name="cannot_load_ringtone">Nie mogÄ™ zaÅ‚adować dzwonka</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Wsparcie</string> + <string name="send_feedback">WyÅ›lij wsparcie</string> + <!--Link Warning--> + <string name="link_warning_title">Uważaj na link</string> + <string name="link_warning_intro">Otwierasz link w zewnÄ™trznej aplikacji.</string> + <string name="link_warning_text">Może to posÅ‚użyć aby CiÄ™ zidentyfikować. Zastanów siÄ™ czy ufasz osobie która wysÅ‚aÅ‚a Ci ten link i rozważ otwarcie go za pomocÄ… przeglÄ…darki Orfox.</string> + <string name="link_warning_open_link">Otwórz Link</string> + <!--Crash Reporter--> + <string name="crash_report_title">ZgÅ‚oÅ› błąd w Briar</string> + <string name="briar_crashed">Przepraszamy, wystÄ…piÅ‚ błąd w Briar</string> + <string name="not_your_fault">To nie Twoja wina.</string> + <string name="please_send_report">ProszÄ™ pomóż nam ulepszać Briar wysyÅ‚ajÄ…c raport z usterki.</string> + <string name="report_is_encrypted">Raport z usterki jest zaszyfrowany i wysyÅ‚any bezpiecznie.</string> + <string name="feedback_title">Wsparcie</string> + <string name="describe_crash">Opisz co siÄ™ staÅ‚o (opcjonalne)</string> + <string name="enter_feedback">Wprowadź swoje uwagi</string> + <string name="optional_contact_email">Twój adres email (opcjonalne)</string> + <string name="include_debug_report_crash">Załącz anonimowe dane na temat usterki</string> + <string name="include_debug_report_feedback">Załącz anonimowe dane o tym urzÄ…dzeniu</string> + <string name="could_not_load_report_data">Nie można byÅ‚o zaÅ‚adować danych.</string> + <string name="send_report">WyÅ›lij raport</string> + <string name="close">Zamknij</string> + <string name="dev_report_saved">Raport zapisany. Zostanie wysÅ‚any nastÄ™pnym razem kiedy zalogujesz siÄ™ do Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">Wylogowywanie z Briar...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Wykryto nakÅ‚adkÄ™ na ekran</string> + <string name="screen_filter_body">Inna aplikacja jest rysowana nad Briar. Aby bronić Twoje bezpieczeÅ„stwo, Briar nie bÄ™dzie odpowiadaÅ‚ na dotyk gdy inna aplikacja jest rysowana nad nim.\n\nNastÄ™pujÄ…ce aplikacje mogÄ… być przyczynÄ…:\n\n%1$s</string> + <string name="screen_filter_allow">Pozwól tym aplikacjom na pozostanie na pierwszym planie</string> + <!--Permission Requests--> + <string name="permission_camera_title">DostÄ™p do aparatu</string> + <string name="permission_camera_request_body">Aby zeskanować kod QR, Briar potrzebuje mieć dostÄ™p do aparatu.</string> + <string name="permission_camera_denied_body">OdmówiÅ‚eÅ› dostÄ™pu do kamery, lecz dodawanie kontaktów tego wymaga.\n\nProszÄ™ udzielić dostÄ™pu.</string> + <string name="permission_camera_denied_toast">DostÄ™p do aparatu nie zostaÅ‚ przyznany</string> + <string name="qr_code">Kod QR</string> + <string name="show_qr_code_fullscreen">Pokaż QR na peÅ‚nym ekranie</string> +</resources> diff --git a/mailbox-android/src/main/res/values-pt-rBR/strings.xml b/mailbox-android/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..7e89a075a1a467d6dd338831d3f79b4f2a452a42 --- /dev/null +++ b/mailbox-android/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,400 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Boas-vindas ao Briar</string> + <string name="setup_name_explanation">Seu nome de usuária será mostrado próximo a qualquer conteúdo que você publicar. Você não pode mudá-lo depois que criar sua conta,</string> + <string name="setup_next">Próximo</string> + <string name="setup_password_intro">Escolha uma senha</string> + <string name="setup_password_explanation">A sua conta do Briar está salva de modo criptografado no seu dispositivo, não na nuvem. Se você esquecer sua senha nou desinstalar o Briar não há como recuperar sua conta.\n\nEscolha uma senha longa que seja difÃcil de ser adivinhada, como cinco palavras aleatórias ou dez letras, números e sÃmbolos aleatórios.</string> + <string name="setup_doze_title">Conexões em segundo plano</string> + <string name="setup_doze_intro">Para receber mensagens, o Briar precisa permanecer conectado em segundo plano.</string> + <string name="setup_doze_explanation">Para receber mensagens, o Briar precisa permanecer conectado em segundo plano. Por favor, desative as otimizações da bateria para que o Briar possa permanecer conectado.</string> + <string name="setup_doze_button">Pemitir conexões</string> + <string name="choose_nickname">Escolha seu apelido</string> + <string name="choose_password">Escolha sua senha</string> + <string name="confirm_password">Confirme sua senha</string> + <string name="name_too_long">O nome está muito grande</string> + <string name="password_too_weak">A senha está muito fraca</string> + <string name="passwords_do_not_match">As senhas não conferem</string> + <string name="create_account_button">Criar conta</string> + <string name="more_info">Informações adicionais</string> + <string name="don_t_ask_again">Não perguntar novamente</string> + <string name="setup_huawei_text">Toque no botão abaixo e verifique se o Briar está protegido na tela \"Aplicativos Protegidos\"</string> + <string name="setup_huawei_button">Proteger o Briar</string> + <string name="setup_huawei_help">Se o Briar não for adicionado à lista de aplicativos protegidos ele não poderá ser executado em segundo plano.</string> + <string name="warning_dozed">%s não pôde ser executado em segundo plano</string> + <!--Login--> + <string name="enter_password">Senha</string> + <string name="try_again">Senha Incorreta, tente novamente</string> + <string name="sign_in_button">Entrar</string> + <string name="forgotten_password">Esqueci minha senha</string> + <string name="dialog_title_lost_password">Perdeu a senha</string> + <string name="dialog_message_lost_password">Sua conta Briar é armazenada em seu dispositivo e criptografada, não na Nuvem, assim não podemos recuperar a senha. Você quer deletar sua conta e começar de novo?\n\nAtenção: Isso irá apagar permanentemente suas identidades, contatos e mensagens</string> + <string name="startup_failed_notification_title">Briar não pode iniciar</string> + <string name="startup_failed_notification_text">Pressione para mais informações.</string> + <string name="startup_failed_activity_title">Inicialização do Briar falhou</string> + <string name="startup_failed_db_error">Por algum motivo, o banco de dados do seu Briar está corrompido e não é possÃvel repará-lo. Sua conta, seus dados e seus contatos foram perdidos. Infelizmente, você precisará reinstalar o Briar ou criar uma nova conta escolhendo a opção \'Esqueci minha senha\'.</string> + <string name="startup_failed_data_too_old_error">Sua conta foi criada numa versão mais antiga do aplicativo e não pode ser aberta nesta versão. Você pode reinstalar a versão antiga ou criar uma conta nova escolhendo a opção \"Esqueci minha senha\".</string> + <string name="startup_failed_data_too_new_error">A versão deste aplicativo é muito antiga. Por favor, atualize para a versão mais nova e tente novamente.</string> + <string name="startup_failed_service_error">O Briar não pode iniciar devido a um plugin. Reinstalar o Briar geralmente resolve esse problema. Porém, note que ao fazer isso você perderá sua conta e todos os dados associados a ela, já que o Briar não usa um servidor central para armazenar seus dados.</string> + <plurals name="expiry_warning"> + <item quantity="one">Esta é uma versão de teste do Briar. Sua conta irá expirar em %d dia e não poderá ser renovada.</item> + <item quantity="other">Esta é uma versão de teste do Briar. Sua conta irá expirar em %d dias e não poderá ser renovada.</item> + </plurals> + <string name="expiry_update">O prazo de validade da versão de teste foi extendido. Agora sua conta irá expirar em %d dias.</string> + <string name="expiry_date_reached">Este software expirou.\nObrigado por testar!</string> + <string name="download_briar">Para continuar usando o Briar, por favor baixe a versão 1.0.</string> + <string name="create_new_account">Você precisará criar uma nova conta, mas poderá usar o mesmo nome de usuária.</string> + <string name="download_briar_button">Baixar Briar 1.0</string> + <string name="startup_open_database">Descriptografando Banco de Dados...</string> + <string name="startup_migrate_database">Atualizando Banco de Dados...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Abrir aba de navegação</string> + <string name="nav_drawer_close_description">Fechar aba de navegação</string> + <string name="contact_list_button">Contatos</string> + <string name="groups_button">Grupos Privados</string> + <string name="forums_button">Fóruns</string> + <string name="blogs_button">Blogs</string> + <string name="settings_button">Configurações</string> + <string name="sign_out_button">Sair</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-fi</string> + <!--Notifications--> + <string name="reminder_notification_title">Saiu do Briar</string> + <string name="ongoing_notification_title">Conectado ao Briar</string> + <string name="ongoing_notification_text">Toque para abrir o Briar</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Nova mensagem privada.</item> + <item quantity="other">%d novas mensagens privadas.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Nova mensagem de um Grupo.</item> + <item quantity="other">%d novas mensagens de Grupos.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Nova postagem de fórum</item> + <item quantity="other">%d novas postagens em fóruns.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Novo post em Blog.</item> + <item quantity="other">%d novos posts em Blogs.</item> + </plurals> + <!--Misc--> + <string name="now">agora</string> + <string name="show">Mostrar</string> + <string name="hide">Esconder</string> + <string name="ok">OK</string> + <string name="cancel">Cancelar</string> + <string name="got_it">Entendi</string> + <string name="delete">Deletar</string> + <string name="accept">Aceitar</string> + <string name="decline">Recusar</string> + <string name="options">Opções</string> + <string name="online">Online</string> + <string name="offline">Offline</string> + <string name="send">Enviar</string> + <string name="allow">Permitir</string> + <string name="open">Abrir</string> + <string name="no_data">Nenhum dado</string> + <string name="ellipsis">…</string> + <string name="text_too_long">O texto entrado é muito grande</string> + <string name="show_onboarding">Mostrar dialogo de ajuda</string> + <string name="fix">Consertar</string> + <string name="help">Ajuda</string> + <string name="sorry">Sentimos muito</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Nenhum contato para serexibido\n\nPressione o Ãcone + para adicionar um novo contato</string> + <string name="date_no_private_messages">Sem Mensagens</string> + <string name="no_private_messages">Nenhuma mensagem para ser exibida</string> + <string name="message_hint">Digite a mensagem</string> + <string name="delete_contact">Apagar contato</string> + <string name="dialog_title_delete_contact">Confirmar remoção do contato</string> + <string name="dialog_message_delete_contact">Você tem certeza que quer remover este contato e todas mensagens trocadas com ele?</string> + <string name="contact_deleted_toast">Contato apagado</string> + <!--Adding Contacts--> + <string name="add_contact_title">Adicionar um contato</string> + <string name="face_to_face">Você deve estar frente-a-frente com a pessoa que deseja adicionar como contato.\n\nIsso evita que alguém se passe por você ou leia suas mensagens no futuro.</string> + <string name="continue_button">Continuar</string> + <string name="connection_failed">Conexão incompleta</string> + <string name="try_again_button">Tente novamente</string> + <string name="waiting_for_contact_to_scan">Esperando pelo contato escanear e conectar\u2026</string> + <string name="exchanging_contact_details">Transferindo detalhes do contato\u2026</string> + <string name="contact_added_toast">Contato adicionado: %s</string> + <string name="contact_already_exists">Contato %s já existe</string> + <string name="contact_exchange_failed">Troca de contatos falhou</string> + <string name="qr_code_invalid">O código QR é inválido</string> + <string name="qr_code_unsupported">O código QR que você está tentando escanear é de uma versão antiga do %s, que não é mais suportada.\n\nPor favor, verifique que você e a outra pessoa está usando a versão mais recente e tentem de novo.</string> + <string name="camera_error">Erro da câmera</string> + <string name="connecting_to_device">Conectando a device\u2026</string> + <string name="authenticating_with_device">Autenticando com o dispositivo\u2026</string> + <string name="connection_aborted_local">Conexão abortada! Isso pode significar que alguém está tentando interferir na sua conexão.</string> + <string name="connection_aborted_remote">Conexão interrompida pelo seu contato! Isto pode significar que algúem está tentando interferir em sua conexão</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Apresente seus contatos</string> + <string name="introduction_onboarding_text">Você pode apresentar seus contatos entre si, assim eles não precisam se encontrar pessoalmente para se comunicar no Briar.</string> + <string name="introduction_menu_item">Fazer apresentação</string> + <string name="introduction_activity_title">Selecionar contato</string> + <string name="introduction_message_title">Apresentar contatos</string> + <string name="introduction_message_hint">Adicione uma mensagem (opcional)</string> + <string name="introduction_button">Fazer apresentação</string> + <string name="introduction_sent">Sua apresentação foi enviada.</string> + <string name="introduction_error">Houve um erro ao fazer a apresentação</string> + <string name="introduction_response_error">Erro ao responder à apresentação</string> + <string name="introduction_request_sent">Você recebeu um pedido para apresentar %1$s a %2$s.</string> + <string name="introduction_request_received">%1$s pediu para apresentar você a %2$s. Você quer adicionar %2$s a sua lista de contatos?</string> + <string name="introduction_request_exists_received">%1$s pediu para apresentar você a %2$s, mas %2$s já está na sua lista de contatos. Já que %1$s não sabe disso, você ainda pode responder:</string> + <string name="introduction_request_answered_received">%1$s pediu para apresentar você a %2$s.</string> + <string name="introduction_response_accepted_sent">Você aceitou ser apresentado a %1$s.</string> + <string name="introduction_response_declined_sent">Você recusou ser apresentado a %1$s.</string> + <string name="introduction_response_accepted_received">%1$s aceitou ser apresentado a %2$s.</string> + <string name="introduction_response_declined_received">%1$s recusou ser apresentado a %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s disse que %2$s recusou a apresentação.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Novo contato adicionado.</item> + <item quantity="other">%d novos contatos adicionados.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">Nenhum grupo para ser exibido\n\nPressione o Ãcone + para criar um novo grupo ou peça para seus contatos compartilharem grupos com você.</string> + <string name="groups_created_by">Criado por %s.</string> + <plurals name="messages"> + <item quantity="one">%d mensagem</item> + <item quantity="other">%d mensagens</item> + </plurals> + <string name="groups_group_is_empty">Esse grupo está vazio</string> + <string name="groups_group_is_dissolved">Esse grupo foi dissolvido</string> + <string name="groups_remove">Remover</string> + <string name="groups_create_group_title">Criar Grupo Privado</string> + <string name="groups_create_group_button">Criar Grupo</string> + <string name="groups_create_group_invitation_button">Enviar Convite</string> + <string name="groups_create_group_hint">Escolha um nome para o seu grupo privado</string> + <string name="groups_invitation_sent">Convite do Grupo enviado </string> + <string name="groups_message_sent">Mensagem enviada</string> + <string name="groups_member_list">Lista de membros</string> + <string name="groups_invite_members">Convidar membros</string> + <string name="groups_member_created_you">Você criou o grupo</string> + <string name="groups_member_created">%s criou o Grupo</string> + <string name="groups_member_joined_you">Você entrou no Grupo</string> + <string name="groups_member_joined">%s entrou no Grupo</string> + <string name="groups_leave">Sair do Grupo</string> + <string name="groups_leave_dialog_title">Confirmar saÃda do Grupo</string> + <string name="groups_leave_dialog_message">Você tem certeza que quer sair desse Grupo?</string> + <string name="groups_dissolve">Dissolver Grupo</string> + <string name="groups_dissolve_dialog_title">Confirmar dissolução do Grupo</string> + <string name="groups_dissolve_dialog_message">Você tem certeza que quer dissolver esse Grupo?\n\nTodos os outros membros não conseguiram continuar recebendo suas conversas e talvez não recebam as ultimas mensagens.</string> + <string name="groups_dissolve_button">Dissolver</string> + <string name="groups_dissolved_dialog_title">O grupo foi dissolvido</string> + <string name="groups_dissolved_dialog_message">O criador desse Grupo o dissolveu.\n\nVocê não pode mais escrever mensagens no grupo e talvez não receba todos posts que foram escritos.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Convites para Grupos</string> + <string name="groups_invitations_invitation_sent">Você convidou %1$s para entrar no grupo \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s convidou você para entrar no Grupo \"%2$s\".</string> + <string name="groups_invitations_joined">Entrou no Grupo</string> + <string name="groups_invitations_declined">Convite do Grupo recusado</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d convite para Grupo aberto</item> + <item quantity="other">%d convites para Grupos abertos</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Você aceitou o convite do Grupo de %s.</string> + <string name="groups_invitations_response_declined_sent">Você recusou o convite do Grupo de %s.</string> + <string name="groups_invitations_response_accepted_received">%s aceitou o convite do Grupo.</string> + <string name="groups_invitations_response_declined_received">%s recusou o convite do Grupo.</string> + <string name="sharing_status_groups">Apenas o criador pode convidar novas pessoas para o grupo. Abaixo estão os atuais membros do grupo.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Revelar contatos</string> + <string name="groups_reveal_dialog_message">Você pode escolher revelar seus contatos para todos os membros presentes e futuros desse Grupo.\n\nRevelar seus contatos torna sua conexão com o grupo mais rápida e confiável, porque você pode comunicar com os contatos revelados mesmo se o criador do Grupo está offline</string> + <string name="groups_reveal_visible">Relação de contatos é está visÃvel para o Grupo</string> + <string name="groups_reveal_visible_revealed_by_us">Relação de contatos está visÃvel para o Grupo (revelado por você)</string> + <string name="groups_reveal_visible_revealed_by_contact">Relação de contatos está visÃvel para o Grupo (revelado por %s)</string> + <string name="groups_reveal_invisible">Relação de contatos não visÃvel para o Grupo </string> + <!--Forums--> + <string name="no_forums">Nenhum fórum para ser exibido\n\nPressione o Ãcone + para criar um fórum ou peça para seus contatos compartilharem fóruns com você.</string> + <string name="create_forum_title">Criar Fórum</string> + <string name="choose_forum_hint">Escolha um nome para o seu fórum</string> + <string name="create_forum_button">Criar fórum</string> + <string name="forum_created_toast">Fórum criado</string> + <string name="no_forum_posts">Nenhum post para ser exibido</string> + <string name="no_posts">Sem Posts</string> + <plurals name="posts"> + <item quantity="one">%d Post</item> + <item quantity="other">%d Posts</item> + </plurals> + <string name="forum_new_message_hint">Nova postagem</string> + <string name="forum_message_reply_hint">Nova resposta</string> + <string name="btn_reply">Responder</string> + <string name="forum_leave">Sair do fórum</string> + <string name="dialog_title_leave_forum">Confirmar saÃda do fórum</string> + <string name="dialog_message_leave_forum">Você tem certeza que quer sair deste fórum?\n\nContatos com quem você tenha compartilhado este fórum podem parar de receber atualizações dele.</string> + <string name="dialog_button_leave">Sair</string> + <string name="forum_left_toast">Sair do fórum</string> + <!--Forum Sharing--> + <string name="forum_share_button">Compartilhar fórum</string> + <string name="contacts_selected">Contatos Selecionados</string> + <string name="activity_share_toolbar_header">Escolher contatos</string> + <string name="no_contacts_selector">Nenhum contato para ser exibido\n\nVolte aqui depois de ter adicionado um contato</string> + <string name="forum_shared_snackbar">Fòrum compartilhado com os contatos escolhidos</string> + <string name="forum_share_message">Adicionar uma mensagem (opcional)</string> + <string name="forum_share_error">Houve um erro em compartilhar esse fórum.</string> + <string name="forum_invitation_received">%1$s compartilhou o fórum \"%2$s\" com você.</string> + <string name="forum_invitation_sent">Você compartilhou o fórum \"%1$s\" com %2$s.</string> + <string name="forum_invitations_title">Convites para Foruns</string> + <string name="forum_invitation_exists">Você já aceitou um convite para este fórum.\n\nAceitar mais convites fará com que sua conexão ao fórum fique mais rápida e mais confiável.</string> + <string name="forum_joined_toast">Entrou no fórum</string> + <string name="forum_declined_toast">Convite recusado</string> + <string name="shared_by_format">Compartilhado por %s</string> + <string name="forum_invitation_already_sharing">Já compartilhado</string> + <string name="forum_invitation_response_accepted_sent">Você aceitou o convite do fórum do %s.</string> + <string name="forum_invitation_response_declined_sent">Você recusou o convite de Fórum de %s.</string> + <string name="forum_invitation_response_accepted_received">%s aceitou o convite de fórum.</string> + <string name="forum_invitation_response_declined_received">%s recusou o convite de fórum.</string> + <string name="sharing_status">Status de compartilhamento</string> + <string name="sharing_status_forum">Qualquer membro do fórum pode compartilhá-lo com seus contatos. Você está compartilhando este fórum com os seguintes contatos. Também podem existir outros membros que você não consegue visualizar.</string> + <string name="shared_with">Compartilhado com %1$d (%2$d online)</string> + <plurals name="forums_shared"> + <item quantity="one">%d fórum compartilhado por contatos</item> + <item quantity="other">%d fóruns compartilhados por contatos</item> + </plurals> + <string name="nobody">Ninguém</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Nenhum post para ser exibido</string> + <string name="read_more">leia mais</string> + <string name="blogs_write_blog_post">Escrever Post do Blog</string> + <string name="blogs_write_blog_post_body_hint">Digite seu post</string> + <string name="blogs_publish_blog_post">Publicar</string> + <string name="blogs_blog_post_created">Post do Blog criado</string> + <string name="blogs_blog_post_received">Novo Post de Blog recebido</string> + <string name="blogs_blog_post_scroll_to">Role Para</string> + <string name="blogs_feed_empty_state">Nenhum post para ser exibido\n\nPosts dos seus contatos e blogs que você está inscrita apareceção aqui\n\nPressione o Ãcone da caneta para escrever um post</string> + <string name="blogs_remove_blog">Remover Blog</string> + <string name="blogs_remove_blog_dialog_message">Você tem certeza que quer remover este blog?\n\nOs posts serão removidos do seu dispositivo mas não dos dispositivos das outras pessoas.\n\nContatos com quem você tenha compartilhado este blog devem parar de receber atualizações dele.</string> + <string name="blogs_remove_blog_ok">Remover</string> + <string name="blogs_blog_removed">Blog removido</string> + <string name="blogs_reblog_comment_hint">Adicionar um comentário (opcional)</string> + <string name="blogs_reblog_button">Reblog</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Compartilhar Blog</string> + <string name="blogs_sharing_error">Houve um erro em compartilhar esse Blog.</string> + <string name="blogs_sharing_button">Compartilhar Blog</string> + <string name="blogs_sharing_snackbar">Blog compartilhado com os contatos escolhidos</string> + <string name="blogs_sharing_response_accepted_sent">Você aceitou o convite do Blog do %s.</string> + <string name="blogs_sharing_response_declined_sent">Você recusou o convite de Blog de %s.</string> + <string name="blogs_sharing_response_accepted_received">%s aceitou o convite de Blog.</string> + <string name="blogs_sharing_response_declined_received">%s recusou o convite de Fórum.</string> + <string name="blogs_sharing_invitation_received">%1$s compartilhou o blog \"%2$s\" com você.</string> + <string name="blogs_sharing_invitation_sent">Você compartilhou o blog \"%1$s\" com %2$s.</string> + <string name="blogs_sharing_invitations_title">Convites para Fóruns</string> + <string name="blogs_sharing_joined_toast">Inscrita ao blog</string> + <string name="blogs_sharing_declined_toast">Convite recusado</string> + <string name="sharing_status_blog">Qualquer pessoa que se inscreva em um blog pode compartilhá-lo com seus contatos. Você está compartilhando este blog com os seguintes contatos. Também podem haver outras pessoas inscritas que você não consegue visualizar.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Importar Feed RSS</string> + <string name="blogs_rss_feeds_import_button">Importar</string> + <string name="blogs_rss_feeds_import_hint">Entre a URL do feed RSS</string> + <string name="blogs_rss_feeds_import_error">Nós lamentamos! Houve um erro ao importar seu Feed.</string> + <string name="blogs_rss_feeds_manage">Gerenciar Feeds RSS</string> + <string name="blogs_rss_feeds_manage_imported">Importado:</string> + <string name="blogs_rss_feeds_manage_author">Autor:</string> + <string name="blogs_rss_feeds_manage_updated">Última Atualização:</string> + <string name="blogs_rss_remove_feed">Remover Feed</string> + <string name="blogs_rss_remove_feed_dialog_message">Você tem certeza que deseja remover este feed?\n\nOs posts serão removidos do seus dispositivo mas não dos dispositivos de outras pessoas.\n\nContatos com quem você tenha compartilhado este feed devem parar de receber atualizações dele.</string> + <string name="blogs_rss_remove_feed_ok">Remover</string> + <string name="blogs_rss_feeds_manage_delete_error">O Feed não pode ser deletado!</string> + <string name="blogs_rss_feeds_manage_empty_state">Nenhum feed RSS para ser exibido\n\nPressione o Ãcone + para importar um feed</string> + <string name="blogs_rss_feeds_manage_error">Houve um problema ao carregar seus Feeds. Por favor tente novamente.</string> + <!--Settings Display--> + <string name="display_settings_title">Visualização</string> + <string name="pref_theme_title">Tema</string> + <string name="pref_theme_light">Claro</string> + <string name="pref_theme_dark">Escuro</string> + <string name="pref_theme_system">Padrão do Sistema</string> + <!--Settings Network--> + <string name="network_settings_title">Redes</string> + <string name="bluetooth_setting">Conectar via Bluetooth</string> + <string name="bluetooth_setting_enabled">Sempre que estiver perto de contatos</string> + <string name="bluetooth_setting_disabled">Somente quando adicionando contatos</string> + <string name="tor_network_setting">Conectar via Tor</string> + <string name="tor_network_setting_never">Nunca</string> + <string name="tor_network_setting_wifi">Apenas ao usar Wi-Fi</string> + <string name="tor_network_setting_always">Quando usar Wi-Fi ou dados móveis</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Segurança</string> + <string name="change_password">Mudar Senha</string> + <string name="choose_new_password">Nova senha</string> + <string name="confirm_new_password">Confirmar nova senha</string> + <string name="password_changed">Senha alterada com sucesso.</string> + <string name="panic_setting">Configurações do botão de pânico</string> + <string name="panic_setting_title">Botão de pânico</string> + <string name="panic_setting_hint">Configurar como o Briar irá reagir quando você usar um aplicativo de botão de pânico</string> + <string name="panic_app_setting_title">Aplicativo de botão de pânico</string> + <string name="unknown_app">um aplicativo desconhecido</string> + <string name="panic_app_setting_summary">Nenhum aplicativo foi selecionado</string> + <string name="panic_app_setting_none">Nenhum</string> + <string name="dialog_title_connect_panic_app">Confirmar aplicativo de pânico</string> + <string name="dialog_message_connect_panic_app">Você tem certeza que quer permitir que %1$s ative ações destrutivas do botão de pânico?</string> + <string name="panic_setting_signout_title">Desconectar</string> + <string name="panic_setting_signout_summary">Desconectar do Briar se o botão de pânico for apertado</string> + <string name="purge_setting_title">Apagar conta</string> + <string name="purge_setting_summary">Apagar sua conta do Briar se o botão de pânico for apertado. Atenção: isso irá apagar permanentemente suas identidades, contatos e mensagens</string> + <string name="uninstall_setting_title">Desinstalar o Briar</string> + <string name="uninstall_setting_summary">Isso requer configuração manual em um evento de pânico</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Notificações</string> + <string name="notify_private_messages_setting_title">Mensagens privadas</string> + <string name="notify_private_messages_setting_summary">Mostrar alertas para mensagens privadas</string> + <string name="notify_private_messages_setting_summary_26">Configurar alertas para mensagens privadas</string> + <string name="notify_group_messages_setting_title">Mensagens de Grupo</string> + <string name="notify_group_messages_setting_summary">Mostrar alertas para mensagens de Grupos</string> + <string name="notify_group_messages_setting_summary_26">Configurar alertas para mensagens de grupos</string> + <string name="notify_forum_posts_setting_title">Postagens do fórum</string> + <string name="notify_forum_posts_setting_summary">Mostrar alertas para postagens nos fóruns</string> + <string name="notify_forum_posts_setting_summary_26">Configurar alertas para posts de fóruns</string> + <string name="notify_blog_posts_setting_title">Posts do blog</string> + <string name="notify_blog_posts_setting_summary">Mostrar alertas para postagens nos blogs</string> + <string name="notify_blog_posts_setting_summary_26">Configurar alertas para posts de blogs</string> + <string name="notify_vibration_setting">Vibrar</string> + <string name="notify_lock_screen_setting_title">Bloquear a tela</string> + <string name="notify_lock_screen_setting_summary">Mostrar notificações enquanto a tela estiver bloqueada</string> + <string name="notify_sound_setting">Som</string> + <string name="notify_sound_setting_default">Toque padrão</string> + <string name="notify_sound_setting_disabled">Nenhum</string> + <string name="choose_ringtone_title">Escolher toque</string> + <string name="cannot_load_ringtone">Não foi possÃvel carregar o toque</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Feedback</string> + <string name="send_feedback">Enviar feedback</string> + <!--Link Warning--> + <string name="link_warning_title">Aviso sobre Link</string> + <string name="link_warning_intro">Você está prestes a abrir esse link em um Aplicativo Externo.</string> + <string name="link_warning_text">Isso pode ser usado para identificar você. Pense se você confia a pessoa que enviou esse link ou considere abrindo o no Orfox.</string> + <string name="link_warning_open_link">Abrir Link</string> + <!--Crash Reporter--> + <string name="crash_report_title">Relatório de falhas do Briar</string> + <string name="briar_crashed">Briar encerrou de maneira inesperada</string> + <string name="not_your_fault">Isso não é sua culpa.</string> + <string name="please_send_report">Nós ajude a construir um Briar melhor enviando um relatório de falhas.</string> + <string name="report_is_encrypted">Nós prometemos que o relatório é criptografado e enviado de forma segura.</string> + <string name="feedback_title">Comentário</string> + <string name="describe_crash">Descreva o que aconteceu (opcional)</string> + <string name="enter_feedback">Digite seu comentário</string> + <string name="optional_contact_email">E-mail de contato (opcional)</string> + <string name="include_debug_report_crash">Incluir informações anonimas sobre o </string> + <string name="include_debug_report_feedback">Incluir dados anônimos sobre esse dispositivo </string> + <string name="could_not_load_report_data">Não foi possÃvel carregar os dados do relatório.</string> + <string name="send_report">Enviar relatório </string> + <string name="close">Fechar</string> + <string name="dev_report_saved">Relatório salvo. Ele será enviado na próxima vez em que você entrar no Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">Saindo do Briar…</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Sobreposição de tela detectada</string> + <string name="screen_filter_body">Outro aplicativo está se sobrepondo sobre o Briar. Para proteger sua segurança, Briar não responderá a seus toques enquanto estiver sobreposto.\n\nOs seguintes aplicativos podem estar se sobrepondo:\n\n%1$s</string> + <string name="screen_filter_allow">Permitir que estes aplicativos se sobreponham</string> + <!--Permission Requests--> + <string name="permission_camera_title">Permissão da câmera</string> + <string name="permission_camera_request_body">O Briar precisa acessar a câmera para pode escanear o código QR.</string> + <string name="permission_camera_denied_body">Você negou acesso à câmera, mas para adicionar contatos você precisa da câmera.\n\nPor favor, pense em liberar o acesso a ela.</string> + <string name="permission_camera_denied_toast">A permissão da câmera não foi concedida</string> + <string name="qr_code">Código QR</string> + <string name="show_qr_code_fullscreen">Mostrar o código QR na tela cheia</string> +</resources> diff --git a/mailbox-android/src/main/res/values-ro/strings.xml b/mailbox-android/src/main/res/values-ro/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..fac76c4a820af91b0886a0832bdff6cb856193ca --- /dev/null +++ b/mailbox-android/src/main/res/values-ro/strings.xml @@ -0,0 +1,424 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Bine ai venit la Briar</string> + <string name="setup_name_explanation">Numele dumneavoastră va fi afiÈ™at lângă orice conÈ›inut trimiteÈ›i. Nu îl veÈ›i putea schimba după crearea contului.</string> + <string name="setup_next">Următorul</string> + <string name="setup_password_intro">AlegeÈ›i o parolă</string> + <string name="setup_password_explanation">Contul dvs. Briar este stocat criptat pe dispozitiv, nu în cloud. Dacă vă uitaÈ›i parola sau È™tergeÈ›i Briar, nu veÈ›i putea să vă recuperaÈ›i contul.\n\nAlegeÈ›i o parolă lungă greu de ghicit, de exemplu, patru cuvinte aleatorii sau zece litere, numere È™i simboluri aleatoare.</string> + <string name="setup_doze_title">Conexiuni în fundal</string> + <string name="setup_doze_intro">Pentru a primi mesaje, Briar are nevoie să stea conectat în fundal.</string> + <string name="setup_doze_explanation">Pentru a primi mesaje, Briar are nevoie să stea conectat în fundal. Vă rugăm să dezactivaÈ›i optimizarea bateriei ca Briar să rămână conectat.</string> + <string name="setup_doze_button">Permite conexiuni</string> + <string name="choose_nickname">AlegeÈ›i-vă numele de utilizator</string> + <string name="choose_password">AlegeÈ›i-vă parola</string> + <string name="confirm_password">ConfirmaÈ›i parola</string> + <string name="name_too_long">Numele este prea lung</string> + <string name="password_too_weak">Parola este prea slabă</string> + <string name="passwords_do_not_match">Parolele nu se potrivesc</string> + <string name="create_account_button">Creează un cont</string> + <string name="more_info">InformaÈ›ii suplimentare</string> + <string name="don_t_ask_again">Nu mai întreba din nou</string> + <string name="setup_huawei_text">Vă rugăm să apăsaÈ›i butonul de mai jos È™i să vă asiguraÈ›i că Briar este marcat ca protejat în fereastra de \"AplicaÈ›ii protejate\".</string> + <string name="setup_huawei_button">Protejează Briar</string> + <string name="setup_huawei_help">Dacă Briar nu este adăugat în lista de aplicaÈ›ii protejate, nu v-a fi capabil să ruleze în fundal.</string> + <string name="warning_dozed">%s nu poate rula în fundal</string> + <!--Login--> + <string name="enter_password">Parola</string> + <string name="try_again">Parolă greÈ™ită, reîncercaÈ›i</string> + <string name="sign_in_button">Autentificare</string> + <string name="forgotten_password">Am uitat parola</string> + <string name="dialog_title_lost_password">Parolă uitată</string> + <string name="dialog_message_lost_password">Contul dvs. Briar este stocat criptat pe dispozitiv, nu în cloud. Dacă vă uitaÈ›i parola sau È™tergeÈ›i Briar, nu veÈ›i putea să vă recuperaÈ›i contul. DoriÈ›i să vă È™tergeÈ›i contul È™i să începeÈ›i din nou?\n\nAtenÈ›ie: identitățile, contactele È™i mesajele dvs. vor fi pierdute definitiv.</string> + <string name="startup_failed_notification_title">Briar nu a putut pornii</string> + <string name="startup_failed_notification_text">AtingeÈ›i pentru informaÈ›ii suplimentare</string> + <string name="startup_failed_activity_title">Eroare de pornire Briar</string> + <string name="startup_failed_db_error">Din anumite motive, baza dvs. de date Briar este deteriorată fără vreo posibilitate de a o recupera. Contul dvs., datele dvs. È™i toate persoanele de contact sunt pierdute. Din nefericire, trebuie să reinstalaÈ›i Briar sau să creaÈ›i un nou cont, selectând \"Am uitat parola\" la promptul de parolă.</string> + <string name="startup_failed_data_too_old_error">Contul dvs. a fost creat cu o versiune veche a acestei aplicaÈ›ii È™i nu poate fi deschis cu această versiune. Trebuie fie să reinstalaÈ›i versiunea veche, fie să configuraÈ›i un nou cont, selectând \"Am uitat parola\" la solicitarea de a introduce parola.</string> + <string name="startup_failed_data_too_new_error">Această versiune a aplicaÈ›iei este prea veche. Vă rugăm să actualizaÈ›i la cea mai nouă versiune È™i să încercaÈ›i din nou.</string> + <string name="startup_failed_service_error">Briar nu a reuÈ™it să pornească un plugin necesar. Reinstalarea lui Briar rezolvă de obicei această problemă. Cu toate acestea, reÈ›ineÈ›i că după aceasta veÈ›i pierde contul È™i toate datele asociate, deoarece Briar nu utilizează serverele centrale pentru a stoca date.</string> + <plurals name="expiry_warning"> + <item quantity="one">Aceasta este o versiune de test pentru Briar. Contul dumneavoastră va expira în %d zi È™i nu se poate reînnoi</item> + <item quantity="few">Aceasta este o versiune de test pentru Briar. Contul dumneavoastră va expira în %d zile È™i nu se poate reînnoi.</item> + <item quantity="other">Aceasta este o versiune de test pentru Briar. Contul dumneavoastră va expira în %d de zile È™i nu se poate reînnoi.</item> + </plurals> + <string name="expiry_update">Data de expirare a versiunii de test a fost extinsă. Contul dumneavoastră va expira acum în %d zile.</string> + <string name="expiry_date_reached">Acest program a expirat.\nVă mulÈ›umim că l-aÈ›i testat!</string> + <string name="download_briar">Pentru a putea să continuaÈ›i utilizarea Briar, vă rugăm să descărcaÈ›i versiunea 1.0.</string> + <string name="create_new_account">Va trebui să creaÈ›i un cont nou, dar puteÈ›i să folosiÈ›i acelaÈ™i nume.</string> + <string name="download_briar_button">Descarcă Briar 1.0</string> + <string name="startup_open_database">Decriptare bază de date...</string> + <string name="startup_migrate_database">Actualizare bază de date...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Deschide bara de navigare</string> + <string name="nav_drawer_close_description">ÃŽnchide bara de navigare</string> + <string name="contact_list_button">Contacte</string> + <string name="groups_button">Grupuri private</string> + <string name="forums_button">Forumuri</string> + <string name="blogs_button">Blog-uri</string> + <string name="settings_button">Setări</string> + <string name="sign_out_button">IeÈ™ire</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="reminder_notification_title">IeÈ™ire din Briar</string> + <string name="reminder_notification_text">AtingeÈ›i pentru autentificare.</string> + <string name="reminder_notification_channel_title">Reamintire autentificare Briar</string> + <string name="reminder_notification_dismiss">Renunță</string> + <string name="ongoing_notification_title">Autentificat în Briar</string> + <string name="ongoing_notification_text">AtingeÈ›i pentru a deschide Briar</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Mesaj privat nou.</item> + <item quantity="few">%d mesaje private noi.</item> + <item quantity="other">%d de mesaje private noi.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Mesaj nou de grup.</item> + <item quantity="few">%d mesaje de grup noi.</item> + <item quantity="other">%d de mesaje de grup noi.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Un nou mesaj pe forum.</item> + <item quantity="few">%d mesaje noi pe forum.</item> + <item quantity="other">%d de mesaje noi pe forum.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Un nou mesaj pe blog.</item> + <item quantity="few">%d mesaje noi pe blog.</item> + <item quantity="other">%d de mesaje noi pe blog.</item> + </plurals> + <!--Misc--> + <string name="now">acum</string> + <string name="show">Arată</string> + <string name="hide">Ascunde</string> + <string name="ok">Bine</string> + <string name="cancel">Anulează</string> + <string name="got_it">Am înÈ›eles</string> + <string name="delete">Șterge</string> + <string name="accept">Acceptă</string> + <string name="decline">Refuză</string> + <string name="options">OpÈ›iuni</string> + <string name="online">Conectat</string> + <string name="offline">Deconectat</string> + <string name="send">Trimite</string> + <string name="allow">Permite</string> + <string name="open">Deschide</string> + <string name="no_data">Fără date</string> + <string name="ellipsis">…</string> + <string name="text_too_long">Textul introdus este prea lung</string> + <string name="show_onboarding">Arata fereastra de ajutor</string> + <string name="fix">Rezolvă</string> + <string name="help">Ajutor</string> + <string name="sorry">Ne pare rău</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Nici un contact de arătat\n\nAtingeÈ›i iconiÈ›a + pentru a adăuga un contact</string> + <string name="date_no_private_messages">Fără mesaje.</string> + <string name="no_private_messages">Nici un mesaj de arătat</string> + <string name="message_hint">ScrieÈ›i mesajul</string> + <string name="delete_contact">Șterge contactul</string> + <string name="dialog_title_delete_contact">Confirmare È™tergere contact</string> + <string name="dialog_message_delete_contact">Sigur doriÈ›i să È™tergeÈ›i acest contact È™i toate mesajele schimbate?</string> + <string name="contact_deleted_toast">Contact È™ters</string> + <!--Adding Contacts--> + <string name="add_contact_title">Adaugă un contact</string> + <string name="face_to_face">Trebuie să vă întâlniÈ›i cu persoana pe care doriÈ›i să o adăugaÈ›i la contacte.\n\nAcest pas împiedică alte persoane să vă fure identitatea sau să vă citească mesajele în viitor.</string> + <string name="continue_button">Continuă</string> + <string name="connection_failed">Conexiune eÈ™uată</string> + <string name="try_again_button">ÃŽncearcă din nou</string> + <string name="waiting_for_contact_to_scan">Se aÈ™teaptă scanarea È™i conectarea contactului\u2026</string> + <string name="exchanging_contact_details">Se face schimbul de date de contact\u2026</string> + <string name="contact_added_toast">Contact adăugat: %s</string> + <string name="contact_already_exists">Contactul %s există deja</string> + <string name="contact_exchange_failed">Schimbul de date de contactului a eÈ™uat</string> + <string name="qr_code_invalid">Codul QR este invalid!</string> + <string name="qr_code_unsupported">Codul QR pe care încercaÈ›i să îl scanaÈ›i aparÈ›ine unei versiuni vechi %s care nu mai este acceptată.\n\nVă rugăm să vă asiguraÈ›i că amândoi executaÈ›i cea mai recentă versiune È™i încercaÈ›i din nou.</string> + <string name="camera_error">Eroare la camera foto</string> + <string name="connecting_to_device">Conectare la dispozitiv\u2026</string> + <string name="authenticating_with_device">Autentificare cu dispozitivul\u2026</string> + <string name="connection_aborted_local">Conexiune întreruptă! Aceasta poate însemna că cineva încearcă să interfereze conexiunea dumneavoastră</string> + <string name="connection_aborted_remote">Conexiune întreruptă de către contactul dumneavoastră! Aceasta poate însemna că cineva încearcă să interfereze conexiunea dumneavoastră</string> + <!--Introductions--> + <string name="introduction_onboarding_title">RecomandaÈ›i-vă contactele</string> + <string name="introduction_onboarding_text">PuteÈ›i să vă recomandaÈ›i contactele unele altora, încât sa nu fie nevoie ca să se vadă față în față pentru a se putea conecta la Briar.</string> + <string name="introduction_menu_item">Fă o recomandare</string> + <string name="introduction_activity_title">Alege un contact</string> + <string name="introduction_not_possible">AÈ›i trimis deja o solicitare la contacte. AÈ™teptaÈ›i să răspundă. Dacă dvs. sau persoanele persoanele de contact sunteÈ›i rareori online, este posibil să dureze ceva timp.</string> + <string name="introduction_message_title">Recomandă contacte</string> + <string name="introduction_message_hint">Adaugă un mesaj (opÈ›ional)</string> + <string name="introduction_button">Fă o recomandare</string> + <string name="introduction_sent">Recomandarea dumneavoastră a fost trimisă.</string> + <string name="introduction_error">A apărut o eroare în procesul de recomandare.</string> + <string name="introduction_response_error">Eroare atunci când s-a răspuns la recomandare</string> + <string name="introduction_request_sent">AÈ›i cerut recomandarea %1$s către %2$s.</string> + <string name="introduction_request_received">%1$s a cerut să vă recomande către %2$s. DoriÈ›i să adăugaÈ›i pe %2$s la lista dumneavoastră de contacte?</string> + <string name="introduction_request_exists_received">%1$s a cerut să vă recomande către %2$s, dar %2$s este deja în lista dumneavoastră de contacte. Cum %1$s s-ar putea să nu È™tie asta, puteÈ›i totuÈ™i răspunde:</string> + <string name="introduction_request_answered_received">%1$s vă recomandă pe %2$s.</string> + <string name="introduction_response_accepted_sent">AÈ›i acceptat recomandarea pentru %1$s.</string> + <string name="introduction_response_accepted_sent_info">ÃŽnainte de a adăuga %1$s ca persoane de contact, este necesar ca ei tot să accepte solicitarea. Aceasta poate dura ceva timp.</string> + <string name="introduction_response_declined_sent">AÈ›i refuzat recomandarea pentru %1$s.</string> + <string name="introduction_response_accepted_received">%1$s a acceptat recomandarea pentru %2$s.</string> + <string name="introduction_response_declined_received">%1$s a refuzat recomandarea pentru %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s spune că %2$s a refuzat recomandarea.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Un nou contact adăugat.</item> + <item quantity="few">%d contacte noi adăugate.</item> + <item quantity="other">%d de contacte noi adăugate.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">Nici un grup de arătat\n\nAtingeÈ›i iconiÈ›a + pentru a crea un grup sau rugaÈ›i-vă contactele să partajele grupuri cu dumneavoastră</string> + <string name="groups_created_by">Creat de %s</string> + <plurals name="messages"> + <item quantity="one">%d mesaj</item> + <item quantity="few">%d mesaje</item> + <item quantity="other">%d de mesaje</item> + </plurals> + <string name="groups_group_is_empty">Acest grup este gol</string> + <string name="groups_group_is_dissolved">Acest grup a fost dizolvat</string> + <string name="groups_remove">Șterge</string> + <string name="groups_create_group_title">Creează grup privat</string> + <string name="groups_create_group_button">Creează grup</string> + <string name="groups_create_group_invitation_button">Trimite invitaÈ›ie</string> + <string name="groups_create_group_hint">AlegeÈ›i un nume pentru grupul dumneavoastră privat</string> + <string name="groups_invitation_sent">InvitaÈ›ia in grup a fost trimisă</string> + <string name="groups_message_sent">Mesaj trimis</string> + <string name="groups_member_list">Lista de membrii</string> + <string name="groups_invite_members">Invită membrii</string> + <string name="groups_member_created_you">AÈ›i creat grupul</string> + <string name="groups_member_created">%s a creat grupul</string> + <string name="groups_member_joined_you">V-aÈ›i alăturat grupului</string> + <string name="groups_member_joined">%s s-a alăturat grupului</string> + <string name="groups_leave">PărăseÈ™te grupul</string> + <string name="groups_leave_dialog_title">Confirmare părăsire grup</string> + <string name="groups_leave_dialog_message">Sigur doriÈ›i să părăsiÈ›i acest grup?</string> + <string name="groups_dissolve">Dizolvă grupul</string> + <string name="groups_dissolve_dialog_title">Confirmă dizolvarea grupului</string> + <string name="groups_dissolve_dialog_message">SunteÈ›i sigur că doriÈ›i să dizolvaÈ›i acest grup?\n\nToÈ›i ceilalÈ›i membri nu vor putea continua conversaÈ›ia lor È™i s-ar putea să nu primească cele mai recente mesaje.</string> + <string name="groups_dissolve_button">Dizolvă</string> + <string name="groups_dissolved_dialog_title">Grupul a fost dizolvat</string> + <string name="groups_dissolved_dialog_message">Creatorul acestui grup a dizolvat-o.\n\nNu mai puteÈ›i scrie mesaje către grup È™i nu mai puteÈ›i primi postările scrise.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">InvitaÈ›ii în grup</string> + <string name="groups_invitations_invitation_sent">AÈ›i invitat pe %1$s să se alăture grupului \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s v-a invitat să vă alăturaÈ›i grupului \"%2$s\".</string> + <string name="groups_invitations_joined">V-aÈ›i alăturat grupului</string> + <string name="groups_invitations_declined">InvitaÈ›ia în grup a fost refuzată</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d invitaÈ›ie în grup disponibilă</item> + <item quantity="few">%d invitaÈ›ii în grup disponibile</item> + <item quantity="other">%d de invitaÈ›ii în grup disponibile</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">AÈ›i acceptat invitaÈ›ia în grup de la %s.</string> + <string name="groups_invitations_response_declined_sent">AÈ›i refuzat invitaÈ›ia în grup pentru %s.</string> + <string name="groups_invitations_response_accepted_received">%s a acceptat invitaÈ›ia în grup.</string> + <string name="groups_invitations_response_declined_received">%s a refuzat invitaÈ›ia în grup.</string> + <string name="sharing_status_groups">Doar persoana care a creat grupul poate invita noi membrii. Mai jos vedeÈ›i membrii actuali ai grupului.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Arată contactele</string> + <string name="groups_reveal_dialog_message">PuteÈ›i alege să dezvăluiÈ›i contacte tuturor membrilor actuali È™i viitori acestui grup.\n\nDeschiderea contactelor face conexiunea dvs. cu grupul mai rapidă È™i mai sigură, deoarece puteÈ›i comunica cu persoanele de contact dezvăluite chiar È™i atunci când creatorul grupului este offline.</string> + <string name="groups_reveal_visible">Lista de contacte este vizibilă grupului</string> + <string name="groups_reveal_visible_revealed_by_us">Lista de contacte este vizibilă grupului (dezvăluită de dumneavoastră)</string> + <string name="groups_reveal_visible_revealed_by_contact">Lista de contacte este vizibilă grupului (dezvăluită de %s)</string> + <string name="groups_reveal_invisible">Lista de contacte nu este vizibilă grupului</string> + <!--Forums--> + <string name="no_forums">Nici un forum de arătat\n\nAtingeÈ›i iconiÈ›a + pentru a crea un forum sau + rugaÈ›i-vă contactele să partajele forumuri cu dumneavoastră</string> + <string name="create_forum_title">Creează forum</string> + <string name="choose_forum_hint">AlegeÈ›i un nume pentru forumul dumneavoastră</string> + <string name="create_forum_button">Creează forum</string> + <string name="forum_created_toast">Forum creat</string> + <string name="no_forum_posts">Nici un mesaj de arătat</string> + <string name="no_posts">Nici un mesaj</string> + <plurals name="posts"> + <item quantity="one">%d mesaj</item> + <item quantity="few">%d mesaje</item> + <item quantity="other">%d de mesaje</item> + </plurals> + <string name="forum_new_entry_posted">Mesajul a fost scris pe forum</string> + <string name="forum_new_message_hint">Mesaj nou</string> + <string name="forum_message_reply_hint">Răspuns nou</string> + <string name="btn_reply">Răspunde</string> + <string name="forum_leave">PărăseÈ™te forum</string> + <string name="dialog_title_leave_forum">Confirmare părăsire forum</string> + <string name="dialog_message_leave_forum">SunteÈ›i sigur că doriÈ›i să părăsiÈ›i acest forum?\n\nOrice persoane de contact cu care aÈ›i împărtășit acest forum s-ar putea să nu mai primească actualizări.</string> + <string name="dialog_button_leave">PărăseÈ™te</string> + <string name="forum_left_toast">Forum părăsit</string> + <!--Forum Sharing--> + <string name="forum_share_button">Partajează forum</string> + <string name="contacts_selected">Contacte selectate</string> + <string name="activity_share_toolbar_header">AlegeÈ›i contactele</string> + <string name="no_contacts_selector">Nici un contact de arătat\n\nReveniÈ›i după ce aÈ›i adăugat un contact</string> + <string name="forum_shared_snackbar">Forum partajat cu contactele alese</string> + <string name="forum_share_message">Adaugă un mesaj (opÈ›ional)</string> + <string name="forum_share_error">A apărut o eroare la partajarea acestui forum.</string> + <string name="forum_invitation_received">%1$s a partajat forumul \"%2$s\" cu dumneavoastră.</string> + <string name="forum_invitation_sent">AÈ›i partajat forumul \"%1$s\" cu %2$s.</string> + <string name="forum_invitations_title">InvitaÈ›ii la forum</string> + <string name="forum_invitation_exists">AÈ›i acceptat deja o invitaÈ›ie la acest forum.\n\nAcceptarea mai multor invitaÈ›ii va face conexiunea dvs. la forum mai rapidă È™i mai sigură.</string> + <string name="forum_joined_toast">Alăturare forum</string> + <string name="forum_declined_toast">InvitaÈ›ia a fost refuzată</string> + <string name="shared_by_format">Partajat de %s</string> + <string name="forum_invitation_already_sharing">Deja partajat</string> + <string name="forum_invitation_response_accepted_sent">AÈ›i acceptat invitaÈ›ia la forum de la %s.</string> + <string name="forum_invitation_response_declined_sent">AÈ›i refuzat invitaÈ›ia la forum pentru %s.</string> + <string name="forum_invitation_response_accepted_received">%s a acceptat invitaÈ›ia la forum.</string> + <string name="forum_invitation_response_declined_received">%s a refuzat invitaÈ›ia la forum.</string> + <string name="sharing_status">Partajare stare</string> + <string name="sharing_status_forum">Orice membru al unui forum poate să-l împărtășească cu contactele lor. ÃŽÈ›i partajaÈ›i acest forum cu următoarele persoane de contact. Pot exista È™i alÈ›i membri pe care nu îi puteÈ›i vedea.</string> + <string name="shared_with">Partajat cu %1$d (%2$d conectaÈ›i)</string> + <plurals name="forums_shared"> + <item quantity="one">%d forum partajat de contacte</item> + <item quantity="few">%d forumuri partajate de contacte</item> + <item quantity="other">%d de forumuri partajate de contacte</item> + </plurals> + <string name="nobody">Nimeni</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Nici un mesaj de arătat</string> + <string name="read_more">citeÈ™te mai mult</string> + <string name="blogs_write_blog_post">Scrie mesaj pe blog</string> + <string name="blogs_write_blog_post_body_hint">IntroduceÈ›i mesajul pentru blog aici</string> + <string name="blogs_publish_blog_post">Publică</string> + <string name="blogs_blog_post_created">Mesaj pe blog creat</string> + <string name="blogs_blog_post_received">O nou mesaj pe blog s-a primit</string> + <string name="blogs_blog_post_scroll_to">Derulează la</string> + <string name="blogs_feed_empty_state">Nici un mesaj de arătat\n\nMesajele de la contactele dumneavoastră È™i de pe blog-urile la care sunteÈ›i abonaÈ›i vor apărea aici\n\nAtingeÈ›i iconiÈ›a cu creion pentru a scrie un mesaj</string> + <string name="blogs_remove_blog">Elimină blog</string> + <string name="blogs_remove_blog_dialog_message">SunteÈ›i sigur că doriÈ›i să eliminaÈ›i acest blog?\n\nPosturile vor fi eliminate de pe dispozitiv, dar nu È™i de dispozitivele altor persoane.\n\nOrice persoane de contact cu care aÈ›i partajat acest blog ar putea să nu mai primească actualizări.</string> + <string name="blogs_remove_blog_ok">Eliminare</string> + <string name="blogs_blog_removed">Blog eliminat</string> + <string name="blogs_reblog_comment_hint">Adaugă un comentariu (opÈ›ional)</string> + <string name="blogs_reblog_button">Repune mesaj</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Partajează blog</string> + <string name="blogs_sharing_error">A apărut o eroare la partajarea acestui blog.</string> + <string name="blogs_sharing_button">Partajează blog</string> + <string name="blogs_sharing_snackbar">Blog partajat cu contactele alese</string> + <string name="blogs_sharing_response_accepted_sent">AÈ›i acceptat invitaÈ›ia la blog de la %s.</string> + <string name="blogs_sharing_response_declined_sent">AÈ›i refuzat invitaÈ›ia la blog de la %s.</string> + <string name="blogs_sharing_response_accepted_received">%s a acceptat invitaÈ›ia la blog.</string> + <string name="blogs_sharing_response_declined_received">%s a refuzat invitaÈ›ia la blog.</string> + <string name="blogs_sharing_invitation_received">%1$s a partajat blogul \"%2$s\" cu dumneavoastră.</string> + <string name="blogs_sharing_invitation_sent">AÈ›i partajat blogul \"%1$s\" cu %2$s.</string> + <string name="blogs_sharing_invitations_title">InvitaÈ›ii la blog-uri</string> + <string name="blogs_sharing_joined_toast">Abonare la blog</string> + <string name="blogs_sharing_declined_toast">InvitaÈ›ia a fost refuzată</string> + <string name="sharing_status_blog">Oricine abonat la un blog poate să-l împărtășească cu persoanele de contact. PartajaÈ›i acest blog cu următoarele persoane de contact. Pot exista È™i alÈ›i abonaÈ›i pe care nu îi puteÈ›i vedea.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Importă flux RSS</string> + <string name="blogs_rss_feeds_import_button">Importă</string> + <string name="blogs_rss_feeds_import_hint">IntroduceÈ›i URL-ul fluxului RSS</string> + <string name="blogs_rss_feeds_import_error">Ne pare rău! A apărut o eroare la importul fluxului dumneavoastră.</string> + <string name="blogs_rss_feeds_manage">Administrare fluxuri RSS</string> + <string name="blogs_rss_feeds_manage_imported">Importat:</string> + <string name="blogs_rss_feeds_manage_author">Autor:</string> + <string name="blogs_rss_feeds_manage_updated">Actualizat ultima dată:</string> + <string name="blogs_rss_remove_feed">Șterge flux</string> + <string name="blogs_rss_remove_feed_dialog_message">SunteÈ›i sigur că doriÈ›i să eliminaÈ›i acest feed?\n\nPosturile vor fi eliminate de pe dispozitiv, dar nu È™i de dispozitivele altor persoane.\n\nOrice persoane de contact cu care aÈ›i distribuit acest feed nu vor mai primi actualizări.</string> + <string name="blogs_rss_remove_feed_ok">Eliminare</string> + <string name="blogs_rss_feeds_manage_delete_error">Fluxul nu a putut fi È™ters!</string> + <string name="blogs_rss_feeds_manage_empty_state">Nici un flux RSS de arătat\n\nAtingeÈ›i iconiÈ›a + pentru a adăuga un flux</string> + <string name="blogs_rss_feeds_manage_error">A apărut o eroare la încărcarea fluxurilor dumneavoastră. Vă rugăm să încercaÈ›i din nou mai târziu.</string> + <!--Settings Display--> + <string name="pref_language_title">Limbă & Regiune</string> + <string name="pref_language_changed">Această setare va avea efect după repornirea Briar. Vă rugăm să ieÈ™iÈ›i din Briar È™i să reporniÈ›i aplicaÈ›ia.</string> + <string name="pref_language_default">Implicit sistem</string> + <string name="display_settings_title">Ecran</string> + <string name="pref_theme_title">Temă</string> + <string name="pref_theme_light">Deschisă</string> + <string name="pref_theme_dark">ÃŽnchisă</string> + <string name="pref_theme_auto">Automat (Zi lumina)</string> + <string name="pref_theme_system">Implicit sistem</string> + <!--Settings Network--> + <string name="network_settings_title">ReÈ›ele</string> + <string name="bluetooth_setting">Conectare prin Bluetooth</string> + <string name="bluetooth_setting_enabled">Atunci când contactele vă sunt în apropiere</string> + <string name="bluetooth_setting_disabled">Doar la adăugarea contactelor</string> + <string name="tor_network_setting">Conectare prin reÈ›eaua Tor</string> + <string name="tor_network_setting_never">Niciodată</string> + <string name="tor_network_setting_wifi">Doar când se foloseÈ™te Wi-Fi</string> + <string name="tor_network_setting_always">Când se foloseÈ™te Wi-Fi sau date mobile</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Securitate</string> + <string name="change_password">Schimbă parola</string> + <string name="current_password">Parolă curentă</string> + <string name="choose_new_password">Parola nouă</string> + <string name="confirm_new_password">ConfirmaÈ›i parola nouă</string> + <string name="password_changed">Parola a fost schimbată.</string> + <string name="panic_setting">Setare buton de panică</string> + <string name="panic_setting_title">Buton de panică</string> + <string name="panic_setting_hint">ConfiguraÈ›i cum va reacÈ›iona Briar atunci când folosiÈ›i o aplicaÈ›ie de buton de panică.</string> + <string name="panic_app_setting_title">AplicaÈ›ia buton de panică</string> + <string name="unknown_app">aplicaÈ›ie necunoscută</string> + <string name="panic_app_setting_summary">Nu a fost setată nici o aplicaÈ›ie</string> + <string name="panic_app_setting_none">Nici una</string> + <string name="dialog_title_connect_panic_app">Confirmare aplicaÈ›ie de panică</string> + <string name="dialog_message_connect_panic_app">Sigur doriÈ›i să permiteÈ›i %1$s să declanÈ™eze acÈ›iuni destructive pentru butonul de panică?</string> + <string name="panic_setting_signout_title">IeÈ™ire</string> + <string name="panic_setting_signout_summary">IeÈ™i din Briar dacă un buton de panică este apăsat</string> + <string name="purge_setting_title">Șterge cont</string> + <string name="purge_setting_summary">ȘtergeÈ›i contul Briar dacă este apăsat buton de panică. AtenÈ›ie: aceasta va È™terge definitiv identitatea, contactele È™i mesajele dvs.</string> + <string name="uninstall_setting_title">Dezinstalare Briar</string> + <string name="uninstall_setting_summary">Aceasta necesită o confirmare manuală în timpul unui eveniment de panică</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Notificări</string> + <string name="notify_sign_in_title">ReaminteÈ™te-mi să mă autentific</string> + <string name="notify_sign_in_summary">Arată o notificare atunci când dispozitivul porneÈ™te sau aplicaÈ›ia a fost actualizată</string> + <string name="notify_private_messages_setting_title">Mesaje private</string> + <string name="notify_private_messages_setting_summary">Arată alerte pentru mesajele private</string> + <string name="notify_private_messages_setting_summary_26">Configurare alerte pentru mesajele private</string> + <string name="notify_group_messages_setting_title">Mesaje de grup</string> + <string name="notify_group_messages_setting_summary">Arată alerte pentru mesajele de grup</string> + <string name="notify_group_messages_setting_summary_26">Configurare alerte pentru mesajele de grup</string> + <string name="notify_forum_posts_setting_title">Mesaje pe forum</string> + <string name="notify_forum_posts_setting_summary">Arată alerte pentru mesajele de pe forum</string> + <string name="notify_forum_posts_setting_summary_26">Configurare alerte pentru mesajele de pe forum</string> + <string name="notify_blog_posts_setting_title">Mesaje pe blog</string> + <string name="notify_blog_posts_setting_summary">Arată alerte pentru mesajele de pe blog</string> + <string name="notify_blog_posts_setting_summary_26">Configurare alerte pentru mesajele de pe blog</string> + <string name="notify_vibration_setting">Vibrează</string> + <string name="notify_lock_screen_setting_title">Ecran de blocare</string> + <string name="notify_lock_screen_setting_summary">Arată notificări pe ecranul de blocare</string> + <string name="notify_sound_setting">Sunet</string> + <string name="notify_sound_setting_default">Sunet implicit</string> + <string name="notify_sound_setting_disabled">Nici unul</string> + <string name="choose_ringtone_title">AlegeÈ›i sunetul</string> + <string name="cannot_load_ringtone">Nu se poate încărca sunetul</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Feed-back</string> + <string name="send_feedback">TrimiteÈ›i feed-back</string> + <!--Link Warning--> + <string name="link_warning_title">Avertizare adresă</string> + <string name="link_warning_intro">Urmează să deschideÈ›i adresa următoare cu o aplicaÈ›ie externă</string> + <string name="link_warning_text">Acest lucru poate fi folosit pentru a vă identifica. GândiÈ›i-vă dacă aveÈ›i încredere în persoana care v-a trimis acest link È™i luaÈ›i în considerare deschiderea acestuia cu Orfox.</string> + <string name="link_warning_open_link">Deschide adresă</string> + <!--Crash Reporter--> + <string name="crash_report_title">Raport de erori Briar</string> + <string name="briar_crashed">Ne pare rău, Briar a întâmpinat o eroare.</string> + <string name="not_your_fault">Nu este vina dumneavoastră.</string> + <string name="please_send_report">Vă rugăm să ne ajutaÈ›i să facem Briar mai bun trimițându-ne raportul de erori.</string> + <string name="report_is_encrypted">Vă promitem ca raportul este criptat È™i este trimis securizat.</string> + <string name="feedback_title">Feed-back</string> + <string name="describe_crash">DescrieÈ›i ce s-a întâmplat (opÈ›ional)</string> + <string name="enter_feedback">IntroduceÈ›i feed-back-ul dumneavoastră</string> + <string name="optional_contact_email">Adresa de email (opÈ›ional)</string> + <string name="include_debug_report_crash">Include date anonime despre eroare</string> + <string name="include_debug_report_feedback">Include date anonime despre acest dispozitiv</string> + <string name="could_not_load_report_data">Nu s-au putut încărca datele din raport.</string> + <string name="send_report">Trimite raport</string> + <string name="close">ÃŽnchide</string> + <string name="dev_report_saved">Raport salvat. V-a fi trimis data viitoare când vă conectaÈ›i la Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">IeÈ™ire din Briar...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">S-a detectat ceva suprapus pe ecran</string> + <string name="screen_filter_body">O altă aplicaÈ›ie este suprapusă pe Briar. Pentru a vă proteja securitatea, Briar nu va reacÈ›iona la atingere în timp ce există o suprapunere.\n\nAplicaÈ›iile următoare pot fi suprapuse:\n\n%1$s</string> + <string name="screen_filter_allow">Permite acestor aplicaÈ›ii să deseneze deasupra</string> + <!--Permission Requests--> + <string name="permission_camera_title">Permisiune de acces la camera foto</string> + <string name="permission_camera_request_body">Pentru a scana codul QR, Briar are nevoie să acceseze camera foto.</string> + <string name="permission_camera_denied_body">AÈ›i refuzat accesul la camera foto, dar pentru a adăuga contacte este necesară folosirea camerei foto.\n\nVă rugăm să luaÈ›i în considerare acordarea accesului.</string> + <string name="permission_camera_denied_toast">Permisiunea de acces la camera foto nu a fost acordată</string> + <string name="qr_code">Cod QR</string> + <string name="show_qr_code_fullscreen">Arată codul QR pe tot ecranul</string> +</resources> diff --git a/mailbox-android/src/main/res/values-ru/strings.xml b/mailbox-android/src/main/res/values-ru/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..a0fb2106598861268927949e0ea3bfc995539f91 --- /dev/null +++ b/mailbox-android/src/main/res/values-ru/strings.xml @@ -0,0 +1,433 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Добро пожаловать в Briar</string> + <string name="setup_name_explanation">Ваш пÑевдоним будет показан Ñ€Ñдом Ñ Ð»ÑŽÐ±Ñ‹Ð¼ публикуемым контентом. Его Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ð·Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ поÑле ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð°ÐºÐºÐ°ÑƒÐ½Ñ‚Ð°.</string> + <string name="setup_next">Вперед</string> + <string name="setup_password_intro">Придумайте пароль</string> + <string name="setup_password_explanation">Ваша ÑƒÑ‡ÐµÑ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ Briar хранитÑÑ Ð² зашифрованном виде только на уÑтройÑтве. ЕÑли вы забудете Ñвой пароль или удалите Briar, то не Ñможете воÑÑтановить Ñвою учетную запиÑÑŒ.\n\nПридумайте длинный пароль, который трудно угадать, например четыре Ñлучайных Ñлова или деÑÑть Ñлучайных букв, цифр и Ñимволов.</string> + <string name="setup_doze_title">Фоновые подключениÑ</string> + <string name="setup_doze_intro">Ð”Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ñообщений Briar должен работать в фоновом режиме.</string> + <string name="setup_doze_explanation">Ð”Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ñообщений Briar должен работать в фоновом режиме. Отключите оптимизацию ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð¿Ð¸Ñ‚Ð°Ð½Ð¸Ñ Ð´Ð»Ñ Briar.</string> + <string name="setup_doze_button">Разрешить подключениÑ</string> + <string name="choose_nickname">Придумайте пÑевдоним</string> + <string name="choose_password">Придумайте пароль</string> + <string name="confirm_password">Подтвердите пароль</string> + <string name="name_too_long">Слишком длинное имÑ</string> + <string name="password_too_weak">Пароль Ñлишком Ñлабый</string> + <string name="passwords_do_not_match">Пароли не Ñовпадают</string> + <string name="create_account_button">Создать учетную запиÑÑŒ</string> + <string name="more_info">Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ</string> + <string name="don_t_ask_again">Больше не Ñпрашивать</string> + <string name="setup_huawei_text">Ðажмите кнопку ниже и убедитеÑÑŒ, что Briar отображаетÑÑ Ð½Ð° Ñкране защищенных приложений.</string> + <string name="setup_huawei_button">Защитить Briar</string> + <string name="setup_huawei_help">ЕÑли Briar не добавлен в ÑпиÑок защищенных приложений, он не Ñможет работать в фоновом режиме.</string> + <string name="warning_dozed">%s не удалоÑÑŒ выполнить в фоновом режиме</string> + <!--Login--> + <string name="enter_password">пароль</string> + <string name="try_again">Ðеверный пароль, повторите попытку</string> + <string name="sign_in_button">Войти</string> + <string name="forgotten_password">Я забыл Ñвой пароль</string> + <string name="dialog_title_lost_password">Пароль утерÑн</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_db_error">По какой-то причине, база данных Briar повреждена без возможноÑти воÑÑтановлениÑ. ВмеÑте Ñ ÑƒÑ‡ÐµÑ‚Ð½Ð¾Ð¹ запиÑью будут потерÑны ваши данные и ваши контакты. К Ñожалению, вам нужно переуÑтановить Briar и Ñоздать новый аккаунт, выбрав \'Ñ Ð·Ð°Ð±Ñ‹Ð» Ñвой пароль\'.</string> + <string name="startup_failed_data_too_old_error">Ваша ÑƒÑ‡ÐµÑ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ была Ñоздана в Ñтарой верÑии Briar и не может быть открыта в Ñтой верÑии. Ð’Ñ‹ должны либо уÑтановить Ñтарую верÑию, либо Ñоздать новую учетную запиÑÑŒ, выбрав \'Ñ Ð·Ð°Ð±Ñ‹Ð» Ñвой пароль\'.</string> + <string name="startup_failed_data_too_new_error">ВерÑÐ¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñлишком ÑтараÑ. Обновите до поÑледней верÑии и повторите попытку.</string> + <string name="startup_failed_service_error">Briar не Ñмог запуÑтить требуемый подключаемый модуль. ПереуÑтановка Briar обычно решает Ñту проблему. Однако обратите внимание, что поÑле Ñтого вы потерÑете Ñвою учетную запиÑÑŒ и вÑе ÑвÑзанные Ñ Ð½ÐµÐ¹ данные, поÑкольку Briar не иÑпользует центральных Ñерверов Ð´Ð»Ñ Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ….</string> + <plurals name="expiry_warning"> + <item quantity="one">Ðто бета-верÑÐ¸Ñ Briar. Срок дейÑÑ‚Ð²Ð¸Ñ Ð²Ð°ÑˆÐµÐ¹ учетной запиÑи иÑтечет через %d день и не может быть продлен.</item> + <item quantity="few">Ðто бета-верÑÐ¸Ñ Briar. Срок дейÑÑ‚Ð²Ð¸Ñ Ð²Ð°ÑˆÐµÐ¹ учетной запиÑи иÑтечет через %d Ð´Ð½Ñ Ð¸ не может быть продлен.</item> + <item quantity="many">Ðто бета-верÑÐ¸Ñ Briar. Срок дейÑÑ‚Ð²Ð¸Ñ Ð²Ð°ÑˆÐµÐ¹ учетной запиÑи иÑтечет через %d дней и не может быть продлен.</item> + <item quantity="other">Ðто бета-верÑÐ¸Ñ Briar. Срок дейÑÑ‚Ð²Ð¸Ñ Ð²Ð°ÑˆÐµÐ¹ учетной запиÑи иÑтечет через %d дней и не может быть продлен.</item> + </plurals> + <string name="expiry_update">Дата Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ñ‚ÐµÑÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð±Ñ‹Ð»Ð° продлена. Срок дейÑÑ‚Ð²Ð¸Ñ Ð²Ð°ÑˆÐµÐ¹ учетной запиÑи иÑтечет через %d дней.</string> + <string name="expiry_date_reached">Срок дейÑÑ‚Ð²Ð¸Ñ Ñтого программного обеÑÐ¿ÐµÑ‡ÐµÐ½Ð¸Ñ Ð¸Ñтек.\nСпаÑибо за теÑтирование!</string> + <string name="download_briar">Ð”Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶ÐµÐ½Ð¸Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Briar, загрузите верÑию 1.0.</string> + <string name="create_new_account">Вам нужно будет Ñоздать новую учетную запиÑÑŒ, но вы можете иÑпользовать один и тот же пÑевдоним.</string> + <string name="download_briar_button">Загрузить Briar 1.0</string> + <string name="startup_open_database">РаÑшифровка базы данных...</string> + <string name="startup_migrate_database">Обновление базы данных...</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Открыть навигационное меню</string> + <string name="nav_drawer_close_description">Закрыть навигационное меню</string> + <string name="contact_list_button">Контакты</string> + <string name="groups_button">Приватные группы</string> + <string name="forums_button">Форумы</string> + <string name="blogs_button">Блоги</string> + <string name="settings_button">ÐаÑтройки</string> + <string name="sign_out_button">Выйти</string> + <!--Transports--> + <string name="transport_tor">Интернет</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="reminder_notification_title">Выход из Briar</string> + <string name="reminder_notification_text">Ðажмите, чтобы Ñнова войти.</string> + <string name="reminder_notification_channel_title">Briar Ðапоминание о входе</string> + <string name="reminder_notification_dismiss">Отклонить</string> + <string name="ongoing_notification_title">Выполнен вход в Briar</string> + <string name="ongoing_notification_text">КоÑнитеÑÑŒ, чтобы открыть Briar</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Ðовое личное Ñообщение.</item> + <item quantity="few">%d новых личных Ñообщений.</item> + <item quantity="many">%d новых личных Ñообщений.</item> + <item quantity="other">%d новых личных Ñообщений.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Ðовое групповое Ñообщение</item> + <item quantity="few">%d новых групповых Ñообщений.</item> + <item quantity="many">%d новых групповых Ñообщений.</item> + <item quantity="other">%d новых групповых Ñообщений.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Ðовый поÑÑ‚ на форуме</item> + <item quantity="few">%d новых поÑта на форуме.</item> + <item quantity="many">%d новых поÑтов на форуме.</item> + <item quantity="other">%d новых поÑтов на форуме.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Ðовый поÑÑ‚ в блоге.</item> + <item quantity="few">%d новых поÑта в блоге.</item> + <item quantity="many">%d новых поÑтов в блоге.</item> + <item quantity="other">%d новых поÑтов в блоге.</item> + </plurals> + <!--Misc--> + <string name="now">ÑейчаÑ</string> + <string name="show">Показать</string> + <string name="hide">Скрыть</string> + <string name="ok">OK</string> + <string name="cancel">Отмена</string> + <string name="got_it">ПонÑтно</string> + <string name="delete">Удалить</string> + <string name="accept">ПринÑть</string> + <string name="decline">Отклонить</string> + <string name="options">Опции</string> + <string name="online">Ð’ Ñети</string> + <string name="offline">Ðе в Ñети</string> + <string name="send">Отправить</string> + <string name="allow">Разрешить</string> + <string name="open">Открыть</string> + <string name="no_data">Ðет данных</string> + <string name="ellipsis">…</string> + <string name="text_too_long">Введенный текÑÑ‚ Ñлишком длинный</string> + <string name="show_onboarding">Показать Ñправку</string> + <string name="fix">ИÑправить</string> + <string name="help">Помощь</string> + <string name="sorry">Сожалеем</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">Ðет контактов Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ\n\nКоÑнитеÑÑŒ значка + Ð´Ð»Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð°</string> + <string name="date_no_private_messages">Ðет Ñообщений.</string> + <string name="no_private_messages">Ðет Ñообщений Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ</string> + <string name="message_hint">Печатает Ñообщение</string> + <string name="delete_contact">Удалить контакт</string> + <string name="dialog_title_delete_contact">Подтвердите удаление контакта</string> + <string name="dialog_message_delete_contact">Ð’Ñ‹ дейÑтвительно хотите удалить Ñтот контакт и вÑе ÑвÑзанные Ñ Ð½Ð¸Ð¼ ÑообщениÑ?</string> + <string name="contact_deleted_toast">Контакт удален</string> + <!--Adding Contacts--> + <string name="add_contact_title">Добавить контакт</string> + <string name="face_to_face">Ð’Ñ‹ должны вÑтретитьÑÑ Ñ Ñ‡ÐµÐ»Ð¾Ð²ÐµÐºÐ¾Ð¼, которого хотите добавить в контакты.\n\nÐто не позволит кому-либо выдать ÑÐµÐ±Ñ Ð·Ð° Ð²Ð°Ñ Ð¸Ð»Ð¸ читать ваши ÑообщениÑ.</string> + <string name="continue_button">Продолжить</string> + <string name="connection_failed">Ошибка подключениÑ</string> + <string name="try_again_button">Попробовать Ñнова</string> + <string name="waiting_for_contact_to_scan">Ожидание контакта Ð´Ð»Ñ ÑÐºÐ°Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸ подключениÑ\u2026</string> + <string name="exchanging_contact_details">Обмен контактными данными\u2026</string> + <string name="contact_added_toast">Контакт добавлен: %s</string> + <string name="contact_already_exists">Контакт %s уже ÑущеÑтвует</string> + <string name="contact_exchange_failed">Обмен контактами не удалÑÑ</string> + <string name="qr_code_invalid">Ðеверный QR-код</string> + <string name="qr_code_unsupported">QR-код, который вы пытаетеÑÑŒ отÑканировать, Ñоздан в Ñтарой верÑии %s, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð±Ð¾Ð»ÑŒÑˆÐµ не поддерживаетÑÑ.\n\nУбедитеÑÑŒ, что вы работаете Ñ Ð¿Ð¾Ñледней верÑией, а затем повторите попытку.</string> + <string name="camera_error">Ошибка камеры</string> + <string name="connecting_to_device">Подключение к уÑтройÑтву\u2026</string> + <string name="authenticating_with_device">ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñ ÑƒÑтройÑтвом\u2026</string> + <string name="connection_aborted_local">Подключение прервано! Ðто может означать, что кто-то пытаетÑÑ Ð²Ð¼ÐµÑˆÐ°Ñ‚ÑŒÑÑ Ð² ваше Ñоединение</string> + <string name="connection_aborted_remote">Соединение прервано вашим контактом! Ðто может означать, что кто-то пытаетÑÑ Ð²Ð¼ÐµÑˆÐ°Ñ‚ÑŒÑÑ Ð² ваше подключение</string> + <!--Introductions--> + <string name="introduction_onboarding_title">ЗнакомÑтво Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð°Ð¼Ð¸</string> + <string name="introduction_onboarding_text">Ð’Ñ‹ можете предÑтавить Ñвои контакты друг другу, поÑтому им не нужно вÑтречатьÑÑ Ð»Ð¸Ñ‡Ð½Ð¾, чтобы подключитьÑÑ Ðº Briar. </string> + <string name="introduction_menu_item">Выполнить знакомÑтво</string> + <string name="introduction_activity_title">Выберите контакт</string> + <string name="introduction_not_possible">Ð’Ñ‹ уже отправили Ð·Ð°Ð¿Ñ€Ð¾Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð°Ð¼. ПожалуйÑта, подождите пока они ответÑÑ‚ на него. ЕÑли вы или ваши контакты редко бываете в Ñети, Ñто может занÑть некоторое времÑ.</string> + <string name="introduction_message_title">Познакомить контакты</string> + <string name="introduction_message_hint">Добавить Ñообщение (необÑзательно)</string> + <string name="introduction_button">Выполнить знакомÑтво</string> + <string name="introduction_sent">Ваше предÑтавление было отправлено.</string> + <string name="introduction_error">Произошла ошибка при выполнении знакомÑтва.</string> + <string name="introduction_response_error">Ошибка при ответе на знакомÑтво</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_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_response_accepted_sent">Ð’Ñ‹ принÑли знакомÑтво Ñ %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_accepted_received">%1$s принÑл знакомÑтво Ñ %2$s.</string> + <string name="introduction_response_declined_received">%1$s отказалÑÑ Ð¾Ñ‚ знакомÑтва Ñ %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s говорит, что %2$s отказалÑÑ Ð¾Ñ‚ знакомÑтва.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Ðовый контакт добавлен.</item> + <item quantity="few">%d новых контакта добавлено.</item> + <item quantity="many">%d новых контактов добавлено.</item> + <item quantity="other">%d новых контактов добавлено.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">Ðет групп Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ\n\nКоÑнитеÑÑŒ значка + Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ñ‹, или попроÑите ваши контакты поделитьÑÑ Ñ Ð²Ð°Ð¼Ð¸ группами</string> + <string name="groups_created_by">Создано %s</string> + <plurals name="messages"> + <item quantity="one">%d Ñообщение</item> + <item quantity="few">%d ÑообщениÑ</item> + <item quantity="many">%d Ñообщений</item> + <item quantity="other">%d Ñообщений</item> + </plurals> + <string name="groups_group_is_empty">Ðта группа пуÑта</string> + <string name="groups_group_is_dissolved">Ðта группа была раÑпущена</string> + <string name="groups_remove">Удалить</string> + <string name="groups_create_group_title">Создать приватную группу</string> + <string name="groups_create_group_button">Создать группу</string> + <string name="groups_create_group_invitation_button">Отправить приглашение</string> + <string name="groups_create_group_hint">Придумайте Ð¸Ð¼Ñ Ð´Ð»Ñ Ñвоей приватной группы</string> + <string name="groups_invitation_sent">Приглашение на вÑтупление в группу было отправлено</string> + <string name="groups_message_sent">Сообщение отправлено</string> + <string name="groups_member_list">СпиÑок учаÑтников</string> + <string name="groups_invite_members">ПриглаÑить учаÑтников</string> + <string name="groups_member_created_you">Ð’Ñ‹ Ñоздали группу</string> + <string name="groups_member_created">%s Ñоздал группу</string> + <string name="groups_member_joined_you">Ð’Ñ‹ приÑоединилиÑÑŒ к группе</string> + <string name="groups_member_joined">%s приÑоединилÑÑ Ðº группе</string> + <string name="groups_leave">Покинуть группу</string> + <string name="groups_leave_dialog_title">Подтверждение</string> + <string name="groups_leave_dialog_message">Ð’Ñ‹ уверены, что хотите покинуть Ñту группу?</string> + <string name="groups_dissolve">РаÑпуÑтить группу</string> + <string name="groups_dissolve_dialog_title">Подтверждение</string> + <string name="groups_dissolve_dialog_message">Ð’Ñ‹ уверены, что хотите раÑпуÑтить Ñту группу?\n\nДругие учаÑтники не Ñмогут продолжить разговор и могут не получить поÑледние ÑообщениÑ.</string> + <string name="groups_dissolve_button">РаÑпуÑтить</string> + <string name="groups_dissolved_dialog_title">Группа была раÑпущена</string> + <string name="groups_dissolved_dialog_message">Создатель Ñтой группы раÑпуÑтил ее.\n\nÐ’Ñ‹ больше не можете пиÑать ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð² группу и можете получить не вÑе ÑообщениÑ, которые были напиÑаны.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">ÐŸÑ€Ð¸Ð³Ð»Ð°ÑˆÐµÐ½Ð¸Ñ Ð² группу</string> + <string name="groups_invitations_invitation_sent">Ð’Ñ‹ предложили %1$s приÑоединитьÑÑ Ðº группе \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s приглашает Ð²Ð°Ñ Ð¿Ñ€Ð¸ÑоединитьÑÑ Ðº группе \"%2$s\".</string> + <string name="groups_invitations_joined">ПриÑоединилÑÑ Ðº группе</string> + <string name="groups_invitations_declined">Приглашение в группу отклонено</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d открытое приглашение в группу</item> + <item quantity="few">%d открытых приглашений в группу</item> + <item quantity="many">%d открытых приглашений в группу</item> + <item quantity="other">%d открытых приглашений в группу</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Ð’Ñ‹ принÑли приглашение в группу от %s.</string> + <string name="groups_invitations_response_declined_sent">Ð’Ñ‹ отклонили приглашение в группу от %s.</string> + <string name="groups_invitations_response_accepted_received">%s принÑл приглашение в группу.</string> + <string name="groups_invitations_response_declined_received">%s отклонил приглашение в группу.</string> + <string name="sharing_status_groups">Только Ñоздатель может приглаÑить новых пользователей в группу. Ðиже перечиÑлены вÑе текущие пользователи группы.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Показать контакты</string> + <string name="groups_reveal_dialog_message">Ð’Ñ‹ можете выбрать, раÑкрывать ли контакты текущим и будущим учаÑтникам Ñтой группы.\n\nПри раÑкрытии контактов ÑвÑзь Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð¾Ð¹ ÑтановитÑÑ Ð±Ð¾Ð»ÐµÐµ быÑтрой и надежной, поÑкольку вы можете общатьÑÑ Ñ Ñ€Ð°Ñкрытыми контактами, даже еÑли Ñоздатель группы находитÑÑ Ð² автономном режиме.</string> + <string name="groups_reveal_visible">СвÑзь между контактами видна группе</string> + <string name="groups_reveal_visible_revealed_by_us">СвÑзь между контактами видна группе (раÑкрываетÑÑ Ð²Ð°Ð¼Ð¸)</string> + <string name="groups_reveal_visible_revealed_by_contact">СвÑзь между контактами видна группе (раÑкрываетÑÑ %s)</string> + <string name="groups_reveal_invisible">СвÑзь между контактами не видна группе</string> + <!--Forums--> + <string name="no_forums">Ðет форумов Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ\n\nКоÑнитеÑÑŒ значка + Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ„Ð¾Ñ€ÑƒÐ¼Ð°, или попроÑите ваши контакты поделитьÑÑ Ñ Ð²Ð°Ð¼Ð¸ форумами</string> + <string name="create_forum_title">Создать форум</string> + <string name="choose_forum_hint">Придумайте Ð¸Ð¼Ñ Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ форума</string> + <string name="create_forum_button">Создать форум</string> + <string name="forum_created_toast">Форум Ñоздан</string> + <string name="no_forum_posts">Ðет поÑтов Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ</string> + <string name="no_posts">Ðет поÑтов</string> + <plurals name="posts"> + <item quantity="one">%d поÑÑ‚</item> + <item quantity="few">%d поÑта</item> + <item quantity="many">%d поÑтов</item> + <item quantity="other">%d поÑтов</item> + </plurals> + <string name="forum_new_entry_posted">ПоÑÑ‚ в форуме опубликован</string> + <string name="forum_new_message_hint">Ðовый поÑÑ‚</string> + <string name="forum_message_reply_hint">Ðовый ответ</string> + <string name="btn_reply">Ответ</string> + <string name="forum_leave">Покинуть форум</string> + <string name="dialog_title_leave_forum">Подтвердить</string> + <string name="dialog_message_leave_forum">Ð’Ñ‹ уверены, что хотите покинуть Ñтот форум?\n\nÐ’Ñе контакты, Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼Ð¸ вы поделилиÑÑŒ Ñтим форумом, могут переÑтать получать обновлениÑ.</string> + <string name="dialog_button_leave">Покинуть</string> + <string name="forum_left_toast">Покинул форум</string> + <!--Forum Sharing--> + <string name="forum_share_button">ПоделитьÑÑ Ñ„Ð¾Ñ€ÑƒÐ¼Ð¾Ð¼</string> + <string name="contacts_selected">Выбранные контакты</string> + <string name="activity_share_toolbar_header">Выбор контактов</string> + <string name="no_contacts_selector">Ðет контактов Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ\n\nПожалуйÑта, вернитеÑÑŒ Ñюда поÑле Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð°</string> + <string name="forum_shared_snackbar">ПоделитьÑÑ Ñ„Ð¾Ñ€ÑƒÐ¼Ð¾Ð¼ ÑовмеÑтно Ñ Ð²Ñ‹Ð±Ñ€Ð°Ð½Ð½Ñ‹Ð¼Ð¸ контактами</string> + <string name="forum_share_message">Добавить Ñообщение (необÑзательно)</string> + <string name="forum_share_error">Произошла ошибка при при попытке поделитьÑÑ Ñтим форумом.</string> + <string name="forum_invitation_received">%1$s поделилÑÑ Ñ„Ð¾Ñ€ÑƒÐ¼Ð¾Ð¼ \"%2$s\" Ñ Ð²Ð°Ð¼Ð¸.</string> + <string name="forum_invitation_sent">Ð’Ñ‹ поделилиÑÑŒ форумом \"%1$s\" Ñ %2$s.</string> + <string name="forum_invitations_title">ÐŸÑ€Ð¸Ð³Ð»Ð°ÑˆÐµÐ½Ð¸Ñ Ð½Ð° форум</string> + <string name="forum_invitation_exists">Ð’Ñ‹ уже принÑли приглашение на Ñтот форум.\n\nПринÑтие большего количеÑтва приглашений Ñделает вашу ÑвÑзь Ñ Ñ„Ð¾Ñ€ÑƒÐ¼Ð¾Ð¼ более быÑтрой и надежной.</string> + <string name="forum_joined_toast">ПриÑоединилÑÑ Ðº форуму</string> + <string name="forum_declined_toast">Приглашение отклонено</string> + <string name="shared_by_format">ПоделилÑÑ %s</string> + <string name="forum_invitation_already_sharing">Уже поделилÑÑ</string> + <string name="forum_invitation_response_accepted_sent">Ð’Ñ‹ принÑли приглашение на форум от %s.</string> + <string name="forum_invitation_response_declined_sent">Ð’Ñ‹ отклонили приглашение на форум от %s.</string> + <string name="forum_invitation_response_accepted_received">%sпринÑл приглашение на форум.</string> + <string name="forum_invitation_response_declined_received">%s отклонил приглашение на форум.</string> + <string name="sharing_status">Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð¾Ð±Ñ‰ÐµÐ³Ð¾ доÑтупа</string> + <string name="sharing_status_forum">Любой учаÑтник форума может поделитьÑÑ Ð¸Ð¼ Ñо Ñвоими контактами. Ð’Ñ‹ делитеÑÑŒ Ñтим форумом Ñо Ñледующими контактами. Могут быть и другие учаÑтники, которых вы не видите.</string> + <string name="shared_with">СовмеÑтно Ñ %1$d (%2$d в Ñети)</string> + <plurals name="forums_shared"> + <item quantity="one">%d форум, общий Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð°Ð¼Ð¸</item> + <item quantity="few">%d форумов, общих Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð°Ð¼Ð¸</item> + <item quantity="many">%d форумов, общих Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð°Ð¼Ð¸</item> + <item quantity="other">%d форумов, общих Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð°Ð¼Ð¸</item> + </plurals> + <string name="nobody">Ðикого</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">Ðет поÑтов Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ</string> + <string name="read_more">подробнее</string> + <string name="blogs_write_blog_post">ÐапиÑать в блоге</string> + <string name="blogs_write_blog_post_body_hint">Ðапишите Ñвой поÑÑ‚ в блоге</string> + <string name="blogs_publish_blog_post">Опубликовать</string> + <string name="blogs_blog_post_created">ПоÑÑ‚ Ñоздан</string> + <string name="blogs_blog_post_received">ПоÑвилÑÑ Ð½Ð¾Ð²Ñ‹Ð¹ поÑÑ‚ в блоге</string> + <string name="blogs_blog_post_scroll_to">Перейти</string> + <string name="blogs_feed_empty_state">Ðет поÑтов Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ\n\nПоÑты ваших контактов и блогов, на которые вы подпиÑаны, поÑвÑÑ‚ÑÑ Ð·Ð´ÐµÑÑŒ\n\nКоÑнитеÑÑŒ значка пера, чтобы напиÑать Ñообщение</string> + <string name="blogs_remove_blog">Удалить блог</string> + <string name="blogs_remove_blog_dialog_message">Ð’Ñ‹ уверены, что хотите удалить Ñтот блог?\n\nПоÑты будут удалены только Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ уÑтройÑтва.\n\nÐ’Ñе контакты, Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼Ð¸ вы поделилиÑÑŒ Ñтим блогом, могут переÑтать получать обновлениÑ.</string> + <string name="blogs_remove_blog_ok">Убрать</string> + <string name="blogs_blog_removed">Блог удален</string> + <string name="blogs_reblog_comment_hint">Добавить комментарий (необÑзательно)</string> + <string name="blogs_reblog_button">ПерепоÑтить</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">ПоделитьÑÑ Ð±Ð»Ð¾Ð³Ð¾Ð¼</string> + <string name="blogs_sharing_error">Произошла ошибка при при попытке поделитьÑÑ Ñтим блогом.</string> + <string name="blogs_sharing_button">ПоделитьÑÑ Ð±Ð»Ð¾Ð³Ð¾Ð¼</string> + <string name="blogs_sharing_snackbar">ПоделитьÑÑ Ð±Ð»Ð¾Ð³Ð¾Ð¼ ÑовмеÑтно Ñ Ð²Ñ‹Ð±Ñ€Ð°Ð½Ð½Ñ‹Ð¼Ð¸ контактами</string> + <string name="blogs_sharing_response_accepted_sent">Ð’Ñ‹ принÑли приглашение в блог от %s.</string> + <string name="blogs_sharing_response_declined_sent">Ð’Ñ‹ отклонили приглашение в блог от %s.</string> + <string name="blogs_sharing_response_accepted_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_sent">Ð’Ñ‹ поделилиÑÑŒ блогом \"%1$s\" Ñ %2$s.</string> + <string name="blogs_sharing_invitations_title">ÐŸÑ€Ð¸Ð³Ð»Ð°ÑˆÐµÐ½Ð¸Ñ Ð² блог</string> + <string name="blogs_sharing_joined_toast">ПодпиÑка на блог</string> + <string name="blogs_sharing_declined_toast">Приглашение отклонено</string> + <string name="sharing_status_blog">Любой, кто подпиÑываетÑÑ Ð½Ð° блог, может поделитьÑÑ Ð¸Ð¼ Ñо Ñвоими контактами. Ð’Ñ‹ делитеÑÑŒ Ñтим блогом Ñо Ñледующими контактами. Могут быть и другие подпиÑчики, которых вы не видите.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Импорт RSS-канала</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_error">Мы Ñожалеем! Ðе удалоÑÑŒ импортировать Ñтот RSS-канал.</string> + <string name="blogs_rss_feeds_manage">Управление RSS-каналами</string> + <string name="blogs_rss_feeds_manage_imported">Импортирован:</string> + <string name="blogs_rss_feeds_manage_author">Ðвтор:</string> + <string name="blogs_rss_feeds_manage_updated">ПоÑледнее обновление:</string> + <string name="blogs_rss_remove_feed">Удалить RSS-канал</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_feeds_manage_delete_error">Ðе удалоÑÑŒ удалить RSS-канал!</string> + <string name="blogs_rss_feeds_manage_empty_state">Ðет RSS-лент Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ\n\nКоÑнитеÑÑŒ значка + Ð´Ð»Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð° ленты</string> + <string name="blogs_rss_feeds_manage_error">Ошибка при загрузке каналов. Повторите попытку позже.</string> + <!--Settings Display--> + <string name="pref_language_title">Язык & регион</string> + <string name="pref_language_changed">Ðтот параметр вÑтупит в Ñилу поÑле перезапуÑка Briar. ПожалуйÑта, выйдите и перезапуÑтите Briar.</string> + <string name="pref_language_default">По умолчанию</string> + <string name="display_settings_title">Отображение</string> + <string name="pref_theme_title">Тема</string> + <string name="pref_theme_light">СветлаÑ</string> + <string name="pref_theme_dark">ТёмнаÑ</string> + <string name="pref_theme_auto">ÐвтоматичеÑкий (Дневной)</string> + <string name="pref_theme_system">По-умолчанию</string> + <!--Settings Network--> + <string name="network_settings_title">Сети</string> + <string name="bluetooth_setting">Подключение через Bluetooth</string> + <string name="bluetooth_setting_enabled">Когда контакты находÑÑ‚ÑÑ Ð¿Ð¾Ð±Ð»Ð¸Ð·Ð¾Ñти</string> + <string name="bluetooth_setting_disabled">Только при добавлении контактов</string> + <string name="tor_network_setting">Подключение через Tor</string> + <string name="tor_network_setting_never">Ðикогда</string> + <string name="tor_network_setting_wifi">Только при иÑпользовании Wi-Fi</string> + <string name="tor_network_setting_always">При иÑпользовании Wi-Fi или мобильных данных</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">БезопаÑноÑть</string> + <string name="change_password">Изменить пароль</string> + <string name="current_password">Текущий пароль</string> + <string name="choose_new_password">Ðовый пароль</string> + <string name="confirm_new_password">Подтвердите новый пароль</string> + <string name="password_changed">Пароль был изменен.</string> + <string name="panic_setting">ÐаÑтройка тревожной кнопки</string> + <string name="panic_setting_title">Ð¢Ñ€ÐµÐ²Ð¾Ð¶Ð½Ð°Ñ ÐºÐ½Ð¾Ð¿ÐºÐ°</string> + <string name="panic_setting_hint">ÐаÑтройте поведение Briar при иÑпользовании тревожной кнопки</string> + <string name="panic_app_setting_title">Приложение тревожной кнопки</string> + <string name="unknown_app">неизвеÑтное приложение</string> + <string name="panic_app_setting_summary">Приложение не уÑтановлено</string> + <string name="panic_app_setting_none">Ðет</string> + <string name="dialog_title_connect_panic_app">Подтвердить приложение тревожной кнопки</string> + <string name="dialog_message_connect_panic_app">Ð’Ñ‹ уверены, что хотите разрешить %1$s запуÑкать дейÑÑ‚Ð²Ð¸Ñ Ñ‚Ñ€ÐµÐ²Ð¾Ð¶Ð½Ð¾Ð¹ кнопки?</string> + <string name="panic_setting_signout_title">Выйти</string> + <string name="panic_setting_signout_summary">Выйти из Briar, еÑли нажата Ñ‚Ñ€ÐµÐ²Ð¾Ð¶Ð½Ð°Ñ ÐºÐ½Ð¾Ð¿ÐºÐ°</string> + <string name="purge_setting_title">Удалить аккаунт</string> + <string name="purge_setting_summary">Удалить вашу учетную запиÑÑŒ Briar при нажатии тревожной кнопки. Внимание: Ñто необратимо удалит ваши идентификаторы, контакты и ÑообщениÑ</string> + <string name="uninstall_setting_title">Удалить Briar</string> + <string name="uninstall_setting_summary">Ðто потребует вашего подтверждениÑ</string> + <!--Settings Notifications--> + <string name="notification_settings_title">УведомлениÑ</string> + <string name="notify_sign_in_title">Ðапомнить мне войти</string> + <string name="notify_sign_in_summary">Показывать напоминание при запуÑке телефона или обновлении приложениÑ.</string> + <string name="notify_private_messages_setting_title">Личные ÑообщениÑ</string> + <string name="notify_private_messages_setting_summary">Показывать Ð¾Ð¿Ð¾Ð²ÐµÑ‰ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð»Ð¸Ñ‡Ð½Ñ‹Ñ… Ñообщений</string> + <string name="notify_private_messages_setting_summary_26">ÐаÑтройка оповещений Ð´Ð»Ñ Ð»Ð¸Ñ‡Ð½Ñ‹Ñ… Ñообщений</string> + <string name="notify_group_messages_setting_title">Групповые ÑообщениÑ</string> + <string name="notify_group_messages_setting_summary">Показывать Ð¾Ð¿Ð¾Ð²ÐµÑ‰ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð¾Ð²Ñ‹Ñ… Ñообщений</string> + <string name="notify_group_messages_setting_summary_26">ÐаÑтройка оповещений Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð¾Ð²Ñ‹Ñ… Ñообщений</string> + <string name="notify_forum_posts_setting_title">ПоÑты форума</string> + <string name="notify_forum_posts_setting_summary">Показывать Ð¾Ð¿Ð¾Ð²ÐµÑ‰ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¿Ð¾Ñтов форума</string> + <string name="notify_forum_posts_setting_summary_26">ÐаÑтройка оповещений Ð´Ð»Ñ Ð¿Ð¾Ñтов форума</string> + <string name="notify_blog_posts_setting_title">ПоÑты блога</string> + <string name="notify_blog_posts_setting_summary">Показывать Ð¾Ð¿Ð¾Ð²ÐµÑ‰ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¿Ð¾Ñтов блога</string> + <string name="notify_blog_posts_setting_summary_26">ÐаÑтройка оповещений Ð´Ð»Ñ Ð¿Ð¾Ñтов блога</string> + <string name="notify_vibration_setting">ВибрациÑ</string> + <string name="notify_lock_screen_setting_title">Ðкран блокировки</string> + <string name="notify_lock_screen_setting_summary">Показывать ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð½Ð° Ñкране блокировки</string> + <string name="notify_sound_setting">Звук</string> + <string name="notify_sound_setting_default">ÐœÐµÐ»Ð¾Ð´Ð¸Ñ Ð¿Ð¾ умолчанию</string> + <string name="notify_sound_setting_disabled">Ðет</string> + <string name="choose_ringtone_title">Выберите мелодию звонка</string> + <string name="cannot_load_ringtone">Ðе удаетÑÑ Ð·Ð°Ð³Ñ€ÑƒÐ·Ð¸Ñ‚ÑŒ мелодию звонка</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">ÐžÐ±Ñ€Ð°Ñ‚Ð½Ð°Ñ ÑвÑзь</string> + <string name="send_feedback">Отправить отзыв</string> + <!--Link Warning--> + <string name="link_warning_title">Внимание</string> + <string name="link_warning_intro">Ð’Ñ‹ ÑобираетеÑÑŒ открыть Ñледующую ÑÑылку в Ñтороннем приложении.</string> + <string name="link_warning_text">Возможно Ð²Ð°Ñ Ñ…Ð¾Ñ‚ÑÑ‚ идентифицировать. Подумайте, доверÑете ли вы человеку, который приÑлал вам Ñту ÑÑылку и раÑÑмотрите возможноÑть Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ ÐµÐµ в Orfox.</string> + <string name="link_warning_open_link">Открыть ÑÑылку</string> + <!--Crash Reporter--> + <string name="crash_report_title">Отчет о Ñбое Briar</string> + <string name="briar_crashed">К Ñожалению, Briar неожиданно завершил работу.</string> + <string name="not_your_fault">Ðто не ваша вина.</string> + <string name="please_send_report">ПожалуйÑта, помогите Ñделать Briar лучше, отправив нам отчет о Ñбое.</string> + <string name="report_is_encrypted">Мы обещаем, что отчет зашифрован и будет отправлен безопаÑно.</string> + <string name="feedback_title">ÐžÐ±Ñ€Ð°Ñ‚Ð½Ð°Ñ ÑвÑзь</string> + <string name="describe_crash">Опишите, что произошло (необÑзательно)</string> + <string name="enter_feedback">Введите Ñвой отзыв</string> + <string name="optional_contact_email">Ваш email Ð°Ð´Ñ€ÐµÑ (необÑзательно)</string> + <string name="include_debug_report_crash">Включить анонимные данные о Ñбое</string> + <string name="include_debug_report_feedback">Включить анонимные данные об Ñтом уÑтройÑтве</string> + <string name="could_not_load_report_data">Ðе удалоÑÑŒ загрузить данные отчета.</string> + <string name="send_report">Отправить отчет</string> + <string name="close">Закрыть</string> + <string name="dev_report_saved">Отчет Ñохранен. Он будет отправлен при Ñледующем входе в Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">Выход из Briar…</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Обнаружено наложение Ñкрана</string> + <string name="screen_filter_body">Другое приложение накладываетÑÑ Ð½Ð° Briar. Чтобы защитить вашу безопаÑноÑть, Briar не будет реагировать на прикоÑновениÑ, пока еÑть наложение.\n\nМогут накладыватьÑÑ Ñледующие приложениÑ:\n\n%1$s</string> + <string name="screen_filter_allow">Разрешить Ñтим приложениÑм наложение?</string> + <!--Permission Requests--> + <string name="permission_camera_title">Разрешение камеры</string> + <string name="permission_camera_request_body">Ð”Ð»Ñ ÑÐºÐ°Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ QR-кода Briar необходим доÑтуп к камере.</string> + <string name="permission_camera_denied_body">ДоÑтуп к камере запрещен, но Ð´Ð»Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð¾Ð² требуетÑÑ Ð´Ð¾Ñтуп к камере.\n\nРаÑÑмотрите возможноÑть предоÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð´Ð¾Ñтупа.</string> + <string name="permission_camera_denied_toast">ДоÑтуп к камере не был предоÑтавлен</string> + <string name="qr_code">QR-код</string> + <string name="show_qr_code_fullscreen">Показать QR-код во веÑÑŒ Ñкран</string> +</resources> diff --git a/mailbox-android/src/main/res/values-sq/strings.xml b/mailbox-android/src/main/res/values-sq/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..9bead86c31520712d61497e1ef245fa81dcd28f4 --- /dev/null +++ b/mailbox-android/src/main/res/values-sq/strings.xml @@ -0,0 +1,413 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Rregullimi i Briar-it</string> + <string name="setup_name_explanation">Nofka juaj do të shfaqet në krah të çfarëdo gjëje që postoni. S\’mund ta ndryshoni më, pas krijimit të llogarisë tuaj.</string> + <string name="setup_next">Pasuesi</string> + <string name="setup_password_intro">Zgjidhni një Fjalëkalim</string> + <string name="setup_password_explanation">Llogaria juaj Briar depozitohet e fshehtëzuar në pajisjen tuaj, jo në re. Nëse harroni fjalëkalimin tuaj apo e çinstaloni Briar-in, nuk ka ndonjë mënyrë për të ringjallur llogarinë tuaj.\n\nZgjidhni një fjalëkalim të gjatë, që është i vështirë për t\’u marrë me mend, f.v., katër fjalë kuturu, ose dhjetë shkronja, numra dhe shenja kuturu.</string> + <string name="setup_doze_title">Lidhje Në Prapaskenë</string> + <string name="setup_doze_intro">Për të marrë mesazhe, Briar-i lypset të qëndrojë i lidhur në prapaskenë.</string> + <string name="setup_doze_explanation">Për të marrë mesazhe, Briar-i lypset të mbetet i lidhur në prapaskenë. Ju lutemi, çaktivizoni optimizime baterie, që kështu Briar-i të mund të qëndrojë i lidhur.</string> + <string name="setup_doze_button">Lejo Lidhje</string> + <string name="choose_nickname">Zgjidhni nofkën tuaj</string> + <string name="choose_password">Zgjidhni fjalëkalimin tuaj</string> + <string name="confirm_password">Ripohoni fjalëkalimin tuaj</string> + <string name="name_too_long">Emri është shumë i gjatë</string> + <string name="password_too_weak">Fjalëkalimi është shumë i dobët</string> + <string name="passwords_do_not_match">Fjalëkalimet nuk përputhen</string> + <string name="create_account_button">Krijoje Llogarinë</string> + <string name="more_info">Më Tepër të Dhëna</string> + <string name="don_t_ask_again">Mos pyet sërish</string> + <string name="setup_huawei_text">Ju lutemi, prekni butoni më poshtë dhe sigurohuni që Briar-i të jetë i mbrojtur, te skena \"Aplikacione të Mbrojtur\".</string> + <string name="setup_huawei_button">Mbroje Briar-in</string> + <string name="setup_huawei_help">Nëse Briar-i s’është shtuar te lista e aplikacioneve të mbrojtur, s’do të jetë në gjendje të xhirojë në prapaskenë.</string> + <string name="warning_dozed">%s s’qe në gjendje të xhirojë në prapaskenë</string> + <!--Login--> + <string name="enter_password">Fjalëkalim</string> + <string name="try_again">Fjalëkalim i gabuar, riprovoni</string> + <string name="sign_in_button">Hyni</string> + <string name="forgotten_password">Kam harruar fjalëkalimin tim</string> + <string name="dialog_title_lost_password">U humb Fjalëkalimi</string> + <string name="dialog_message_lost_password">Llogaria juaj Briar depozitohet e fshehtëzuar në pajisjen tuaj, jo në re, ndaj s\’mund ta ricaktojmë fjalëkalimin tuaj. Do të donit ta fshini llogarinë tuaj dhe t\’ia filloni nga e para?\n\nKujdes: Identitetet, kontaktet dhe mesazhet tuaja do të humbin përgjithnjë.</string> + <string name="startup_failed_notification_title">Briar-i s\’u nis dot</string> + <string name="startup_failed_notification_text">Prekeni për më tepër të dhëna.</string> + <string name="startup_failed_activity_title">Dështim Nisjeje i Briar-it</string> + <string name="startup_failed_db_error">Për ndonjë arsye, baza e të dhënave të Briar-it është e dëmtuar sa nuk ndreqet dot. Llogaria juaj, të dhënat tuaja dhe krejt kontaktet tuaja humbën. Mjerisht, ju duhet të ri-instaloni Briar-in dhe të rregulloni një llogari të re duke zgjedhur \'Kam harruar fjalëkalimin tim\' te hapi për fjalëkalimin.</string> + <string name="startup_failed_data_too_old_error">Llogaria juaj qe krijuar me një version të vjetër të këtij aplikacioni dhe s’mund të hapet me këtë version. Ose duhet të ri-instaloni versionin e vjetër, ose të fshini llogarinë tuaj të vjetër duke zgjedhur \'Kam harruar fjalëkalimin tim\' te hapi për fjalëkalimin.</string> + <string name="startup_failed_data_too_new_error">Ky version i aplikacionit është shumë i vjetër. Ju lutemi, përmirësojeni me versionin më të ri dhe riprovoni.</string> + <string name="startup_failed_service_error">Briar-i s\’arriti të nisë një shtojcë të domosdoshme. Ri-instalimi i Briar-it zakonisht e zgjidh këtë problem. Por, ju lutemi, kini parasysh se me të do të humbni llogarinë tuaj dhe krejt të dhënat e lidhura me të, ngaqë Briar nuk përdor shërbyes qendrorë për të depozituar në ta të dhënat tuaja.</string> + <plurals name="expiry_warning"> + <item quantity="one">Ky është një version beta i Briar-it. Llogaria juaj do të skadojë për %d ditë dhe s\’mund të rinovohet.</item> + <item quantity="other">Ky është një version beta i Briar-it. Llogaria juaj do të skadojë për %d ditë dhe s\’mund të rinovohet.</item> + </plurals> + <string name="expiry_update">Data e skadimit të periudhës së testimit është shtyrë më tej. Tani llogaria juaj do të skadojë për %d ditë.</string> + <string name="expiry_date_reached">Ky software ka skaduar.\nFaleminderit që e provuat!</string> + <string name="download_briar">Që të vazhdoni të përdorni Briar-in, ju lutemi, shkarkoni versionin 1.0.</string> + <string name="create_new_account">Do t’ju duhet të krijoni një llogari të re, por mund të përdorni të njëjtën nofkë.</string> + <string name="download_briar_button">Shkarko Briar 1.0</string> + <string name="startup_open_database">Po shfshehtëzohet Baza e të dhënave…</string> + <string name="startup_migrate_database">Po përditësohet Baza e të dhënave…</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Hap sirtarin e lëvizjeve</string> + <string name="nav_drawer_close_description">Mbylle sirtarin e lëvizjeve</string> + <string name="contact_list_button">Kontakte</string> + <string name="groups_button">Grupe Private</string> + <string name="forums_button">Forume</string> + <string name="blogs_button">Blogje</string> + <string name="settings_button">Rregullime</string> + <string name="sign_out_button">Dilni</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="reminder_notification_title">U dol nga Briar-i</string> + <string name="reminder_notification_text">Prekeni që të ribëhet hyrja.</string> + <string name="reminder_notification_channel_title">Kujtues Hyrjeje Briar</string> + <string name="reminder_notification_dismiss">Hidhe tej</string> + <string name="ongoing_notification_title">Hytë në Briar</string> + <string name="ongoing_notification_text">Prekeni, që të hapet Briar-i</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Mesazh i ri privat.</item> + <item quantity="other">%d mesazhe të reja private.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Mesazh i ri grupi.</item> + <item quantity="other">%d mesazhe të rinj grupi.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Postim i ri forumi</item> + <item quantity="other">%d postime të rinj forumi.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Postim i ri blogu.</item> + <item quantity="other">%d postime të reja blogu.</item> + </plurals> + <!--Misc--> + <string name="now">tani</string> + <string name="show">Shfaqi</string> + <string name="hide">Fshihi</string> + <string name="ok">OK</string> + <string name="cancel">Anuloje</string> + <string name="got_it">Kuptova</string> + <string name="delete">Fshije</string> + <string name="accept">Pranoje</string> + <string name="decline">Hidhe poshtë</string> + <string name="options">Mundësi</string> + <string name="online">Në linjë</string> + <string name="offline">Jo në linjë</string> + <string name="send">Dërgoje</string> + <string name="allow">Lejoje</string> + <string name="open">Hape</string> + <string name="no_data">S\’ka të dhëna</string> + <string name="ellipsis">…</string> + <string name="text_too_long">Teksti i dhënë është shumë i gjatë</string> + <string name="show_onboarding">Shfaq Dialog Ndihme</string> + <string name="fix">Ndreqeni</string> + <string name="help">Ndihmë</string> + <string name="sorry">Na ndjeni</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">S’ka kontakte për shfaqje\n\nPrekni ikonën + që të shtoni një kontakt</string> + <string name="date_no_private_messages">S\’ka mesazhe.</string> + <string name="no_private_messages">S’ka mesazhe për shfaqje</string> + <string name="message_hint">Shtypni mesazhin</string> + <string name="delete_contact">Fshije kontaktin</string> + <string name="dialog_title_delete_contact">Ripohoni Fshirje Kontakti</string> + <string name="dialog_message_delete_contact">Jeni i sigurt se doni të hiqet ky kontakt dhe krejt mesazhet e shkëmbyer me këtë kontakt?</string> + <string name="contact_deleted_toast">Kontakti u fshi</string> + <!--Adding Contacts--> + <string name="add_contact_title">Shtoni një Kontakt</string> + <string name="face_to_face">Duhet të takoheni me personin që doni ta shtoni si kontakt.\n\nKjo do të pengojë cilindo të hiqet si ju ose të lexojë në të ardhmen mesazhet tuaj.</string> + <string name="continue_button">Vazhdo</string> + <string name="connection_failed">Lidhja dështoi</string> + <string name="try_again_button">Riprovoni</string> + <string name="waiting_for_contact_to_scan">Po pritet që kontakti ta skanojë dhe të lidhet\u2026</string> + <string name="exchanging_contact_details">Po shkëmbehen hollësi kontaktesh\u2026</string> + <string name="contact_added_toast">Kontakti u shtua: %s</string> + <string name="contact_already_exists">Kontakti %s ekziston tashmë</string> + <string name="contact_exchange_failed">Shkëmbimi i kontaktit dështoi</string> + <string name="qr_code_invalid">Kodi QR është i pavlefshëm</string> + <string name="qr_code_unsupported">Kodi QR që po provoni të skanoni më poshtë i përket një versioni të vjetër të %s-it, i cili nuk mbulohet më.\n\nJu lutemi, sigurohuni që që të dy ju xhironi versionin më të ri dhe mandej riprovoni.</string> + <string name="camera_error">Gabim kamere</string> + <string name="connecting_to_device">Po lidhet me pajisjen\u2026</string> + <string name="authenticating_with_device">Po bëhet mirëfilltësimi me pajisjen\u2026</string> + <string name="connection_aborted_local">Lidhje e ndërprerë nga ne! Kjo mund të jetë shenjë se dikush po përpiqet të fusë hundët në lidhjen tuaj</string> + <string name="connection_aborted_remote">Lidhje e ndërprerë nga kontakti juaj! Kjo mund të jetë shenjë se dikush po përpiqet të fusë hundët në lidhjen tuaj</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Prezantoni kontaktet tuaja</string> + <string name="introduction_onboarding_text">Kontaktet tuaja mund t\’ia prezantoni njëri-tjetrit, që kështu të mos u duhet të takohen realisht për të mundur të lidhen në Briar.</string> + <string name="introduction_menu_item">Bëje prezantimin</string> + <string name="introduction_activity_title">Përzgjidhni Kontakt</string> + <string name="introduction_not_possible">Keni filluar tashmë një prezantim me këto kontakte. Ju lutemi, lëreni të përfundojë së pari. Nëse ju ose kontaktet tuaja rrallë gjenden <em>online</em>, kjo mund të dojë ca kohë.</string> + <string name="introduction_message_title">Prezantoni Kontakte</string> + <string name="introduction_message_hint">Shtoni një mesazh (në daçi)</string> + <string name="introduction_button">Bëje prezantimin</string> + <string name="introduction_sent">Prezantimi juaj u dërgua.</string> + <string name="introduction_error">Pati një gabim me bërjen e prezantimit.</string> + <string name="introduction_response_error">Gabim në përgjigjen ndaj prezantimit</string> + <string name="introduction_request_sent">Keni kërkuar të prezantoni %1$s te %2$s.</string> + <string name="introduction_request_received">%1$s ka kërkuar t\’ju prezantojë te %2$s. Doni të shtohet %2$s te lista juaj e kontakteve?</string> + <string name="introduction_request_exists_received">%1$s ka kërkuar t\’ju prezantojë te %2$s, por %2$s gjendet tashmë te lista juaj e kontakteve. Meqë %1$s mund të mos ta dijë këtë gjë, mundeni prapëseprapë t\’i përgjigjeni:</string> + <string name="introduction_request_answered_received">%1$s ka kërkuar t\’ju prezantojë te %2$s.</string> + <string name="introduction_response_accepted_sent">Pranuat prezantimin te %1$s.</string> + <string name="introduction_response_accepted_sent_info">Para se %1$s të shtohet te kontaktet tuaja, duhet të pranojë prezantimin tuaj. Kjo mund të dojë ca kohë.</string> + <string name="introduction_response_declined_sent">Hodhët poshtë prezantimin te %1$s.</string> + <string name="introduction_response_accepted_received">%1$s pranoi prezantimin te %2$s.</string> + <string name="introduction_response_declined_received">%1$s hodhi poshtë prezantimin te %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s thotë se %2$s hodhi poshtë prezantimin.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">U shtua kontakt i ri.</item> + <item quantity="other">U shtuan %d kontakte të rinj.</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">S\’ka grupe për shfaqje.\n\nPrekni ikonën + që të krijoni një grup ose kërkojuni kontakteve tuaj t\’ju ftojnë në një prej grupeve të tyre</string> + <string name="groups_created_by">Krijuar nga %s</string> + <plurals name="messages"> + <item quantity="one">%d mesazh</item> + <item quantity="other">%d mesazhe</item> + </plurals> + <string name="groups_group_is_empty">Ky grup është i zbrazët</string> + <string name="groups_group_is_dissolved">Ky grup është shkrirë</string> + <string name="groups_remove">Hiqe</string> + <string name="groups_create_group_title">Krijoni Grup Privat</string> + <string name="groups_create_group_button">Krijoje Grupin</string> + <string name="groups_create_group_invitation_button">Dërgoje Ftesën</string> + <string name="groups_create_group_hint">Zgjidhni një emër për grupin tuaj privat</string> + <string name="groups_invitation_sent">Ftesa e grupit u dërgua</string> + <string name="groups_message_sent">Mesazhi u dërgua</string> + <string name="groups_member_list">Listë Anëtarësh</string> + <string name="groups_invite_members">Ftoni Anëtarë</string> + <string name="groups_member_created_you">E krijuat grupin</string> + <string name="groups_member_created">%s krijoi grupin</string> + <string name="groups_member_joined_you">U bëtë pjesë e grupit</string> + <string name="groups_member_joined">%s u bë pjesë e grupit</string> + <string name="groups_leave">Braktiseni Grupin</string> + <string name="groups_leave_dialog_title">Ripohoni Braktisjen e Grupit</string> + <string name="groups_leave_dialog_message">Jeni i sigurt se doni ta braktisni këtë grup?</string> + <string name="groups_dissolve">Shkrijeni Grupin</string> + <string name="groups_dissolve_dialog_title">Ripohoni Shkrirjen e Grupit</string> + <string name="groups_dissolve_dialog_message">Jeni i sigurt se doni të shkrihet ky grup?\n\nKrejt anëtarët e tjerë s\’do të jenë në gjendje të vazhdojnë bisedat e tyre dhe mundet të mos i marrin mesazhet më të rinj.</string> + <string name="groups_dissolve_button">Shkrije</string> + <string name="groups_dissolved_dialog_title">Grupi u Shkri</string> + <string name="groups_dissolved_dialog_message">Krijuesi i këtij grupi e ka shkrirë atë.\n\nS\’mund të shkruani më mesazhe për grupin dhe mundet të mos i merrni krejt postimet që janë shkruar.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Ftesa Grupi</string> + <string name="groups_invitations_invitation_sent">Keni ftuar %1$s të bëhet pjesë e grupit \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s ju ka ftuar të bëheni pjesë e grupit \"%2$s\".</string> + <string name="groups_invitations_joined">U bëtë pjesë e grupit</string> + <string name="groups_invitations_declined">Ftesa e grupit u hodh poshtë</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d ftesë grupi e hapur</item> + <item quantity="other">%d ftesa grupi të hapura</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">Pranuat ftesën e grupit nga %s.</string> + <string name="groups_invitations_response_declined_sent">Hodhët poshtë ftesën e grupit nga %s.</string> + <string name="groups_invitations_response_accepted_received">%s e pranoi ftesën e grupit.</string> + <string name="groups_invitations_response_declined_received">%s e hodhi poshtë ftesën e grupit.</string> + <string name="sharing_status_groups">Vetëm krijuesi mund të ftojë anëtarë të rinj në grup. Më poshtë gjenden tërë anëtarët e tanishëm të grupit.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Shfaqua Kontaktet</string> + <string name="groups_reveal_dialog_message">Mund të zgjidhni t\’ua shfaqni ose jo kontaktet krejt anëtarëve të tanishëm dhe të ardhshëm të këtij grupi.\n\nShfaqja e kontakteve e bën lidhjen tuaj me grupin më të shpejtë dhe më të besueshme, ngaqë mund të komunikoni me kontaktet e shfaqura edhe kur krijuesi i grupit s\’është në linjë.</string> + <string name="groups_reveal_visible">Marrëdhënia e kontaktit është e dukshme për grupin</string> + <string name="groups_reveal_visible_revealed_by_us">Marrëdhënia e kontaktit është e dukshme për grupin (shfaqur nga ju)</string> + <string name="groups_reveal_visible_revealed_by_contact">Marrëdhënia e kontaktit është e dukshme për grupin (shfaqur nga %s)</string> + <string name="groups_reveal_invisible">Marrëdhënia e kontaktit s\’është e dukshme për grupin</string> + <!--Forums--> + <string name="no_forums">S\’ka forume për shfaqje.\n\nPrekni ikonën + që të krijoni një forum ose kërkojuni kontakteve tuaj t\’ju ftojnë në një prej forumeve të tyre</string> + <string name="create_forum_title">Krijoje Forumin</string> + <string name="choose_forum_hint">Zgjidhni një emër për forumin tuaj</string> + <string name="create_forum_button">Krijoje Forumin</string> + <string name="forum_created_toast">Forumi u krijua</string> + <string name="no_forum_posts">S\’ka postime për shfaqje</string> + <string name="no_posts">S\’ka postime</string> + <plurals name="posts"> + <item quantity="one">%d postim</item> + <item quantity="other">%d postime</item> + </plurals> + <string name="forum_new_entry_posted">U botua postim forumi</string> + <string name="forum_new_message_hint">Postim i Ri</string> + <string name="forum_message_reply_hint">Përgjigje e Re</string> + <string name="btn_reply">Përgjigju</string> + <string name="forum_leave">Braktiseni Forumin</string> + <string name="dialog_title_leave_forum">Ripohoni Braktisjen e Forumit</string> + <string name="dialog_message_leave_forum">Jeni i sigurt se doni ta braktisni këtë forum?\n\nÇfarëdo kontaktesh me të cilët e keni ndarë këtë forum mundet të reshtin së marri përditësime.</string> + <string name="dialog_button_leave">Braktise</string> + <string name="forum_left_toast">E braktisët forumin</string> + <!--Forum Sharing--> + <string name="forum_share_button">Ndajeni Forumin Me të Tjerë</string> + <string name="contacts_selected">Kontaktet u përzgjodhën</string> + <string name="activity_share_toolbar_header">Zgjidhni Kontakte</string> + <string name="no_contacts_selector">S’ka kontakte për shfaqje\n\nJu lutemi, rikthehuni këtu pasi të shtoni një kontakt</string> + <string name="forum_shared_snackbar">Forumi u nda me kontaktet e zgjedhur</string> + <string name="forum_share_message">Shtoni një mesazh (në daçi)</string> + <string name="forum_share_error">Pati një gabim në ndarjen e këtij forumi me të tjerët.</string> + <string name="forum_invitation_received">%1$s ndau me ju forumin \"%2$s\".</string> + <string name="forum_invitation_sent">Ndatë me \"%2$s\" forumin %1$s.</string> + <string name="forum_invitations_title">Ftesa Forumi</string> + <string name="forum_invitation_exists">Keni pranuar tashmë një ftesë për te ky forum.\n\nPranimi i më tepër ftesave do ta bëjë lidhjen tuaj me këtë forum më të shpejtë dhe më të qëndrueshme.</string> + <string name="forum_joined_toast">Hytë në forum</string> + <string name="forum_declined_toast">Ftesa u hodh poshtë</string> + <string name="shared_by_format">Ndarë nga %s</string> + <string name="forum_invitation_already_sharing">Ndarë tashmë</string> + <string name="forum_invitation_response_accepted_sent">Pranuat ftesën e forumit nga %s.</string> + <string name="forum_invitation_response_declined_sent">Hodhët poshtë ftesën e forumit nga %s.</string> + <string name="forum_invitation_response_accepted_received">%s pranoi ftesën e forumit.</string> + <string name="forum_invitation_response_declined_received">%s e hodhi poshtë ftesën e forumit.</string> + <string name="sharing_status">Gjendje Ndarjeje Me të Tjerë</string> + <string name="sharing_status_forum">Cilido anëtar i grupit mund ta ndajë me të tjerët. Këtë forum po e ndani me kontaktet vijuese. Mund të ketë edhe anëtarë të tjerët, të cilët s\’mund t\’i shihni.</string> + <string name="shared_with">E ndarë me %1$d (%2$d në linjë)</string> + <plurals name="forums_shared"> + <item quantity="one">%d forum ndarë nga kontakte</item> + <item quantity="other">%d forum ndarë nga kontakte</item> + </plurals> + <string name="nobody">Askush</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">S\’ka postime për shfaqje</string> + <string name="read_more">lexoni më tepër</string> + <string name="blogs_write_blog_post">Shkruani Postim Blogu</string> + <string name="blogs_write_blog_post_body_hint">Shtypni postimin tuaj të blogut</string> + <string name="blogs_publish_blog_post">Botoje</string> + <string name="blogs_blog_post_created">Postimi i Blogut u Krijua</string> + <string name="blogs_blog_post_received">U morën Postime të Reja Blogu</string> + <string name="blogs_blog_post_scroll_to">Kalo Te</string> + <string name="blogs_feed_empty_state">S’ka postime për shfaqje\n\nPostimet prej kontakteve tuaja dhe blogjeve ku pajtoheni do të shfaqen këtu\n\nPrekni ikonën penë që të shkruani një postim</string> + <string name="blogs_remove_blog">hiqe Blogun</string> + <string name="blogs_remove_blog_dialog_message">Jeni i sigurt se doni të hiqet ky blog?\n\nPostimet do të hiqen nga pajisja juaj, por jo nga pajisjet e personave të tjerë.\n\nÇfarëdo kontaktesh me të cilët e keni ndarë këtë blog mund të reshtin së marri përditësime.</string> + <string name="blogs_remove_blog_ok">Hiqe</string> + <string name="blogs_blog_removed">Blogu u hoq</string> + <string name="blogs_reblog_comment_hint">Shtoni një koment (në daçi)</string> + <string name="blogs_reblog_button">Riblogojeni</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Ndajeni Blogun Me të Tjerë</string> + <string name="blogs_sharing_error">Pati një gabim në ndarjen e këtij blogu me të tjerë.</string> + <string name="blogs_sharing_button">Ndaje Blogun Me të Tjerë</string> + <string name="blogs_sharing_snackbar">Blogu u nda me kontaktet e zgjedhur</string> + <string name="blogs_sharing_response_accepted_sent">Pranuat ftesën e blogut nga %s.</string> + <string name="blogs_sharing_response_declined_sent">Hodhët poshtë ftesën e blogut nga %s.</string> + <string name="blogs_sharing_response_accepted_received">%s pranoi ftesën e blogut.</string> + <string name="blogs_sharing_response_declined_received">%s hodhi poshtë ftesën e blogut.</string> + <string name="blogs_sharing_invitation_received">%1$s ndau me ju \"%2$s\".</string> + <string name="blogs_sharing_invitation_sent">Ndatë blogun \"%1$s\" me %2$s.</string> + <string name="blogs_sharing_invitations_title">Ftesa Blogu</string> + <string name="blogs_sharing_joined_toast">U pajtuat te blogu</string> + <string name="blogs_sharing_declined_toast">Ftesa u hodh poshtë</string> + <string name="sharing_status_blog">Cilido që pajtohet te një blog mund ta ndajë atë me kontaktet e veta. Këtë blog po e ndani me kontaktet vijuese. Mund të ketë edhe pajtimtarë të tjerë, të cilët s\’mund t\’i shihni.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Importoni Prurje RSS</string> + <string name="blogs_rss_feeds_import_button">Importo</string> + <string name="blogs_rss_feeds_import_hint">Jepni URL-në e prurjes RSS</string> + <string name="blogs_rss_feeds_import_error">Na ndjeni! Pati një gabim me importimin e prurjes tuaj.</string> + <string name="blogs_rss_feeds_manage">Administroni Prurje RSS</string> + <string name="blogs_rss_feeds_manage_imported">Të importuara:</string> + <string name="blogs_rss_feeds_manage_author">Autor:</string> + <string name="blogs_rss_feeds_manage_updated">Përditësuar Së Fundi:</string> + <string name="blogs_rss_remove_feed">Hiqe Prurjen</string> + <string name="blogs_rss_remove_feed_dialog_message">Jeni i sigurt se doni të hiqet kjo prurje?\n\nPostimet do të hiqen nga pajisja juaj, por jo nga pajisjet e njerëzve të tjerë.\n\nÇfarëdo kontaktesh me të cilët e keni ndarë këtë prurje mund të reshtin së marri përditësime.</string> + <string name="blogs_rss_remove_feed_ok">Hiqe</string> + <string name="blogs_rss_feeds_manage_delete_error">S\’u fshi dot prurja!</string> + <string name="blogs_rss_feeds_manage_empty_state">S’ka prurje RSS për shfaqje\n\nPrekni ikonën + që të importohet një prurje</string> + <string name="blogs_rss_feeds_manage_error">Pati një problem me ngarkimin e prurjeve tuaja. Ju lutemi, riprovoni më vonë.</string> + <!--Settings Display--> + <string name="pref_language_title">Gjuhë & rajon</string> + <string name="pref_language_changed">Ky rregullim do të hyjë në fuqi kur të rinisni Briar-in. Ju lutemi, bëni daljen nga llogaria dhe rinisni Briar-in.</string> + <string name="pref_language_default">Parazgjedhje sistemi</string> + <string name="display_settings_title">Shfaqje</string> + <string name="pref_theme_title">Temë</string> + <string name="pref_theme_light">E çelët</string> + <string name="pref_theme_dark">E errët</string> + <string name="pref_theme_auto">Automatike (Daytime)</string> + <string name="pref_theme_system">Parazgjedhje Sistemi</string> + <!--Settings Network--> + <string name="network_settings_title">Rrjete</string> + <string name="bluetooth_setting">Lidhu përmes Bluetooth-i</string> + <string name="bluetooth_setting_enabled">Kurdo që kontaktet janë këtej pari</string> + <string name="bluetooth_setting_disabled">Vetëm kur shtohen kontakte</string> + <string name="tor_network_setting">Lidhu përmes Tor-i</string> + <string name="tor_network_setting_never">Kurrë</string> + <string name="tor_network_setting_wifi">Vetëm kur përdoret Wi-Fi</string> + <string name="tor_network_setting_always">Kur përdoret Wi-Fi ose të dhëna celulari</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Siguri</string> + <string name="change_password">Ndryshoni fjalëkalimin</string> + <string name="current_password">Fjalëkalimi i tanishëm</string> + <string name="choose_new_password">Fjalëkalim i ri</string> + <string name="confirm_new_password">Konfirmo fjalëkalimin e ri</string> + <string name="password_changed">Fjalëkalimi u ndryshua.</string> + <string name="panic_setting">Rregullimi i butonit të panikut</string> + <string name="panic_setting_title">Buton paniku</string> + <string name="panic_setting_hint">Formësoni si do të reagojë Briar-i kur përdorni aplikacion butoni paniku</string> + <string name="panic_app_setting_title">Aplikacion Butoni Paniku</string> + <string name="unknown_app">aplikacion i panjohur</string> + <string name="panic_app_setting_summary">S\’është rregulluar ndonjë aplikacion</string> + <string name="panic_app_setting_none">Asnjë</string> + <string name="dialog_title_connect_panic_app">Ripohoni Aplikacion Paniku</string> + <string name="dialog_message_connect_panic_app">Jeni i sigurt se doni të lejohet %1$s të prodhojë veprime shkatërruese butoni paniku?</string> + <string name="panic_setting_signout_title">Dilni</string> + <string name="panic_setting_signout_summary">Dil nga Briar-i nëse shtypet një buton paniku</string> + <string name="purge_setting_title">Fshi Llogarinë</string> + <string name="purge_setting_summary">Fshijeni llogarinë tuaj Briar, nëse shtypet një buton paniku. Kujdes: Kjo do të shkaktojë fshirjen e identiteteve, kontakteve dhe mesazheve tuaj</string> + <string name="uninstall_setting_title">Çinstalo Briar-in</string> + <string name="uninstall_setting_summary">Kjo lyp ripohim dorazi, në rast akti paniku</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Njoftime</string> + <string name="notify_sign_in_title">Rikujtomë të bëj hyrjen</string> + <string name="notify_sign_in_summary">Shfaq një kujtues kur niset telefoni ose aplikacioni është përditësuar</string> + <string name="notify_private_messages_setting_title">Mesazhe private</string> + <string name="notify_private_messages_setting_summary">Shfaq sinjalizime për mesazhe private</string> + <string name="notify_private_messages_setting_summary_26">Formësoni sinjalizimet për mesazhe private</string> + <string name="notify_group_messages_setting_title">Mesazhe grupi</string> + <string name="notify_group_messages_setting_summary">Shfaq sinjalizime për mesazhe grupi</string> + <string name="notify_group_messages_setting_summary_26">Formësoni sinjalizimet për mesazhi grupi</string> + <string name="notify_forum_posts_setting_title">Postime forumi</string> + <string name="notify_forum_posts_setting_summary">Shfaq sinjalizime për postime forumi</string> + <string name="notify_forum_posts_setting_summary_26">Formësoni sinjalizimet për postime forumi</string> + <string name="notify_blog_posts_setting_title">Postime blogu</string> + <string name="notify_blog_posts_setting_summary">Shfaq sinjalizime për postime blogu</string> + <string name="notify_blog_posts_setting_summary_26">Formësoni sinjalizime për postime blogu</string> + <string name="notify_vibration_setting">Dridhu</string> + <string name="notify_lock_screen_setting_title">Kyçe Ekranin</string> + <string name="notify_lock_screen_setting_summary">Shfaqi njoftimet edhe me ekran të kyçur</string> + <string name="notify_sound_setting">Tingull</string> + <string name="notify_sound_setting_default">Zilja parazgjedhje</string> + <string name="notify_sound_setting_disabled">Asnjë</string> + <string name="choose_ringtone_title">Zgjidhni zile</string> + <string name="cannot_load_ringtone">S\’ngarkohet dot zile</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Përshtypje</string> + <string name="send_feedback">Dërgoji përshtypjet</string> + <!--Link Warning--> + <string name="link_warning_title">Sinjalizim Lidhjeje</string> + <string name="link_warning_intro">Ju ndan një hap nga hapja e lidhjes vijuese me një aplikacion të jashtëm.</string> + <string name="link_warning_text">Kjo mund të përdoret për t\’ju identifikuar. Mendohuni nëse e besoni apo jo personin që ju dërgoi këtë lidhje dhe shihni mundësinë e hapjes së sja me Orfox</string> + <string name="link_warning_open_link">Hape Lidhjen</string> + <!--Crash Reporter--> + <string name="crash_report_title">Njoftim Vithisjesh Briar</string> + <string name="briar_crashed">Na ndjeni, Briar-i u vithis.</string> + <string name="not_your_fault">S\’është faji juaj.</string> + <string name="please_send_report">Ju lutemi, na ndihmoni të ndërtojmë një Briar më të mirë, duke na dërguar një njoftim vithisjeje.</string> + <string name="report_is_encrypted">Premtojmë që njoftimi fshehtëzohet dhe dërgohet në mënyrë të sigurt.</string> + <string name="feedback_title">Përshtypje</string> + <string name="describe_crash">Përshkruani se ç\’ndodhi (në daçi)</string> + <string name="enter_feedback">Jepni përshtypjet tuaja</string> + <string name="optional_contact_email">Adresa juaj email (në daçi)</string> + <string name="include_debug_report_crash">Përfshi të dhëna anonime rreth vithisjes</string> + <string name="include_debug_report_feedback">Përfshi të dhëna anonime rreth kësaj pajisjeje</string> + <string name="could_not_load_report_data">S\’u ngarkuan dot të dhëna njoftimi.</string> + <string name="send_report">Dërgoje njoftimin</string> + <string name="close">Mbylle</string> + <string name="dev_report_saved">Njoftimi u ruajt. Do të dërgohet herën tjetër që do të hyni në Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">Po dilet nga Briar-i…</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">U kap dalje jashtë ekrani</string> + <string name="screen_filter_body">Sipër Briar-it po vizaton një tjetër aplikacion. Për të mbrojtur sigurinë tuaj, Briar-i nuk do t’u përgjigjet prekjeve kur një tjetër aplikacion vizaton përsipër.\n\nPërsipër mund të jenë duke vizatuar aplikacionet vijues:\n\n%1$s</string> + <string name="screen_filter_allow">Lejoji këto aplikacione të vizatojnë përsipër</string> + <!--Permission Requests--> + <string name="permission_camera_title">Leje mbi kamerën</string> + <string name="permission_camera_request_body">Që të skanojë kodin QR, Briar-i lypset të hyjë te kamera.</string> + <string name="permission_camera_denied_body">Keni mohuar hyrjen në kamera, por shtimi i kontakteve lyp përdorimin e kamerës.\n\nJu lutemi, shihni mundësinë e akordimit të hyrjes.</string> + <string name="permission_camera_denied_toast">S\’u dhanë leje mbi kamerën</string> + <string name="qr_code">Kod QR</string> + <string name="show_qr_code_fullscreen">Shfaqe kodin QR sa tërë ekrani</string> +</resources> diff --git a/mailbox-android/src/main/res/values-sr/strings.xml b/mailbox-android/src/main/res/values-sr/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..7e93c1b8bf31a14bfc8c2983c6ad2ca968db5153 --- /dev/null +++ b/mailbox-android/src/main/res/values-sr/strings.xml @@ -0,0 +1,292 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_next">Следећи</string> + <string name="choose_nickname">Izaberite vaÅ¡ nadimak</string> + <string name="choose_password">Izaberite vaÅ¡u Å¡ifru</string> + <string name="confirm_password">Potvrdite vaÅ¡u Å¡ifru</string> + <string name="name_too_long">Ime je predugo</string> + <string name="password_too_weak">Å ifra je slaba</string> + <string name="passwords_do_not_match">Å ifre se ne poklapaju</string> + <string name="create_account_button">Kreirajte raÄun</string> + <!--Login--> + <string name="enter_password">Лозинка</string> + <string name="try_again">PogreÅ¡na Å¡ifra, probajte opet</string> + <string name="sign_in_button">Prijavite se</string> + <string name="forgotten_password">Zaboravio sam Å¡ifru</string> + <string name="dialog_title_lost_password">Izgubljena Å¡ifra</string> + <string name="dialog_message_lost_password">VaÅ¡ Briar raÄun je kriptovan i saÄuvan na vaÅ¡em ureÄ‘aju, ne u server-oblaku, pa nemožemo resetovati vaÅ¡u Å¡ifru. Želite li da izbriÅ¡ete raÄun i poÄnete iz poÄetka?\n\nPozor: VaÅ¡i identiteti, kontakti i poruke će biti premanentno izgubljeni.</string> + <string name="startup_failed_notification_title">Brirar nije mogao da startuje</string> + <string name="startup_failed_activity_title">Briar neuspjeÅ¡no startovanje</string> + <string name="startup_failed_service_error">Briar nije mogao da startuje potreban plugin. Reinstaliranje Briara obiÄno rijeÅ¡i problem. MeÄ‘utim, imajte na umu da ćete izgubiti vaÅ¡ raÄun i sve podatke vezane za njega poÅ¡to Briar ne koristi centralne servere da saÄuva vaÅ¡e podatke.</string> + <string name="expiry_date_reached">Ovaj softver je istekao.\nHvala na testiranju!</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Otvorite navigacionu fioku</string> + <string name="nav_drawer_close_description">Zatvorite navigacionu fioku</string> + <string name="contact_list_button">Kontakti</string> + <string name="groups_button">Privatne Grupe</string> + <string name="forums_button">Forumi</string> + <string name="blogs_button">Blogovi</string> + <string name="settings_button">PodeÅ¡avanja</string> + <string name="sign_out_button">Odjava</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="ongoing_notification_title">Prijavljeni ste u Briar</string> + <string name="ongoing_notification_text">Dodirnite da otvorite Briar.</string> + <!--Misc--> + <string name="now">sada</string> + <string name="show">Pokazi</string> + <string name="hide">Sakrij</string> + <string name="ok">OK</string> + <string name="cancel">Odustani</string> + <string name="got_it">Jasno</string> + <string name="delete">BriÅ¡i</string> + <string name="accept">Prihvati</string> + <string name="decline">Odbij</string> + <string name="options">Opcije</string> + <string name="online">Na vezi</string> + <string name="offline">Iskljucen</string> + <string name="send">Å alji</string> + <string name="allow">Dozvoli</string> + <string name="open">Otvori</string> + <string name="no_data">Nema podataka</string> + <string name="ellipsis">...</string> + <string name="text_too_long">Uneti tekst je predugaÄak</string> + <string name="show_onboarding">Pokazi Pomoc dijalog </string> + <string name="help">Помоћ</string> + <!--Contacts and Private Conversations--> + <string name="date_no_private_messages">Nema poruka.</string> + <string name="message_hint">Ukucajte poruku</string> + <string name="delete_contact">IzbriÅ¡ite kontakt</string> + <string name="dialog_title_delete_contact">Potvrdite brisanje kontakta</string> + <string name="dialog_message_delete_contact">Jeste li sigurni da želite da uklonite ovaj kontakt i sve poruke koje ste razmijenili?</string> + <string name="contact_deleted_toast">Kontakt izbrisan</string> + <!--Adding Contacts--> + <string name="add_contact_title">Dodaj kontakt</string> + <string name="face_to_face">Morate se sresti sa osobom koju želite da dodate kao kontakt.\n\nOvo će sprijeÄiti bilo koga da se predstavi kao vi ili da ubuduće Äita poruke.</string> + <string name="continue_button">Dalje</string> + <string name="connection_failed">Veza je pukla</string> + <string name="try_again_button">Probajte opet</string> + <string name="waiting_for_contact_to_scan">ÄŒekam da kontakt skenira i poveže se\u2026</string> + <string name="exchanging_contact_details">Razmjenjujem detalje kontakta\u2026</string> + <string name="contact_added_toast">Kontakt dodat: %s</string> + <string name="contact_already_exists">Kontakt %s već postoji</string> + <string name="contact_exchange_failed">Razmjena kontakata nije uspjela</string> + <string name="qr_code_invalid">QR kod nije validan</string> + <string name="connecting_to_device">Povezujem se sa ureÄ‘ajem\u2026</string> + <string name="authenticating_with_device">Autentikacija sa ureÄ‘ajem\u2026</string> + <string name="connection_aborted_remote">Konekcija prekinuta sa od strane kontakta! Ovo može znaÄiti da neko pokuÅ¡ava da se umijeÅ¡a u vaÅ¡u vezu</string> + <!--Introductions--> + <string name="introduction_onboarding_title">Upoznajte vaÅ¡e kontakte</string> + <string name="introduction_onboarding_text">Vi možete da upoznate vaÅ¡e kontakte meÄ‘usobno, da nebi morali da srijeću lice u liceda bi se povezali na Briar.</string> + <string name="introduction_menu_item">IzvrÅ¡ite upoznavanje</string> + <string name="introduction_activity_title">Izaberite kontakt</string> + <string name="introduction_message_title">Upoznajte kontakte</string> + <string name="introduction_message_hint">Dodajte poruku (opciono)</string> + <string name="introduction_button">IzvrÅ¡ite upoznavanje</string> + <string name="introduction_sent">VaÅ¡e poziv na upoznavanje je poslat</string> + <string name="introduction_error">DoÅ¡lo je do greÅ¡ke pri izvrÅ¡enju upoznavanja.</string> + <string name="introduction_response_error">GreÅ¡ka pri odgovoru na upoznavanje</string> + <string name="introduction_request_sent">Tražili ste da se %1$s i %2$s upoznaju.</string> + <string name="introduction_request_received">%1$s je tražio da vas upozna sa %2$s. Da li želite da dodate %2$s u vaÅ¡u listu kontakata?</string> + <string name="introduction_request_exists_received">%1$s je tražio da vas upozna sa %2$s, ali %2$s je već u vaÅ¡oj listi kontakata. PoÅ¡to %1$s to možda nezna, vi i dalje možete da odgovorite: </string> + <string name="introduction_request_answered_received">%1$s je tražio da vas upozna sa %2$s.</string> + <string name="introduction_response_accepted_sent">Prihvatili ste upoznavanje sa kontaktom %1$s.</string> + <string name="introduction_response_declined_sent">Odbili ste upoznavanje sa kontaktom %1$s.</string> + <string name="introduction_response_accepted_received">%1$s prihvata upoznavanje sa %2$s.</string> + <string name="introduction_response_declined_received">%1$s je prihvatio-la upoznavanje sa kontaktom %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s kaže da je %2$s odbio-la upoznavanje.</string> + <!--Private Groups--> + <string name="groups_created_by">Kreator je %s</string> + <string name="groups_group_is_empty">Grupa je prazna</string> + <string name="groups_group_is_dissolved">Ova grupa je rasformirana</string> + <string name="groups_remove">Ukloni</string> + <string name="groups_create_group_title">Kreiraj privatnu grupu</string> + <string name="groups_create_group_button">Kreiraj grupu</string> + <string name="groups_create_group_invitation_button">PoÅ¡alji poziv</string> + <string name="groups_create_group_hint">Izaberite ime za vaÅ¡u privatnu grupu</string> + <string name="groups_invitation_sent">Grupna pozivnica je poslata</string> + <string name="groups_message_sent">Poruka poslata</string> + <string name="groups_member_list">Lista Älanova</string> + <string name="groups_invite_members">PoÅ¡aljite poziv Älanovima</string> + <string name="groups_member_created_you">Vi ste kreirali grupu</string> + <string name="groups_member_created">%s je kreator grupe</string> + <string name="groups_member_joined_you">Pristupili ste grupi</string> + <string name="groups_member_joined">1%s je pristupio-la grupi</string> + <string name="groups_leave">Napustite grupu</string> + <string name="groups_leave_dialog_title">Potvrdite napuÅ¡tanje grupe</string> + <string name="groups_leave_dialog_message">Jeste li sigurni da želite da napustite grupu?</string> + <string name="groups_dissolve">Raspustite grupu</string> + <string name="groups_dissolve_dialog_title">Potvrdite raspuÅ¡tanje grupe</string> + <string name="groups_dissolve_dialog_message">Jeste li sigurni da želite da raspustite ovu grupu?\n\nOstali Älanovi neće viÅ¡e moći da nastave njihovu konverzaciju i možda neće dobiti poslednje poruke.</string> + <string name="groups_dissolve_button">Raspusti</string> + <string name="groups_dissolved_dialog_title">Grupa je raspuÅ¡tena</string> + <string name="groups_dissolved_dialog_message">Kreator je raspustio ovu grupu.\n\nNemožete viÅ¡e pisati poruke u grupi i možda nećete primiti poljednje poruke koje su napisane.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Grupni pozivi</string> + <string name="groups_invitations_invitation_sent">Pozvali ste kontakt %1$s da se pridruzi grupi \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s je poslao-la poziv da pristupite grupi \"%2$s\".</string> + <string name="groups_invitations_joined">Pristupili ste grupi</string> + <string name="groups_invitations_declined">Grupni poziv je odbijen</string> + <string name="groups_invitations_response_accepted_sent">Prihvatili ste grupni poziv od kontakta %s.</string> + <string name="groups_invitations_response_declined_sent">Odbili ste grupni poziv od kontakta %s.</string> + <string name="groups_invitations_response_accepted_received">%s je prihvatio-la grupni poziv.</string> + <string name="groups_invitations_response_declined_received">1%s je odbio-la grupni poziv.</string> + <string name="sharing_status_groups">Samo kreator moze da pozove nove Älanove u grupu. Ispod su trenutni Älanovi grupe.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">Otkrijte kontakte</string> + <string name="groups_reveal_dialog_message">Možete odluÄiti da otkrijete kontakte svim trenutnim i budućim Älanovima ove grupe.\n\nOtkrivanje kontakata Äini konekciju ka Älanovima grupe bržom i pouzdanijom, jer možete da komunicirate sa otkrivenim kontaktima Äak i kad kreator grupe nije na vezi.</string> + <string name="groups_reveal_visible">Veze kontakata su vidljive grupi</string> + <string name="groups_reveal_visible_revealed_by_us">Veze kontakata su vidljive grupi (vi ste je otkrili)</string> + <string name="groups_reveal_visible_revealed_by_contact">Veze kontakata su vidljive grupi (otkriveno od strane %s)</string> + <string name="groups_reveal_invisible">Veze kontakata nisu vidljive grupi</string> + <!--Forums--> + <string name="create_forum_title">Kreirajte forum</string> + <string name="choose_forum_hint">Izaberite ime za vaÅ¡ forum</string> + <string name="create_forum_button">Kreirajte forum</string> + <string name="forum_created_toast">Forum je kreiran</string> + <string name="no_posts">Nema postova</string> + <string name="forum_message_reply_hint">Novi odgovor</string> + <string name="btn_reply">Odgovor</string> + <string name="forum_leave">Napustite forum</string> + <string name="dialog_title_leave_forum">Potvrdite napuÅ¡tanje foruma</string> + <string name="dialog_button_leave">Napusti</string> + <!--Forum Sharing--> + <string name="forum_share_button">Dijelite forum</string> + <string name="contacts_selected">Kontakti selektovani</string> + <string name="activity_share_toolbar_header">Izaberite kontakte</string> + <string name="forum_shared_snackbar">Forum je podijeljen sa izabranim kontaktima</string> + <string name="forum_share_message">Dodajte poruku (opciono)</string> + <string name="forum_share_error">DoÅ¡lo je do greÅ¡ke prilikom slanja ovog foruma.</string> + <string name="forum_invitation_received">%1$s je podijelio-la forum \"%2$s\" sa vama.</string> + <string name="forum_invitation_sent">Podijelili ste forum \"%1$s\" sa %2$s.</string> + <string name="forum_invitations_title">Pozivnice za forum</string> + <string name="shared_by_format">Podijelio-la %s</string> + <string name="forum_invitation_already_sharing">Već se dijeli</string> + <string name="forum_invitation_response_accepted_sent">Prihvatili ste poziv u forum od %s.</string> + <string name="forum_invitation_response_declined_sent">Odbili ste poziv u forum od %s.</string> + <string name="forum_invitation_response_accepted_received">1%s prihvata vaÅ¡ poziv u forum.</string> + <string name="forum_invitation_response_declined_received">%s odbija vaÅ¡ poziv u forum.</string> + <string name="sharing_status">Status dijeljenja</string> + <string name="sharing_status_forum">Bilo koji Älan foruma može ga podijeliti sa svojim kontaktima. Vi dijelite forum sa slijedećim kontaktima. Moguće je da ima drugih Älanova koje ne vidite.</string> + <string name="shared_with">Pdijeljeno sa %1$d (%2$d na vezi)</string> + <string name="nobody">Niko</string> + <!--Blogs--> + <string name="read_more">proÄitaj ostalo</string> + <string name="blogs_write_blog_post">NapiÅ¡i Blog Post</string> + <string name="blogs_publish_blog_post">Objavi</string> + <string name="blogs_blog_post_created">Blog post je kreiran</string> + <string name="blogs_blog_post_received">Primljen je novi blog post</string> + <string name="blogs_blog_post_scroll_to">Skroluj do</string> + <string name="blogs_remove_blog">Ukloni blog</string> + <string name="blogs_remove_blog_ok">Ukloni</string> + <string name="blogs_reblog_comment_hint">Dodajte komentar (opciono)</string> + <string name="blogs_reblog_button">Reblogujte</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Podijelite blog</string> + <string name="blogs_sharing_error">DoÅ¡lo je do greÅ¡ke pri podjeli bloga.</string> + <string name="blogs_sharing_button">Podijeli blog</string> + <string name="blogs_sharing_snackbar">Blog je podijeljen sa izabranim kontaktima</string> + <string name="blogs_sharing_response_accepted_sent">Prihvatili ste blog pozivnicu od %s.</string> + <string name="blogs_sharing_response_declined_sent">Odbili ste blog pozivnicu od %s.</string> + <string name="blogs_sharing_response_accepted_received">%s je prihvatio-la blog pozivnicu.</string> + <string name="blogs_sharing_response_declined_received">%s je odbio-la blog pozivnicu.</string> + <string name="blogs_sharing_invitation_received">%1$s je podijelio-la blog \"%2$s\" sa vama.</string> + <string name="blogs_sharing_invitation_sent">Podijelili ste blog \"%1$s\" sa %2$s.</string> + <string name="blogs_sharing_invitations_title">Blog pozivnice</string> + <string name="sharing_status_blog">Ko god se potpiÅ¡e za ovaj blog može da ga podijeli sa svojim kontaktima. Vi dijelite blog sa slijedećim kontaktima. Moguće je da ima joÅ¡ potpisnika koje nemožete da vidite.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">Uvezi RSS kanal</string> + <string name="blogs_rss_feeds_import_button">Uvezi</string> + <string name="blogs_rss_feeds_import_hint">Unesi URL od RSS kanala</string> + <string name="blogs_rss_feeds_import_error">Žao nam je! DoÅ¡lo je do greÅ¡ke pri unosu vaÅ¡eg kanala.</string> + <string name="blogs_rss_feeds_manage">Rukujte RSS kanalima</string> + <string name="blogs_rss_feeds_manage_imported">Uvezeno:</string> + <string name="blogs_rss_feeds_manage_author">Autor:</string> + <string name="blogs_rss_feeds_manage_updated">Zadnje ažuriranje:</string> + <string name="blogs_rss_remove_feed">Uklonite kanal</string> + <string name="blogs_rss_remove_feed_ok">Ukloni</string> + <string name="blogs_rss_feeds_manage_delete_error">Kanal nije bilo moguće ukloniti!</string> + <string name="blogs_rss_feeds_manage_error">DoÅ¡lo je do problema pri uÄitavanju vaÅ¡ih kanala. Probajte opet kasnije.</string> + <!--Settings Display--> + <string name="pref_theme_title">Тема</string> + <string name="pref_theme_light">Светла</string> + <string name="pref_theme_dark">Тамна</string> + <!--Settings Network--> + <string name="network_settings_title">Mreže</string> + <string name="bluetooth_setting">Povežite se preko Bluetooth-a</string> + <string name="bluetooth_setting_enabled">Kad god su kontakti blizu</string> + <string name="bluetooth_setting_disabled">Samo pri dodavanju kontakata</string> + <string name="tor_network_setting">Povežite se preko Tor-a</string> + <string name="tor_network_setting_never">Nikad</string> + <string name="tor_network_setting_wifi">Samo kad koristim Wi-Fi</string> + <string name="tor_network_setting_always">Kad koristim Wi-Fi ili mobile data</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Sigurnost</string> + <string name="change_password">Promijeni sifru</string> + <string name="password_changed">Å ifra je promijenjena</string> + <string name="panic_setting">PodeÅ¡avanje panik dugmeta</string> + <string name="panic_setting_title">Panik dugme</string> + <string name="panic_setting_hint">Podesite kako Briar reaguje kad koristite panik dugme app</string> + <string name="panic_app_setting_title">Panik Dugne App</string> + <string name="unknown_app">nepoznata aplikacija</string> + <string name="panic_app_setting_summary">Nema postavljene aplikacije</string> + <string name="panic_app_setting_none">NiÅ¡ta</string> + <string name="dialog_title_connect_panic_app">Potvrdi Panic App</string> + <string name="dialog_message_connect_panic_app">Jeste li sigurni da želite da dozvolite %1$s da pokrene destruktivne akcije panik dugmeta?</string> + <string name="panic_setting_signout_title">Izlogujte se</string> + <string name="panic_setting_signout_summary">Izloguj se iz Briar-a ako je pritisnuto panik dugme</string> + <string name="purge_setting_title">IzbriÅ¡i raÄun</string> + <string name="purge_setting_summary">IzbriÅ¡i Briar raÄun ako je panik dugme pritisnuto. Pažnja: Ovo će permanentno izbrisati vaÅ¡e identitete, kontakte i poruke</string> + <string name="uninstall_setting_title">Deinstaliraj Briar</string> + <string name="uninstall_setting_summary">Ovo zahtijeva ruÄnu potvrdu u sluÄaju panike</string> + <!--Settings Notifications--> + <string name="notification_settings_title">ObavjeÅ¡tenja</string> + <string name="notify_private_messages_setting_title">Privatne poruke</string> + <string name="notify_private_messages_setting_summary">Prikaži upozorenja na privatne poruke</string> + <string name="notify_group_messages_setting_title">Grupne poruke</string> + <string name="notify_group_messages_setting_summary">Prikaži upozorenja za grupne poruke</string> + <string name="notify_forum_posts_setting_title">Forum postovi</string> + <string name="notify_forum_posts_setting_summary">Prikaži upozorenja za forum postove</string> + <string name="notify_blog_posts_setting_title">Blog postovi</string> + <string name="notify_blog_posts_setting_summary">Prikaži upozorenja na blog postove</string> + <string name="notify_vibration_setting">Vibriranje</string> + <string name="notify_lock_screen_setting_title">ZakljuÄaj ekran</string> + <string name="notify_lock_screen_setting_summary">Prikaži obavjeÅ¡tenja na zakljuÄanom ekranu</string> + <string name="notify_sound_setting">Zvuk</string> + <string name="notify_sound_setting_default">Podrazumijevanio zvono</string> + <string name="notify_sound_setting_disabled">NiÅ¡ta</string> + <string name="choose_ringtone_title">Izaberi zvuk zvona</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Povratne informacije</string> + <string name="send_feedback">Å alji povratne informacije</string> + <!--Link Warning--> + <string name="link_warning_title">Link upozorenje</string> + <string name="link_warning_intro">Upravo ćete otvoriti slijedeći link sa eksternom aplikacijom</string> + <string name="link_warning_text">Ovo može biti upotrijebljeno da vas identifikuju. Razmislite da li vjerujete osobi koja vam je poslala ovaj link i razmotrite da ga možda otvorite u Orfox-u.</string> + <string name="link_warning_open_link">Otvori link</string> + <!--Crash Reporter--> + <string name="crash_report_title">Briar izvjeÅ¡taj po krahu</string> + <string name="briar_crashed">Izvinite, Briar je krahirao.</string> + <string name="not_your_fault">Nijeste vi krivi.</string> + <string name="please_send_report">Molimo pomozite nam da napravimo bolji Briar tako Å¡to ćete nam poslati izvjeÅ¡taj o krahu.</string> + <string name="report_is_encrypted">Obećavamo da je izvjeÅ¡taj kriptovan i sigurno poslat.</string> + <string name="feedback_title">Povratna informacija</string> + <string name="describe_crash">OpiÅ¡ite Å¡ta se desilo (opciono)</string> + <string name="enter_feedback">Unesite vaÅ¡u povratnu informaciju</string> + <string name="optional_contact_email">VaÅ¡a email adres (opciono)</string> + <string name="include_debug_report_crash">UkljuÄite anonimne podatke o krahu</string> + <string name="include_debug_report_feedback">UkljuÄite anonimne podatke o ovom ureÄ‘aju</string> + <string name="could_not_load_report_data">Nije bilo moguće uÄitati podatke izvjeÅ¡taja</string> + <string name="send_report">PoÅ¡alji izvjeÅ¡taj</string> + <string name="close">Zatvori</string> + <string name="dev_report_saved">IzvjeÅ¡taj saÄuvan. Biće poslat slijedeći put kada se ulogujete u Briar.</string> + <!--Sign Out--> + <string name="progress_title_logout">IskljuÄujete se iz Briara...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Detektovano je prekrivanje ekrana</string> + <!--Permission Requests--> +</resources> diff --git a/mailbox-android/src/main/res/values-sv/strings.xml b/mailbox-android/src/main/res/values-sv/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..49ef2ba629c2919aab75d4c02caa57c3099b224a --- /dev/null +++ b/mailbox-android/src/main/res/values-sv/strings.xml @@ -0,0 +1,158 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">Välkommen till Briar</string> + <string name="setup_name_explanation">Ditt användarnamn kommer att visas bredvid allt innehÃ¥ll som du lägger upp. Du kan inte ändra ditt användarnamn efter att ditt konto skapats.</string> + <string name="setup_next">Nästa</string> + <string name="setup_password_intro">Skapa lösenord</string> + <string name="setup_password_explanation">Ditt Briar-konto lagras krypterat pÃ¥ din mobil eller läsplatta, inte hos en molntjänst. Om du glömmer ditt lösenord eller avinstallerar Briar är det därför inte möjligt att Ã¥terställa ditt konto.\n\nSkapa ett lÃ¥ngt lösenord som är svÃ¥rgissat, till exempel fyra slumpvalda ord eller en kombination av tio slumpvalda bokstäver, siffror och andra tecken.</string> + <string name="setup_doze_title">Dataanslutningar i bakgrunden</string> + <string name="setup_doze_intro">För att kunna ta emot meddelanden mÃ¥ste Briar vara anslutet i bakgrunden.</string> + <string name="setup_doze_explanation">För att kunna ta emot meddelanden mÃ¥ste Briar vara anslutet i bakgrunden. Avaktivera batterioptimering sÃ¥ att Briar kan hÃ¥lla sig anslutet.</string> + <string name="setup_doze_button">TillÃ¥t dataanslutningar</string> + <string name="choose_nickname">Skapa användarnamn </string> + <string name="choose_password">Skapa lösenord</string> + <string name="confirm_password">Bekräfta lösenordet</string> + <string name="name_too_long">Namnet har för mÃ¥nga tecken </string> + <string name="password_too_weak">Lösenordet är för svagt</string> + <string name="passwords_do_not_match">Lösenorden överensstämmer inte </string> + <string name="create_account_button">Skapa konto </string> + <string name="more_info">Mer information</string> + <string name="don_t_ask_again">FrÃ¥ga inte igen</string> + <string name="setup_huawei_text">Tryck pÃ¥ knappen längre ner för att lägga till Briar till listan över \"skyddade appar\".</string> + <string name="setup_huawei_button">Skydda Briar</string> + <string name="setup_huawei_help">Om Briar inte läggs till listan över skyddade appar kan det inte köras i bakgrunden.</string> + <string name="warning_dozed">%s kunde inte köras i bakgrunden</string> + <!--Login--> + <string name="enter_password">Lösenord</string> + <string name="try_again">Felaktigt lösenord, försök igen </string> + <string name="sign_in_button">Logga in</string> + <string name="forgotten_password">Jag har glömt mitt lösenord </string> + <string name="dialog_title_lost_password">Glömt lösenord?</string> + <string name="dialog_message_lost_password">Eftersom ditt Briar-konto lagras krypterat pÃ¥ din mobil eller läsplatta och inte hos en molntjänst kan vi inte Ã¥terställa ditt lösenord. Vill du radera ditt konto och skapa ett nytt?\n\nCaution: Du kommer att förlora din profil, dina kontakter och dina meddelanden.</string> + <string name="startup_failed_notification_title">Briar kunde inte startas </string> + <string name="startup_failed_service_error">Briar kunde inte starta ett nödvändigt insticksprogram. Att Ã¥terinstallera Briar brukar lösa problemet, men eftersom dina data inte lagras pÃ¥ en central server innebär detta att du kommer att förlora ditt konto och alla dess tillhörande data.</string> + <string name="expiry_date_reached">Mjukvaran har gÃ¥tt ut.\nTack för att du bidragit till att testa!</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Öppna navigeringsfacket</string> + <string name="nav_drawer_close_description">Stäng navigeringsfacket</string> + <string name="contact_list_button">Kontakter</string> + <string name="groups_button">Privatgrupper</string> + <string name="forums_button">Forum</string> + <string name="blogs_button">Bloggar</string> + <string name="settings_button">Inställningar</string> + <string name="sign_out_button">Logga ut</string> + <!--Transports--> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">wifi</string> + <!--Notifications--> + <string name="ongoing_notification_title">Inloggad pÃ¥ Briar</string> + <string name="ongoing_notification_text">Tryck för att öppna Briar</string> + <!--Misc--> + <string name="now">nu</string> + <string name="show">Visa</string> + <string name="hide">Göm</string> + <string name="ok">OK</string> + <string name="cancel">Avbryt</string> + <string name="got_it">FörstÃ¥tt</string> + <string name="delete">Radera</string> + <string name="accept">Acceptera</string> + <string name="decline">Neka</string> + <string name="options">Alternativ</string> + <string name="online">Uppkopplad</string> + <string name="offline">Nedkopplad</string> + <string name="send">Skicka</string> + <string name="allow">TillÃ¥t</string> + <string name="open">Öppen</string> + <string name="text_too_long">Texten innehÃ¥ller för mÃ¥nga tecken</string> + <string name="show_onboarding">Visa hjälprutan</string> + <string name="fix">Laga</string> + <string name="help">Hjälp</string> + <!--Contacts and Private Conversations--> + <string name="date_no_private_messages">Inga meddelanden</string> + <string name="message_hint">Skriv ett meddelande</string> + <string name="delete_contact">Radera kontakt</string> + <string name="dialog_title_delete_contact">Bekräfta radering av kontakt</string> + <string name="dialog_message_delete_contact">Är du säker att du vill radera denna kontakt och alla meddelanden?</string> + <string name="contact_deleted_toast">Kontakt raderad</string> + <!--Adding Contacts--> + <string name="add_contact_title">Lägg till en kontakt</string> + <string name="continue_button">Fortsätt</string> + <string name="connection_failed">Anslutning misslyckats</string> + <string name="try_again_button">Försök igen</string> + <!--Introductions--> + <string name="introduction_onboarding_text">Du kan presentera dina kontakter för varandra, pÃ¥ sÃ¥ sätt behöver de inte ses i verkligheten för att kunna lägga till varandra pÃ¥ Briar.</string> + <string name="introduction_activity_title">Välj kontakt</string> + <!--Private Groups--> + <string name="groups_group_is_empty">Denna grupp har inga medlemmar</string> + <string name="groups_group_is_dissolved">Denna grupp har raderats</string> + <string name="groups_remove">Ta bort</string> + <string name="groups_create_group_title">Skapa privatgrupp</string> + <string name="groups_create_group_button">Skapa grupp</string> + <string name="groups_create_group_invitation_button">Skicka inbjudan</string> + <string name="groups_create_group_hint">Skapa ett namn för din privatgrupp</string> + <string name="groups_invitation_sent">Gruppinbjudan har skickats</string> + <string name="groups_message_sent">Meddelandet har skickats</string> + <string name="groups_member_list">Medlemmar</string> + <string name="groups_invite_members">Bjuda in medlem</string> + <string name="groups_member_created_you">Du har skapat en grupp</string> + <string name="groups_member_joined_you">Du har gÃ¥tt med i en grupp</string> + <string name="groups_leave">Lämna grupp</string> + <!--Private Group Invitations--> + <!--Private Groups Revealing Contacts--> + <!--Forums--> + <string name="btn_reply">Svara</string> + <string name="dialog_button_leave">Tillbaka</string> + <!--Forum Sharing--> + <!--Blogs--> + <string name="blogs_remove_blog_ok">&Ta bort</string> + <!--Blog Sharing--> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import_button">Importera</string> + <string name="blogs_rss_feeds_manage_author">Författare:</string> + <string name="blogs_rss_feeds_manage_updated">Senast uppdaterad:</string> + <string name="blogs_rss_remove_feed_ok">&Ta bort</string> + <!--Settings Display--> + <string name="display_settings_title">Visa</string> + <string name="pref_theme_title">Tema</string> + <string name="pref_theme_light">Ljus</string> + <string name="pref_theme_dark">Mörk</string> + <!--Settings Network--> + <string name="network_settings_title">Nätverk</string> + <string name="bluetooth_setting">Anslut via Bluetooth</string> + <string name="tor_network_setting">Anslut via Tor</string> + <string name="tor_network_setting_never">Aldrig</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Säkerhet</string> + <string name="change_password">Ändra lösenord</string> + <string name="choose_new_password">Nytt lösenord</string> + <string name="confirm_new_password">Bekräfta nytt lösenord</string> + <string name="panic_app_setting_none">Ingen</string> + <string name="panic_setting_signout_title">Logga ut</string> + <string name="panic_setting_signout_summary">Logga ut frÃ¥n Briar om panikknappen tryckts</string> + <string name="purge_setting_title">Radera kontot</string> + <string name="uninstall_setting_title">Avinstallera Briar</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Aviseringar</string> + <string name="notify_private_messages_setting_title">Privata meddelanden</string> + <string name="notify_lock_screen_setting_title">LÃ¥s skärmen</string> + <string name="notify_lock_screen_setting_summary">Visa meddelanden pÃ¥ lÃ¥sskärmen</string> + <string name="notify_sound_setting">Ljud</string> + <string name="notify_sound_setting_disabled">Ingen</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Feedback</string> + <!--Link Warning--> + <string name="link_warning_open_link">Öppna länk</string> + <!--Crash Reporter--> + <string name="crash_report_title">Briar-felrapport</string> + <string name="not_your_fault">Detta är inte ditt fel.</string> + <string name="please_send_report">Hjälp oss att förbättra Briar genom att skicka en felrapport.</string> + <string name="report_is_encrypted">Vi lovar att felrapporten är krypterad och skickas säkert.</string> + <string name="feedback_title">Feedback</string> + <string name="describe_crash">Beskriv vad som hänt (valfritt)</string> + <string name="close">Stäng</string> + <!--Sign Out--> + <!--Screen Filters & Tapjacking--> + <!--Permission Requests--> +</resources> diff --git a/mailbox-android/src/main/res/values-tr/strings.xml b/mailbox-android/src/main/res/values-tr/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..295fd1d5da2d8ca806ceeddd260bd530b8610110 --- /dev/null +++ b/mailbox-android/src/main/res/values-tr/strings.xml @@ -0,0 +1,314 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_next">Sonraki</string> + <string name="choose_nickname">Kullanıcı adınızı belirleyin</string> + <string name="choose_password">Parolanızı belirleyin</string> + <string name="confirm_password">Parolanızı doÄŸrulayın</string> + <string name="name_too_long">İsim çok uzun</string> + <string name="password_too_weak">Parola çok zayıf</string> + <string name="passwords_do_not_match">GirdiÄŸiniz iki parola uyuÅŸmuyor</string> + <string name="create_account_button">Hesabı OluÅŸtur</string> + <!--Login--> + <string name="enter_password">Parola</string> + <string name="try_again">Parola yanlış, tekrar deneyin</string> + <string name="sign_in_button">GiriÅŸ Yap</string> + <string name="forgotten_password">Parolamı unuttum</string> + <string name="dialog_title_lost_password">Kayıp Parola</string> + <string name="dialog_message_lost_password">Briar hesabınız, bulutta deÄŸil ÅŸifreli olarak cihazınızda saklanır, bu nedenle ÅŸifrenizi sıfırlayamıyoruz. Hesabınızı silmek ve tekrar baÅŸlamak ister misiniz? \n\nUyarı: Kimlikleriniz, kiÅŸileriniz ve iletileriniz kaybolur.</string> + <string name="startup_failed_notification_title">Briar baÅŸlayamadı</string> + <string name="startup_failed_activity_title">Briar BaÅŸlangıç Hatası</string> + <string name="startup_failed_service_error">Briar gerekli bir eklentiyi baÅŸlatamadı. Briar\'ı yeniden yüklemek genellikle bu sorunu çözer. Bununla birlikte, lütfen Briar\'ın verilerinizi depolamak için merkezi sunucuları kullanmadığından hesabınızı ve onunla iliÅŸkili tüm verileri kaybedeceÄŸinizi unutmayın.</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">Gezinme çekmecesini aç</string> + <string name="nav_drawer_close_description">Gezinme çekmecesini kapat</string> + <string name="contact_list_button">KiÅŸiler</string> + <string name="groups_button">Özel Gruplar</string> + <string name="forums_button">Forumlar</string> + <string name="blogs_button">Bloglar</string> + <string name="settings_button">Ayarlar</string> + <string name="sign_out_button">Oturumu Kapat</string> + <!--Transports--> + <string name="transport_tor">İnternet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + <!--Notifications--> + <string name="ongoing_notification_title">Briar\'a giriÅŸ yapıldı</string> + <string name="ongoing_notification_text">Briar\'ı açmak için dokunun</string> + <plurals name="private_message_notification_text"> + <item quantity="one">Yeni özel mesaj.</item> + <item quantity="other">%d yeni özel mesaj.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">Yeni grup mesajı.</item> + <item quantity="other">%d yeni grup mesajı.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">Yeni forum iletisi.</item> + <item quantity="other">%d yeni forum iletisi.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">Yeni blog iletisi.</item> + <item quantity="other">%d yeni blog iletisi.</item> + </plurals> + <!--Misc--> + <string name="now">ÅŸimdi</string> + <string name="show">Göster</string> + <string name="hide">Gizle</string> + <string name="ok">Tamam</string> + <string name="cancel">İptal</string> + <string name="got_it">Anladım</string> + <string name="delete">Sil</string> + <string name="accept">Onayla</string> + <string name="decline">Reddet</string> + <string name="options">Seçenekler</string> + <string name="online">Çevrimiçi</string> + <string name="offline">Çevrimdışı</string> + <string name="send">Gönder</string> + <string name="allow">İzin ver</string> + <string name="open">Aç</string> + <string name="no_data">Bilgi yok</string> + <string name="ellipsis">…</string> + <string name="text_too_long">Girilen metin çok uzun</string> + <string name="show_onboarding">Yardım Penceresini Göster</string> + <string name="help">Yardım</string> + <!--Contacts and Private Conversations--> + <string name="date_no_private_messages">Hiç mesaj yok.</string> + <string name="message_hint">Mesaj yazın</string> + <string name="delete_contact">KiÅŸiyi sil</string> + <string name="dialog_title_delete_contact">KiÅŸi Silmeyi Onayla</string> + <string name="dialog_message_delete_contact">Bu kiÅŸiyi ve bu kiÅŸiyle ilgili tüm iletileri kaldırmak istediÄŸinize emin misiniz?</string> + <string name="contact_deleted_toast">KiÅŸi silindi</string> + <!--Adding Contacts--> + <string name="add_contact_title">KiÅŸi ekle</string> + <string name="face_to_face">KiÅŸi olarak eklemek istediÄŸiniz kiÅŸiyle buluÅŸmanız gerekir.\n\nBu, gelecekte baÅŸkalarının sizin kimliÄŸinize bürünmesini veya mesajlarınızı okumasını engelleyecektir.</string> + <string name="continue_button">Devam et</string> + <string name="connection_failed">BaÄŸlantı hatası</string> + <string name="try_again_button">Tekrar deneyin</string> + <string name="waiting_for_contact_to_scan">KiÅŸinin QR kodu taraması ve baÄŸlantı kurması bekleniyor\u2026</string> + <string name="exchanging_contact_details">KiÅŸi ayrıntıları karşılıklı paylaşılıyor\u2026</string> + <string name="contact_added_toast">KiÅŸi eklendi: %s</string> + <string name="contact_already_exists"> %s kiÅŸisi zaten var</string> + <string name="contact_exchange_failed">KiÅŸi deÄŸiÅŸimi hatası</string> + <string name="qr_code_invalid">QR kod hatalı</string> + <string name="connecting_to_device">Cihaza baÄŸlanıyor\u2026</string> + <string name="authenticating_with_device">Cihazla kimlik doÄŸrulama\u2026</string> + <string name="connection_aborted_remote">BaÄŸlantı kiÅŸi tarafından kesildi! Bu, birisinin baÄŸlantınızı kesmeye çalıştığı anlamına gelebilir</string> + <!--Introductions--> + <string name="introduction_onboarding_title">KiÅŸilerinizi tanıştırın</string> + <string name="introduction_onboarding_text">KiÅŸilerinizi birbirinize tanıtabilirsiniz, bu nedenle Briar\'a baÄŸlanmak için ÅŸahsen bir araya gelmeniz gerekmez.</string> + <string name="introduction_menu_item">Tanıştır</string> + <string name="introduction_activity_title">KiÅŸi seç</string> + <string name="introduction_message_title">KiÅŸileri Tanıştırın</string> + <string name="introduction_button">Tanıştır</string> + <string name="introduction_sent">Tanıştırma isteÄŸiniz gönderildi.</string> + <string name="introduction_error">Tanıştırma isteÄŸi yaparken bir hata oluÅŸtu.</string> + <string name="introduction_response_error">Tanışma isteÄŸine yanıt verirken hata oluÅŸtu</string> + <string name="introduction_request_sent">%1$s ile %2$s kiÅŸilerini tanıştırmak istediniz.</string> + <string name="introduction_request_received"> %1$s sizi %2$s ile tanıştırmak istedi. KiÅŸi listesine %2$s kiÅŸisini eklemek ister misiniz?</string> + <string name="introduction_request_exists_received">%1$s sizi %2$s ile tanıştırmak istiyor, ancak %2$s zaten kiÅŸi listenizde ekli. %1$s, bunu bilmediÄŸinden, siz yine de yanıt verebilirsiniz:</string> + <string name="introduction_request_answered_received">%1$s sizi %2$s ile tanıştırmak istedi.</string> + <string name="introduction_response_accepted_sent">%1$s kiÅŸisinin tanıştırma isteÄŸini kabul ettiniz.</string> + <string name="introduction_response_declined_sent">%1$s kiÅŸisinin tanıştırma isteÄŸini reddettiniz.</string> + <string name="introduction_response_accepted_received">%1$s, %2$s ile tanışmayı kabul etti.</string> + <string name="introduction_response_declined_received">%1$s, %2$s ile tanışmayı reddetti.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s, %2$s kiÅŸisinin tanışmayı reddettiÄŸini söyledi.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">Yeni kiÅŸi eklendi.</item> + <item quantity="other">%d yeni kiÅŸi eklendi.</item> + </plurals> + <!--Private Groups--> + <string name="groups_created_by">%s tarafından oluÅŸturuldu</string> + <plurals name="messages"> + <item quantity="one">%d mesaj</item> + <item quantity="other">%d mesaj</item> + </plurals> + <string name="groups_group_is_empty">Bu grup boÅŸ</string> + <string name="groups_group_is_dissolved">Bu grup dağıldı</string> + <string name="groups_remove">Sil</string> + <string name="groups_create_group_title">Özel Grup OluÅŸtur</string> + <string name="groups_create_group_button">Grup OluÅŸtur</string> + <string name="groups_create_group_invitation_button">Davetiye Gönder</string> + <string name="groups_invitation_sent">Grup davetiyesi gönderildi</string> + <string name="groups_message_sent">Mesaj gönderildi</string> + <string name="groups_member_list">Üye Listesi</string> + <string name="groups_invite_members">Üyeleri Davet Edin</string> + <string name="groups_member_created_you">Grubu siz oluÅŸturdunuz</string> + <string name="groups_member_created">Grubu %s oluÅŸturdu</string> + <string name="groups_member_joined_you">Gruba katıldınız</string> + <string name="groups_member_joined">%s gruba katıldı</string> + <string name="groups_leave">Gruptan Ayrıl</string> + <string name="groups_leave_dialog_title">Gruptan Ayrılmayı Onayla</string> + <string name="groups_leave_dialog_message">Bu gruptan ayrılmak istediÄŸinizden emin misiniz?</string> + <string name="groups_dissolve">Grubu Dağıt</string> + <string name="groups_dissolve_dialog_title">Grubu Dağıtmayı Onayla</string> + <string name="groups_dissolve_dialog_message">Bu grubu dağıtmak istediÄŸinizden emin misiniz?\n\nDiÄŸer tüm üyeler sohbetlerine devam edemeyecek ve en yeni mesajları alamayacak.</string> + <string name="groups_dissolve_button">Dağıt</string> + <string name="groups_dissolved_dialog_title">Grup Dağıtıldı</string> + <string name="groups_dissolved_dialog_message">Bu grubun kurucusu, grubu dağıttı.\n\nArtık gruba mesaj yazamazsınız ve yazılmış olan mesajları alamayabilirsiniz.</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">Grup Davetleri</string> + <string name="groups_invitations_invitation_sent">%1$s kiÅŸisini \"%2$s\" grubuna davet ettiniz.</string> + <string name="groups_invitations_invitation_received">%1$s sizi \"%2$s\" grubuna davet etti.</string> + <string name="groups_invitations_joined">Gruba katıldı</string> + <string name="groups_invitations_declined">Grup davetiyesi reddedildi</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d açık grup davetiyesi</item> + <item quantity="other">%d açık grup davetiyesi</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">%s kiÅŸisinden gelen grup davetini kabul ettiniz.</string> + <string name="groups_invitations_response_declined_sent">%s kiÅŸisinden gelen grup davetini reddettiniz.</string> + <string name="groups_invitations_response_accepted_received">%s grup davetini kabul etti.</string> + <string name="groups_invitations_response_declined_received">%s grup davetini reddetti.</string> + <string name="sharing_status_groups">Sadece grubu oluÅŸturan kiÅŸi gruba yeni üyeler davet edebilir. AÅŸağıda, grubun ÅŸimdiki üyeleri bulunmaktadır.</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">KiÅŸileri Göster</string> + <string name="groups_reveal_dialog_message">KiÅŸileri bu grubun ÅŸimdiki ve gelecekteki üyelerinin tümüne gösterip göstermeyeceÄŸinizi seçebilirsiniz.\n\nKiÅŸileri görünür yapmak , grupla olan baÄŸlantınızı daha hızlı ve güvenilir hale getirir, çünkü grubun oluÅŸturucusu çevrimdışı olduÄŸunda bile görünen kiÅŸilerle iletiÅŸim kurabilirsiniz.</string> + <string name="groups_reveal_visible">KiÅŸi iliÅŸkisi grup tarafından görülebilir</string> + <string name="groups_reveal_visible_revealed_by_us">KiÅŸi iliÅŸkisi grup tarafından görülebilir (siz bildirdiniz)</string> + <string name="groups_reveal_visible_revealed_by_contact">KiÅŸi iliÅŸkileri grup tarafından görülebilir (%s görünür yaptı)</string> + <string name="groups_reveal_invisible">KiÅŸi iliÅŸkisi grup tarafından görülemez</string> + <!--Forums--> + <string name="create_forum_title">Forumu OuÅŸtur</string> + <string name="create_forum_button">Forumu OuÅŸtur</string> + <string name="forum_created_toast">Forum OluÅŸturuldu</string> + <string name="no_posts">Gönderi yok</string> + <plurals name="posts"> + <item quantity="one">%d gönderi</item> + <item quantity="other">%d gönderi</item> + </plurals> + <string name="forum_message_reply_hint">Yeni Cevap</string> + <string name="btn_reply">Cevapla</string> + <string name="forum_leave">Forumdan Ayrıl</string> + <string name="dialog_title_leave_forum">Forumdan Ayrılmayı Onayla</string> + <string name="dialog_button_leave">Ayrıl</string> + <!--Forum Sharing--> + <string name="forum_share_button">Forumu PaylaÅŸ</string> + <string name="contacts_selected">KiÅŸiler Seçildi</string> + <string name="activity_share_toolbar_header">KiÅŸi Seç</string> + <string name="forum_shared_snackbar">Forum, seçilen kiÅŸiler ile paylaşıldı</string> + <string name="forum_share_error">Forumu paylaşırken bir hata meydana geldi.</string> + <string name="forum_invitation_received">%1$s sizinle \"%2$s\" forumunu paylaÅŸtı.</string> + <string name="forum_invitation_sent">\"%1$s\" forumunu %2$s ile paylaÅŸtınız.</string> + <string name="forum_invitations_title">Forum Davetleri</string> + <string name="shared_by_format">%s tarafından paylaşıldı</string> + <string name="forum_invitation_already_sharing">Zaten paylaşılıyor</string> + <string name="forum_invitation_response_accepted_sent">%s tarafından yapılan forum davetini kabul ettiniz.</string> + <string name="forum_invitation_response_declined_sent">%s tarafından yapılan forum davetini reddettiniz.</string> + <string name="forum_invitation_response_accepted_received">%s forum davetini kabul etti.</string> + <string name="forum_invitation_response_declined_received">%s forum davetini reddetti.</string> + <string name="sharing_status">Paylaşım Durumu</string> + <string name="sharing_status_forum">Bir forumun herhangi bir üyesi o forumu arkadaÅŸlarıyla paylaÅŸabilir. Bu forumu aÅŸağıdaki kiÅŸilerle paylaşıyorsunuz. GöremediÄŸiniz diÄŸer üyeler de olabilir</string> + <string name="shared_with">%1$d ile paylaşıldı (%2$d çevrimiçi)</string> + <plurals name="forums_shared"> + <item quantity="one">%d kiÅŸiler tarafından paylaşılan forum</item> + <item quantity="other">%d kiÅŸiler tarafından paylaşılan forum.</item> + </plurals> + <string name="nobody">Hiç kimse</string> + <!--Blogs--> + <string name="read_more">daha fazlasını oku</string> + <string name="blogs_write_blog_post">Blog Gönderisi Yaz</string> + <string name="blogs_publish_blog_post">Yayınla</string> + <string name="blogs_blog_post_created">Blog Gönderisi OluÅŸturuldu</string> + <string name="blogs_blog_post_received">Yeni Blog Gönderisi Alındı</string> + <string name="blogs_blog_post_scroll_to">Kaydırma</string> + <string name="blogs_remove_blog">Blog\'u sil</string> + <string name="blogs_remove_blog_ok">TuÅŸu Sil</string> + <string name="blogs_reblog_button">Tekrar Blogla</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">Blog\'u PaylaÅŸ</string> + <string name="blogs_sharing_error">Blog\'u paylaşırken bir hata meydana geldi.</string> + <string name="blogs_sharing_button">Blog\'u PaylaÅŸ</string> + <string name="blogs_sharing_snackbar">Blog seçilen kiÅŸilerle paylaşıldı</string> + <string name="blogs_sharing_response_accepted_sent">%s kiÅŸisinden gelen blog davetini kabul ettiniz.</string> + <string name="blogs_sharing_response_declined_sent">%s kiÅŸisinden gelen blog davetini reddettiniz.</string> + <string name="blogs_sharing_response_accepted_received">%s blog davetini kabul etti.</string> + <string name="blogs_sharing_response_declined_received">%s blog davetini reddetti.</string> + <string name="blogs_sharing_invitations_title">Blog Davetleri</string> + <string name="sharing_status_blog">Bir blog\'a abone olan herkes, blog\'u kiÅŸileriyle paylaÅŸabilir. Bu blog\'u ÅŸu kiÅŸilerle paylaşıyorsunuz. GöremediÄŸiniz diÄŸer aboneler de olabilir.</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">RSS kaynaklarını içeri aktar</string> + <string name="blogs_rss_feeds_import_button">İçeri Aktar</string> + <string name="blogs_rss_feeds_import_hint">URL ya da RSS kaynağı girin</string> + <string name="blogs_rss_feeds_import_error">Üzgünüz! RSS beslemenizi içe aktarırken bir hata oluÅŸtu.</string> + <string name="blogs_rss_feeds_manage">RSS\'leri Yönet</string> + <string name="blogs_rss_feeds_manage_imported">İçeri Aktarıldı:</string> + <string name="blogs_rss_feeds_manage_author">Yazar:</string> + <string name="blogs_rss_feeds_manage_updated">Son Güncelleme:</string> + <string name="blogs_rss_remove_feed">Kaynağı Sil</string> + <string name="blogs_rss_remove_feed_ok">TuÅŸu Sil</string> + <string name="blogs_rss_feeds_manage_delete_error">Besleme silinemedi!</string> + <string name="blogs_rss_feeds_manage_error">Beslemeleriniz yüklenirken bir hata meydana geldi. Lütfen daha sonra tekrar deneyin.</string> + <!--Settings Display--> + <string name="display_settings_title">Görüntüle</string> + <!--Settings Network--> + <string name="network_settings_title">AÄŸlar</string> + <string name="bluetooth_setting">Bluetooth ile BaÄŸlan</string> + <string name="bluetooth_setting_enabled">Yakınlardaki her kiÅŸi</string> + <string name="bluetooth_setting_disabled">Yalnızca kiÅŸi eklerken</string> + <string name="tor_network_setting">Tor ile BaÄŸlan</string> + <string name="tor_network_setting_never">Asla</string> + <string name="tor_network_setting_wifi">Yanlızca Wi-Fi kullanırken</string> + <string name="tor_network_setting_always">Mobil veri veya Wi-Fi kullanırken</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">Güvenlik</string> + <string name="change_password">Parola deÄŸiÅŸtir</string> + <string name="confirm_new_password">Yeni parolayı onaylayın</string> + <string name="password_changed">Parolanız baÅŸarıyla deÄŸiÅŸti.</string> + <string name="panic_setting">Panik buton ayarları</string> + <string name="panic_setting_title">Panik butonu</string> + <string name="panic_setting_hint">Panik düğmesi uygulaması kullandığınızda Briar\'ın nasıl tepki vereceÄŸini yapılandırma</string> + <string name="panic_app_setting_title">Panik Butonu Uygulaması</string> + <string name="unknown_app">bilinmeyen bir uygulama</string> + <string name="panic_app_setting_summary">KurulmuÅŸ bir uygulama yok</string> + <string name="panic_app_setting_none">Yok</string> + <string name="dialog_title_connect_panic_app">Panik Uygulaması DoÄŸrulama</string> + <string name="dialog_message_connect_panic_app">%1$s kiÅŸisinin yıkıcı panik düğmesi eylemlerini tetiklemesine izin vermek istediÄŸinizden emin misiniz?</string> + <string name="panic_setting_signout_title">Çıkış Yap</string> + <string name="panic_setting_signout_summary">Panik Butonuna basıldığında Briar\'dan çıkış yap</string> + <string name="purge_setting_title">Hesabı Sil</string> + <string name="purge_setting_summary">Bir panik düğmesine basıldığında Briar hesabınızı silin. Dikkat: Bu, kimliklerinizi, kayıtlarınızı ve iletilerinizi kalıcı olarak silecektir.</string> + <string name="uninstall_setting_title">Briar\'ı Kaldır</string> + <string name="uninstall_setting_summary">Bu, bir panik olayında manuel onay gerektirir</string> + <!--Settings Notifications--> + <string name="notification_settings_title">Bildirimler</string> + <string name="notify_private_messages_setting_title">Özel Mesajlar</string> + <string name="notify_private_messages_setting_summary">Özel mesajlar için uyarıları göster</string> + <string name="notify_group_messages_setting_summary">Grup mesajları için uyarıları göster</string> + <string name="notify_forum_posts_setting_summary">Forum gönderileri için uyarıları göster</string> + <string name="notify_blog_posts_setting_summary">Blog gönderileri için uyarıları göster</string> + <string name="notify_vibration_setting">TitretiÅŸim</string> + <string name="notify_lock_screen_setting_title">Ekranı Kilitle</string> + <string name="notify_sound_setting">Ses</string> + <string name="notify_sound_setting_default">Varsayılan zil sesi</string> + <string name="notify_sound_setting_disabled">Yok</string> + <string name="choose_ringtone_title">Zil sesi seçin</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">Geri bildirim</string> + <string name="send_feedback">Geri bildirim gönder</string> + <!--Link Warning--> + <string name="link_warning_title">Uyarı BaÄŸlantısı</string> + <string name="link_warning_intro">AÅŸağıdaki baÄŸlantıyı harici bir uygulamayla açmak üzeresiniz.</string> + <string name="link_warning_text">Bu kimliÄŸinizi ele geçirmek için kullanılabilir. Bu baÄŸlantıyı gönderen kiÅŸiye güvenip güvenmediÄŸinize karar verin ve Orfox ile açmayı deneyin.</string> + <string name="link_warning_open_link">BaÄŸlantı Aç</string> + <!--Crash Reporter--> + <string name="crash_report_title">Briar Çökme Raporu</string> + <string name="briar_crashed">Üzgünüz, Briar çöktü.</string> + <string name="not_your_fault">Bu senin hatan deÄŸil.</string> + <string name="please_send_report">Bize bir çökme raporu göndererek Briar\'ı daha iyi bir hale getirmemize yardımcı olun.</string> + <string name="report_is_encrypted">Raporun ÅŸifrelendiÄŸine ve güvenli bir ÅŸekilde gönderildiÄŸine söz veriyoruz.</string> + <string name="feedback_title">Geri bildirim</string> + <string name="describe_crash">Ne olduÄŸunu bize anlatın (isteÄŸe baÄŸlı)</string> + <string name="enter_feedback">Geri bildiriminizi girin</string> + <string name="optional_contact_email">E-posta adresiniz (isteÄŸe baÄŸlı)</string> + <string name="include_debug_report_crash">Çökme ile ilgili anonim verileri içerir</string> + <string name="include_debug_report_feedback">Bu cihazla ilgili anonim verileri içerir</string> + <string name="could_not_load_report_data">Rapor verileri yüklenemedi.</string> + <string name="send_report">Raporu gönder</string> + <string name="close">Kapat</string> + <string name="dev_report_saved">Rapor kaydedildi. Briar\'a bir sonraki giriÅŸinizde gönderilecektir.</string> + <!--Sign Out--> + <string name="progress_title_logout">Briar\'dan çıkılıyor...</string> + <!--Screen Filters & Tapjacking--> + <!--Permission Requests--> +</resources> diff --git a/mailbox-android/src/main/res/values-v21/dimens.xml b/mailbox-android/src/main/res/values-v21/dimens.xml new file mode 100644 index 0000000000000000000000000000000000000000..a9b85afbb8306bef9d44358ac9110d0590e76a4a --- /dev/null +++ b/mailbox-android/src/main/res/values-v21/dimens.xml @@ -0,0 +1,5 @@ +<resources> + + <dimen name="message_bubble_stroke">0px</dimen> + +</resources> diff --git a/mailbox-android/src/main/res/values-zh-rCN/strings.xml b/mailbox-android/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..7dfa06f4ab1a6f4f035a22cebf3d1f9a6017edc6 --- /dev/null +++ b/mailbox-android/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,403 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <!--Setup--> + <string name="setup_title">欢迎æ¥åˆ° Briar</string> + <string name="setup_name_explanation">您的昵称将显示在您å‘布的任何内容æ—ã€‚æ˜µç§°åœ¨åˆ›å»ºå¸æˆ·åŽæ— 法更改。</string> + <string name="setup_next">下一æ¥</string> + <string name="setup_password_intro">设置一个密ç </string> + <string name="setup_password_explanation">您的 Briar è´¦å·å°†è¢«åР坆傍å˜åœ¨æ‚¨çš„设备上,而éžäº‘端,å¸è½½ Briar 或忘记密ç ,账å·å°†æ— 法æ¢å¤ã€‚请设置难以猜出的长密ç ï¼Œæ¯”å¦‚å››ä¸ªéšæ„çš„å•è¯ï¼Œæˆ–是åä¸ªéšæœºå—æ¯ã€æ•°å—和符å·ã€‚</string> + <string name="setup_doze_title">åŽå°è¿žæŽ¥</string> + <string name="setup_doze_intro">为了收到消æ¯ï¼ŒBriar 需è¦ä¿æŒåŽå°è¿žæŽ¥ã€‚</string> + <string name="setup_doze_explanation">为了收到消æ¯ï¼ŒBriar 需è¦ä¿æŒåŽå°è¿žæŽ¥ã€‚请ç¦ç”¨ç”µé‡ä¼˜åŒ–选项以使 Briar ä¿æŒè¿žæŽ¥ã€‚</string> + <string name="setup_doze_button">å…许连接</string> + <string name="choose_nickname">设置昵称</string> + <string name="choose_password">设置密ç </string> + <string name="confirm_password">确认密ç </string> + <string name="name_too_long">昵称过长</string> + <string name="password_too_weak">密ç 强度过弱</string> + <string name="passwords_do_not_match">两次键入密ç ä¸ä¸€è‡´</string> + <string name="create_account_button">创建账å·</string> + <string name="more_info">更多信æ¯</string> + <string name="don_t_ask_again">ä¸å†è¯¢é—®</string> + <string name="setup_huawei_text">轻触下方的按钮以ä¿è¯ Briar åŠ å…¥â€œå—ä¿æŠ¤çš„åº”ç”¨â€ã€‚</string> + <string name="setup_huawei_button">ä¿æŠ¤ Briar</string> + <string name="setup_huawei_help">如果没有将 Briar åŠ å…¥å—ä¿æŠ¤åº”ç”¨åˆ—è¡¨ï¼Œå°†æ— æ³•åœ¨åŽå°è¿è¡Œã€‚</string> + <string name="warning_dozed">%s æ— æ³•åœ¨åŽå°è¿è¡Œã€‚</string> + <!--Login--> + <string name="enter_password">密ç </string> + <string name="try_again">密ç 䏿£ç¡®ï¼Œè¯·é‡è¯•</string> + <string name="sign_in_button">登录</string> + <string name="forgotten_password">我忘记了密ç </string> + <string name="dialog_title_lost_password">忘记密ç </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_db_error">ç”±äºŽä¸€äº›åŽŸå› ï¼ŒBriar æ•°æ®åº“å·²æŸåå¹¶ä¸”æ— æ³•ä¿®å¤ã€‚æ‚¨çš„å¸æˆ·ã€æ•°æ®å’Œæ‰€æœ‰è”系人已ç»ä¸¢å¤±ã€‚ä¸å¹¸çš„æ˜¯ï¼Œæ‚¨éœ€è¦é‡æ–°å®‰è£… Briar 或者在æç¤ºè¾“å…¥å¯†ç æ—¶é€‰æ‹©â€œæˆ‘忘记了密ç â€ä»¥é‡æ–°åˆ›å»ºä¸€ä¸ª Briar 叿ˆ·ã€‚</string> + <string name="startup_failed_data_too_old_error">æ‚¨çš„å¸æˆ·ç”±æ—§ç‰ˆæœ¬åº”ç”¨åˆ›å»ºï¼Œæ— æ³•åœ¨æ¤ç‰ˆæœ¬ä¸Šæ‰“开。您需è¦é‡æ–°å®‰è£…旧版本应用或在æç¤ºè¾“å…¥å¯†ç æ—¶é€‰æ‹©â€œæˆ‘忘记了密ç â€ä»¥åˆ›å»ºæ–°å¸æˆ·ã€‚</string> + <string name="startup_failed_data_too_new_error">该应用版本过旧。请å‡çº§è‡³æœ€æ–°ç‰ˆæœ¬å¹¶é‡è¯•。</string> + <string name="startup_failed_service_error">Briar æ— æ³•å¼€å¯ä¸€ä¸ªå¿…è¦æ’ä»¶ã€‚é€šå¸¸æƒ…å†µä¸‹ï¼Œé‡æ–°å®‰è£… Briar å¯ä»¥è§£å†³è¿™ä¸ªé—®é¢˜ã€‚但是由于 Briar å¹¶ä¸é‡‡ç”¨ä¸å¤®æœåС噍æ¥å‚¨å˜æ‚¨çš„æ•°æ®ï¼Œæ‚¨å°†ä¸¢å¤±æ‚¨çš„è´¦å·å’Œä¸Žæ‚¨çš„è´¦å·ç›¸å…³çš„一切数æ®ã€‚</string> + <plurals name="expiry_warning"> + <item quantity="other">这是 Briar çš„ä¸€ä¸ªæµ‹è¯•ç‰ˆæœ¬ã€‚æ‚¨çš„å¸æˆ·å°†åœ¨ %d 天åŽè¿‡æœŸï¼Œä¸”é€¾æœŸåŽæ— 法继ç»ä½¿ç”¨ã€‚</item> + </plurals> + <string name="expiry_update">æµ‹è¯•åˆ°æœŸæ—¶é—´å»¶é•¿ï¼Œæ‚¨çš„å¸æˆ·å°†åœ¨ %d 天åŽè¿‡æœŸã€‚</string> + <string name="expiry_date_reached">本软件已过期。\n感谢您的测试ï¼</string> + <string name="download_briar">如想继ç»ä½¿ç”¨ Briar,请下载 1.0 版。</string> + <string name="create_new_account">ä½ éœ€è¦åˆ›å»ºä¸€ä¸ªæ–°è´¦æˆ·ï¼Œä½†ä¸èƒ½ä½¿ç”¨ç›¸åŒçš„æ˜µç§°ã€‚</string> + <string name="download_briar_button">下载 Briar 1.0</string> + <string name="startup_open_database">æ£åœ¨è§£å¯†æ•°æ®åº“……</string> + <string name="startup_migrate_database">æ£åœ¨å‡çº§æ•°æ®åº“……</string> + <!--Navigation Drawer--> + <string name="nav_drawer_open_description">打开抽屉å¼å¯¼èˆªæ </string> + <string name="nav_drawer_close_description">关闿н屉å¼å¯¼èˆªæ </string> + <string name="contact_list_button">è”系人</string> + <string name="groups_button">ç§æœ‰ç¾¤èŠ</string> + <string name="forums_button">论å›</string> + <string name="blogs_button">åšå®¢</string> + <string name="settings_button">设置</string> + <string name="sign_out_button">登出</string> + <!--Transports--> + <string name="transport_tor">网络</string> + <string name="transport_bt">è“牙</string> + <string name="transport_lan">æ— çº¿å±€åŸŸç½‘</string> + <!--Notifications--> + <string name="reminder_notification_title">退出登录 Briar</string> + <string name="reminder_notification_text">è½»æŒ‰ä»¥é‡æ–°ç™»å½•。</string> + <string name="reminder_notification_channel_title">Briar 登录æé†’</string> + <string name="reminder_notification_dismiss">解散</string> + <string name="ongoing_notification_title">登录 Briar</string> + <string name="ongoing_notification_text">轻触以打开 Briar</string> + <plurals name="private_message_notification_text"> + <item quantity="other">%d æ¡æ–°ç§ä¿¡ã€‚</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="other">%d æ¡æ–°ç¾¤æ¶ˆæ¯ã€‚</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="other">%d æ¡æ–°è®ºå›å¸–å。</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="other">%d æ¡æ–°åšæ–‡ã€‚</item> + </plurals> + <!--Misc--> + <string name="now">现在</string> + <string name="show">显示</string> + <string name="hide">éšè—</string> + <string name="ok">确定</string> + <string name="cancel">å–æ¶ˆ</string> + <string name="got_it">知é“了</string> + <string name="delete">åˆ é™¤</string> + <string name="accept">接å—</string> + <string name="decline">æ‹’ç»</string> + <string name="options">选项</string> + <string name="online">在线</string> + <string name="offline">离线</string> + <string name="send">å‘é€</string> + <string name="allow">å…许</string> + <string name="open">打开</string> + <string name="no_data">没有数æ®</string> + <string name="ellipsis">…</string> + <string name="text_too_long">输入的文本过长</string> + <string name="show_onboarding">显示帮助对è¯</string> + <string name="fix">ä¿®å¤</string> + <string name="help">帮助</string> + <string name="sorry">抱æ‰</string> + <!--Contacts and Private Conversations--> + <string name="no_contacts">没有è”系人\n\n点击 + å·æ·»åŠ </string> + <string name="date_no_private_messages">æ— æ¶ˆæ¯ã€‚</string> + <string name="no_private_messages">没有消æ¯</string> + <string name="message_hint">键入信æ¯</string> + <string name="delete_contact">åˆ é™¤è”系人</string> + <string name="dialog_title_delete_contact">ç¡®è®¤åˆ é™¤è”系人</string> + <string name="dialog_message_delete_contact">确认è¦åˆ 除该è”系人和所有èŠå¤©è®°å½•å—?</string> + <string name="contact_deleted_toast">è”ç³»äººå·²åˆ é™¤</string> + <!--Adding Contacts--> + <string name="add_contact_title">æ·»åŠ è”系人</string> + <string name="face_to_face">æ‚¨å¿…é¡»ä¸Žæ‚¨æƒ³è¦æ·»åŠ çš„è”系人è§é¢ã€‚\n\nè¿™æ ·å¯ä»¥é˜²æ¢æœªæ¥ä»–人冒充您的身份并查看您的信æ¯ã€‚</string> + <string name="continue_button">ç»§ç»</string> + <string name="connection_failed">连接失败</string> + <string name="try_again_button">é‡è¯•</string> + <string name="waiting_for_contact_to_scan">ç‰å¾…è”系人扫æå¹¶è¿žæŽ¥\u2026</string> + <string name="exchanging_contact_details">交æ¢è”系人细节\u2026</string> + <string name="contact_added_toast">è”ç³»äººå·²æ·»åŠ ï¼š %s</string> + <string name="contact_already_exists">è”系人 %s å·²å˜åœ¨</string> + <string name="contact_exchange_failed">è”系人交æ¢å¤±è´¥</string> + <string name="qr_code_invalid">äºŒç»´ç æ— 效</string> + <string name="qr_code_unsupported">您æ£åœ¨æ‰«æçš„æ˜¯æ¥è‡ªæ—§ç‰ˆæœ¬ %s 版的二维ç ,目å‰ä¸å†æ”¯æŒã€‚\n\n请确ä¿ä½ 们两人都在è¿è¡Œæœ€æ–°ç‰ˆæœ¬å¹¶é‡è¯•。</string> + <string name="camera_error">æ‘„åƒå¤´å‡ºé”™</string> + <string name="connecting_to_device">æ£åœ¨è¿žæŽ¥è‡³è®¾å¤‡\u2026</string> + <string name="authenticating_with_device">æ£åœ¨éªŒè¯è®¾å¤‡\u2026</string> + <string name="connection_aborted_local">è¿žæŽ¥ä¸æ¢ï¼è¿™å¯èƒ½æ„å‘³ç€æœ‰äººæ£åœ¨å°è¯•å¹²é¢„ä½ çš„è¿žæŽ¥</string> + <string name="connection_aborted_remote">连接已被您的è”ç³»äººä¸æ¢ï¼è¿™å¯èƒ½æ„å‘³ç€æœ‰äººæ£åœ¨å°è¯•å¹²é¢„ä½ ä»¬çš„è¿žæŽ¥</string> + <!--Introductions--> + <string name="introduction_onboarding_title">ä»‹ç»æ‚¨çš„è”系人</string> + <string name="introduction_onboarding_text">您å¯ä»¥äº’相介ç»è”ç³»äººï¼Œè¿™æ ·ä»–ä»¬å¯ä»¥ç›´æŽ¥åœ¨ Briar 上建立è”系而ä¸å¿…亲自è§é¢ã€‚</string> + <string name="introduction_menu_item">完æˆä»‹ç»</string> + <string name="introduction_activity_title">选择è”系人</string> + <string name="introduction_not_possible">æ‚¨å½“å‰æ£ç»™è¿™äº›è”系人交æ¢å片。请先ç‰å¾…交æ¢å®Œæˆã€‚如果您或您的好å‹å¾ˆå°‘在线,那需è¦èŠ±äº›æ—¶é—´ã€‚</string> + <string name="introduction_message_title">介ç»è”系人</string> + <string name="introduction_message_hint">æ·»åŠ ä¸€å¥è¯ (选填)</string> + <string name="introduction_button">完æˆä»‹ç»</string> + <string name="introduction_sent">您的介ç»å·²é€å‡ºã€‚</string> + <string name="introduction_error">ä»‹ç»æ—¶å‘生错误。</string> + <string name="introduction_response_error">å“åº”ä»‹ç»æ—¶å‡ºé”™</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_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_response_accepted_sent">您已接å—与 %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_accepted_received">%1$s 接å—与 %2$s 建立è”ç³»</string> + <string name="introduction_response_declined_received">%1$s è°¢ç»ä¸Ž %2$s 建立è”ç³»</string> + <string name="introduction_response_declined_received_by_introducee">%1$s 表示 %2$s è°¢ç»äº†ä»‹ç»ã€‚</string> + <plurals name="introduction_notification_text"> + <item quantity="other">å·²æ·»åŠ %d 使–°è”系人。</item> + </plurals> + <!--Private Groups--> + <string name="groups_list_empty">没有群组\n\n点击 + å·åˆ›å»ºç¾¤èŠï¼Œæˆ–者让您的è”系人分享群组给您</string> + <string name="groups_created_by">ç”± %s 创建</string> + <plurals name="messages"> + <item quantity="other">%d æ¡æ¶ˆæ¯ã€‚</item> + </plurals> + <string name="groups_group_is_empty">è¯¥ç¾¤èŠæ˜¯ç©ºçš„</string> + <string name="groups_group_is_dissolved">该群èŠå·²è¢«è§£æ•£</string> + <string name="groups_remove">åˆ é™¤</string> + <string name="groups_create_group_title">åˆ›å»ºç§æœ‰ç¾¤èŠ</string> + <string name="groups_create_group_button">创建群èŠ</string> + <string name="groups_create_group_invitation_button">å‘é€é‚€è¯·</string> + <string name="groups_create_group_hint">ä¸ºç§æœ‰ç¾¤èŠå‘½å</string> + <string name="groups_invitation_sent">群èŠé‚€è¯·å·²å‘é€</string> + <string name="groups_message_sent">消æ¯å·²å‘é€</string> + <string name="groups_member_list">æˆå‘˜åˆ—表</string> + <string name="groups_invite_members">邀请æˆå‘˜</string> + <string name="groups_member_created_you">您创建了群èŠ</string> + <string name="groups_member_created">%s 创建了群èŠ</string> + <string name="groups_member_joined_you">æ‚¨åŠ å…¥äº†ç¾¤èŠ</string> + <string name="groups_member_joined">%s åŠ å…¥äº†ç¾¤èŠ</string> + <string name="groups_leave">退出群èŠ</string> + <string name="groups_leave_dialog_title">确认退出群èŠ</string> + <string name="groups_leave_dialog_message">确认è¦é€€å‡ºè¯¥ç¾¤èŠå—?</string> + <string name="groups_dissolve">解散群èŠ</string> + <string name="groups_dissolve_dialog_title">确认解散群èŠ</string> + <string name="groups_dissolve_dialog_message">确认è¦è§£æ•£è¯¥ç¾¤èŠå—?\n\n所有其他æˆå‘˜å°†æ— 法继ç»ä¼šè¯å¹¶å¯èƒ½æ— 法接收最新的消æ¯ã€‚</string> + <string name="groups_dissolve_button">解散</string> + <string name="groups_dissolved_dialog_title">群èŠå·²è§£æ•£</string> + <string name="groups_dissolved_dialog_message">群èŠåˆ›å»ºè€…已解散该群èŠã€‚\n\næ‚¨å°†æ— æ³•åœ¨ç¾¤èŠä¸å‘逿¶ˆæ¯ï¼Œå¹¶å¯èƒ½æ— 法接收所有已编辑好的消æ¯ã€‚</string> + <!--Private Group Invitations--> + <string name="groups_invitations_title">群èŠé‚€è¯·</string> + <string name="groups_invitations_invitation_sent">您已邀请 %1$s åŠ å…¥ç¾¤èŠ â€œ%2$sâ€ã€‚</string> + <string name="groups_invitations_invitation_received">%1$s å·²é‚€è¯·æ‚¨åŠ å…¥ç¾¤èŠ â€œ%2$sâ€ã€‚</string> + <string name="groups_invitations_joined">群èŠå·²åŠ å…¥</string> + <string name="groups_invitations_declined">群èŠé‚€è¯·å·²è°¢ç»</string> + <plurals name="groups_invitations_open"> + <item quantity="other">%d 打开了群èŠé‚€è¯·</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">您接å—了æ¥è‡ª %s的群èŠé‚€è¯·</string> + <string name="groups_invitations_response_declined_sent">您谢ç»äº†æ¥è‡ª %s的群èŠé‚€è¯·</string> + <string name="groups_invitations_response_accepted_received">%s 接å—了群èŠé‚€è¯·ã€‚</string> + <string name="groups_invitations_response_declined_received">%s è°¢ç»äº†ç¾¤èŠé‚€è¯·ã€‚</string> + <string name="sharing_status_groups">åªæœ‰åˆ›å»ºè€…å¯ä»¥é‚€è¯·æ–°æˆå‘˜åŠ å…¥ç¾¤èŠã€‚䏋颿˜¯ç›®å‰çš„群æˆå‘˜ã€‚</string> + <!--Private Groups Revealing Contacts--> + <string name="groups_reveal_contacts">显示è”系人</string> + <string name="groups_reveal_dialog_message">您å¯ä»¥å†³å®šæ˜¯å¦å¯¹å½“å‰å’Œå°†æ¥çš„群æˆå‘˜æ˜¾ç¤ºè”系人列表\n\nè¿™å°†ä½¿ä½ ä»¬ä¹‹é—´çš„è”系更快æ·å’Œç¨³å®šï¼Œå› ä¸ºä½ ä»¬å¯ä¸Žå·²æ˜¾ç¤ºçš„è”系人交æµï¼Œå³ä½¿ç¾¤åˆ›å»ºè€…离线。</string> + <string name="groups_reveal_visible">è”系人关系对群èŠå¯è§</string> + <string name="groups_reveal_visible_revealed_by_us">è”系人关系对群èŠå¯è§ (由您设定)</string> + <string name="groups_reveal_visible_revealed_by_contact">è”系人关系对群èŠå¯è§ (ç”± %s 设定)</string> + <string name="groups_reveal_invisible">è”系人关系对群èŠä¸å¯è§</string> + <!--Forums--> + <string name="no_forums">没有论å›\n\n点击 + å·æ¥åˆ›å»ºä¸€ä¸ªï¼Œæˆ–者让您的è”系人分享一个论å›ç»™æ‚¨</string> + <string name="create_forum_title">创建论å›</string> + <string name="choose_forum_hint">为论å›å‘½å</string> + <string name="create_forum_button">创建论å›</string> + <string name="forum_created_toast">论å›å·²åˆ›å»º</string> + <string name="no_forum_posts">å°šæ— å¸–åå¯ä¾›å±•示</string> + <string name="no_posts">æ— å¸–å</string> + <plurals name="posts"> + <item quantity="other">%d æ¡å¸–å</item> + </plurals> + <string name="forum_new_entry_posted">论å›å¸–åå·²å‘布</string> + <string name="forum_new_message_hint">新帖å</string> + <string name="forum_message_reply_hint">新回å¤</string> + <string name="btn_reply">回å¤</string> + <string name="forum_leave">退出论å›</string> + <string name="dialog_title_leave_forum">确认退出论å›</string> + <string name="dialog_message_leave_forum">确定è¦é€€å‡ºè®ºå›ï¼Ÿ\n\n那些您分享过论å›çš„è”系人将ä¸ä¼šå†æ”¶åˆ°æ›´æ–°ã€‚</string> + <string name="dialog_button_leave">退出</string> + <string name="forum_left_toast">已退出论å›</string> + <!--Forum Sharing--> + <string name="forum_share_button">分享论å›</string> + <string name="contacts_selected">已选择è”系人</string> + <string name="activity_share_toolbar_header">选择è”系人</string> + <string name="no_contacts_selector">没有è”系人\n\nè¯·æ·»åŠ è”系人åŽå†æ¥</string> + <string name="forum_shared_snackbar">论å›å·²åˆ†äº«ç»™é€‰ä¸çš„è”系人</string> + <string name="forum_share_message">æ·»åŠ ä¸€å¥è¯ (选填)</string> + <string name="forum_share_error">分享æ¤è®ºå›æ—¶å‘生错误。</string> + <string name="forum_invitation_received">%1$s å·²å°†è®ºå› â€œ%2$sâ€ åˆ†äº«ç»™ä½ ã€‚</string> + <string name="forum_invitation_sent">æ‚¨å·²å°†è®ºå› â€œ%1$s†分享给 %2$s。</string> + <string name="forum_invitations_title">论å›é‚€è¯·</string> + <string name="forum_invitation_exists">您已接å—论å›é‚€è¯·ã€‚\n\næŽ¥å—æ›´å¤šçš„邀请,会使论å›è®¿é—®é€Ÿåº¦æ›´å¿«æ›´å¯é 。</string> + <string name="forum_joined_toast">å·²åŠ å…¥è®ºå›</string> + <string name="forum_declined_toast">邀请已拒ç»</string> + <string name="shared_by_format">ç”± %s 分享</string> + <string name="forum_invitation_already_sharing">已在分享</string> + <string name="forum_invitation_response_accepted_sent">您接å—了æ¥è‡ª %s的论å›é‚€è¯·</string> + <string name="forum_invitation_response_declined_sent">您谢ç»äº†æ¥è‡ª %s的论å›é‚€è¯·</string> + <string name="forum_invitation_response_accepted_received">%s 接å—了论å›é‚€è¯·ã€‚</string> + <string name="forum_invitation_response_declined_received">%s è°¢ç»äº†è®ºå›é‚€è¯·ã€‚</string> + <string name="sharing_status">分享状æ€</string> + <string name="sharing_status_forum">论å›çš„任何æˆå‘˜éƒ½å¯ä»¥å°†è®ºå›åˆ†äº«ç»™ä»–们的è”系人。您æ£åœ¨åˆ†äº«æ¤è®ºå›ç»™ä¸‹åˆ—è”系人。论å›ä¸å¯èƒ½æœ‰æ‚¨æ‰€ä¸å¯è§çš„å…¶ä»–æˆå‘˜ã€‚</string> + <string name="shared_with">被 %1$d 人分享 (%2$d 人在线)</string> + <plurals name="forums_shared"> + <item quantity="other">%d 个论å›è¢«è”系人分享</item> + </plurals> + <string name="nobody">没有人</string> + <!--Blogs--> + <string name="blogs_other_blog_empty_state">å°šæ— å¸–åå¯ä¾›å±•示</string> + <string name="read_more">阅读更多</string> + <string name="blogs_write_blog_post">å†™åšæ–‡</string> + <string name="blogs_write_blog_post_body_hint">è¾“å…¥åšæ–‡å†…容</string> + <string name="blogs_publish_blog_post">å‘布</string> + <string name="blogs_blog_post_created">åšæ–‡å·²åˆ›å»º</string> + <string name="blogs_blog_post_received">æ”¶åˆ°æ–°åšæ–‡</string> + <string name="blogs_blog_post_scroll_to">滑动至</string> + <string name="blogs_feed_empty_state">æ²¡æœ‰æ–‡ç« \n\næ¤å¤„显示您好å‹çš„åšæ–‡æˆ–æ‚¨è®¢é˜…çš„æ–‡ç« \n\nç‚¹å‡»é’¢ç¬”å›¾æ ‡æ¥å†™ä¸€ç¯‡æ–‡ç« </string> + <string name="blogs_remove_blog">åˆ é™¤åšå®¢</string> + <string name="blogs_remove_blog_dialog_message">确定è¦åˆ é™¤åšæ–‡å—?\n\næ–‡ç« å°†ä¼šä»Žæ‚¨çš„è®¾å¤‡åˆ é™¤ï¼Œä½†ä»å˜åœ¨äºŽåˆ«äººçš„设备上。\n\næ‚¨åˆ†äº«è¿‡åšæ–‡çš„用户将ä¸å†æ”¶åˆ°æ›´æ–°ã€‚</string> + <string name="blogs_remove_blog_ok">åˆ é™¤</string> + <string name="blogs_blog_removed">åšå®¢å·²åˆ 除</string> + <string name="blogs_reblog_comment_hint">æ·»åŠ è¯„è®º (选填)</string> + <string name="blogs_reblog_button">转载</string> + <!--Blog Sharing--> + <string name="blogs_sharing_share">分享åšå®¢</string> + <string name="blogs_sharing_error">分享æ¤åšå®¢æ—¶å‘生错误。</string> + <string name="blogs_sharing_button">分享åšå®¢</string> + <string name="blogs_sharing_snackbar">åšå®¢å·²åˆ†äº«ç»™é€‰ä¸çš„è”系人</string> + <string name="blogs_sharing_response_accepted_sent">您接å—了æ¥è‡ª %sçš„åšå®¢é‚€è¯·</string> + <string name="blogs_sharing_response_declined_sent">您谢ç»äº†æ¥è‡ª %sçš„åšå®¢é‚€è¯·</string> + <string name="blogs_sharing_response_accepted_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_sent">您已将åšå®¢ “%1$s†分享给 %2$s。</string> + <string name="blogs_sharing_invitations_title">åšå®¢é‚€è¯·</string> + <string name="blogs_sharing_joined_toast">订阅åšå®¢</string> + <string name="blogs_sharing_declined_toast">邀请已拒ç»</string> + <string name="sharing_status_blog">任何订阅åšå®¢çš„人都å¯ä»¥å°†å®ƒåˆ†äº«ç»™ä»–çš„è”系人。您æ£åœ¨å°†è¯¥åšå®¢åˆ†äº«ç»™ä¸‹åˆ—è”系人。å¯èƒ½æœ‰å…¶ä»–您所ä¸å¯è§çš„订阅者å˜åœ¨ã€‚</string> + <!--RSS Feeds--> + <string name="blogs_rss_feeds_import">导入 RSS 订阅</string> + <string name="blogs_rss_feeds_import_button">导入</string> + <string name="blogs_rss_feeds_import_hint">输入 RSS 订阅链接</string> + <string name="blogs_rss_feeds_import_error">抱æ‰ï¼å¯¼å…¥è®¢é˜…时出错。</string> + <string name="blogs_rss_feeds_manage">ç®¡ç† RSS 订阅</string> + <string name="blogs_rss_feeds_manage_imported">已导入:</string> + <string name="blogs_rss_feeds_manage_author">作者:</string> + <string name="blogs_rss_feeds_manage_updated">æœ€åŽæ›´æ–°äºŽï¼š</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_ok">åˆ é™¤</string> + <string name="blogs_rss_feeds_manage_delete_error">è¯¥è®¢é˜…æ— æ³•è¢«åˆ é™¤ï¼</string> + <string name="blogs_rss_feeds_manage_empty_state">没有订阅内容\n\n点击 + å·å¯¼å…¥ä¸€ä¸ª RSS ä¿¡æ¯æµ</string> + <string name="blogs_rss_feeds_manage_error">åŠ è½½è®¢é˜…æ—¶å‡ºé”™ã€‚è¯·ç¨å€™å†è¯•。</string> + <!--Settings Display--> + <string name="pref_language_title">è¯è¨€ & 区域</string> + <string name="pref_language_changed">这些设置会在 Briar é‡å¯åŽç”Ÿæ•ˆã€‚请登出并é‡å¯ Briar。</string> + <string name="pref_language_default">系统默认</string> + <string name="display_settings_title">显示</string> + <string name="pref_theme_title">主题</string> + <string name="pref_theme_light">浅色</string> + <string name="pref_theme_dark">深色</string> + <string name="pref_theme_auto">自动(按照时间)</string> + <string name="pref_theme_system">系统默认</string> + <!--Settings Network--> + <string name="network_settings_title">网络</string> + <string name="bluetooth_setting">通过è“牙连接</string> + <string name="bluetooth_setting_enabled">è”系人在附近时</string> + <string name="bluetooth_setting_disabled">ä»…åœ¨æ·»åŠ è”系人时</string> + <string name="tor_network_setting">通过 Tor 连接</string> + <string name="tor_network_setting_never">从ä¸</string> + <string name="tor_network_setting_wifi">ä»…åœ¨ä½¿ç”¨æ— çº¿å±€åŸŸç½‘æ—¶</string> + <string name="tor_network_setting_always">ä½¿ç”¨æ— çº¿å±€åŸŸç½‘æˆ–æ•°æ®æµé‡æ—¶</string> + <!--Settings Security and Panic--> + <string name="security_settings_title">安全</string> + <string name="change_password">更改密ç </string> + <string name="current_password">当å‰å¯†ç </string> + <string name="choose_new_password">新密ç </string> + <string name="confirm_new_password">确认新密ç </string> + <string name="password_changed">密ç 已更改。</string> + <string name="panic_setting">创建应急开关</string> + <string name="panic_setting_title">应急开关</string> + <string name="panic_setting_hint">设置触å‘应急开关时 Briar çš„å“应</string> + <string name="panic_app_setting_title">应急开关应用程åº</string> + <string name="unknown_app">未知应用</string> + <string name="panic_app_setting_summary">未设置应用</string> + <string name="panic_app_setting_none">æ— </string> + <string name="dialog_title_connect_panic_app">确认应急应用</string> + <string name="dialog_message_connect_panic_app">是å¦å…许 %1$s 触å‘ç ´åæ€§åº”急开关å应?</string> + <string name="panic_setting_signout_title">登出</string> + <string name="panic_setting_signout_summary">触å‘应急开关时登出 Briar</string> + <string name="purge_setting_title">åˆ é™¤è´¦å·</string> + <string name="purge_setting_summary">触å‘åº”æ€¥å¼€å…³æ—¶åˆ é™¤æ‚¨çš„è´¦å·ã€‚注æ„:您的身份ã€è”系人和消æ¯å°†ä¼šæ°¸ä¹…é—失。</string> + <string name="uninstall_setting_title">å¸è½½ Briar</string> + <string name="uninstall_setting_summary">这需è¦åœ¨ç´§æ€¥äº‹ä»¶ä¸è¿›è¡Œäººå·¥ç¡®è®¤</string> + <!--Settings Notifications--> + <string name="notification_settings_title">æ¶ˆæ¯æé†’</string> + <string name="notify_sign_in_title">æé†’我登录</string> + <string name="notify_sign_in_summary">当手机开机或应用更新时,显示æç¤º</string> + <string name="notify_private_messages_setting_title">ç§ä¿¡</string> + <string name="notify_private_messages_setting_summary">显示ç§ä¿¡é€šçŸ¥</string> + <string name="notify_private_messages_setting_summary_26">é…ç½®ç§èŠæ¶ˆæ¯é€šçŸ¥</string> + <string name="notify_group_messages_setting_title">群消æ¯</string> + <string name="notify_group_messages_setting_summary">æ˜¾ç¤ºç¾¤èŠæ¶ˆæ¯é€šçŸ¥</string> + <string name="notify_group_messages_setting_summary_26">é…ç½®ç¾¤èŠæ¶ˆæ¯é€šçŸ¥</string> + <string name="notify_forum_posts_setting_title">论å›å¸–å</string> + <string name="notify_forum_posts_setting_summary">显示论å›å¸–å通知</string> + <string name="notify_forum_posts_setting_summary_26">é…ç½®è®ºå›æ–‡ç« 通知</string> + <string name="notify_blog_posts_setting_title">åšæ–‡</string> + <string name="notify_blog_posts_setting_summary">æ˜¾ç¤ºåšæ–‡é€šçŸ¥</string> + <string name="notify_blog_posts_setting_summary_26">é…ç½®åšå®¢æ–‡ç« 通知</string> + <string name="notify_vibration_setting">震动</string> + <string name="notify_lock_screen_setting_title">é”定å±å¹•</string> + <string name="notify_lock_screen_setting_summary">在é”定å±å¹•上显示通知</string> + <string name="notify_sound_setting">声音</string> + <string name="notify_sound_setting_default">默认铃声</string> + <string name="notify_sound_setting_disabled">æ— </string> + <string name="choose_ringtone_title">选择铃声</string> + <string name="cannot_load_ringtone">æ— æ³•åŠ è½½é“ƒå£°</string> + <!--Settings Feedback--> + <string name="feedback_settings_title">å馈</string> + <string name="send_feedback">æäº¤å馈</string> + <!--Link Warning--> + <string name="link_warning_title">链接è¦å‘Š</string> + <string name="link_warning_intro">您将è¦åœ¨å¦ä¸€ä¸ªåº”ç”¨ä¸æ‰“开以下链接</string> + <string name="link_warning_text">è¿™å¯èƒ½è¢«ç”¨æ¥è¾¨è®¤æ‚¨ã€‚请考虑您是å¦ä¿¡ä»»å‘é€é“¾æŽ¥çš„人,并考虑使用 Orfox 打开链接。</string> + <string name="link_warning_open_link">打开链接</string> + <!--Crash Reporter--> + <string name="crash_report_title">Briar 崩溃报告</string> + <string name="briar_crashed">抱æ‰ï¼Œ Briar 已崩溃。</string> + <string name="not_your_fault">è¿™å¹¶éžæ‚¨çš„错误所致。</string> + <string name="please_send_report">å‘é€å´©æºƒæŠ¥å‘Šï¼Œä»¥å¸®åŠ©æˆ‘ä»¬ä¼˜åŒ– Briar 。</string> + <string name="report_is_encrypted">我们ä¿è¯æŠ¥å‘Šå°†ä¼šåŠ å¯†å¹¶è¢«å®‰å…¨åœ°å‘é€ã€‚</string> + <string name="feedback_title">å馈</string> + <string name="describe_crash">æè¿°å‘生了什么 (选填)</string> + <string name="enter_feedback">输入您的å馈</string> + <string name="optional_contact_email">æ‚¨çš„é‚®ç®±åœ°å€ (选填)</string> + <string name="include_debug_report_crash">åŒ…å«æœ¬æ¬¡å´©æºƒçš„åŒ¿åæ•°æ®</string> + <string name="include_debug_report_feedback">åŒ…å«æœ¬è®¾å¤‡çš„åŒ¿åæ•°æ®</string> + <string name="could_not_load_report_data">æ— æ³•åŠ è½½æŠ¥å‘Šæ•°æ®ã€‚</string> + <string name="send_report">å‘é€æŠ¥å‘Š</string> + <string name="close">å…³é—</string> + <string name="dev_report_saved">报告已ä¿å˜ï¼Œå°†äºŽä¸‹æ¬¡ç™»å½•æ—¶å‘é€ã€‚</string> + <!--Sign Out--> + <string name="progress_title_logout">登出 Briar…</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">检测到å±å¹•覆盖</string> + <string name="screen_filter_body">å¦ä¸€ä¸ªåº”用覆盖在 Briar ä¸Šã€‚ä¸ºäº†ä¿æŠ¤æ‚¨çš„å®‰å…¨ï¼Œåœ¨æœ‰å…¶ä»–åº”ç”¨è¦†ç›–çš„æƒ…å†µä¸‹ï¼Œ Briar å°†ä¸ä¼šå¯¹è§¦æŽ§åšå‡ºå应。\n\n这些应用å¯èƒ½è¦†ç›–在上:\n\n%1$s</string> + <string name="screen_filter_allow">å…许这些应用覆盖在上</string> + <!--Permission Requests--> + <string name="permission_camera_title">相机æƒé™</string> + <string name="permission_camera_request_body">Briar 需è¦èŽ·å¾—ç›¸æœºæƒé™ä»¥æ‰«æäºŒç»´ç 。</string> + <string name="permission_camera_denied_body">您拒ç»äº†ç›¸æœºæƒé™ï¼Œè€Œæ·»åŠ è”系人需è¦ä½¿ç”¨ç›¸æœº\n\n请考虑授予相机æƒé™ã€‚</string> + <string name="permission_camera_denied_toast">未授予相机æƒé™</string> + <string name="qr_code">二维ç </string> + <string name="show_qr_code_fullscreen">免屿˜¾ç¤ºäºŒç»´ç </string> +</resources> diff --git a/mailbox-android/src/main/res/values/arrays.xml b/mailbox-android/src/main/res/values/arrays.xml new file mode 100644 index 0000000000000000000000000000000000000000..cf459d0e0b6a4fecc64dd84cdfb95f87a8ebcbe0 --- /dev/null +++ b/mailbox-android/src/main/res/values/arrays.xml @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string-array name="boolean_array"> + <item>true</item> + <item>false</item> + </string-array> + <string-array name="bt_setting_names"> + <item>@string/bluetooth_setting_enabled</item> + <item>@string/bluetooth_setting_disabled</item> + </string-array> + + <string-array name="tor_network_setting_names"> + <item>@string/tor_network_setting_automatic</item> + <item>@string/tor_network_setting_without_bridges</item> + <item>@string/tor_network_setting_with_bridges</item> + <item>@string/tor_network_setting_never</item> + </string-array> + <string-array name="tor_network_setting_values"> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + </string-array> + + <string-array name="pref_language_values"> + <item>default</item> + <item>en-US</item> + <item>ast</item> + <item>bg</item> + <item>br</item> + <item>ca</item> + <item>cs</item> + <item>de</item> + <item>es</item> + <item>eu</item> + <item>fa</item> + <item>fi</item> + <item>fr</item> + <item>gl</item> + <item>he</item> + <item>hi</item> + <item>it</item> + <item>ja</item> + <item>ms</item> + <item>nb</item> + <item>nl</item> + <item>oc</item> + <item>pl</item> + <item>pt-BR</item> + <item>ro</item> + <item>ru</item> + <item>sq</item> + <item>sr</item> + <item>sv</item> + <item>tr</item> + <item>zh-CN</item> + </string-array> + <string-array name="pref_theme_entries"> + <item>@string/pref_theme_light</item> + <item>@string/pref_theme_dark</item> + <item>@string/pref_theme_auto</item> + <item>@string/pref_theme_system</item> + </string-array> + <string name="pref_theme_light_value">light</string> + <string name="pref_theme_dark_value">dark</string> + <string name="pref_theme_auto_value">auto</string> + <string name="pref_theme_system_value">system</string> + <string-array name="pref_theme_values"> + <item>@string/pref_theme_light_value</item> + <item>@string/pref_theme_dark_value</item> + <item>@string/pref_theme_auto_value</item> + <item>@string/pref_theme_system_value</item> + </string-array> + + <string-array name="pref_key_lock_timeout_entries"> + <item>@string/pref_lock_timeout_never</item> + <item>@string/pref_lock_timeout_1</item> + <item>@string/pref_lock_timeout_5</item> + <item>@string/pref_lock_timeout_15</item> + <item>@string/pref_lock_timeout_30</item> + <item>@string/pref_lock_timeout_60</item> + </string-array> + <string name="pref_lock_timeout_value_default">5</string> + <string name="pref_lock_timeout_value_never">-1</string> + <string-array name="pref_key_lock_timeout_values"> + <item>@string/pref_lock_timeout_value_never</item> + <item>1</item> + <item>5</item> + <item>15</item> + <item>30</item> + <item>60</item> + </string-array> +</resources> diff --git a/mailbox-android/src/main/res/values/attrs.xml b/mailbox-android/src/main/res/values/attrs.xml new file mode 100644 index 0000000000000000000000000000000000000000..d2e212bb73cf61eeccba282ea506d75540ef699c --- /dev/null +++ b/mailbox-android/src/main/res/values/attrs.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <declare-styleable name="BriarRecyclerView"> + <attr name="scrollToEnd" format="boolean" /> + <attr name="emptyImage" format="integer" /> + <attr name="emptyText" format="string" /> + <attr name="emptyAction" format="string" /> + </declare-styleable> + + <declare-styleable name="AuthorView"> + <attr name="persona" format="enum"> + <enum name="normal" value="0"/> + <enum name="reblogger" value="1"/> + <enum name="commenter" value="2"/> + <enum name="list" value="3"/> + <enum name="rss_feed" value="4"/> + <enum name="rss_feed_reblogged" value="5"/> + </attr> + </declare-styleable> + + <declare-styleable name="TextInputView"> + <attr name="hint" format="string"/> + </declare-styleable> + + <declare-styleable name="LargeTextInputView"> + <attr name="buttonText" format="string"/> + <attr name="maxLines" format="integer"/> + <attr name="fillHeight" format="boolean"/> + </declare-styleable> + + <declare-styleable name="UnreadMessageButton"> + <attr name="direction" format="enum"> + <enum name="up" value="0"/> + <enum name="down" value="1"/> + </attr> + </declare-styleable> + +</resources> \ No newline at end of file diff --git a/mailbox-android/src/main/res/values/color.xml b/mailbox-android/src/main/res/values/color.xml new file mode 100644 index 0000000000000000000000000000000000000000..3d57fec4d00a1206a526831fa2a9b41bbb041b9b --- /dev/null +++ b/mailbox-android/src/main/res/values/color.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="briar_blue">#2D3E50</color> + <color name="briar_blue_dark">#222E3C</color> + <color name="briar_blue_very_dark">#0F1720</color> + <color name="briar_blue_medium">#4F6C8C</color> + <color name="briar_blue_elio">#236087</color> + <color name="briar_blue_elio_light">#3C80A9</color> + <color name="briar_blue_light">#2A93C6</color> + <color name="briar_blue_grey">#EBEFF2</color> + <color name="briar_green">#5C940D</color> + <color name="briar_green_light">#95D220</color> + <color name="briar_red">#ff0000</color> + <color name="briar_white">#FFFFFF</color> + <color name="briar_black">#000000</color> + <color name="briar_black_almost">#080C10</color> + + <color name="m_grey_300">#e0e0e0</color> + <color name="m_grey_500">#9e9e9e</color> + <color name="m_blue_grey_50">#eceff1</color> + + <color name="briar_primary">@color/briar_blue</color> + <color name="briar_primary_dark">@color/briar_blue_very_dark</color> + <color name="briar_accent">@color/briar_blue</color> + + <color name="window_background">#E3EBEF</color> + <color name="card_background">@color/cardview_light_background</color> + <color name="item_background_highlight">#DCDCDC</color> + <color name="briar_warning_background">@color/briar_red</color> + <color name="action_bar_text">@color/briar_white</color> + <color name="private_message_date_inverse">@color/m_grey_300</color> + <color name="forum_avatar_shadow">#99000000</color> + + <color name="color_primary">#dd000000</color> + + <color name="msg_in">@color/briar_white</color> + <color name="msg_out">@color/briar_blue_elio_light</color> + <color name="notice_in">@color/briar_blue_grey</color> + <color name="notice_out">@color/briar_blue_elio</color> + <color name="msg_stroke_light">#cbcbcb</color> + <color name="msg_stroke_dark">#333333</color> + <color name="msg_stroke">@color/msg_stroke_light</color> + + <!-- text colors --> + <color name="briar_text_link">@color/briar_blue_light</color> + <color name="briar_text_primary">#df000000</color> + <color name="briar_text_primary_inverse">@color/briar_white</color> + <color name="briar_text_secondary_inverse">#b4ffffff</color> + <color name="briar_text_tertiary_inverse">#80ffffff</color> + + <color name="preference_category">@color/briar_blue_medium</color> + <color name="preference_category_background">@color/window_background</color> + + <color name="briar_button_background_color">@color/briar_accent</color> + <color name="briar_button_text_positive">@color/briar_blue_light</color> + <color name="briar_button_text_neutral">@color/briar_blue_medium</color> + <color name="briar_button_text_negative">@color/briar_red</color> + <color name="briar_button_text_disabled">#28000000</color> + + <color name="thread_indicator">@color/m_grey_500</color> + <color name="thread_item_background">@color/m_blue_grey_50</color> + <color name="thread_item_highlight">@color/briar_white</color> + + <color name="divider">#c1c1c1</color> +</resources> \ No newline at end of file diff --git a/mailbox-android/src/main/res/values/dimens.xml b/mailbox-android/src/main/res/values/dimens.xml new file mode 100644 index 0000000000000000000000000000000000000000..cf0d23ccd57f35dcea5613ebe66b3d66e4e2ade2 --- /dev/null +++ b/mailbox-android/src/main/res/values/dimens.xml @@ -0,0 +1,74 @@ +<resources> + + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="margin_activity_horizontal">16dp</dimen> + <dimen name="margin_activity_vertical">16dp</dimen> + + <dimen name="margin_separator">1dp</dimen> + <dimen name="margin_tiny">2dp</dimen> + <dimen name="margin_small">4dp</dimen> + <dimen name="margin_medium">8dp</dimen> + <dimen name="margin_large">16dp</dimen> + <dimen name="margin_xlarge">32dp</dimen> + <dimen name="margin_xxlarge">64dp</dimen> + + <!-- v2 dimens --> + <dimen name="text_size_tiny">12sp</dimen> + <dimen name="text_size_small">14sp</dimen> + <dimen name="text_size_medium">16sp</dimen> + <dimen name="text_size_large">20sp</dimen> + <dimen name="text_size_xlarge">34sp</dimen> + + <dimen name="listitem_horizontal_margin">16dp</dimen> + <dimen name="listitem_vertical_margin">10dp</dimen> + <dimen name="listitem_height_one_line_avatar">56dp</dimen> + <dimen name="listitem_picture_size">48dp</dimen> + <dimen name="listitem_picture_size_small">23dp</dimen> + <dimen name="listitem_picture_frame_size">51dp</dimen> + <dimen name="listitem_picture_frame_offset_horizontal">1dp</dimen> + <dimen name="listitem_picture_frame_offset_vertical">2dp</dimen> + <dimen name="listitem_selectable_picture_size">40dp</dimen> + <dimen name="listitem_group_member_indentation">32dp</dimen> + <dimen name="avatar_forum_size">48dp</dimen> + <dimen name="avatar_border_width">2dp</dimen> + <dimen name="avatar_text_size">30sp</dimen> + <dimen name="button_size">48dp</dimen> + + <dimen name="unread_bubble_text_size">12sp</dimen> + <dimen name="unread_bubble_padding_horizontal">6dp</dimen> + <dimen name="unread_bubble_size">19dp</dimen> + + <dimen name="message_bubble_radius_big">16dp</dimen> + <dimen name="message_bubble_radius_small">4dp</dimen> + <dimen name="message_bubble_margin">6dp</dimen> + <dimen name="message_bubble_padding_sides">12dp</dimen> + <dimen name="message_bubble_padding_top">6dp</dimen> + <dimen name="message_bubble_padding_bottom">4dp</dimen> + <dimen name="message_bubble_timestamp_margin">4dp</dimen> + <dimen name="message_bubble_elevation">2dp</dimen> + <dimen name="message_bubble_margin_tail">8dp</dimen> + <dimen name="message_bubble_margin_non_tail">30dp</dimen> + <dimen name="message_bubble_stroke">1px</dimen> + + <dimen name="forum_nested_line_width">2dp</dimen> + <dimen name="forum_nested_indicator">24dp</dimen> + + <dimen name="blogs_avatar_normal_size">30dp</dimen> + <dimen name="blogs_avatar_icon_size">15dp</dimen> + <dimen name="blogs_avatar_comment_size">20dp</dimen> + + <!-- Emoji --> + <dimen name="text_input_height">42dp</dimen> + <dimen name="conversation_item_body_text_size">16sp</dimen> + <dimen name="emoji_drawer_size">32sp</dimen> + <dimen name="emoji_drawer_indicator_height">2dp</dimen> + <dimen name="emoji_drawer_item_padding">5dp</dimen> + <dimen name="emoji_drawer_left_right_padding">2dp</dimen> + + <!-- Keyboard Sizes --> + <dimen name="min_keyboard_size">50dp</dimen> + <dimen name="default_custom_keyboard_size">220dp</dimen> + <dimen name="min_custom_keyboard_size">110dp</dimen> + <dimen name="min_custom_keyboard_top_margin">170dp</dimen> + +</resources> diff --git a/mailbox-android/src/main/res/values/emoji.xml b/mailbox-android/src/main/res/values/emoji.xml new file mode 100644 index 0000000000000000000000000000000000000000..ab8e62d011f28e504cc41b3f8c78d371226021d0 --- /dev/null +++ b/mailbox-android/src/main/res/values/emoji.xml @@ -0,0 +1,1352 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <array + name="emoji_symbols" + format="string"> + <item>1f3c1</item> + <item>1f3f3</item> + <item>1f3f4</item> + <item>1f6a9</item> + <item>1f3e7</item> + <item>1f6ae</item> + <item>1f6b0</item> + <item>267f</item> + <item>1f6b9</item> + <item>1f6ba</item> + <item>1f6bb</item> + <item>1f6bc</item> + <item>1f6be</item> + <item>1f6c2</item> + <item>1f6c3</item> + <item>1f6c4</item> + <item>1f6c5</item> + <item>26a0</item> + <item>1f6b8</item> + <item>26d4</item> + <item>1f6ab</item> + <item>1f6b3</item> + <item>1f6ad</item> + <item>1f6af</item> + <item>1f6b1</item> + <item>1f6b7</item> + <item>2622</item> + <item>2623</item> + <item>2b06</item> + <item>2197</item> + <item>27a1</item> + <item>2198</item> + <item>2b07</item> + <item>2199</item> + <item>2b05</item> + <item>2196</item> + <item>2195</item> + <item>2194</item> + <item>21a9</item> + <item>21aa</item> + <item>2934</item> + <item>2935</item> + <item>1f503</item> + <item>1f504</item> + <item>1f519</item> + <item>1f51a</item> + <item>1f51b</item> + <item>1f51c</item> + <item>1f51d</item> + <item>1f6d0</item> + <item>269b</item> + <item>1f549</item> + <item>2721</item> + <item>2638</item> + <item>262f</item> + <item>271d</item> + <item>2626</item> + <item>262a</item> + <item>262e</item> + <item>1f54e</item> + <item>1f52f</item> + <item>267b</item> + <item>1f4db</item> + <item>269c</item> + <item>1f530</item> + <item>1f531</item> + <item>2b55</item> + <item>2705</item> + <item>2611</item> + <item>2714</item> + <item>2716</item> + <item>274c</item> + <item>274e</item> + <item>2795</item> + <item>2796</item> + <item>2797</item> + <item>27b0</item> + <item>27bf</item> + <item>303d</item> + <item>2733</item> + <item>2734</item> + <item>2747</item> + <item>1f4b1</item> + <item>1f4b2</item> + <item>203c</item> + <item>2049</item> + <item>2753</item> + <item>2754</item> + <item>2755</item> + <item>2757</item> + <item>3030</item> + <item>a9</item> + <item>ae</item> + <item>2122</item> + <item>2648</item> + <item>2649</item> + <item>264a</item> + <item>264b</item> + <item>264c</item> + <item>264d</item> + <item>264e</item> + <item>264f</item> + <item>2650</item> + <item>2651</item> + <item>2652</item> + <item>2653</item> + <item>26ce</item> + <item>1f500</item> + <item>1f501</item> + <item>1f502</item> + <item>25b6</item> + <item>23e9</item> + <item>23ed</item> + <item>23ef</item> + <item>25c0</item> + <item>23ea</item> + <item>23ee</item> + <item>1f53c</item> + <item>23eb</item> + <item>1f53d</item> + <item>23ec</item> + <item>23f8</item> + <item>23f9</item> + <item>23fa</item> + <item>23cf</item> + <item>1f3a6</item> + <item>1f505</item> + <item>1f506</item> + <item>1f4f6</item> + <item>1f4f5</item> + <item>1f4f3</item> + <item>1f4f4</item> + <item>23,20e3</item> + <item>2a,20e3</item> + <item>30,20e3</item> + <item>31,20e3</item> + <item>32,20e3</item> + <item>33,20e3</item> + <item>34,20e3</item> + <item>35,20e3</item> + <item>36,20e3</item> + <item>37,20e3</item> + <item>38,20e3</item> + <item>39,20e3</item> + <item>1f51f</item> + <item>1f4af</item> + <item>1f51e</item> + <item>1f520</item> + <item>1f521</item> + <item>1f522</item> + <item>1f523</item> + <item>1f524</item> + <item>1f170</item> + <item>1f18e</item> + <item>1f171</item> + <item>1f191</item> + <item>1f192</item> + <item>1f193</item> + <item>2139</item> + <item>1f194</item> + <item>24c2</item> + <item>1f195</item> + <item>1f196</item> + <item>1f17e</item> + <item>1f197</item> + <item>1f17f</item> + <item>1f198</item> + <item>1f199</item> + <item>1f19a</item> + <item>1f201</item> + <item>1f202</item> + <item>1f237</item> + <item>1f236</item> + <item>1f22f</item> + <item>1f250</item> + <item>1f239</item> + <item>1f21a</item> + <item>1f232</item> + <item>1f251</item> + <item>1f238</item> + <item>1f234</item> + <item>1f233</item> + <item>3297</item> + <item>3299</item> + <item>1f23a</item> + <item>1f235</item> + <item>25aa</item> + <item>25ab</item> + <item>25fb</item> + <item>25fc</item> + <item>25fd</item> + <item>25fe</item> + <item>2b1b</item> + <item>2b1c</item> + <item>1f536</item> + <item>1f537</item> + <item>1f538</item> + <item>1f539</item> + <item>1f53a</item> + <item>1f53b</item> + <item>1f4a0</item> + <item>1f518</item> + <item>1f532</item> + <item>1f533</item> + <item>26aa</item> + <item>26ab</item> + <item>1f534</item> + <item>1f535</item> + </array> + <array + name="emoji_animals_nature" + format="string"> + <item>1f435</item> + <item>1f412</item> + <item>1f436</item> + <item>1f415</item> + <item>1f429</item> + <item>1f43a</item> + <item>1f431</item> + <item>1f408</item> + <item>1f981</item> + <item>1f42f</item> + <item>1f405</item> + <item>1f406</item> + <item>1f434</item> + <item>1f40e</item> + <item>1f984</item> + <item>1f42e</item> + <item>1f402</item> + <item>1f403</item> + <item>1f404</item> + <item>1f437</item> + <item>1f416</item> + <item>1f417</item> + <item>1f43d</item> + <item>1f40f</item> + <item>1f411</item> + <item>1f410</item> + <item>1f42a</item> + <item>1f42b</item> + <item>1f418</item> + <item>1f42d</item> + <item>1f401</item> + <item>1f400</item> + <item>1f439</item> + <item>1f430</item> + <item>1f407</item> + <item>1f43f</item> + <item>1f43b</item> + <item>1f428</item> + <item>1f43c</item> + <item>1f43e</item> + <item>1f983</item> + <item>1f414</item> + <item>1f413</item> + <item>1f423</item> + <item>1f424</item> + <item>1f425</item> + <item>1f426</item> + <item>1f427</item> + <item>1f54a</item> + <item>1f438</item> + <item>1f40a</item> + <item>1f422</item> + <item>1f40d</item> + <item>1f432</item> + <item>1f409</item> + <item>1f433</item> + <item>1f40b</item> + <item>1f42c</item> + <item>1f41f</item> + <item>1f420</item> + <item>1f421</item> + <item>1f419</item> + <item>1f41a</item> + <item>1f980</item> + <item>1f40c</item> + <item>1f41b</item> + <item>1f41c</item> + <item>1f41d</item> + <item>1f41e</item> + <item>1f577</item> + <item>1f578</item> + <item>1f982</item> + <item>1f490</item> + <item>1f338</item> + <item>1f4ae</item> + <item>1f3f5</item> + <item>1f339</item> + <item>1f33a</item> + <item>1f33b</item> + <item>1f33c</item> + <item>1f337</item> + <item>2618</item> + <item>1f331</item> + <item>1f332</item> + <item>1f333</item> + <item>1f334</item> + <item>1f335</item> + <item>1f33e</item> + <item>1f33f</item> + <item>1f340</item> + <item>1f341</item> + <item>1f342</item> + <item>1f343</item> + </array> + <array + name="emoji_smiley_people" + format="string"> + <item>1f600</item> + <item>1f601</item> + <item>1f602</item> + <item>1f603</item> + <item>1f604</item> + <item>1f605</item> + <item>1f606</item> + <item>1f609</item> + <item>1f60a</item> + <item>1f60b</item> + <item>1f60e</item> + <item>1f60d</item> + <item>1f618</item> + <item>1f617</item> + <item>1f619</item> + <item>1f61a</item> + <item>263a</item> + <item>1f642</item> + <item>1f917</item> + <item>1f607</item> + <item>1f914</item> + <item>1f610</item> + <item>1f611</item> + <item>1f636</item> + <item>1f644</item> + <item>1f60f</item> + <item>1f623</item> + <item>1f625</item> + <item>1f62e</item> + <item>1f910</item> + <item>1f62f</item> + <item>1f62a</item> + <item>1f62b</item> + <item>1f634</item> + <item>1f60c</item> + <item>1f913</item> + <item>1f61b</item> + <item>1f61c</item> + <item>1f61d</item> + <item>2639</item> + <item>1f641</item> + <item>1f612</item> + <item>1f613</item> + <item>1f614</item> + <item>1f615</item> + <item>1f616</item> + <item>1f643</item> + <item>1f637</item> + <item>1f912</item> + <item>1f915</item> + <item>1f911</item> + <item>1f632</item> + <item>1f61e</item> + <item>1f61f</item> + <item>1f624</item> + <item>1f622</item> + <item>1f62d</item> + <item>1f626</item> + <item>1f627</item> + <item>1f628</item> + <item>1f629</item> + <item>1f62c</item> + <item>1f630</item> + <item>1f631</item> + <item>1f633</item> + <item>1f635</item> + <item>1f621</item> + <item>1f620</item> + <item>1f608</item> + <item>1f47f</item> + <item>1f479</item> + <item>1f47a</item> + <item>1f480</item> + <item>2620</item> + <item>1f47b</item> + <item>1f47d</item> + <item>1f47e</item> + <item>1f916</item> + <item>1f4a9</item> + <item>1f63a</item> + <item>1f638</item> + <item>1f639</item> + <item>1f63b</item> + <item>1f63c</item> + <item>1f63d</item> + <item>1f640</item> + <item>1f63f</item> + <item>1f63e</item> + <item>1f648</item> + <item>1f649</item> + <item>1f64a</item> + <item>1f466</item> + <item>1f467</item> + <item>1f468</item> + <item>1f469</item> + <item>1f474</item> + <item>1f475</item> + <item>1f476</item> + <item>1f471</item> + <item>1f46e</item> + <item>1f472</item> + <item>1f473</item> + <item>1f477</item> + <item>26d1</item> + <item>1f478</item> + <item>1f482</item> + <item>1f575</item> + <item>1f385</item> + <item>1f47c</item> + <item>1f46f</item> + <item>1f486</item> + <item>1f487</item> + <item>1f470</item> + <item>1f64d</item> + <item>1f64e</item> + <item>1f645</item> + <item>1f646</item> + <item>1f481</item> + <item>1f64b</item> + <item>1f647</item> + <item>1f64c</item> + <item>1f64f</item> + <item>1f5e3</item> + <item>1f464</item> + <item>1f465</item> + <item>1f6b6</item> + <item>1f3c3</item> + <item>1f483</item> + <item>1f574</item> + <item>1f46b</item> + <item>1f46c</item> + <item>1f46d</item> + <item>1f48f</item> + <item>1f468,200d,2764,fe0f,200d,1f48b,200d,1f468</item> + <item>1f469,200d,2764,fe0f,200d,1f48b,200d,1f469</item> + <item>1f491</item> + <item>1f468,200d,2764,fe0f,200d,1f468</item> + <item>1f469,200d,2764,fe0f,200d,1f469</item> + <item>1f46a</item> + <item>1f468,200d,1f468,200d,1f466</item> + <item>1f468,200d,1f468,200d,1f466,200d,1f466</item> + <item>1f468,200d,1f468,200d,1f467</item> + <item>1f468,200d,1f468,200d,1f467,200d,1f466</item> + <item>1f468,200d,1f468,200d,1f467,200d,1f467</item> + <item>1f468,200d,1f469,200d,1f466</item> + <item>1f468,200d,1f469,200d,1f466,200d,1f466</item> + <item>1f468,200d,1f469,200d,1f467</item> + <item>1f468,200d,1f469,200d,1f467,200d,1f466</item> + <item>1f468,200d,1f469,200d,1f467,200d,1f467</item> + <item>1f469,200d,1f469,200d,1f466</item> + <item>1f469,200d,1f469,200d,1f466,200d,1f466</item> + <item>1f469,200d,1f469,200d,1f467</item> + <item>1f469,200d,1f469,200d,1f467,200d,1f466</item> + <item>1f469,200d,1f469,200d,1f467,200d,1f467</item> + <item>1f3fb</item> + <item>1f3fc</item> + <item>1f3fd</item> + <item>1f3fe</item> + <item>1f3ff</item> + <item>1f4aa</item> + <item>1f448</item> + <item>1f449</item> + <item>261d</item> + <item>1f446</item> + <item>1f595</item> + <item>1f447</item> + <item>270c</item> + <item>1f596</item> + <item>1f918</item> + <item>1f590</item> + <item>270a</item> + <item>270b</item> + <item>1f44a</item> + <item>1f44c</item> + <item>1f44d</item> + <item>1f44e</item> + <item>1f44b</item> + <item>1f44f</item> + <item>1f450</item> + <item>270d</item> + <item>1f485</item> + <item>1f442</item> + <item>1f443</item> + <item>1f463</item> + <item>1f440</item> + <item>1f441</item> + <item>1f445</item> + <item>1f444</item> + <item>1f48b</item> + <item>1f498</item> + <item>2764</item> + <item>1f493</item> + <item>1f494</item> + <item>1f495</item> + <item>1f496</item> + <item>1f497</item> + <item>1f499</item> + <item>1f49a</item> + <item>1f49b</item> + <item>1f49c</item> + <item>1f49d</item> + <item>1f49e</item> + <item>1f49f</item> + <item>2763</item> + <item>1f48c</item> + <item>1f4a4</item> + <item>1f4a2</item> + <item>1f4a3</item> + <item>1f4a5</item> + <item>1f4a6</item> + <item>1f4a8</item> + <item>1f4ab</item> + <item>1f4ac</item> + <item>1f5e8</item> + <item>1f5ef</item> + <item>1f4ad</item> + <item>1f441,200d,1f5e8</item> + <item>1f573</item> + <item>1f453</item> + <item>1f576</item> + <item>1f454</item> + <item>1f455</item> + <item>1f456</item> + <item>1f457</item> + <item>1f458</item> + <item>1f459</item> + <item>1f45a</item> + <item>1f45b</item> + <item>1f45c</item> + <item>1f45d</item> + <item>1f6cd</item> + <item>1f392</item> + <item>1f45e</item> + <item>1f45f</item> + <item>1f460</item> + <item>1f461</item> + <item>1f462</item> + <item>1f451</item> + <item>1f452</item> + <item>1f3a9</item> + <item>1f393</item> + <item>1f4ff</item> + <item>1f484</item> + <item>1f48d</item> + <item>1f48e</item> + </array> + <array + name="emoji_food_drink" + format="string"> + <item>1f347</item> + <item>1f348</item> + <item>1f349</item> + <item>1f34a</item> + <item>1f34b</item> + <item>1f34c</item> + <item>1f34d</item> + <item>1f34e</item> + <item>1f34f</item> + <item>1f350</item> + <item>1f351</item> + <item>1f352</item> + <item>1f353</item> + <item>1f345</item> + <item>1f346</item> + <item>1f33d</item> + <item>1f336</item> + <item>1f344</item> + <item>1f330</item> + <item>1f35e</item> + <item>1f9c0</item> + <item>1f356</item> + <item>1f357</item> + <item>1f354</item> + <item>1f35f</item> + <item>1f355</item> + <item>1f32d</item> + <item>1f32e</item> + <item>1f32f</item> + <item>1f37f</item> + <item>1f372</item> + <item>1f371</item> + <item>1f358</item> + <item>1f359</item> + <item>1f35a</item> + <item>1f35b</item> + <item>1f35c</item> + <item>1f35d</item> + <item>1f360</item> + <item>1f362</item> + <item>1f363</item> + <item>1f364</item> + <item>1f365</item> + <item>1f361</item> + <item>1f366</item> + <item>1f367</item> + <item>1f368</item> + <item>1f369</item> + <item>1f36a</item> + <item>1f382</item> + <item>1f370</item> + <item>1f36b</item> + <item>1f36c</item> + <item>1f36d</item> + <item>1f36e</item> + <item>1f36f</item> + <item>1f37c</item> + <item>2615</item> + <item>1f375</item> + <item>1f376</item> + <item>1f37e</item> + <item>1f377</item> + <item>1f378</item> + <item>1f379</item> + <item>1f37a</item> + <item>1f37b</item> + <item>1f37d</item> + <item>1f374</item> + <item>1f373</item> + <item>1f3fa</item> + </array> + <array + name="emoji_objects" + format="string"> + <item>1f507</item> + <item>1f508</item> + <item>1f509</item> + <item>1f50a</item> + <item>1f4e2</item> + <item>1f4e3</item> + <item>1f4ef</item> + <item>1f514</item> + <item>1f515</item> + <item>1f3bc</item> + <item>1f3b5</item> + <item>1f3b6</item> + <item>1f399</item> + <item>1f39a</item> + <item>1f39b</item> + <item>1f3a4</item> + <item>1f3a7</item> + <item>1f3b7</item> + <item>1f3b8</item> + <item>1f3b9</item> + <item>1f3ba</item> + <item>1f3bb</item> + <item>1f4fb</item> + <item>1f4f1</item> + <item>1f4f2</item> + <item>260e</item> + <item>1f4de</item> + <item>1f4df</item> + <item>1f4e0</item> + <item>1f50b</item> + <item>1f50c</item> + <item>1f4bb</item> + <item>1f5a5</item> + <item>1f5a8</item> + <item>2328</item> + <item>1f5b1</item> + <item>1f5b2</item> + <item>1f4bd</item> + <item>1f4be</item> + <item>1f4bf</item> + <item>1f4c0</item> + <item>1f3a5</item> + <item>1f3ac</item> + <item>1f4fd</item> + <item>1f4fa</item> + <item>1f4f7</item> + <item>1f4f8</item> + <item>1f4f9</item> + <item>1f4fc</item> + <item>1f50d</item> + <item>1f50e</item> + <item>1f52c</item> + <item>1f52d</item> + <item>1f4e1</item> + <item>1f56f</item> + <item>1f4a1</item> + <item>1f526</item> + <item>1f3ee</item> + <item>1f4d4</item> + <item>1f4d5</item> + <item>1f4d6</item> + <item>1f4d7</item> + <item>1f4d8</item> + <item>1f4d9</item> + <item>1f4da</item> + <item>1f4d3</item> + <item>1f4d2</item> + <item>1f4c3</item> + <item>1f4dc</item> + <item>1f4c4</item> + <item>1f4f0</item> + <item>1f5de</item> + <item>1f4d1</item> + <item>1f516</item> + <item>1f4b0</item> + <item>1f4b4</item> + <item>1f4b5</item> + <item>1f4b6</item> + <item>1f4b7</item> + <item>1f4b8</item> + <item>1f4b3</item> + <item>1f4b9</item> + <item>2709</item> + <item>1f4e7</item> + <item>1f4e8</item> + <item>1f4e9</item> + <item>1f4e4</item> + <item>1f4e5</item> + <item>1f4e6</item> + <item>1f4eb</item> + <item>1f4ea</item> + <item>1f4ec</item> + <item>1f4ed</item> + <item>1f4ee</item> + <item>1f5f3</item> + <item>270f</item> + <item>2712</item> + <item>1f58b</item> + <item>1f58a</item> + <item>1f58c</item> + <item>1f58d</item> + <item>1f4dd</item> + <item>1f4bc</item> + <item>1f4c1</item> + <item>1f4c2</item> + <item>1f5c2</item> + <item>1f4c5</item> + <item>1f4c6</item> + <item>1f5d2</item> + <item>1f5d3</item> + <item>1f4c7</item> + <item>1f4c8</item> + <item>1f4c9</item> + <item>1f4ca</item> + <item>1f4cb</item> + <item>1f4cc</item> + <item>1f4cd</item> + <item>1f4ce</item> + <item>1f587</item> + <item>1f4cf</item> + <item>1f4d0</item> + <item>2702</item> + <item>1f5c3</item> + <item>1f5c4</item> + <item>1f5d1</item> + <item>1f512</item> + <item>1f513</item> + <item>1f50f</item> + <item>1f510</item> + <item>1f511</item> + <item>1f5dd</item> + <item>1f528</item> + <item>26cf</item> + <item>2692</item> + <item>1f6e0</item> + <item>1f527</item> + <item>1f529</item> + <item>2699</item> + <item>1f5dc</item> + <item>2697</item> + <item>2696</item> + <item>1f517</item> + <item>26d3</item> + <item>1f489</item> + <item>1f48a</item> + <item>1f5e1</item> + <item>1f52a</item> + <item>2694</item> + <item>1f52b</item> + <item>1f6e1</item> + <item>1f3f9</item> + <item>1f6ac</item> + <item>26b0</item> + <item>26b1</item> + <item>1f5ff</item> + <item>1f6e2</item> + <item>1f52e</item> + </array> + <array + name="emoji_activity" + format="string"> + <item>1f383</item> + <item>1f384</item> + <item>1f386</item> + <item>1f387</item> + <item>2728</item> + <item>1f388</item> + <item>1f389</item> + <item>1f38a</item> + <item>1f38b</item> + <item>1f38c</item> + <item>1f38d</item> + <item>1f38e</item> + <item>1f38f</item> + <item>1f390</item> + <item>1f391</item> + <item>1f380</item> + <item>1f381</item> + <item>1f396</item> + <item>1f397</item> + <item>1f39e</item> + <item>1f39f</item> + <item>1f3ab</item> + <item>1f3f7</item> + <item>26bd</item> + <item>26be</item> + <item>1f3c0</item> + <item>1f3c8</item> + <item>1f3c9</item> + <item>1f3be</item> + <item>1f3b1</item> + <item>1f3b3</item> + <item>26f3</item> + <item>1f3cc</item> + <item>26f8</item> + <item>1f3a3</item> + <item>1f3bd</item> + <item>1f3bf</item> + <item>26f7</item> + <item>1f3c2</item> + <item>1f3c4</item> + <item>1f3c7</item> + <item>1f3ca</item> + <item>26f9</item> + <item>1f3cb</item> + <item>1f6b4</item> + <item>1f6b5</item> + <item>1f3ce</item> + <item>1f3cd</item> + <item>1f3c5</item> + <item>1f3c6</item> + <item>1f3cf</item> + <item>1f3d0</item> + <item>1f3d1</item> + <item>1f3d2</item> + <item>1f3d3</item> + <item>1f3f8</item> + <item>1f3af</item> + <item>1f3ae</item> + <item>1f579</item> + <item>1f3b2</item> + <item>2660</item> + <item>2665</item> + <item>2666</item> + <item>2663</item> + <item>1f0cf</item> + <item>1f004</item> + <item>1f3b4</item> + </array> + <array + name="emoji_travel_places" + format="string"> + <item>1f30d</item> + <item>1f30e</item> + <item>1f30f</item> + <item>1f310</item> + <item>1f5fa</item> + <item>1f3d4</item> + <item>26f0</item> + <item>1f30b</item> + <item>1f5fb</item> + <item>1f3d5</item> + <item>1f3d6</item> + <item>1f3dc</item> + <item>1f3dd</item> + <item>1f3de</item> + <item>1f3df</item> + <item>1f3db</item> + <item>1f3d7</item> + <item>1f3d8</item> + <item>1f3d9</item> + <item>1f3da</item> + <item>1f3e0</item> + <item>1f3e1</item> + <item>26ea</item> + <item>1f54b</item> + <item>1f54c</item> + <item>1f54d</item> + <item>26e9</item> + <item>1f3e2</item> + <item>1f3e3</item> + <item>1f3e4</item> + <item>1f3e5</item> + <item>1f3e6</item> + <item>1f3e8</item> + <item>1f3e9</item> + <item>1f3ea</item> + <item>1f3eb</item> + <item>1f3ec</item> + <item>1f3ed</item> + <item>1f3ef</item> + <item>1f3f0</item> + <item>1f492</item> + <item>1f5fc</item> + <item>1f5fd</item> + <item>1f5fe</item> + <item>26f2</item> + <item>26fa</item> + <item>1f301</item> + <item>1f303</item> + <item>1f304</item> + <item>1f305</item> + <item>1f306</item> + <item>1f307</item> + <item>1f309</item> + <item>2668</item> + <item>1f30c</item> + <item>1f3a0</item> + <item>1f3a1</item> + <item>1f3a2</item> + <item>1f488</item> + <item>1f3aa</item> + <item>1f3ad</item> + <item>1f5bc</item> + <item>1f3a8</item> + <item>1f3b0</item> + <item>1f682</item> + <item>1f683</item> + <item>1f684</item> + <item>1f685</item> + <item>1f686</item> + <item>1f687</item> + <item>1f688</item> + <item>1f689</item> + <item>1f68a</item> + <item>1f69d</item> + <item>1f69e</item> + <item>1f68b</item> + <item>1f68c</item> + <item>1f68d</item> + <item>1f68e</item> + <item>1f68f</item> + <item>1f690</item> + <item>1f691</item> + <item>1f692</item> + <item>1f693</item> + <item>1f694</item> + <item>1f695</item> + <item>1f696</item> + <item>1f697</item> + <item>1f698</item> + <item>1f699</item> + <item>1f69a</item> + <item>1f69b</item> + <item>1f69c</item> + <item>1f6b2</item> + <item>26fd</item> + <item>1f6e3</item> + <item>1f6e4</item> + <item>1f6a8</item> + <item>1f6a5</item> + <item>1f6a6</item> + <item>1f6a7</item> + <item>2693</item> + <item>26f5</item> + <item>1f6a3</item> + <item>1f6a4</item> + <item>1f6f3</item> + <item>26f4</item> + <item>1f6e5</item> + <item>1f6a2</item> + <item>2708</item> + <item>1f6e9</item> + <item>1f6eb</item> + <item>1f6ec</item> + <item>1f4ba</item> + <item>1f681</item> + <item>1f69f</item> + <item>1f6a0</item> + <item>1f6a1</item> + <item>1f680</item> + <item>1f6f0</item> + <item>1f6ce</item> + <item>1f6aa</item> + <item>1f6cc</item> + <item>1f6cf</item> + <item>1f6cb</item> + <item>1f6bd</item> + <item>1f6bf</item> + <item>1f6c0</item> + <item>1f6c1</item> + <item>231b</item> + <item>23f3</item> + <item>231a</item> + <item>23f0</item> + <item>23f1</item> + <item>23f2</item> + <item>1f570</item> + <item>1f55b</item> + <item>1f567</item> + <item>1f550</item> + <item>1f55c</item> + <item>1f551</item> + <item>1f55d</item> + <item>1f552</item> + <item>1f55e</item> + <item>1f553</item> + <item>1f55f</item> + <item>1f554</item> + <item>1f560</item> + <item>1f555</item> + <item>1f561</item> + <item>1f556</item> + <item>1f562</item> + <item>1f557</item> + <item>1f563</item> + <item>1f558</item> + <item>1f564</item> + <item>1f559</item> + <item>1f565</item> + <item>1f55a</item> + <item>1f566</item> + <item>1f311</item> + <item>1f312</item> + <item>1f313</item> + <item>1f314</item> + <item>1f315</item> + <item>1f316</item> + <item>1f317</item> + <item>1f318</item> + <item>1f319</item> + <item>1f31a</item> + <item>1f31b</item> + <item>1f31c</item> + <item>1f321</item> + <item>2600</item> + <item>1f31d</item> + <item>1f31e</item> + <item>2b50</item> + <item>1f31f</item> + <item>1f320</item> + <item>2601</item> + <item>26c5</item> + <item>26c8</item> + <item>1f324</item> + <item>1f325</item> + <item>1f326</item> + <item>1f327</item> + <item>1f328</item> + <item>1f329</item> + <item>1f32a</item> + <item>1f32b</item> + <item>1f32c</item> + <item>1f300</item> + <item>1f308</item> + <item>1f302</item> + <item>2602</item> + <item>2614</item> + <item>26f1</item> + <item>26a1</item> + <item>2744</item> + <item>2603</item> + <item>26c4</item> + <item>2604</item> + <item>1f525</item> + <item>1f4a7</item> + <item>1f30a</item> + </array> + <array + name="emoji_flags" + format="string"> + <item>1f1e6,1f1e8</item> + <item>1f1e6,1f1e9</item> + <item>1f1e6,1f1ea</item> + <item>1f1e6,1f1eb</item> + <item>1f1e6,1f1ec</item> + <item>1f1e6,1f1ee</item> + <item>1f1e6,1f1f1</item> + <item>1f1e6,1f1f2</item> + <item>1f1e6,1f1f4</item> + <item>1f1e6,1f1f6</item> + <item>1f1e6,1f1f7</item> + <item>1f1e6,1f1f8</item> + <item>1f1e6,1f1f9</item> + <item>1f1e6,1f1fa</item> + <item>1f1e6,1f1fc</item> + <item>1f1e6,1f1fd</item> + <item>1f1e6,1f1ff</item> + <item>1f1e7,1f1e6</item> + <item>1f1e7,1f1e7</item> + <item>1f1e7,1f1e9</item> + <item>1f1e7,1f1ea</item> + <item>1f1e7,1f1eb</item> + <item>1f1e7,1f1ec</item> + <item>1f1e7,1f1ed</item> + <item>1f1e7,1f1ee</item> + <item>1f1e7,1f1ef</item> + <item>1f1e7,1f1f1</item> + <item>1f1e7,1f1f2</item> + <item>1f1e7,1f1f3</item> + <item>1f1e7,1f1f4</item> + <item>1f1e7,1f1f6</item> + <item>1f1e7,1f1f7</item> + <item>1f1e7,1f1f8</item> + <item>1f1e7,1f1f9</item> + <item>1f1e7,1f1fb</item> + <item>1f1e7,1f1fc</item> + <item>1f1e7,1f1fe</item> + <item>1f1e7,1f1ff</item> + <item>1f1e8,1f1e6</item> + <item>1f1e8,1f1e8</item> + <item>1f1e8,1f1e9</item> + <item>1f1e8,1f1eb</item> + <item>1f1e8,1f1ec</item> + <item>1f1e8,1f1ed</item> + <item>1f1e8,1f1ee</item> + <item>1f1e8,1f1f0</item> + <item>1f1e8,1f1f1</item> + <item>1f1e8,1f1f2</item> + <item>1f1e8,1f1f3</item> + <item>1f1e8,1f1f4</item> + <item>1f1e8,1f1f5</item> + <item>1f1e8,1f1f7</item> + <item>1f1e8,1f1fa</item> + <item>1f1e8,1f1fb</item> + <item>1f1e8,1f1fc</item> + <item>1f1e8,1f1fd</item> + <item>1f1e8,1f1fe</item> + <item>1f1e8,1f1ff</item> + <item>1f1e9,1f1ea</item> + <item>1f1e9,1f1ec</item> + <item>1f1e9,1f1ef</item> + <item>1f1e9,1f1f0</item> + <item>1f1e9,1f1f2</item> + <item>1f1e9,1f1f4</item> + <item>1f1e9,1f1ff</item> + <item>1f1ea,1f1e6</item> + <item>1f1ea,1f1e8</item> + <item>1f1ea,1f1ea</item> + <item>1f1ea,1f1ec</item> + <item>1f1ea,1f1ed</item> + <item>1f1ea,1f1f7</item> + <item>1f1ea,1f1f8</item> + <item>1f1ea,1f1f9</item> + <item>1f1ea,1f1fa</item> + <item>1f1eb,1f1ee</item> + <item>1f1eb,1f1ef</item> + <item>1f1eb,1f1f0</item> + <item>1f1eb,1f1f2</item> + <item>1f1eb,1f1f4</item> + <item>1f1eb,1f1f7</item> + <item>1f1ec,1f1e6</item> + <item>1f1ec,1f1e7</item> + <item>1f1ec,1f1e9</item> + <item>1f1ec,1f1ea</item> + <item>1f1ec,1f1eb</item> + <item>1f1ec,1f1ec</item> + <item>1f1ec,1f1ed</item> + <item>1f1ec,1f1ee</item> + <item>1f1ec,1f1f1</item> + <item>1f1ec,1f1f2</item> + <item>1f1ec,1f1f3</item> + <item>1f1ec,1f1f5</item> + <item>1f1ec,1f1f6</item> + <item>1f1ec,1f1f7</item> + <item>1f1ec,1f1f8</item> + <item>1f1ec,1f1f9</item> + <item>1f1ec,1f1fa</item> + <item>1f1ec,1f1fc</item> + <item>1f1ec,1f1fe</item> + <item>1f1ed,1f1f0</item> + <item>1f1ed,1f1f2</item> + <item>1f1ed,1f1f3</item> + <item>1f1ed,1f1f7</item> + <item>1f1ed,1f1f9</item> + <item>1f1ed,1f1fa</item> + <item>1f1ee,1f1e8</item> + <item>1f1ee,1f1e9</item> + <item>1f1ee,1f1ea</item> + <item>1f1ee,1f1f1</item> + <item>1f1ee,1f1f2</item> + <item>1f1ee,1f1f3</item> + <item>1f1ee,1f1f4</item> + <item>1f1ee,1f1f6</item> + <item>1f1ee,1f1f7</item> + <item>1f1ee,1f1f8</item> + <item>1f1ee,1f1f9</item> + <item>1f1ef,1f1ea</item> + <item>1f1ef,1f1f2</item> + <item>1f1ef,1f1f4</item> + <item>1f1ef,1f1f5</item> + <item>1f1f0,1f1ea</item> + <item>1f1f0,1f1ec</item> + <item>1f1f0,1f1ed</item> + <item>1f1f0,1f1ee</item> + <item>1f1f0,1f1f2</item> + <item>1f1f0,1f1f3</item> + <item>1f1f0,1f1f5</item> + <item>1f1f0,1f1f7</item> + <item>1f1f0,1f1fc</item> + <item>1f1f0,1f1fe</item> + <item>1f1f0,1f1ff</item> + <item>1f1f1,1f1e6</item> + <item>1f1f1,1f1e7</item> + <item>1f1f1,1f1e8</item> + <item>1f1f1,1f1ee</item> + <item>1f1f1,1f1f0</item> + <item>1f1f1,1f1f7</item> + <item>1f1f1,1f1f8</item> + <item>1f1f1,1f1f9</item> + <item>1f1f1,1f1fa</item> + <item>1f1f1,1f1fb</item> + <item>1f1f1,1f1fe</item> + <item>1f1f2,1f1e6</item> + <item>1f1f2,1f1e8</item> + <item>1f1f2,1f1e9</item> + <item>1f1f2,1f1ea</item> + <item>1f1f2,1f1eb</item> + <item>1f1f2,1f1ec</item> + <item>1f1f2,1f1ed</item> + <item>1f1f2,1f1f0</item> + <item>1f1f2,1f1f1</item> + <item>1f1f2,1f1f2</item> + <item>1f1f2,1f1f3</item> + <item>1f1f2,1f1f4</item> + <item>1f1f2,1f1f5</item> + <item>1f1f2,1f1f6</item> + <item>1f1f2,1f1f7</item> + <item>1f1f2,1f1f8</item> + <item>1f1f2,1f1f9</item> + <item>1f1f2,1f1fa</item> + <item>1f1f2,1f1fb</item> + <item>1f1f2,1f1fc</item> + <item>1f1f2,1f1fd</item> + <item>1f1f2,1f1fe</item> + <item>1f1f2,1f1ff</item> + <item>1f1f3,1f1e6</item> + <item>1f1f3,1f1e8</item> + <item>1f1f3,1f1ea</item> + <item>1f1f3,1f1eb</item> + <item>1f1f3,1f1ec</item> + <item>1f1f3,1f1ee</item> + <item>1f1f3,1f1f1</item> + <item>1f1f3,1f1f4</item> + <item>1f1f3,1f1f5</item> + <item>1f1f3,1f1f7</item> + <item>1f1f3,1f1fa</item> + <item>1f1f3,1f1ff</item> + <item>1f1f4,1f1f2</item> + <item>1f1f5,1f1e6</item> + <item>1f1f5,1f1ea</item> + <item>1f1f5,1f1eb</item> + <item>1f1f5,1f1ec</item> + <item>1f1f5,1f1ed</item> + <item>1f1f5,1f1f0</item> + <item>1f1f5,1f1f1</item> + <item>1f1f5,1f1f2</item> + <item>1f1f5,1f1f3</item> + <item>1f1f5,1f1f7</item> + <item>1f1f5,1f1f8</item> + <item>1f1f5,1f1f9</item> + <item>1f1f5,1f1fc</item> + <item>1f1f5,1f1fe</item> + <item>1f1f6,1f1e6</item> + <item>1f1f7,1f1ea</item> + <item>1f1f7,1f1f4</item> + <item>1f1f7,1f1f8</item> + <item>1f1f7,1f1fa</item> + <item>1f1f7,1f1fc</item> + <item>1f1f8,1f1e6</item> + <item>1f1f8,1f1e7</item> + <item>1f1f8,1f1e8</item> + <item>1f1f8,1f1e9</item> + <item>1f1f8,1f1ea</item> + <item>1f1f8,1f1ec</item> + <item>1f1f8,1f1ed</item> + <item>1f1f8,1f1ee</item> + <item>1f1f8,1f1ef</item> + <item>1f1f8,1f1f0</item> + <item>1f1f8,1f1f1</item> + <item>1f1f8,1f1f2</item> + <item>1f1f8,1f1f3</item> + <item>1f1f8,1f1f4</item> + <item>1f1f8,1f1f7</item> + <item>1f1f8,1f1f8</item> + <item>1f1f8,1f1f9</item> + <item>1f1f8,1f1fb</item> + <item>1f1f8,1f1fd</item> + <item>1f1f8,1f1fe</item> + <item>1f1f8,1f1ff</item> + <item>1f1f9,1f1e6</item> + <item>1f1f9,1f1e8</item> + <item>1f1f9,1f1e9</item> + <item>1f1f9,1f1eb</item> + <item>1f1f9,1f1ec</item> + <item>1f1f9,1f1ed</item> + <item>1f1f9,1f1ef</item> + <item>1f1f9,1f1f0</item> + <item>1f1f9,1f1f1</item> + <item>1f1f9,1f1f2</item> + <item>1f1f9,1f1f3</item> + <item>1f1f9,1f1f4</item> + <item>1f1f9,1f1f7</item> + <item>1f1f9,1f1f9</item> + <item>1f1f9,1f1fb</item> + <item>1f1f9,1f1fc</item> + <item>1f1f9,1f1ff</item> + <item>1f1fa,1f1e6</item> + <item>1f1fa,1f1ec</item> + <item>1f1fa,1f1f2</item> + <item>1f1fa,1f1f8</item> + <item>1f1fa,1f1fe</item> + <item>1f1fa,1f1ff</item> + <item>1f1fb,1f1e6</item> + <item>1f1fb,1f1e8</item> + <item>1f1fb,1f1ea</item> + <item>1f1fb,1f1ec</item> + <item>1f1fb,1f1ee</item> + <item>1f1fb,1f1f3</item> + <item>1f1fb,1f1fa</item> + <item>1f1fc,1f1eb</item> + <item>1f1fc,1f1f8</item> + <item>1f1fd,1f1f0</item> + <item>1f1fe,1f1ea</item> + <item>1f1fe,1f1f9</item> + <item>1f1ff,1f1e6</item> + <item>1f1ff,1f1f2</item> + <item>1f1ff,1f1fc</item> + </array> +</resources> diff --git a/mailbox-android/src/main/res/values/strings.xml b/mailbox-android/src/main/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..294b1c6b08f2a8ce4cc48288ecd355326bfa17ab --- /dev/null +++ b/mailbox-android/src/main/res/values/strings.xml @@ -0,0 +1,487 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name" translatable="false">Briar Mailbox</string> + <string name="app_package" translatable="false">org.briarproject.mailbox.android</string> + + <!-- Setup --> + <string name="setup_title">Welcome to Briar Mailbox</string> + <string name="setup_name_explanation">Your nickname will be shown next to any content you post. You can\'t change it after creating your account.</string> + <string name="setup_next">Next</string> + <string name="setup_password_intro">Choose a Password</string> + <string name="setup_password_explanation">Your Briar Mailbox account is stored encrypted on your device, not in the cloud. If you forget your password or uninstall Briar, there\'s no way to recover your account.\n\nChoose a long password that\'s hard to guess, such as four random words, or ten random letters, numbers and symbols.</string> + <string name="setup_doze_title">Background Connections</string> + <string name="setup_doze_intro">To receive messages, Briar Mailbox needs to stay connected in the background.</string> + <string name="setup_doze_explanation">To receive messages, Briar Mailbox needs to stay connected in the background. Please disable battery optimizations so Briar Mailbox can stay connected.</string> + <string name="setup_doze_button">Allow Connections</string> + <string name="choose_nickname">Choose your nickname</string> + <string name="choose_password">Choose your password</string> + <string name="confirm_password">Confirm your password</string> + <string name="name_too_long">Name is too long</string> + <string name="password_too_weak">Password is too weak</string> + <string name="passwords_do_not_match">Passwords do not match</string> + <string name="create_account_button">Create Account</string> + <string name="more_info">More Information</string> + <string name="don_t_ask_again">Don\'t ask again</string> + + <string name="setup_huawei_text">Please tap the button below and make sure Briar Mailbox is protected in the \"Protected Apps\" screen.</string> + <string name="setup_huawei_button">Protect Briar Mailbox</string> + <string name="setup_huawei_help">If Briar Mailbox is not added to the protected apps list, it will be unable to run in the background.</string> + <string name="warning_dozed">%s was unable to run in the background</string> + + <!-- Login --> + <string name="enter_password">Password</string> + <string name="try_again">Wrong password, try again</string> + <string name="sign_in_button">Sign In</string> + <string name="forgotten_password">I have forgotten my password</string> + <string name="dialog_title_lost_password">Lost Password</string> + <string name="dialog_message_lost_password">Your Briar Mailbox account is stored encrypted on your device, not in the cloud, so we can\'t reset your password. Would you like to delete your account and start again?\n\nCaution: Your identities, contacts and messages will be permanently lost.</string> + <string name="startup_failed_notification_title">Briar Mailbox could not start</string> + <string name="startup_failed_notification_text">Tap for more information.</string> + <string name="startup_failed_activity_title">Briar Mailbox Startup Failure</string> + <string name="startup_failed_db_error">For some reason, your Briar Mailbox database is corrupted beyond repair. Your account, your data and all your contacts are lost. Unfortunately, you need to reinstall Briar Mailbox or set up a new account by choosing \'I have forgotten my password\' at the password prompt.</string> + <string name="startup_failed_data_too_old_error">Your account was created with an old version of this app and cannot be opened with this version. You must either reinstall the old version or set up a new account by choosing \'I have forgotten my password\' at the password prompt.</string> + <string name="startup_failed_data_too_new_error">This version of the app is too old. Please upgrade to the latest version and try again.</string> + <string name="startup_failed_service_error">Briar Mailbox was unable to start a required plugin. Reinstalling Briar Mailbox usually solves this problem. However, please note that you will then lose your account and all data associated with it since Briar Mailbox is not using central servers to store your data on.</string> + <plurals name="expiry_warning"> + <item quantity="one">This is a test version of Briar Mailbox. Your account will expire in %d day and cannot be renewed.</item> + <item quantity="other">This is a test version of Briar Mailbox. Your account will expire in %d days and cannot be renewed.</item> + </plurals> + <string name="expiry_update">The testing expiry date has been extended. Your account will now expire in %d days.</string> + <string name="expiry_date_reached">This software has expired.\nThank you for testing!</string> + <string name="download_briar">To continue using Briar Mailbox, please download version 1.0.</string> + <string name="create_new_account">You will need to create a new account, but you can use the same nickname.</string> + <string name="download_briar_button">Download Briar Mailbox 1.0</string> + <string name="startup_open_database">Decrypting Database…</string> + <string name="startup_migrate_database">Upgrading Database…</string> + + <!-- Navigation Drawer --> + <string name="nav_drawer_open_description">Open the navigation drawer</string> + <string name="nav_drawer_close_description">Close the navigation drawer</string> + <string name="contact_list_button">Contacts</string> + <string name="groups_button">Private Groups</string> + <string name="forums_button">Forums</string> + <string name="blogs_button">Blogs</string> + <!-- This is part of the main menu. The app will be locked when this is tapped. --> + <string name="lock_button">Lock App</string> + <string name="settings_button">Settings</string> + <string name="sign_out_button">Sign Out</string> + + <!-- Transports --> + <string name="transport_tor">Internet</string> + <string name="transport_bt">Bluetooth</string> + <string name="transport_lan">Wi-Fi</string> + + <!-- Notifications --> + <string name="reminder_notification_title">Signed out of Briar Mailbox</string> + <string name="reminder_notification_text">Tap to sign back in.</string> + <string name="reminder_notification_channel_title">Briar Mailbox Sign-in Reminder</string> + <string name="reminder_notification_dismiss">Dismiss</string> + <string name="ongoing_notification_title">Signed into Briar Mailbox</string> + <string name="ongoing_notification_text">Touch to open Briar Mailbox.</string> + <plurals name="private_message_notification_text"> + <item quantity="one">New private message.</item> + <item quantity="other">%d new private messages.</item> + </plurals> + <plurals name="group_message_notification_text"> + <item quantity="one">New group message.</item> + <item quantity="other">%d new group messages.</item> + </plurals> + <plurals name="forum_post_notification_text"> + <item quantity="one">New forum post.</item> + <item quantity="other">%d new forum posts.</item> + </plurals> + <plurals name="blog_post_notification_text"> + <item quantity="one">New blog post.</item> + <item quantity="other">%d new blog posts.</item> + </plurals> + + <!-- Misc --> + <string name="now">now</string> + <string name="show">Show</string> + <string name="hide">Hide</string> + <string name="ok">OK</string> + <string name="cancel">Cancel</string> + <string name="got_it">Got it</string> + <string name="delete">Delete</string> + <string name="accept">Accept</string> + <string name="decline">Decline</string> + <string name="options">Options</string> + <string name="online">Online</string> + <string name="offline">Offline</string> + <string name="send">Send</string> + <string name="allow">Allow</string> + <string name="open">Open</string> + <string name="no_data">No data</string> + <string name="ellipsis">…</string> + <string name="text_too_long">The entered text is too long</string> + <string name="show_onboarding">Show Help Dialog</string> + <string name="fix">Fix</string> + <string name="help">Help</string> + <string name="sorry">Sorry</string> + + <!-- Contacts and Private Conversations--> + <string name="no_contacts">No contacts to show</string> + <string name="no_contacts_action">Tap the + icon to add a contact</string> + <string name="date_no_private_messages">No messages.</string> + <string name="no_private_messages">No messages to show</string> + <string name="message_hint">Type message</string> + <string name="delete_contact">Delete contact</string> + <string name="dialog_title_delete_contact">Confirm Contact Deletion</string> + <string name="dialog_message_delete_contact">Are you sure that you want to remove this contact and all messages exchanged with this contact?</string> + <string name="contact_deleted_toast">Contact deleted</string> + + <!-- Adding Contacts --> + <string name="add_contact_title">Add a Contact</string> + <string name="face_to_face">You must meet up with the person you want to add as a contact.\n\nThis will prevent anyone from impersonating you or reading your messages in future.</string> + <string name="continue_button">Continue</string> + <string name="try_again_button">Try Again</string> + <string name="waiting_for_contact_to_scan">Waiting for contact to scan and connect\u2026</string> + <string name="exchanging_contact_details">Exchanging contact details\u2026</string> + <string name="contact_added_toast">Contact added: %s</string> + <string name="contact_already_exists">Contact %s already exists</string> + <string name="qr_code_invalid">The QR code is invalid</string> + <string name="qr_code_unsupported">The QR code you are trying to scan belongs to an old version of %s which is no longer supported.\n\nPlease ensure that both of you are running the latest version and then try again.</string> + <string name="camera_error">Camera error</string> + <string name="connecting_to_device">Connecting to device\u2026</string> + <string name="authenticating_with_device">Authenticating with device\u2026</string> + <string name="connection_error_title">Could not connect to your contact</string> + <string name="connection_error_explanation">Please check that you\'re both connected to the same Wi-Fi network.</string> + <string name="connection_error_feedback">If this problem persists, please <a href="feedback">send feedback</a> to help us improve the app.</string> + + <!-- Introductions --> + <string name="introduction_onboarding_title">Introduce your contacts</string> + <string name="introduction_onboarding_text">You can introduce your contacts to each other, so they don\'t need to meet in person to connect on Briar Mailbox.</string> + <string name="introduction_menu_item">Make Introduction</string> + <string name="introduction_activity_title">Select Contact</string> + <string name="introduction_not_possible">You already have one introduction in progress with these contacts. Please allow for this to finish first. If you or your contacts are rarely online, this can take some time.</string> + <string name="introduction_message_title">Introduce Contacts</string> + <string name="introduction_message_hint">Add a message (optional)</string> + <string name="introduction_button">Make Introduction</string> + <string name="introduction_sent">Your introduction has been sent.</string> + <string name="introduction_error">There was an error making the introduction.</string> + <string name="introduction_response_error">Error when responding to introduction</string> + <string name="introduction_request_sent">You have asked to introduce %1$s to %2$s.</string> + <string name="introduction_request_received">%1$s has asked to introduce you to %2$s. Do you want to add %2$s to your contact list?</string> + <string name="introduction_request_exists_received">%1$s has asked to introduce you to %2$s, but %2$s is already in your contact list. Since %1$s might not know that, you can still respond:</string> + <string name="introduction_request_answered_received">%1$s has asked to introduce you to %2$s.</string> + <string name="introduction_response_accepted_sent">You accepted the introduction to %1$s.</string> + <string name="introduction_response_accepted_sent_info">Before %1$s gets added to your contacts, they need to accept the introduction as well. This might take some time.</string> + <string name="introduction_response_declined_sent">You declined the introduction to %1$s.</string> + <string name="introduction_response_accepted_received">%1$s accepted the introduction to %2$s.</string> + <string name="introduction_response_declined_received">%1$s declined the introduction to %2$s.</string> + <string name="introduction_response_declined_received_by_introducee">%1$s says that %2$s declined the introduction.</string> + <plurals name="introduction_notification_text"> + <item quantity="one">New contact added.</item> + <item quantity="other">%d new contacts added.</item> + </plurals> + + <!-- Private Groups --> + <string name="groups_list_empty">No groups to show</string> + <string name="groups_list_empty_action">Tap the + icon to create a group, or ask your contacts to share groups with you</string> + <string name="groups_created_by">Created by %s</string> + <plurals name="messages"> + <item quantity="one">%d message</item> + <item quantity="other">%d messages</item> + </plurals> + <string name="groups_group_is_empty">This group is empty</string> + <string name="groups_group_is_dissolved">This group has been dissolved</string> + <string name="groups_remove">Remove</string> + <string name="groups_create_group_title">Create Private Group</string> + <string name="groups_create_group_button">Create Group</string> + <string name="groups_create_group_invitation_button">Send Invitation</string> + <string name="groups_create_group_hint">Choose a name for your private group</string> + <string name="groups_invitation_sent">Group invitation has been sent</string> + <string name="groups_message_sent">Message sent</string> + <string name="groups_member_list">Member List</string> + <string name="groups_invite_members">Invite Members</string> + <string name="groups_member_created_you">You created the group</string> + <string name="groups_member_created">%s created the group</string> + <string name="groups_member_joined_you">You joined the group</string> + <string name="groups_member_joined">%s joined the group</string> + <string name="groups_leave">Leave Group</string> + <string name="groups_leave_dialog_title">Confirm Leaving Group</string> + <string name="groups_leave_dialog_message">Are you sure that you want to leave this group?</string> + <string name="groups_dissolve">Dissolve Group</string> + <string name="groups_dissolve_dialog_title">Confirm Dissolving Group</string> + <string name="groups_dissolve_dialog_message">Are you sure that you want to dissolve this group?\n\nAll other members will not be able to continue their conversation and might not receive the latest messages.</string> + <string name="groups_dissolve_button">Dissolve</string> + <string name="groups_dissolved_dialog_title">Group Has Been Dissolved</string> + <string name="groups_dissolved_dialog_message">The creator of this group has dissolved it.\n\nYou can no longer write messages to the group and might not receive all posts that have been written.</string> + + <!-- Private Group Invitations --> + <string name="groups_invitations_title">Group Invitations</string> + <string name="groups_invitations_invitation_sent">You have invited %1$s to join the group \"%2$s\".</string> + <string name="groups_invitations_invitation_received">%1$s has invited you to join the group \"%2$s\".</string> + <string name="groups_invitations_joined">Joined group</string> + <string name="groups_invitations_declined">Group invitation declined</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d open group invitation</item> + <item quantity="other">%d open group invitations</item> + </plurals> + <string name="groups_invitations_response_accepted_sent">You accepted the group invitation from %s.</string> + <string name="groups_invitations_response_declined_sent">You declined the group invitation from %s.</string> + <string name="groups_invitations_response_accepted_received">%s accepted the group invitation.</string> + <string name="groups_invitations_response_declined_received">%s declined the group invitation.</string> + <string name="sharing_status_groups">Only the creator can invite new members to the group. Below are all current members of the group.</string> + + <!-- Private Groups Revealing Contacts --> + <string name="groups_reveal_contacts">Reveal Contacts</string> + <string name="groups_reveal_dialog_message">You can choose whether to reveal contacts to all current and future members of this group.\n\nRevealing contacts makes your connection to the group faster and more reliable, because you can communicate with revealed contacts even when the creator of the group is offline.</string> + <string name="groups_reveal_visible">Contact relationship is visible to the group</string> + <string name="groups_reveal_visible_revealed_by_us">Contact relationship is visible to the group (revealed by you)</string> + <string name="groups_reveal_visible_revealed_by_contact">Contact relationship is visible to the group (revealed by %s)</string> + <string name="groups_reveal_invisible">Contact relationship is not visible to the group</string> + + <!-- Forums --> + <string name="no_forums">No forums to show</string> + <string name="no_forums_action">Tap the + icon to create a forum, or ask your contacts to share forums with you</string> + <string name="create_forum_title">Create Forum</string> + <string name="choose_forum_hint">Choose a name for your forum</string> + <string name="create_forum_button">Create Forum</string> + <string name="forum_created_toast">Forum created</string> + <string name="no_forum_posts">No posts to show</string> + <string name="no_posts">No posts</string> + <plurals name="posts"> + <item quantity="one">%d post</item> + <item quantity="other">%d posts</item> + </plurals> + <string name="forum_new_entry_posted">Forum post published</string> + <string name="forum_new_message_hint">New Post</string> + <string name="forum_message_reply_hint">New Reply</string> + <string name="btn_reply">Reply</string> + <string name="forum_leave">Leave Forum</string> + <string name="dialog_title_leave_forum">Confirm Leaving Forum</string> + <string name="dialog_message_leave_forum">Are you sure that you want to leave this forum?\n\nAny contacts you\'ve shared this forum with might stop receiving updates.</string> + <string name="dialog_button_leave">Leave</string> + <string name="forum_left_toast">Left forum</string> + + <!-- Forum Sharing --> + <string name="forum_share_button">Share Forum</string> + <string name="contacts_selected">Contacts selected</string> + <string name="activity_share_toolbar_header">Choose Contacts</string> + <string name="no_contacts_selector">No contacts to show</string> + <string name="no_contacts_selector_action">Please come back here after adding a contact</string> + <string name="forum_shared_snackbar">Forum shared with chosen contacts</string> + <string name="forum_share_message">Add a message (optional)</string> + <string name="forum_share_error">There was an error sharing this forum.</string> + <string name="forum_invitation_received">%1$s has shared the forum \"%2$s\" with you.</string> + <string name="forum_invitation_sent">You have shared the forum \"%1$s\" with %2$s.</string> + <string name="forum_invitations_title">Forum Invitations</string> + <string name="forum_invitation_exists">You accepted an invitation to this forum already.\n\nAccepting more invitations will make your connection to the forum faster and more reliable.</string> + <string name="forum_joined_toast">Joined forum</string> + <string name="forum_declined_toast">Invitation declined</string> + <string name="shared_by_format">Shared by %s</string> + <string name="forum_invitation_already_sharing">Already sharing</string> + <string name="forum_invitation_response_accepted_sent">You accepted the forum invitation from %s.</string> + <string name="forum_invitation_response_declined_sent">You declined the forum invitation from %s.</string> + <string name="forum_invitation_response_accepted_received">%s accepted the forum invitation.</string> + <string name="forum_invitation_response_declined_received">%s declined the forum invitation.</string> + + <string name="sharing_status">Sharing Status</string> + <string name="sharing_status_forum">Any member of a forum can share it with their contacts. You are sharing this forum with the following contacts. There may also be other members who you can\'t see.</string> + <string name="shared_with">Shared with %1$d (%2$d online)</string> + <plurals name="forums_shared"> + <item quantity="one">%d forum shared by contacts</item> + <item quantity="other">%d forums shared by contacts</item> + </plurals> + <string name="nobody">Nobody</string> + + <!-- Blogs --> + <string name="blogs_other_blog_empty_state">No posts to show</string> + <string name="read_more">read more</string> + <string name="blogs_write_blog_post">Write Blog Post</string> + <string name="blogs_write_blog_post_body_hint">Type your blog post</string> + <string name="blogs_publish_blog_post">Publish</string> + <string name="blogs_blog_post_created">Blog Post Created</string> + <string name="blogs_blog_post_received">New Blog Post Received</string> + <string name="blogs_blog_post_scroll_to">Scroll To</string> + <string name="blogs_feed_empty_state">No posts to show</string> + <string name="blogs_feed_empty_state_action">Posts from your contacts and blogs you subscribe to will appear here\n\nTap the pen icon to write a post</string> + <string name="blogs_remove_blog">Remove Blog</string> + <string name="blogs_remove_blog_dialog_message">Are you sure that you want to remove this blog?\n\nPosts will be removed from your device but not from other people\'s devices.\n\nAny contacts you\'ve shared this blog with might stop receiving updates.</string> + <string name="blogs_remove_blog_ok">Remove</string> + <string name="blogs_blog_removed">Blog removed</string> + <string name="blogs_reblog_comment_hint">Add a comment (optional)</string> + <string name="blogs_reblog_button">Reblog</string> + + <!-- Blog Sharing --> + <string name="blogs_sharing_share">Share Blog</string> + <string name="blogs_sharing_error">There was an error sharing this blog.</string> + <string name="blogs_sharing_button">Share Blog</string> + <string name="blogs_sharing_snackbar">Blog shared with chosen contacts</string> + <string name="blogs_sharing_response_accepted_sent">You accepted the blog invitation from %s.</string> + <string name="blogs_sharing_response_declined_sent">You declined the blog invitation from %s.</string> + <string name="blogs_sharing_response_accepted_received">%s accepted the blog invitation.</string> + <string name="blogs_sharing_response_declined_received">%s declined the blog invitation.</string> + <string name="blogs_sharing_invitation_received">%1$s has shared the blog \"%2$s\" with you.</string> + <string name="blogs_sharing_invitation_sent">You have shared the blog \"%1$s\" with %2$s.</string> + <string name="blogs_sharing_invitations_title">Blog Invitations</string> + <string name="blogs_sharing_joined_toast">Subscribed to blog</string> + <string name="blogs_sharing_declined_toast">Invitation declined</string> + <string name="sharing_status_blog">Anyone who subscribes to a blog can share it with their contacts. You are sharing this blog with the following contacts. There may also be other subscribers who you can\'t see.</string> + + <!-- RSS Feeds --> + <string name="blogs_rss_feeds_import">Import RSS Feed</string> + <string name="blogs_rss_feeds_import_button">Import</string> + <string name="blogs_rss_feeds_import_hint">Enter the URL of the RSS feed</string> + <string name="blogs_rss_feeds_import_error">We are sorry! There was an error importing your feed.</string> + <string name="blogs_rss_feeds_manage">Manage RSS Feeds</string> + <string name="blogs_rss_feeds_manage_imported">Imported:</string> + <string name="blogs_rss_feeds_manage_author">Author:</string> + <string name="blogs_rss_feeds_manage_updated">Last Updated:</string> + <string name="blogs_rss_remove_feed">Remove Feed</string> + <string name="blogs_rss_remove_feed_dialog_message">Are you sure that you want to remove this feed?\n\nPosts will be removed from your device but not from other people\'s devices.\n\nAny contacts you\'ve shared this feed with might stop receiving updates.</string> + <string name="blogs_rss_remove_feed_ok">Remove</string> + <string name="blogs_rss_feeds_manage_delete_error">The feed could not be deleted!</string> + <string name="blogs_rss_feeds_manage_empty_state">No RSS feeds to show\n\nTap the + icon to import a feed</string> + <string name="blogs_rss_feeds_manage_error">There was a problem loading your feeds. Please try again later.</string> + + <!-- Settings Display --> + <string name="pref_language_title">Language & region</string> + <string name="pref_language_changed">This setting will take effect when you restart Briar Mailbox. Please sign out and restart Briar Mailbox.</string> + <string name="pref_language_default">System default</string> + <string name="display_settings_title">Display</string> + <string name="pref_theme_title">Theme</string> + <string name="pref_theme_light">Light</string> + <string name="pref_theme_dark">Dark</string> + <string name="pref_theme_auto">Automatic (Daytime)</string> + <string name="pref_theme_system">System Default</string> + + <!-- Settings Network --> + <string name="network_settings_title">Networks</string> + <string name="bluetooth_setting">Connect via Bluetooth</string> + <string name="bluetooth_setting_enabled">Whenever contacts are nearby</string> + <string name="bluetooth_setting_disabled">Only when adding contacts</string> + <string name="tor_network_setting">Connect via Internet (Tor)</string> + <string name="tor_network_setting_automatic">Automatic based on location</string> + <string name="tor_network_setting_without_bridges">Use Tor without bridges</string> + <string name="tor_network_setting_with_bridges">Use Tor with bridges</string> + <string name="tor_network_setting_never">Don\'t connect</string> + <!-- How and when Tor will connect after Automatic: E.g. Don't connect (in China) or Use Tor with bridges (in Belarus) --> + <string name="tor_network_setting_summary">Automatic: %1$s (in %2$s)</string> + <string name="tor_mobile_data_title">Use mobile data</string> + + <!-- Settings Security and Panic --> + <string name="security_settings_title">Security</string> + <string name="pref_lock_title">Screen lock</string> + <string name="pref_lock_summary">Use the device\'s screen lock to protect Briar Mailbox while signed in</string> + <string name="pref_lock_disabled_summary">To use this feature, set up a screen lock for your device</string> + <string name="pref_lock_timeout_title">Screen lock inactivity timeout</string> + <!-- The %s placeholder is replaced with the following time spans, e.g. 5 Minutes, 1 Hour --> + <string name="pref_lock_timeout_summary">When not using Briar Mailbox, automatically lock it after %s</string> + <!-- Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s" --> + <string name="pref_lock_timeout_1">1 minute</string> + <!-- Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s" --> + <string name="pref_lock_timeout_5">5 minutes</string> + <!-- Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s" --> + <string name="pref_lock_timeout_15">15 minutes</string> + <!-- Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s" --> + <string name="pref_lock_timeout_30">30 minutes</string> + <!-- Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s" --> + <string name="pref_lock_timeout_60">1 hour</string> + <string name="pref_lock_timeout_never">Never</string> + <string name="pref_lock_timeout_never_summary">Never lock Briar Mailbox automatically</string> + + <string name="change_password">Change password</string> + <string name="current_password">Current password</string> + <string name="choose_new_password">New password</string> + <string name="confirm_new_password">Confirm new password</string> + <string name="password_changed">Password has been changed.</string> + <string name="panic_setting">Panic button setup</string> + <string name="panic_setting_title">Panic button</string> + <string name="panic_setting_hint">Configure how Briar Mailbox will react when you use a panic button app</string> + <string name="panic_app_setting_title">Panic Button App</string> + <string name="unknown_app">an unknown app</string> + <string name="panic_app_setting_summary">No app has been set</string> + <string name="panic_app_setting_none">None</string> + <string name="dialog_title_connect_panic_app">Confirm Panic App</string> + <string name="dialog_message_connect_panic_app">Are you sure that you want to allow %1$s to trigger destructive panic button actions?</string> + <string name="panic_setting_signout_title">Sign Out</string> + <string name="panic_setting_signout_summary">Sign out of Briar Mailbox if a panic button is pressed</string> + <string name="purge_setting_title">Delete Account</string> + <string name="purge_setting_summary">Delete your Briar Mailbox account if a panic button is pressed. Caution: This will permanently delete your identities, contacts and messages</string> + <string name="uninstall_setting_title">Uninstall Briar Mailbox</string> + <string name="uninstall_setting_summary">This requires manual confirmation in a panic event</string> + + <!-- Settings Notifications --> + <string name="notification_settings_title">Notifications</string> + <string name="notify_sign_in_title">Remind me to sign in</string> + <string name="notify_sign_in_summary">Show a reminder when the phone starts or the app has been updated</string> + <string name="notify_private_messages_setting_title">Private messages</string> + <string name="notify_private_messages_setting_summary">Show alerts for private messages</string> + <string name="notify_private_messages_setting_summary_26">Configure alerts for private messages</string> + <string name="notify_group_messages_setting_title">Group messages</string> + <string name="notify_group_messages_setting_summary">Show alerts for group messages</string> + <string name="notify_group_messages_setting_summary_26">Configure alerts for group messages</string> + <string name="notify_forum_posts_setting_title">Forum posts</string> + <string name="notify_forum_posts_setting_summary">Show alerts for forum posts</string> + <string name="notify_forum_posts_setting_summary_26">Configure alerts for forum posts</string> + <string name="notify_blog_posts_setting_title">Blog posts</string> + <string name="notify_blog_posts_setting_summary">Show alerts for blog posts</string> + <string name="notify_blog_posts_setting_summary_26">Configure alerts for blog posts</string> + <string name="notify_vibration_setting">Vibrate</string> + <string name="notify_lock_screen_setting_title">Lock Screen</string> + <string name="notify_lock_screen_setting_summary">Show notifications on the lock screen</string> + <string name="notify_sound_setting">Sound</string> + <string name="notify_sound_setting_default">Default ringtone</string> + <string name="notify_sound_setting_disabled">None</string> + <string name="choose_ringtone_title">Choose ringtone</string> + <string name="cannot_load_ringtone">Cannot load ringtone</string> + + <!-- Settings Feedback --> + <string name="feedback_settings_title">Feedback</string> + <string name="send_feedback">Send feedback</string> + + <!-- Link Warning --> + <string name="link_warning_title">Link Warning</string> + <string name="link_warning_intro">You are about to open the following link with an external app.</string> + <string name="link_warning_text">This can be used to identify you. Think about whether you trust the person that sent you this link and consider opening it with Orfox.</string> + <string name="link_warning_open_link">Open Link</string> + + <!-- Crash Reporter --> + <string name="crash_report_title">Briar Mailbox Crash Report</string> + <string name="briar_crashed">Sorry, Briar Mailbox has crashed.</string> + <string name="not_your_fault">This is not your fault.</string> + <string name="please_send_report">Please help us build a better Briar Mailbox by sending us a crash report.</string> + <string name="report_is_encrypted">We promise that the report is encrypted and sent securely.</string> + <string name="feedback_title">Feedback</string> + <string name="describe_crash">Describe what happened (optional)</string> + <string name="enter_feedback">Enter your feedback</string> + <string name="optional_contact_email">Your email address (optional)</string> + <string name="include_debug_report_crash">Include anonymous data about the crash</string> + <string name="include_debug_report_feedback">Include anonymous data about this device</string> + <string name="could_not_load_report_data">Could not load report data.</string> + <string name="send_report">Send report</string> + <string name="close">Close</string> + <string name="dev_report_saved">Report saved. It will be sent the next time you log into Briar Mailbox.</string> + + <!-- Sign Out --> + <string name="progress_title_logout">Signing out of Briar Mailbox…</string> + + <!-- Screen Filters & Tapjacking --> + <string name="screen_filter_title">Screen overlay detected</string> + <string name="screen_filter_body">Another app is drawing on top of Briar Mailbox. To protect your security, Briar Mailbox will not respond to touches when another app is drawing on top.\n\nThe following apps might be drawing on top:\n\n%1$s</string> + <string name="screen_filter_allow">Allow these apps to draw on top</string> + + <!-- Permission Requests --> + <string name="permission_camera_title">Camera permission</string> + <string name="permission_camera_request_body">To scan the QR code, Briar Mailbox needs access to the camera.</string> + <string name="permission_camera_denied_body">You have denied access to the camera, but adding contacts requires using the camera.\n\nPlease consider granting access.</string> + <string name="permission_camera_denied_toast">Camera permission was not granted</string> + <string name="qr_code">QR code</string> + <string name="show_qr_code_fullscreen">Show QR code fullscreen</string> + + <!-- App Locking --> + <string name="lock_unlock">Unlock Briar Mailbox</string> + <string name="lock_unlock_verbose">Enter your device PIN, pattern or password to unlock Briar Mailbox</string> + <string name="lock_is_locked">Briar Mailbox is locked</string> + <string name="lock_tap_to_unlock">Tap to unlock</string> + + <!-- Overview --> + <string name="overview">Overview</string> + <string name="mailbox_pairing">Pair with Briar</string> + <string name="mailbox_paired">Succesfully paired</string> + <string name="mailbox_already_paired">Your Mailbox is already paired with this Briar account</string> + <string name="mailbox_unpaired">not paired</string> +</resources> diff --git a/mailbox-android/src/main/res/values/styles.xml b/mailbox-android/src/main/res/values/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..a77c7649737da2a1605338fc4d200a563689a1b3 --- /dev/null +++ b/mailbox-android/src/main/res/values/styles.xml @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + + <style name="BriarToolbar" parent="Widget.AppCompat.Toolbar"> + <item name="android:background">?colorPrimary</item> + <item name="android:textColorPrimary">@color/briar_text_primary_inverse</item> + <item name="android:textSize">@dimen/text_size_medium</item> + <item name="colorPrimary">@color/briar_primary</item> + <item name="titleTextAppearance">@style/BriarToolbarTitleTextAppearance</item> + <item name="subtitleTextAppearance">@style/BriarToolbarSubTitleTextAppearance</item> + <item name="android:theme">@style/BriarToolbarTheme</item> + <item name="popupTheme">@style/PopupMenu</item> + </style> + + <style name="BriarToolbarTheme"> + <item name="colorControlNormal">@color/briar_text_primary_inverse</item> + </style> + + <style name="BriarToolbarTitleTextAppearance" parent="TextAppearance.Widget.AppCompat.Toolbar.Title"> + <item name="android:textColor">@color/briar_text_primary_inverse</item> + </style> + + <style name="BriarToolbarSubTitleTextAppearance" parent="TextAppearance.Widget.AppCompat.Toolbar.Subtitle"> + <item name="android:textColor">@color/briar_text_secondary_inverse</item> + </style> + + <style name="PopupMenu" parent="Theme.AppCompat.DayNight.DarkActionBar"> + <item name="android:colorBackground">@color/window_background</item> + </style> + + <style name="ButtonTheme" parent="Theme.AppCompat.DayNight"> + <!-- A strange hack needed only to override button color on all API levels --> + <item name="colorAccent">@color/briar_button_background_color</item> + </style> + + <style name="BriarButton" parent="Widget.AppCompat.Button.Colored"> + <item name="android:theme">@style/ButtonTheme</item> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:textSize">@dimen/text_size_medium</item> + <item name="android:padding">@dimen/margin_large</item> + <item name="android:textColor">@color/button_text</item> + </style> + + <style name="BriarButtonFlat.Negative" parent="Widget.AppCompat.Button.Borderless"> + <item name="android:textColor">@color/briar_button_text_negative</item> + <item name="android:textSize">@dimen/text_size_medium</item> + </style> + + <style name="BriarButtonFlat.Positive" parent="Widget.AppCompat.Button.Borderless"> + <item name="android:textColor">@color/briar_button_text_positive</item> + <item name="android:textSize">@dimen/text_size_medium</item> + </style> + + <style name="BriarButtonFlat.Neutral" parent="Widget.AppCompat.Button.Borderless"> + <item name="android:textColor">@color/briar_button_text_neutral</item> + <item name="android:textSize">@dimen/text_size_medium</item> + </style> + + <style name="BriarButtonFlat.Positive.Tiny" parent="BriarButtonFlat.Positive"> + <item name="android:textSize">@dimen/text_size_tiny</item> + <item name="android:padding">@dimen/margin_medium</item> + <item name="android:minWidth">@dimen/button_size</item> + </style> + + <style name="Divider"> + <item name="android:background">@color/divider</item> + </style> + + <style name="Divider.Horizontal" parent="Divider"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">1px</item> + </style> + + <style name="Divider.ContactList" parent="Divider"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">1px</item> + <item name="android:layout_marginLeft">72dp</item> + </style> + + <style name="Divider.ThreadItem" parent="Divider"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">1dp</item> + </style> + + <style name="BriarAvatar"> + <item name="civ_border_width">@dimen/avatar_border_width</item> + <item name="civ_border_color">?android:attr/textColorSecondary</item> + </style> + + <style name="TextMessage"> + <item name="android:textIsSelectable">true</item> + <item name="android:textSize">@dimen/text_size_medium</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> + </style> + + <style name="TextMessage.Notice"> + <item name="android:textIsSelectable">true</item> + <item name="android:textSize">@dimen/text_size_small</item> + <item name="android:textColor">?android:attr/textColorSecondary</item> + <item name="android:textStyle">italic</item> + </style> + + <style name="TextMessage.Timestamp"> + <item name="android:textIsSelectable">false</item> + <item name="android:textSize">@dimen/text_size_tiny</item> + <item name="android:textColor">?android:attr/textColorTertiary</item> + <item name="android:maxLines">1</item> + </style> + + <style name="DiscussionLevelIndicator"> + <item name="android:layout_marginLeft">4dp</item> + <item name="android:background">@color/thread_indicator</item> + </style> + + <style name="BriarCard" parent="CardView"> + <item name="cardUseCompatPadding">true</item> + <item name="cardBackgroundColor">@color/card_background</item> + <item name="android:layout_margin">@dimen/margin_small</item> + </style> + +</resources> \ No newline at end of file diff --git a/mailbox-android/src/main/res/values/themes.xml b/mailbox-android/src/main/res/values/themes.xml new file mode 100644 index 0000000000000000000000000000000000000000..806783e3aaca2d4b32586634993b630d8363482e --- /dev/null +++ b/mailbox-android/src/main/res/values/themes.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <style name="BriarTheme" parent="Theme.AppCompat.DayNight.DarkActionBar"> + <item name="colorPrimary">@color/briar_primary</item> + <item name="colorPrimaryDark">@color/briar_primary_dark</item> + <item name="colorAccent">@color/briar_accent</item> + <item name="android:textColorLink">@color/briar_text_link</item> + <item name="android:windowBackground">@color/window_background</item> + <item name="android:windowAnimationStyle">@style/ActivityAnimation</item> + <item name="alertDialogTheme">@style/BriarDialogTheme.Neutral</item> + <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item> + </style> + + <style name="BriarTheme.NoActionBar" parent="BriarTheme"> + <item name="windowActionBar">false</item> + <item name="windowNoTitle">true</item> + <item name="toolbarStyle">@style/BriarToolbar</item> + </style> + + <style name="ActivityAnimation" parent="@android:style/Animation.Activity"> + <item name="android:activityOpenEnterAnimation">@anim/screen_new_in</item> + <item name="android:activityOpenExitAnimation">@anim/screen_old_out</item> + <item name="android:activityCloseEnterAnimation">@anim/screen_old_in</item> + <item name="android:activityCloseExitAnimation">@anim/screen_new_out</item> + </style> + + <style name="BriarDialogTheme" parent="Theme.AppCompat.DayNight.Dialog"> + <item name="colorPrimary">@color/briar_primary</item> + <item name="colorPrimaryDark">@color/briar_primary_dark</item> + <item name="colorAccent">@color/briar_accent</item> + <item name="buttonBarPositiveButtonStyle">@style/BriarButtonFlat.Positive</item> + <item name="buttonBarNeutralButtonStyle">@style/BriarButtonFlat.Neutral</item> + <item name="buttonBarNegativeButtonStyle">@style/BriarButtonFlat.Negative</item> + <item name="android:textColorLink">@color/briar_text_link</item> + <item name="android:windowBackground">@color/window_background</item> + <item name="android:windowAnimationStyle">@style/DialogAnimation</item> + <item name="android:filterTouchesWhenObscured">true</item> + </style> + + <!-- Use this with care. Only used for the screen filter warning dialog --> + <style name="BriarDialogThemeNoFilter" parent="BriarDialogTheme"> + <item name="android:filterTouchesWhenObscured">false</item> + </style> + + <!-- Uses neutral colors for the buttons --> + <style name="BriarDialogTheme.Neutral" parent="BriarDialogTheme"> + <item name="buttonBarPositiveButtonStyle">@style/BriarButtonFlat.Neutral</item> + <item name="buttonBarNeutralButtonStyle">@style/BriarButtonFlat.Neutral</item> + <item name="buttonBarNegativeButtonStyle">@style/BriarButtonFlat.Neutral</item> + </style> + + <style name="DialogAnimation" parent="@android:style/Animation.Dialog"> + <item name="android:windowEnterAnimation">@anim/fade_in</item> + <item name="android:windowExitAnimation">@anim/fade_out</item> + </style> + + <style name="OnboardingDialogTheme" parent="BriarDialogTheme"> + <item name="android:background">@color/briar_primary</item> + <item name="android:textColorPrimary">@color/briar_text_primary_inverse</item> + <item name="android:textColorSecondary">@color/briar_text_secondary_inverse</item> + <item name="buttonBarNeutralButtonStyle">@style/Widget.AppCompat.Button.Borderless</item> + </style> + +</resources> \ No newline at end of file diff --git a/mailbox-android/src/main/res/xml/panic_preferences.xml b/mailbox-android/src/main/res/xml/panic_preferences.xml new file mode 100644 index 0000000000000000000000000000000000000000..d823e6f0fc77b768166cd3fa84cba7f8df31a9cd --- /dev/null +++ b/mailbox-android/src/main/res/xml/panic_preferences.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<PreferenceScreen + xmlns:android="http://schemas.android.com/apk/res/android"> + + <ListPreference + android:icon="@android:drawable/ic_menu_close_clear_cancel" + android:key="pref_key_panic_app" + android:summary="@string/panic_app_setting_summary" + android:title="@string/panic_app_setting_title"/> + + <SwitchPreference + android:defaultValue="true" + android:enabled="false" + android:key="pref_key_lock" + android:summary="@string/panic_setting_signout_summary" + android:title="@string/panic_setting_signout_title"/> + + <SwitchPreference + android:defaultValue="false" + android:enabled="false" + android:key="pref_key_purge" + android:summary="@string/purge_setting_summary" + android:title="@string/purge_setting_title"/> + + <SwitchPreference + android:defaultValue="false" + android:enabled="false" + android:key="pref_key_uninstall" + android:summary="@string/uninstall_setting_summary" + android:title="@string/uninstall_setting_title"/> + +</PreferenceScreen> diff --git a/mailbox-android/src/main/res/xml/settings.xml b/mailbox-android/src/main/res/xml/settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..f325934e97334374e649d108a1cbabbd76f3580b --- /dev/null +++ b/mailbox-android/src/main/res/xml/settings.xml @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="utf-8"?> +<PreferenceScreen + xmlns:android="http://schemas.android.com/apk/res/android"> + <PreferenceCategory + android:layout="@layout/preferences_category" + android:title="@string/display_settings_title"> + + <ListPreference + android:defaultValue="default" + android:entryValues="@array/pref_language_values" + android:key="pref_key_language" + android:summary="%s" + android:title="@string/pref_language_title"/> + + <ListPreference + android:defaultValue="@string/pref_theme_light_value" + android:entries="@array/pref_theme_entries" + android:entryValues="@array/pref_theme_values" + android:key="pref_key_theme" + android:summary="%s" + android:title="@string/pref_theme_title"/> + + </PreferenceCategory> + + <PreferenceCategory + android:layout="@layout/preferences_category" + android:title="@string/network_settings_title"> + + <ListPreference + android:defaultValue="false" + android:entries="@array/bt_setting_names" + android:entryValues="@array/boolean_array" + android:key="pref_key_bluetooth" + android:persistent="false" + android:summary="%s" + android:title="@string/bluetooth_setting"/> + + <ListPreference + android:defaultValue="0" + android:entries="@array/tor_network_setting_names" + android:entryValues="@array/tor_network_setting_values" + android:key="pref_key_tor_network" + android:persistent="false" + android:summary="%s" + android:title="@string/tor_network_setting"/> + + <SwitchPreference + android:defaultValue="true" + android:key="pref_key_tor_mobile_data" + android:persistent="false" + android:title="@string/tor_mobile_data_title" + android:widgetLayout="@layout/preference_switch_compat"/> + + </PreferenceCategory> + + <PreferenceCategory + android:layout="@layout/preferences_category" + android:title="@string/security_settings_title"> + + <SwitchPreference + android:enabled="false" + android:key="pref_key_lock" + android:persistent="false" + android:summary="@string/pref_lock_summary" + android:title="@string/pref_lock_title" + android:widgetLayout="@layout/preference_switch_compat"/> + + <ListPreference + android:defaultValue="@string/pref_lock_timeout_value_default" + android:dependency="pref_key_lock" + android:entries="@array/pref_key_lock_timeout_entries" + android:entryValues="@array/pref_key_lock_timeout_values" + android:key="pref_key_lock_timeout" + android:persistent="false" + android:summary="@string/pref_lock_timeout_summary" + android:title="@string/pref_lock_timeout_title"/> + + <Preference + android:key="pref_key_change_password" + android:title="@string/change_password"> + + <intent + android:targetClass="org.briarproject.briar.android.login.ChangePasswordActivity" + android:targetPackage="@string/app_package"/> + </Preference> + + </PreferenceCategory> + + <PreferenceCategory + android:layout="@layout/preferences_category" + android:title="@string/panic_setting_title"> + + <Preference + android:summary="@string/panic_setting_hint" + android:title="@string/panic_setting"> + + <intent + android:targetClass="org.briarproject.briar.android.panic.PanicPreferencesActivity" + android:targetPackage="@string/app_package"/> + + </Preference> + + </PreferenceCategory> + + <PreferenceCategory + android:layout="@layout/preferences_category" + android:title="@string/notification_settings_title"> + + <SwitchPreference + android:defaultValue="true" + android:key="pref_key_notify_sign_in" + android:summary="@string/notify_sign_in_summary" + android:title="@string/notify_sign_in_title" + android:widgetLayout="@layout/preference_switch_compat"/> + + <SwitchPreference + android:defaultValue="true" + android:key="pref_key_notify_private_messages" + android:persistent="false" + android:summary="@string/notify_private_messages_setting_summary" + android:title="@string/notify_private_messages_setting_title" + android:widgetLayout="@layout/preference_switch_compat"/> + + <SwitchPreference + android:defaultValue="true" + android:key="pref_key_notify_group_messages" + android:persistent="false" + android:summary="@string/notify_group_messages_setting_summary" + android:title="@string/notify_group_messages_setting_title" + android:widgetLayout="@layout/preference_switch_compat"/> + + <SwitchPreference + android:defaultValue="true" + android:key="pref_key_notify_forum_posts" + android:persistent="false" + android:summary="@string/notify_forum_posts_setting_summary" + android:title="@string/notify_forum_posts_setting_title" + android:widgetLayout="@layout/preference_switch_compat"/> + + <SwitchPreference + android:defaultValue="true" + android:key="pref_key_notify_blog_posts" + android:persistent="false" + android:summary="@string/notify_blog_posts_setting_summary" + android:title="@string/notify_blog_posts_setting_title" + android:widgetLayout="@layout/preference_switch_compat"/> + + <SwitchPreference + android:defaultValue="false" + android:key="pref_key_notify_lock_screen" + android:persistent="false" + android:summary="@string/notify_lock_screen_setting_summary" + android:title="@string/notify_lock_screen_setting_title" + android:visibility="gone" + android:widgetLayout="@layout/preference_switch_compat"/> + + <SwitchPreference + android:defaultValue="true" + android:key="pref_key_notify_vibration" + android:persistent="false" + android:title="@string/notify_vibration_setting" + android:widgetLayout="@layout/preference_switch_compat"/> + + <Preference + android:key="pref_key_notify_sound" + android:title="@string/notify_sound_setting"/> + + </PreferenceCategory> + + <PreferenceCategory + android:layout="@layout/preferences_category" + android:title="@string/feedback_settings_title"/> + + <Preference + android:key="pref_key_send_feedback" + android:title="@string/send_feedback"/> + + <PreferenceCategory + android:layout="@layout/preferences_category" + android:title="Testing"> + + <Preference + android:key="pref_key_test_data" + android:title="Create Test Data"> + + <intent + android:targetClass="org.briarproject.briar.android.test.TestDataActivity" + android:targetPackage="@string/app_package"/> + </Preference> + + <Preference + android:key="pref_key_explode" + android:title="Crash"/> + + </PreferenceCategory> + +</PreferenceScreen> diff --git a/mailbox-android/src/screenshotDebug/AndroidManifest.xml b/mailbox-android/src/screenshotDebug/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..7f44f753f9c05204075505dacbc93319c094208b --- /dev/null +++ b/mailbox-android/src/screenshotDebug/AndroidManifest.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest + package="org.briarproject.mailbox" + xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- The following permissions are only needed for taking automatic screenshots (fastlane) --> + + <!-- Allows unlocking your device and activating its screen so UI tests can succeed --> + <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/> + <uses-permission android:name="android.permission.WAKE_LOCK"/> + + <!-- Allows for storing and retrieving screenshots --> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + + <!-- Allows changing locales --> + <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" /> +</manifest> diff --git a/mailbox-android/src/screenshotDebug/res/values/strings.xml b/mailbox-android/src/screenshotDebug/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..6a7574e563e9ee2efe29546c968cbaaa1631851c --- /dev/null +++ b/mailbox-android/src/screenshotDebug/res/values/strings.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name" translatable="false">Briar</string> + <string name="app_package" translatable="false">org.briarproject.briar.android.screenshot.debug</string> +</resources> diff --git a/mailbox-android/src/test/java/android/net/http/AndroidHttpClient.java b/mailbox-android/src/test/java/android/net/http/AndroidHttpClient.java new file mode 100644 index 0000000000000000000000000000000000000000..e83fb8177a3feb5317a9ff82c7edf079f08c4575 --- /dev/null +++ b/mailbox-android/src/test/java/android/net/http/AndroidHttpClient.java @@ -0,0 +1,7 @@ +package android.net.http; + +// This class is here to fix an issue with Robolectric. +// https://github.com/robolectric/robolectric/issues/1862 +// TODO: Check if this class can be removed on next Robolectric update +public class AndroidHttpClient { +} \ No newline at end of file diff --git a/mailbox-android/src/test/java/org/briarproject/mailbox/android/TestMailboxApplication.java b/mailbox-android/src/test/java/org/briarproject/mailbox/android/TestMailboxApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..f1e4c1ee1431623a5e271d8ba49cb6c3705ea381 --- /dev/null +++ b/mailbox-android/src/test/java/org/briarproject/mailbox/android/TestMailboxApplication.java @@ -0,0 +1,58 @@ +package org.briarproject.mailbox.android; + +import android.app.Application; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import org.briarproject.bramble.BrambleCoreModule; + +import java.util.Collection; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import static java.util.Collections.emptyList; + +/** + * This class only exists to avoid static initialisation of ACRA + */ +public class TestMailboxApplication extends Application + implements MailboxApplication { + + private static final Logger LOG = + Logger.getLogger(TestMailboxApplication.class.getName()); + + private AndroidComponent applicationComponent; + private volatile SharedPreferences prefs; + + @Override + public void onCreate() { + super.onCreate(); + LOG.info("Created"); + + prefs = PreferenceManager.getDefaultSharedPreferences(this); + Localizer.initialize(prefs); + applicationComponent = DaggerAndroidComponent.builder() + .appModule(new AppModule(this)) + .build(); + + // We need to load the eager singletons directly after making the + // dependency graphs + BrambleCoreModule.initEagerSingletons(applicationComponent); + AndroidEagerSingletons.initEagerSingletons(applicationComponent); + } + + @Override + public Collection<LogRecord> getRecentLogRecords() { + return emptyList(); + } + + @Override + public AndroidComponent getApplicationComponent() { + return applicationComponent; + } + + @Override + public SharedPreferences getDefaultSharedPreferences() { + return prefs; + } +} diff --git a/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/ChangePasswordActivityTest.java b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/ChangePasswordActivityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5c86e541fc531a8bb6a4e4a9ba9e8370c327b110 --- /dev/null +++ b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/ChangePasswordActivityTest.java @@ -0,0 +1,158 @@ +package org.briarproject.mailbox.android.login; + +import android.support.design.widget.TextInputLayout; +import android.widget.Button; +import android.widget.EditText; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.TestMailboxApplication; +import org.briarproject.mailbox.android.controller.handler.ResultHandler; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import static junit.framework.Assert.assertEquals; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.NONE; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_STRONG; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.STRONG; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.WEAK; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = 21, application = TestMailboxApplication.class, + packageName = "org.briarproject.mailbox") +public class ChangePasswordActivityTest { + + private TestChangePasswordActivity changePasswordActivity; + private TextInputLayout passwordConfirmationWrapper; + private EditText currentPassword; + private EditText newPassword; + private EditText newPasswordConfirmation; + private StrengthMeter strengthMeter; + private Button changePasswordButton; + + @Mock + private PasswordController passwordController; + @Captor + private ArgumentCaptor<ResultHandler<Boolean>> resultCaptor; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + changePasswordActivity = + Robolectric.setupActivity(TestChangePasswordActivity.class); + passwordConfirmationWrapper = changePasswordActivity + .findViewById(R.id.new_password_confirm_wrapper); + currentPassword = changePasswordActivity + .findViewById(R.id.current_password_entry); + newPassword = changePasswordActivity + .findViewById(R.id.new_password_entry); + newPasswordConfirmation = changePasswordActivity + .findViewById(R.id.new_password_confirm); + strengthMeter = changePasswordActivity + .findViewById(R.id.strength_meter); + changePasswordButton = changePasswordActivity + .findViewById(R.id.change_password); + } + + private void testStrengthMeter(String pass, float strength, int color) { + newPassword.setText(pass); + assertEquals(strengthMeter.getProgress(), + (int) (strengthMeter.getMax() * strength)); + assertEquals(color, strengthMeter.getColor()); + } + + @Test + public void testPasswordMatchUI() { + // Password mismatch + newPassword.setText("really.safe.password"); + newPasswordConfirmation.setText("really.safe.pass"); + assertEquals(changePasswordButton.isEnabled(), false); + assertEquals(passwordConfirmationWrapper.getError(), + changePasswordActivity + .getString(R.string.passwords_do_not_match)); + // Button enabled + newPassword.setText("really.safe.pass"); + newPasswordConfirmation.setText("really.safe.pass"); + // Confirm that the password mismatch error message is not visible + Assert.assertNotEquals(passwordConfirmationWrapper.getError(), + changePasswordActivity + .getString(R.string.passwords_do_not_match)); + // Nick has not been set, expect the button to be disabled + assertEquals(changePasswordButton.isEnabled(), false); + } + + @Test + public void testChangePasswordUI() { + changePasswordActivity.setPasswordController(passwordController); + // Mock strong password strength answer + when(passwordController.estimatePasswordStrength(anyString())) + .thenReturn(STRONG); + String curPass = "old.password"; + String safePass = "really.safe.password"; + currentPassword.setText(curPass); + newPassword.setText(safePass); + newPasswordConfirmation.setText(safePass); + // Confirm that the create account button is clickable + assertEquals(changePasswordButton.isEnabled(), true); + changePasswordButton.performClick(); + // Verify that the controller's method was called with the correct + // params and get the callback + verify(passwordController, times(1)) + .changePassword(eq(curPass), eq(safePass), + resultCaptor.capture()); + // execute the callbacks + resultCaptor.getValue().onResult(true); + assertEquals(changePasswordActivity.isFinishing(), true); + } + + @Test + public void testStrengthMeterUI() { + Assert.assertNotNull(changePasswordActivity); + // replace the password controller with our mocked copy + changePasswordActivity.setPasswordController(passwordController); + // Mock answers for UI testing only + when(passwordController.estimatePasswordStrength("strong")).thenReturn( + STRONG); + when(passwordController.estimatePasswordStrength("qstrong")).thenReturn( + QUITE_STRONG); + when(passwordController.estimatePasswordStrength("qweak")).thenReturn( + QUITE_WEAK); + when(passwordController.estimatePasswordStrength("weak")).thenReturn( + WEAK); + when(passwordController.estimatePasswordStrength("empty")).thenReturn( + NONE); + // Test the meters progress and color for several values + testStrengthMeter("strong", STRONG, StrengthMeter.GREEN); + Mockito.verify(passwordController, Mockito.times(1)) + .estimatePasswordStrength(eq("strong")); + testStrengthMeter("qstrong", QUITE_STRONG, StrengthMeter.LIME); + Mockito.verify(passwordController, Mockito.times(1)) + .estimatePasswordStrength(eq("qstrong")); + testStrengthMeter("qweak", QUITE_WEAK, StrengthMeter.YELLOW); + Mockito.verify(passwordController, Mockito.times(1)) + .estimatePasswordStrength(eq("qweak")); + testStrengthMeter("weak", WEAK, StrengthMeter.ORANGE); + Mockito.verify(passwordController, Mockito.times(1)) + .estimatePasswordStrength(eq("weak")); + // Not sure this should be the correct behaviour on an empty input ? + testStrengthMeter("empty", NONE, StrengthMeter.RED); + Mockito.verify(passwordController, Mockito.times(1)) + .estimatePasswordStrength(eq("empty")); + } + +} diff --git a/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/PasswordControllerImplTest.java b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/PasswordControllerImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..80aaba3ff5d764c11774ee58cb7adb4dec6bdb2b --- /dev/null +++ b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/PasswordControllerImplTest.java @@ -0,0 +1,58 @@ +package org.briarproject.mailbox.android.login; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; +import org.briarproject.bramble.test.BrambleMockTestCase; +import org.briarproject.bramble.test.ImmediateExecutor; +import org.jmock.Expectations; +import org.junit.Test; + +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; +import static org.briarproject.bramble.util.StringUtils.getRandomString; + +public class PasswordControllerImplTest extends BrambleMockTestCase { + + private final AccountManager accountManager = + context.mock(AccountManager.class); + private final PasswordStrengthEstimator estimator = + context.mock(PasswordStrengthEstimator.class); + + private final Executor ioExecutor = new ImmediateExecutor(); + + private final String oldPassword = getRandomString(10); + private final String newPassword = getRandomString(10); + + @Test + public void testChangePasswordReturnsTrue() { + context.checking(new Expectations() {{ + oneOf(accountManager).changePassword(oldPassword, newPassword); + will(returnValue(true)); + }}); + + PasswordControllerImpl p = new PasswordControllerImpl(accountManager, + ioExecutor, estimator); + + AtomicBoolean capturedResult = new AtomicBoolean(false); + p.changePassword(oldPassword, newPassword, capturedResult::set); + assertTrue(capturedResult.get()); + } + + @Test + public void testChangePasswordReturnsFalseIfOldPasswordIsWrong() { + context.checking(new Expectations() {{ + oneOf(accountManager).changePassword(oldPassword, newPassword); + will(returnValue(false)); + }}); + + PasswordControllerImpl p = new PasswordControllerImpl(accountManager, + ioExecutor, estimator); + + AtomicBoolean capturedResult = new AtomicBoolean(true); + p.changePassword(oldPassword, newPassword, capturedResult::set); + assertFalse(capturedResult.get()); + } +} diff --git a/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/PasswordFragmentTest.java b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/PasswordFragmentTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f37fa089469ac96c7c8d2c8184f9ba6362db537c --- /dev/null +++ b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/PasswordFragmentTest.java @@ -0,0 +1,115 @@ +package org.briarproject.mailbox.android.login; + +import android.support.design.widget.TextInputLayout; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.TestMailboxApplication; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import static junit.framework.Assert.assertEquals; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.NONE; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_STRONG; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.STRONG; +import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.WEAK; +import static org.junit.Assert.assertNotEquals; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.robolectric.shadows.support.v4.SupportFragmentTestUtil.startFragment; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = 21, application = TestMailboxApplication.class, + packageName = "org.briarproject.mailbox") +public class PasswordFragmentTest { + + private PasswordFragment passwordFragment = new PasswordFragment(); + private EditText passwordEntry; + private EditText passwordConfirmation; + private TextInputLayout passwordConfirmationWrapper; + private StrengthMeter strengthMeter; + private Button createAccountButton; + + @Mock + private SetupController setupController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + startFragment(passwordFragment, SetupActivity.class); + + View v = passwordFragment.getView(); + passwordEntry = v.findViewById(R.id.password_entry); + passwordConfirmation = v.findViewById(R.id.password_confirm); + passwordConfirmationWrapper = + v.findViewById(R.id.password_confirm_wrapper); + strengthMeter = v.findViewById(R.id.strength_meter); + createAccountButton = v.findViewById(R.id.next); + } + + @Test + public void testCreateAccountUI() { + String safePass = "really.safe.password"; + + passwordFragment.setupController = setupController; + when(setupController.needToShowDozeFragment()).thenReturn(false); + when(setupController.estimatePasswordStrength(safePass)) + .thenReturn(STRONG); + + passwordEntry.setText(safePass); + passwordConfirmation.setText(safePass); + // Confirm that the create account button is clickable + assertEquals(createAccountButton.isEnabled(), true); + createAccountButton.performClick(); + + // assert controller has been called properly + verify(setupController, times(1)).setPassword(safePass); + verify(setupController, times(1)).createAccount(); + } + + @Test + public void testStrengthMeterUI() { + // Test the meters' progress and color for several values + testStrengthMeter("1234567890ab", STRONG, StrengthMeter.GREEN); + testStrengthMeter("123456789", QUITE_STRONG, StrengthMeter.LIME); + testStrengthMeter("123456", QUITE_WEAK, StrengthMeter.YELLOW); + testStrengthMeter("123", WEAK, StrengthMeter.ORANGE); + testStrengthMeter("", NONE, StrengthMeter.RED); + } + + private void testStrengthMeter(String pass, float strength, int color) { + passwordEntry.setText(pass); + assertEquals(strengthMeter.getProgress(), + (int) (strengthMeter.getMax() * strength)); + assertEquals(color, strengthMeter.getColor()); + } + + + @Test + public void testPasswordMatchUI() { + // Password mismatch + passwordEntry.setText("really.safe.password"); + passwordConfirmation.setText("really.safe.pass"); + assertEquals(createAccountButton.isEnabled(), false); + assertEquals(passwordConfirmationWrapper.getError(), + passwordFragment.getString(R.string.passwords_do_not_match)); + // Button enabled + passwordEntry.setText("really.safe.pass"); + passwordConfirmation.setText("really.safe.pass"); + // Confirm that the password mismatch error message is not visible + assertNotEquals(passwordConfirmationWrapper.getError(), + passwordFragment.getString(R.string.passwords_do_not_match)); + // Passwords match, so button should be enabled + assertEquals(createAccountButton.isEnabled(), true); + } + +} diff --git a/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/SetupActivityTest.java b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/SetupActivityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e2bb2b9f873fafc8cdfa91ac02395bbb85fdfc90 --- /dev/null +++ b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/SetupActivityTest.java @@ -0,0 +1,48 @@ +package org.briarproject.mailbox.android.login; + +import android.support.design.widget.TextInputLayout; +import android.widget.EditText; + +import org.briarproject.mailbox.R; +import org.briarproject.mailbox.android.TestMailboxApplication; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import static junit.framework.Assert.assertEquals; +import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; +import static org.briarproject.bramble.util.StringUtils.getRandomString; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = 21, application = TestMailboxApplication.class, + packageName = "org.briarproject.mailbox") +public class SetupActivityTest { + + private SetupActivity setupActivity; + private TextInputLayout nicknameEntryWrapper; + private EditText nicknameEntry; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + setupActivity = Robolectric.setupActivity(SetupActivity.class); + nicknameEntryWrapper = + setupActivity.findViewById(R.id.nickname_entry_wrapper); + nicknameEntry = setupActivity.findViewById(R.id.nickname_entry); + } + + @Test + public void testNicknameUI() { + Assert.assertNotNull(setupActivity); + String longNick = getRandomString(MAX_AUTHOR_NAME_LENGTH + 1); + nicknameEntry.setText(longNick); + // Nickname should be too long + assertEquals(nicknameEntryWrapper.getError(), + setupActivity.getString(R.string.name_too_long)); + } +} diff --git a/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/SetupControllerImplTest.java b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/SetupControllerImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d40074c01d2aba00404b5e707cf608acddce272b --- /dev/null +++ b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/SetupControllerImplTest.java @@ -0,0 +1,63 @@ +package org.briarproject.mailbox.android.login; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; +import org.briarproject.bramble.test.BrambleMockTestCase; +import org.briarproject.bramble.test.ImmediateExecutor; +import org.jmock.Expectations; +import org.jmock.lib.legacy.ClassImposteriser; +import org.junit.Test; + +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +import static junit.framework.Assert.assertTrue; +import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; +import static org.briarproject.bramble.util.StringUtils.getRandomString; + +public class SetupControllerImplTest extends BrambleMockTestCase { + + private final AccountManager accountManager = + context.mock(AccountManager.class); + private final PasswordStrengthEstimator estimator = + context.mock(PasswordStrengthEstimator.class); + private final SetupActivity setupActivity; + + private final Executor ioExecutor = new ImmediateExecutor(); + + private final String authorName = getRandomString(MAX_AUTHOR_NAME_LENGTH); + private final String password = getRandomString(10); + + public SetupControllerImplTest() { + context.setImposteriser(ClassImposteriser.INSTANCE); + setupActivity = context.mock(SetupActivity.class); + } + + @Test + @SuppressWarnings("ResultOfMethodCallIgnored") + public void testCreateAccount() { + context.checking(new Expectations() {{ + // Set the author name and password + oneOf(setupActivity).setAuthorName(authorName); + oneOf(setupActivity).setPassword(password); + // Get the author name and password + oneOf(setupActivity).getAuthorName(); + will(returnValue(authorName)); + oneOf(setupActivity).getPassword(); + will(returnValue(password)); + // Create the account + oneOf(accountManager).createAccount(authorName, password); + will(returnValue(true)); + }}); + + SetupControllerImpl s = new SetupControllerImpl(accountManager, + ioExecutor, estimator); + s.setSetupActivity(setupActivity); + + AtomicBoolean called = new AtomicBoolean(false); + s.setAuthorName(authorName); + s.setPassword(password); + s.createAccount(result -> called.set(true)); + assertTrue(called.get()); + } +} diff --git a/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/TestChangePasswordActivity.java b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/TestChangePasswordActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..d283e1696165a339b0abbcb51f2bb8e5d9270ad3 --- /dev/null +++ b/mailbox-android/src/test/java/org/briarproject/mailbox/android/login/TestChangePasswordActivity.java @@ -0,0 +1,13 @@ +package org.briarproject.mailbox.android.login; + +/** + * This class exposes the PasswordController and offers the possibility to + * replace it. + */ +public class TestChangePasswordActivity extends ChangePasswordActivity { + + public void setPasswordController(PasswordController passwordController) { + this.passwordController = passwordController; + } + +} diff --git a/mailbox-android/witness.gradle b/mailbox-android/witness.gradle new file mode 100644 index 0000000000000000000000000000000000000000..ace73b9df0fcd33f1847e190cec978e882ad01a5 --- /dev/null +++ b/mailbox-android/witness.gradle @@ -0,0 +1,4 @@ +dependencyVerification { + verify = [ + ] +} diff --git a/settings.gradle b/settings.gradle index 3f3670622d0acfba7ef41fb6a026608542f8379e..1f811046660c95484b2d9ed936a24f29fc259dce 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,3 +5,4 @@ include ':bramble-j2se' include ':briar-api' include ':briar-core' include ':briar-android' +include ':mailbox-android'